__module_name__ = "SnakeByte Greetings" __module_version__ = "0.1" __module_description__ = "Python-based Greetings plugin for X-Chat" __module_author__ = "Stephan Sokolow (deitarion)" __module_license__ = "GPL" __doc__ = """SnakeByte Greetins Python-based cross-platform Greetings plugin for X-Chat. Target Platforms: Linux, MacOS X, Windows (In that order) Target Functionality: SysReset Eventual Goal: The most feature-rich greetings plugin on the net without adding useless or off-topic features. Planned Sibling Scripts: The rest of the SnakeByte suite. TODO List: X a /greeting command which supports ADD , DELETE , and SET X Multiple greeting styles (format string) X Advanced-mode configuration of greeting syntax as well as random variables. / Support for multiple greeting phrases (Requires code editing to change at the moment) - A help file detailing how to use the partial greeting randomizer. - Grab the randomizer data from separate files - Cleaner code design - Take some settings like color scheme from the main SnakeByte config file. (and create such a thing. Maybe common.conf) - Test shelve for crash tolerance. (And ask about it on #python2) - Remember my Two/Three data files approach to data safety. - Switch to normal text files where each line is a greeting with the first space splitting the nick from the greeting. - Make it so that it only opens shelve files when it's necessary to update or read from them """ # Import the xchat plugin API import xchat # Imports from the standard Python libraries import string, random, os, shelve CONFIG_DIR = os.path.expanduser('~/.xchat2/snakebyte') # Default settings begin ------------------ SETTINGS = { 'color_1' : 4, 'color_2' : 2, 'color_message' : -1, # -1 means None, -2 means random. How should I work this into the overall system? 'bracket_opening' : '<', 'bracket_closing' : '>', 'greet_format' : "%(c1)s%(oBracket)s%(c2)s%(greeting)s%(c1)s%(cBracket)s %(oBracket)s%(c2)s%(nick)s%(c1)s%(cBracket)s -%(cMsg)s %(message)s", 'greeting' : 'Welcome Back', 'use_random_greeting' : True, 'use_notice' : False, # Only use one of these or things may not turn out the way you want. This is not a bug. 'channels_allowed' : '', 'channels_disallowed' : '', } # Default settings end -------------------- (Except for the __init__ section of class WordList) # Automatic Initialization begins --------------- # This allows defaults (capitalized) and something that can possibly be loaded from file a at runtime (lowercase). settings = SETTINGS greetings = ["Welcome Back","Yo!","Wazzup!?","Hello Again","G'Day!"] if not os.path.exists(CONFIG_DIR): os.makedirs(CONFIG_DIR) nicks = shelve.open(os.path.join(CONFIG_DIR,'greetings.shelf')) if not nicks.has_key('@settings@'): nicks['@settings@'] = settings else: settings = nicks['@settings@'] for key in SETTINGS.keys(): if not settings.has_key(key): settings[key] = SETTINGS[key] nicks['@settings@'] = settings for key in settings.keys(): if not SETTINGS.has_key(key): del(settings[key]) nicks['@settings@'] = settings # Main program begins ------------------------- class WordList: """Stores the word list for the randomizer""" def __init__(self): """Provides a good way to abstract wordlist loading""" animals = ['ape','aardvark','butterfly','budgie','chimp','dragon','donkey', 'emu','elephant','ferret','fox','goat','gnu','gopher','hog','ibis', 'jackass','jellyfish','kudu','kangaroo','lemur','mongoose','microbe', 'ostrich','octopus','piranha','primate','rat','snake','toad','turtle', 'viper','warthog','weasel','yak'] plants = ['tree','weed','grass','vine','flower','rice','wheat','rye','marijuana'] past = ['chased','jumped','sat on','climbed','fought','ate'] present = ['chase','jump','sit on','climb','fight','eat'] adj_base = ['dirty','crazy','mighty','silly','evil','dark','spotted','pointy'] adv_base = ['quickly','quietly','noisily','badly','very stupidly'] self.wordList = { 'nouns' : {'animals':animals,'plants':plants}, 'verbs' : {'past':past,'present':present}, 'adjectives' : {'base':adj_base}, 'adverbs' : {'base':adv_base} } def __getitem__(self,item): """Called by string substitutions. Can take a word_class:category pair or just a word_class in which case it randomizes through the whole category.""" temp = item.split(':',1) req_word_class = temp[0] req_category = '' if len(temp) == 2: req_category = temp[1] if self.wordList.has_key(req_word_class): word_class = self.wordList[req_word_class] if len(req_category) > 0 and word_class.has_key(req_category): category = word_class[req_category] if len(category) > 0: return random.choice(category) else: return 'category_is_empty' elif len(req_category) == 0: return random.choice(random.choice(list(word_class.values()))) else: return 'no_such_category' else: return 'no_such_word_class' def color(color_var): if color_var == 1: return '\003'+str(settings['color_1']).zfill(2) elif color_var == 2: return '\003'+str(settings['color_2']).zfill(2) elif color_var == 3: if settings['color_message'] >= 0: return '\003'+str(settings['color_message']).zfill(2) else: return '\003 ' elif color_var == -1: return '\003 ' elif color_var == -2: return '\003'+str(random.randrange(0,16)).zfill(2) def sendLine(nick,channel,message): """An alias to keep the code clean. Sends a line to someone.""" if settings['use_notice']: xchat.command("notice "+nick+" "+message) else: xchat.command("msg "+channel+" "+message) def handleJoin_cb(word, word_eol, userdata): """Called when a user joins a channel.""" nick = string.split(word[0],'!',1)[0].lower() if nick[0] == ':': nick = nick[1:] channel = word[2] if channel[0] == ':': channel = channel[1:] if nick in nicks.keys(): send = True if settings['channels_allowed'] and channel.lower() not in settings['channels_allowed'].lower(): send = False if settings['channels_disallowed'] and channel.lower() in settings['channels_disallowed'].lower(): send = False if send: greet = { 'oBracket' : settings['bracket_opening'], 'cBracket' : settings['bracket_closing'], 'message' : nicks[nick] % wordList, 'nick' : nick, 'c1' : color(1), 'c2' : color(2), 'cMsg' : color(3) } if settings['use_random_greeting']: greet['greeting'] = random.choice(greetings) else: greet['greeting'] = settings['greeting'] greet_line = settings['greet_format'] % greet sendLine(nick,channel,greet_line) return xchat.EAT_NONE def handleCommand_cb(word, word_eol, userdata): command = word[1].lower() if len(word) >= 3: arguments = word_eol[2] else: arguments = '' if command == 'add': temp = arguments.split(' ',1) if len(temp) >= 2: nicks[temp[0].lower()] = temp[1] print color(1)+"Greeting for "+color(2)+temp[0]+color(1)+" added" else: print color(1)+"Syntax: "+color(2)+"/greeting add " elif command == 'delete': if nicks.has_key(arguments.lower()): del nicks[arguments.lower()] print color(1)+"Greeting for "+color(2)+arguments+color(1)+" deleted" else: print color(1)+"Nick not found" print color(1)+"Syntax: "+color(2)+"/greeting delete " print color(1)+"Multi-nick delete will be added on first request." elif command == 'list': print print color(1)+'Current Greetings:' for nick in nicks.keys(): if nick != '@settings@': print color(2)+nick+color(1)+" :\003 "+nicks[nick] elif command == 'set': if len(arguments) == 0: temp = settings.keys() temp.sort(lambda x, y: cmp(string.lower(x), string.lower(y))) for item in temp: print item+color(1)+" ="+color(-1)+str(nicks['@settings@'][item]) print color(1)+"Syntax: "+color(2)+"/greeting set []" else: temp = arguments.split(' ',1) if len(temp) == 1 and settings.has_key(temp[0]): print temp[0]+" = "+str(settings[temp[0]]) elif len(temp) == 2 and settings.has_key(temp[0]): if temp[1].lower() == 'true': settings[temp[0]] = True elif temp[1].lower() == 'false': settings[temp[0]] = False else: settings[temp[0]] = temp[1] nicks['@settings@'] = settings print color(1)+"Settings Changed:"+color(-1)+temp[0]+color(1)+" ="+color(-1)+temp[1] pass elif command == 'help': print color(1)+"Available commands: "+color(2)+" add delete list help" print color(1)+"Commands are used by typing"+color(2)+" /greeting []" print color(1)+"For example, "+color(2)+" /greeting help"+color(1)+" shows this message." print color(1)+"Type a command without arguments to get help on that specific command." print print color(1)+"Help for the partial greetings randomizer will come later." print color(1)+"For now, you'll have to look at the source code to see what's possible." print color(1)+"The syntax is %(nouns:animals)s to insert a random animal." print print color(1)+"Setting a color value to -1 will tell it to not use a color." print color(1)+"Setting a color value to -2 will make it randomly choose a color." return xchat.EAT_XCHAT def unload_cb(userdata): nicks['@settings@'] = settings nicks.close() print color(1)+"Data file safely closed. "+color(2)+__module_name__+color(1)+" Unloading..." def handleSuiteAnnounce_cb(word, word_eol, userdata): print color(2)+__module_name__+' v'+__module_version__+color(1)+" active. Type "+color(2)+'/greeting help'+color(1)+" for more information." return xchat.EAT_XCHAT wordList = WordList() xchat.hook_server("JOIN", handleJoin_cb) xchat.hook_command("greeting", handleCommand_cb) xchat.hook_command("snakebyte", handleSuiteAnnounce_cb) xchat.hook_unload(unload_cb) print color(2)+__module_name__+' v'+__module_version__+color(1)+' Loaded. For help, type '+color(2)+'/greeting help'