Development

Here is a short guide to customizing EasyTMD:

EasyTMD is an HTA application, rather than an executable. HTA applications allow for an extremely small distributable size (in the case of version 2.0, under 200 KB) while being powerful enough for many purposes. They also make the application easy to customize and extend.

The only external piece of the application is a small ActiveX control used for the IRC client's socket connections. This is SocketWrench Freeware Edition from Catalyst Development. It is required because there is no internal support for sockets in HTA applications.

The IRC client in version 2.0 has only the minimum functionality necessary for EasyTMD's features, but is built to be extendable. It functions off of a timer in the main EasyTMD program (easytmd.js) which reads information from the server and triggers appropriate events which are set up from the calling application.

The main part of the program controls the IRC client, channel and DCC chat text parsing, and updates the GUI to reflect this process. It could be divided into four sets of functions: event handlers, control processors run from another timer, text parsing functions, and GUI functions.

    oIRC.addHandler("onconnect", ircconnected);
    oIRC.addHandler("ondisconnect", ircdisconnected);
    oIRC.addHandler("ontext", irctext);
    oIRC.addHandler("ondccchat", ircdccchat);
    oIRC.addHandler("ondccchatconnect", ircdccchatconnect);
    oIRC.addHandler("ondccsend", ircdccsend);
    oIRC.addHandler("ondccsendconnect", ircdccsendconnect);
    oIRC.addHandler("onupdate", ircupdatenext);
Setting event handlers

function ircupdatenext(iStatus) {
 var iTimeout = 21;
 switch (iStatus) {
 case 1 : // connecting
  if ((new Date()).valueOf() > oIRC.connectStartTime + (1000 * 5)) {
   processmessage("Unable to connect to " + f.elements["Server"].value + "...");
   outmessage("Unable to connect to " + f.elements["Server"].value +
      " (" + oIRC.hostAddress + ")...\n");
  }
  break;
 case 2 : // connected but not logged in
  if ((new Date()).valueOf() > oIRC.connectStartTime + (1000 * 55)) {
   oIRC.connect(f.elements["Server"].value, 6667);
   processmessage("Retrying " + f.elements["Server"].value + "...");
   outmessage("Retrying " + f.elements["Server"].value +
      " (" + oIRC.hostAddress + ")...\n");
  }
 case 4 : // disconnecting
  iTimeout = 102
  break;
 }
 oIRC.timer = window.setTimeout("ircupdate();", 21);
}
Control processors

function parsetrigger(sText) {
 var aText = sText.split(" ");
 var sTrigger = "";
 if (aText[1] && aText[1].length && aText[0].indexOf("File") > -1) {
  for (var i=0; i<aText.length; i++) {
   if (aText[i].indexOf("Trigger") > -1) {
    for(; i<aText.length && aText[i] && aText[i].length && aText[i].indexOf(chr(187)) == -1; i++) {
     sTrigger += aText[i] + " ";
    }
    sTrigger += aText[i];
    sTrigger = sTrigger.substring(sTrigger.indexOf(chr(171)) + 1)
    for (var i=sTrigger.length; i > 0; i--) {
     if (sTrigger.charCodeAt(i) == 187) {
      sTrigger=sTrigger.substring(0, i);
      break;
     } else sTrigger=sTrigger.substring(0, i);
    }
    break;
   }
  }
  if (sTrigger.length) {
   sTrigger = sTrigger.substring(sTrigger.indexOf(" ") + 1);
   sTrigger = sTrigger.substring(sTrigger.indexOf(" ") + 1);
   // allow for text [already parsed trigger 1](space)(separator)(space)(/ctcp)[trigger 2]
   // discard extra triggers
   if (sTrigger.indexOf("/ctcp") > -1) sTrigger = sTrigger.substring(0, sTrigger.indexOf("/ctcp") - 3)
  }
 }
 return sTrigger;
}
Text parsing function

function showpane(iPane) {
 if (iPane != -1) {
  document.all["WEB"].style.display = "inline";
  document.all["CREATEMOVIELIST"].style.display = "none";
  document.all["STATUS"].style.display = "none";
  document.all["SETTINGS"].style.display = "none";
  document.all["FILES"].style.display = "none";
  document.all["IRC"].style.display = "none";
  document.all["HELP0"].style.display = "none";
  document.all["HELP1"].style.display = "none";
  document.all["HELP2"].style.display = "none";
  document.all["BTN_SETUP"].className = "topbutton";
  document.all["BTN_FIND"].className = "topbutton";
  document.all["BTN_STATUS"].className = "topbutton";
  document.all["BTN_FILES"].className = "topbutton";
  document.all["BTN_IRC"].className = "topbutton";
 }
 switch (iPane) {
 case -2 :
  document.all["BTN_IRC"].className = "topbuttonselected";
  document.all["IRC"].style.display = "inline";
  break;
 case -1 :
  var oWshShell = new ActiveXObject("WScript.Shell");
  oWshShell.SendKeys("%+{TAB}");
  window.blur();
  window.moveTo(-800, -600);
  window.onfocus = unminimize;
  break;
 case 0 :
  document.all["HELP0"].style.display = "inline";
  document.all["BTN_SETUP"].className = "topbuttonselected";
  document.all["SETTINGS"].style.display = "inline";
  loadsettings();
  break;
 case 1 :
  document.all["BTN_FIND"].className = "topbuttonselected";
  document.all["CREATEMOVIELIST"].style.display = "inline";
  document.all["HELP1"].style.display = "inline";
  f.elements["Movie"].value = "";
  f.elements["Movie"].focus();
  break;
 case 2 :
  document.all["BTN_STATUS"].className = "topbuttonselected";
  //if (!aNew.length) document.all["HELP2"].style.display = "inline";
  document.all["STATUS"].style.display = "inline";
  break;
 case 3 :
  document.all["FILES"].style.display = "inline";
  document.all["WEB"].style.display = "none";
  document.all["BTN_FILES"].className = "topbuttonselected";
  document.all["BTN_COPY"].onclick = copyselected;
  refreshfiles();
  break;
 }
}
GUI (graphical user interface) function

This is hybrid object oriented and procedural programming, meant to be easily understood so that extending or adding to it is... Easy.

In the future, EasyTMD will be modified with a plugin architecture to allow it to be used on any IRC server and channels with FServes running. For now, modifying the event handlers and possibly the text parsing functions will allow EasyTMD to function on other networks and channels. Using Mozilla's cross platform framework instead of Microsoft's HTA is also a possibility to all EasyTMD to run on Linux and Macintosh.