# Time-stamp: <2003-12-03 11:35:57 crabbkw> # Code and design by Casey Crabb (crabbkw@nafai.dyndns.org) # This code is licensed under the BSD license. # See the LICENSE file for details # # Copyright Casey Crabb (crabbkw@nafai.dyndns.org) October 2002 # import os import string import pprint import traceback import codecs import types import xml.dom.minidom import xml.dom pp = pprint.PrettyPrinter(indent=4) class Profile: def __init__(self): self.name = None self.server = None self.port = None self.user = None self.logdir = None self.password = None self.resource = None self.commands = {} # key is one of the command keys, see command class. self.colors = {} # key is one of, {desc, messagebody, key, sep, default, error, time, user, status} self.aliases = {} self.audiocmd = None self.audioargs = None self.priority = 6 self.autoStatusList = [] self.encoding = "iso-8859-1" self.sessioncolors = {} self.sessioncommands = {} self.DTCPPort = 8000 self.modules = {} # keys are strings of module names, values are module instances self.loadedModules = [] # contains a list of modules objects that are loaded, in order of loading. self.moduleConfigs = {} # keys are names of modules, values are XMLDom nodes. self.moduleCommands = {} # keys are command names, values are [commandString, commandFunction] self.profileModules = [] # contains a list of module configurations in order they originally appeared # # list is: "default (true/false)", # "prettyname (must be the same as key excepting case", # "help text" # self.switches = { "debug" : [ "false", "debug" , "show debug messages?"], "statusshow" : [ "true" , "statusShow" , "show presence updates?" ], "ssl" : [ "false", "ssl" , "encrypt communications over an SSL layer?" ], "clearpass" : [ "false", "clearpass" , "transmit password as clear text ?" ], "colors" : [ "true" , "Colors" , "use colors when displaying?" ], "ringbell" : [ "true" , "ringBell" , "ring the bell on message arrival?" ], "confringbell" : [ "true" , "confRingBell" , "ring the bell on message from conference?" ], "nickprompt" : [ "false", "nickPrompt" , "Use the nick you're writing to as the prompt?" ], "allowinterrupt" : [ "false", "allowInterrupt", "Allow new incoming messages to interrupt your composing a message?" ], "autostatus" : [ "false", "autoStatus" , "use autostatus rules?" ], "statusnag" : [ "false", "statusNag" , "warn if status is not online while sending messages?" ], "confsuppress" : [ "false", "confSuppress" , "Suppress the 'from line' on conference messages?" ], "igndupstatus" : [ "true" , "ignDupStatus" , "Ignore duplicate status messages?" ], "clearline" : [ "true", "clearLine" , "Clear the current line then display message?" ] } def __repr__(self): return pp.pformat(self.__dict__) def getModuleConfig(self, aMod): if self.moduleConfigs.has_key(aMod): return self.moduleConfigs[aMod] return None def toXML(self): towrite = " " + fix(self.server) + "\n" +\ " " + fix(str(self.port)) + "\n" +\ " " + fix(self.user) + "\n" +\ " " + fix(self.password) + "\n" +\ " " + fix(self.resource) + "\n" +\ " " + fix(str(self.priority)) + "\n" +\ " " + fix(self.encoding) + "\n" if self.audiocmd: towrite = towrite + " " + fix(self.audiocmd) + "\n" if self.audioargs: towrite = towrite + " " + fix(self.audioargs) + "\n" if len(self.colors) > 0: towrite = towrite + " \n" aColors = Colors() for item in self.colors.keys(): thecolor = fix(getHashKeyFromValue(aColors.cdict, self.colors[item])) towrite = towrite + " <" + fix(item) + ">" + thecolor + "\n" towrite = towrite + " \n" if len(self.commands) > 0: towrite = towrite + " \n" for item in self.commands.keys(): towrite = towrite + " <" + fix(item) + ">" + fix(self.commands[item]) + "\n" towrite = towrite + " \n" if len(self.aliases) > 0: towrite = towrite + " \n" for item in self.aliases.keys(): towrite = towrite + " " + fix(self.aliases[item]) + "\n" towrite = towrite + " \n" if self.autoStatusList: towrite = towrite + " \n" for item in self.autoStatusList: towrite = towrite + " \n" towrite = towrite + " \n" if len(self.loadedModules) > 0: towrite = towrite + " \n" self.profileModules = [] # there is some wackiness here to save the module preferences to memory as well as disk. # I have to save it in memory in two places as well.. ICK for aMod in self.loadedModules: amodconfig = " \n" configInfo = aMod.getConfigurationString(" ") if configInfo != None: amodconfig += configInfo amodconfig += " \n" self.profileModules.append(amodconfig) try: modDomNode = xml.dom.minidom.parseString(amodconfig) self.moduleConfigs[aMod.getName()] = modDomNode.documentElement except: pass towrite += amodconfig towrite += " \n" elif len(self.profileModules) > 0: towrite = towrite + " \n" for aMod in self.profileModules: towrite = towrite + aMod + "\n" towrite = towrite + " \n" towrite = towrite + " \n" return towrite class Preferences: def __init__(self): self.profiles = {} self.default = None self.debug = 0 self.commands = Commands() self.colors = Colors() self.commands.initDefaults() self.colors.initDefaults() self.parsePrefs() def createSessionColorsAndCommands(self): for profilename in self.profiles.keys(): profile = self.profiles[profilename] for key in self.colors.colorsdict.keys(): profile.sessioncolors[key] = self.colors.colorsdict[key] for key in profile.colors.keys(): profile.sessioncolors[key] = profile.colors[key] for key in self.commands.commandsdict.keys(): profile.sessioncommands[key] = self.commands.commandsdict[key] for key in profile.commands.keys(): profile.sessioncommands[key] = profile.commands[key] def getDefaultProfile(self): if self.default != None and self.profiles.has_key(self.default): return self.profiles[self.default] return None def getProfile(self, name): if self.profiles.has_key(name): return self.profiles[name] return None def checkCommandCollision(self, commandName, commandString, dictionary): if dictionary.has_key(commandName): return 1 for key in dictionary.keys(): val = dictionary[key] if type(val) == types.ListType: if commandString == val[0]: return 1 else: if commandString == val: return 1 return 0 def getCommand(self, profile, name): if profile.moduleCommands.has_key(name): return profile.moduleCommands[name][0] return profile.sessioncommands[name] def createInitialProfile(self, name, host, useSSL, clearpass, port, user, password, resource, encoding): towrite = '\n' towrite = towrite + "\n"\ " "+host+"\n"\ " "+port+"\n"\ " "+user+"\n"\ " "+fix(password)+"\n"\ " "+fix(resource)+"\n"\ " 6\n"\ " "+encoding+"\n"\ " \n"\ " Auto-away after 10 minutes\n"\ " Auto-away after 20 minutes\n"\ " "\ " \n"\ " \n"\ "\n" try: os.mkdir(os.path.join(os.path.expanduser("~"),".imcom"),0700) except: pass f = codecs.open(os.path.join(os.path.expanduser("~"),".imcom","imcomrc"),"w", "utf8") os.chmod(os.path.join(os.path.expanduser("~"),".imcom","imcomrc"), 0600) f.write(towrite) f.flush() f.close() f = codecs.open(os.path.join(os.path.expanduser("~"),".imcom","imcomrc"), "r", "utf8") self.profiles = {} self.default = None self.parsePrefs() def parsePrefs(self): prefsDoc = None imcomrcfile = os.path.join(os.path.expanduser("~"), ".imcom", "imcomrc") if not os.path.exists(imcomrcfile): return try: prefsDoc = xml.dom.minidom.parse(os.path.join(os.path.expanduser("~"), ".imcom", "imcomrc")) except: traceback.print_exc() return for element in prefsDoc.documentElement.childNodes: # deal with profiles if element.nodeName == "profile": aProfile = self.parseProfile(element) if(aProfile != None): self.profiles[element.getAttribute("name")] = aProfile # deal with default colors if element.nodeName == "color": self.parseDefaultColors(element) # deal with default commands if element.nodeName == "command": self.parseDefaultCommands(element) # deal with the default profile. tmp = prefsDoc.documentElement.getAttribute("default") if self.profiles.has_key(tmp): self.default = tmp else: print "No default, big problems." # create color and command dicts. self.createSessionColorsAndCommands() def parseDefaultCommands(self, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: cmd = getText(child) self.commands.commandsdict[child.nodeName] = cmd def parseDefaultColors(self, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: color = getText(child) if child.nodeName == "background": color = "b" + color if self.colors.cdict.has_key(color): self.colors.colorsdict[child.nodeName] = self.colors.cdict[color] def parseProfile(self, prof): aProfile = Profile() aProfile.name = prof.getAttribute("name") # deal with all the other attributes for switch in aProfile.switches.keys(): result = prof.getAttribute(switch) if len(result) > 0: aProfile.switches[switch][0] = result aProfile.server = self.parseSingleElement(prof, "server") aProfile.port = int(self.parseSingleElement(prof, "port")) aProfile.user = self.parseSingleElement(prof, "user") aProfile.password = self.parseSingleElement(prof, "password") aProfile.resource = self.parseSingleElement(prof, "resource") aProfile.audiocmd = self.parseSingleElement(prof, "audiocmd") aProfile.audioargs = self.parseSingleElement(prof, "audioargs") aProfile.logdir = os.path.join(os.path.expanduser("~"),".imcom",aProfile.name) tmp = self.parseSingleElement(prof, "dtcpport") if tmp != None: aProfile.DTCPPort = int(tmp) tmp = self.parseSingleElement(prof, "priority") if(tmp != None): aProfile.priority = int(tmp) tmp = self.parseSingleElement(prof, "encoding") if(tmp != None): aProfile.encoding = tmp self.parseAutoStatus(aProfile, getElementByName(prof, "autostatus")) self.parseColors(aProfile, getElementByName(prof, "color")) self.parseCommands(aProfile, getElementByName(prof, "command")) self.parseAliases(aProfile, getElementByName(prof, "aliases")) self.parseModules(aProfile, getElementByName(prof, "modules")) return aProfile def parseAutoStatus(self, aProfile, prof): if prof == None: return for status in getElementsByName(prof, "status"): # pre init default variables. beginHour = -1 beginMin = -1 endHour = -1 endMin = -1 currentStatus = "all" autoStatus = "all" idleDuration = None newStatus = None newMessage = "" time = status.getAttribute("time") if len(time) > 0: beginHour = time[0:2] beginMin = time[3:5] endHour = time[6:8] endMin = time[9:11] tmp = status.getAttribute("current") if len(tmp) > 0: currentStatus = tmp.split(",") tmp = status.getAttribute("auto") if len(tmp) > 0: autoStatus = tmp tmp = status.getAttribute("idle") if len(tmp) > 0: idleDuration = int(tmp) tmp = status.getAttribute("new") if len(tmp) > 0: newStatus = tmp newMessage = getText(status) myStatusEntry = ([beginHour,beginMin], [endHour, endMin], currentStatus, autoStatus, idleDuration, newStatus, newMessage) aProfile.autoStatusList.append( myStatusEntry ) def parseColors(self, aProfile, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: color = getText(child) if child.nodeName == "background": color = 'b' + color if self.colors.cdict.has_key(color): aProfile.colors[child.nodeName] = self.colors.cdict[color] def parseCommands(self, aProfile, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: cmd = getText(child) aProfile.commands[child.nodeName] = cmd def parseModules(self, aProfile, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: # load them in order of appearance. moduleName = child.getAttribute("name") aProfile.modules[moduleName] = None aProfile.moduleConfigs[moduleName] = child aProfile.profileModules.append(child.toxml()) def parseAliases(self, aProfile, parent): if parent == None: return for child in parent.childNodes: if child.nodeType == child.ELEMENT_NODE: cmd = getText(child) name = child.getAttribute("name") if name != None and cmd != None: aProfile.aliases[name] = cmd def parseSingleElement(self, parent, desired): r = getElementByName(parent, desired) if(r == None): return None return getText(r) def writePreferences(self): towrite = '\n' towrite = towrite + "\n" towrite = towrite + " \n" keys = self.colors.colorsdict.keys() for item in keys: colorname = fix(getHashKeyFromValue(self.colors.cdict, self.colors.colorsdict[item])) towrite = towrite + " <" + fix(item) + ">" + colorname + "\n" towrite = towrite + " \n \n" keys = self.commands.commandsdict.keys() for item in keys: towrite = towrite + " <" + fix(item) + ">" + fix(self.commands.commandsdict[item]) + "\n" towrite = towrite + " \n" keys = self.profiles.keys() for item in keys: towrite = towrite + self.profiles[item].toXML() towrite = towrite + "\n" try: os.mkdir(os.path.join(os.path.expanduser("~"),".imcom"),0700) except: pass f = codecs.open(os.path.join(os.path.expanduser("~"),".imcom","imcomrc"),"w", "utf8") os.chmod(os.path.join(os.path.expanduser("~"),".imcom","imcomrc"),0600) f.write(towrite) f.flush() f.close() return towrite def fix(str): str = string.replace( str, "&", "&" ); str = string.replace( str, '"', """); str = string.replace( str, "'", "'"); str = string.replace( str, "<", "<"); str = string.replace( str, ">", ">"); return str; def getHashKeyFromValue(hash, value): keys = hash.keys() for item in keys: if hash[item] == value: return item return None def getText(parent): rc = "" for node in parent.childNodes: if node.nodeType == node.TEXT_NODE: rc = rc + node.data return rc def getElementByName(startElement, wantedName): """Returns the first child of startElement who's name is wantedName.""" for blah in startElement.childNodes: if blah.nodeName == wantedName: return blah return None def getElementsByName(startElement, wantedName): """Returns all direct children of startElement whose name is wantedName.""" result = [] for blah in startElement.childNodes: if blah.nodeName == wantedName: result.append(blah) return result class Commands: def __init__(self): self.commandsdict = {} self.helpcommands = { "msg" : "Send a message to a user", "e" : "Show users that are currently online", "w" : "Show the status of all users on your Roster", "info" : "Get information on a user", "add" : "Add a user to your roster", "remove" : "Unsubscribe from a user's presence", "chat" : "Set your status to chat", "away" : "Set your status to away", "xa" : "Set your status to eXtended Away", "dnd" : "Set your status to DND", "quit" : "Quit IMCom", "reply" : "Message the last user you messaged.", "respond" : "Message the last user who messaged you", "set" : "Set boolean variables", "auth" : "Authorize a user to add you to their roster", "bang" : "execute a shell command", "rename" : "rename a user on your roster", "delete" : "DANGER, deletes a user from your roster", "listprofiles" : "List all the profile in your config", "switchprofile" : "Switch to another profile from your config", "help" : "Get help", "online" : "set status to online", "show" : "Show members of a particular group", "addgroup" : "Add a user to a group", "delgroup" : "Remove a group from a user", "setgroup" : "Set the user's only group", "membership" : "Show the groups that a user is in", "sendfile" : "Send a file to a user", "agents" : "List the agents or transports that the jabber server recognizes", "agenthelp" : "Gets information on how to register with the transport. \nRequired to begin registration process", "agentreg" : "Register with a transport.", "getfile" : "Accept a file transfer offer", "alias" : "Create a textual-substitution alias", "saveprefs" : "Save your preferences (colors, commands aliases)", "unalias" : "Remove an existing alias", "msgr" : "Send a multiline message to a user with a resource", "last" : "Show the history of exchanges with a nick", "logs" : "View or search the logfiles", "submitvcard" : "Submit your vCard information to the server", "admin" : "Sends a message to all users online, or sets a MOTD (Admin users only)", "adminwho" : "Shows a list of users on your server currently (Admin users only)", "setpriority" : "Set the priority of this connection. (used when logged onto the same account from more than one resource.", "joinconf" : "Join a group-chat or conference", "leaveconf" : "Leave a group-chat or conference", "confusers" : "Shows the users in a conference", "unregister" : "Unregister with a transport", # "jidlinktest" : "Test a JIDLink with someone", "changepassword" : "Change your password", "deny" : "Deny someone from subscribing to your presence", "version" : "Print out the version of IMCom you are using, or query a user about what client they are using.", "confnickchange" : "Change your nick name in a conference", "confinvite" : "Invite someone into a conference.", "confsubject" : "Change the subject in a conference.", "confkick" : "Kick someone out of a conference (if you are moderator)", "confvoice" : "Grant someone participant role.", "confdevoice" : "Revoke participant role from someone", "confban" : "Ban someone from the conference.", "confmod" : "Grant someone moderator role in a conference", "confdemod" : "Revoke moderator role from someone in a conference", "confmember" : "Grant someone member affiliation in a conference", "confdemember" : "Revoke member affiliation from someone in a conference.", "confadmin" : "Grant someone admin affiliation in a conference", "confdeadmin" : "Revoke admin affiliation from someone in a conference.", "confowner" : "Grant someone onwer affiliation in a conference", "confdeowner" : "Revoke owner affiliation from someone in a conference.", "confdestroy" : "Completely remove a conference you are the owner of.", "confconfig" : "Request the configuration form for a conference.", "msgbang" : "Send the results of a shell command to someone as a message.", "msggroup" : "Send a message to everyone in a group.", "modload" : "Load a module", "modunload" : "Unload a module", "modconfig" : "Configure a module" } def registerModuleCommandHelp(self, commandName, commandHelp): if self.helpcommands.has_key(commandName): return -1 self.helpcommands[commandName] = commandHelp def unRegisterModuleCommandHelp(self, commandName): try: del self.helpcommands[commandName] except: pass def initDefaults(self): self.commandsdict = { "msg" : "/msg", "e" : "e", "w" : "w", "info" : "/info", "add" : "/add", "remove" : "/remove", "chat" : "/chat", "away" : "/away", "xa" : "/xa", "dnd" : "/dnd", "quit" : "/quit", "reply" : "//", "respond" : "/r", "set" : "/set", "auth" : "/auth", "bang" : "!", "rename" : "/rename", "delete" : "/delete", "idle" : "/idle", "interactivereg" : "/interactivereg", "listprofiles" : "/listprofiles", "switchprofile" : "/switchprofile", "help" : "/help", "online" : "/online", "show" : "/show", "addgroup" : "/addgroup", "delgroup" : "/delgroup", "setgroup" : "/setgroup", "membership" : "/membership", "sendfile" : "/sendfile", "agents" : "/agents", "agenthelp" : "/agenthelp", "agentreg" : "/reg", "getfile" : "/getfile", "alias" : "/alias", "saveprefs" : "/saveprefs", "unalias" : "/unalias", "msgr" : "/msgr", "last" : "/last", "logs" : "/logs", "submitvcard" : "/submitvcard", "admin" : "/admin", "adminwho" : "/adminwho", "setpriority" : "/setpriority", "joinconf" : "/joinconf", "leaveconf" : "/leaveconf", "confusers" : "/confusers", "unregister" : "/unregister", #"jidlinktest" : "/jidlinktest", "changepassword" : "/changepassword", "deny" : "/deny", "version" : "/version", "confnickchange" : "/confnickchange", "confinvite" : "/confinvite", "confsubject" : "/confsubjectchange", "confkick" : "/confkick", "confvoice" : "/confvoice", "confdevoice" : "/confdevoice", "confban" : "/confban", "confmod" : "/confmod", "confdemod" : "/confdemod", "confmember" : "/confmember", "confdemember" : "/confdemember", "confadmin" : "/confadmin", "confdeadmin" : "/condeadmin", "confowner" : "/confowner", "confdeowner" : "/confdeowner", "confdestroy" : "/confdestroy", "confconfig" : "/confconfig", "msgbang" : "/msg!", "msggroup" : "/msggroup", "modload" : "/loadmod", "modunload" : "/unloadmod", "modconfig" : "/configmod" } class Colors: def __init__(self): self.darkgray = chr(27)+"[1;30m" self.brightred = chr(27)+"[1;31m" self.brightgreen = chr(27)+"[1;32m" self.yellow = chr(27)+"[1;33m" self.brightblue = chr(27)+"[1;34m" self.purple = chr(27)+"[1;35m" self.brightcyan = chr(27)+"[1;36m" self.white = chr(27)+"[1;37m" self.black = chr(27)+"[0;30m" self.red = chr(27)+"[0;31m" self.green = chr(27)+"[0;32m" self.brown = chr(27)+"[0;33m" self.blue = chr(27)+"[0;34m" self.magenta = chr(27)+"[0;35m" self.cyan = chr(27)+"[0;36m" self.lightgray = chr(27)+"[0;37m" self.bclear = "" self.bdarkgray = chr(27)+"[1;40m" self.bbrightred = chr(27)+"[1;41m" self.bbrightgreen = chr(27)+"[1;42m" self.byellow = chr(27)+"[1;43m" self.bbrightblue = chr(27)+"[1;44m" self.bpurple = chr(27)+"[1;45m" self.bbrightcyan = chr(27)+"[1;46m" self.bwhite = chr(27)+"[1;47m" self.bblack = chr(27)+"[0;40m" self.bred = chr(27)+"[0;41m" self.bgreen = chr(27)+"[0;42m" self.bbrown = chr(27)+"[0;43m" self.bblue = chr(27)+"[0;44m" self.bmagenta = chr(27)+"[0;45m" self.bcyan = chr(27)+"[0;46m" self.blightgray = chr(27)+"[0;47m" self.cdict = { "darkgray":self.darkgray, "brightred":self.brightred, "brightgreen":self.brightgreen, "yellow":self.yellow, "brightblue":self.brightblue, "purple":self.purple, "brightcyan":self.brightcyan, "white":self.white, "black":self.black, "red":self.red, "green":self.green, "brown":self.brown, "blue":self.blue, "magenta":self.magenta, "cyan":self.cyan, "lightgray":self.lightgray, "bclear" : self.bclear, "bdarkgray" : self.bdarkgray, "bbrightred" : self.bbrightred, "bbrightgreen" : self.bbrightgreen, "byellow" : self.byellow, "bbrightblue" : self.bbrightblue, "bpurple" : self.bpurple, "bbrightcyan" : self.bbrightcyan, "bwhite" : self.bwhite, "bblack" : self.bblack, "bred" : self.bred, "bgreen" : self.bgreen, "bbrown" : self.bbrown, "bblue" : self.bblue, "bmagenta" : self.bmagenta, "bcyan" : self.bcyan, "blightgray" : self.blightgray } self.colorsdict = {} self.sessioncolors = {} def initDefaults(self): self.colorsdict = { "user" : self.cdict["brightgreen"], "status" : self.cdict["yellow"], "error" : self.cdict["brightred"], "messagebody" : self.cdict["yellow"], "time" : self.cdict["brightcyan"], "desc" : self.cdict["purple"], "sep" : self.cdict["brightblue"], "default" : self.cdict["white"], "key" : self.cdict["brightcyan"], "background" : self.cdict["bblack"]} if __name__ == "__main__": prefs = Preferences() for profile in prefs.profiles: print prefs.profiles[profile].__repr__() print "Default Colors: ", prefs.colors.colorsdict print "Default commands: ", prefs.commands.commandsdict