iq, commands, makefile up default tip
authorStiletto <blasux@blasux.ru>
Mon, 05 Nov 2012 23:54:44 +0400
changeset 12 d3e36b368fc5
parent 11 0f0cf428409f
iq, commands, makefile up
.hgignore
Makefile
iswydt.vala
muc_commands.vala
muc_log.vala
simple_iq.vala
--- a/.hgignore	Mon Nov 05 23:53:52 2012 +0400
+++ b/.hgignore	Mon Nov 05 23:54:44 2012 +0400
@@ -1,4 +1,7 @@
 ^config.ini$
 ^iswydt-bot$
-.swp$
+.sw[op]$
 ^cfiles/
+^logs/.*.html$
+^test/
+^version.vala$
--- a/Makefile	Mon Nov 05 23:53:52 2012 +0400
+++ b/Makefile	Mon Nov 05 23:54:44 2012 +0400
@@ -5,11 +5,14 @@
 VALAONLYLIBS := posix
 VALALIBS  := $(patsubst %, --pkg %, $(LIBS) $(VALAONLYLIBS))
 VFLAGS = -g
+SOURCES = iswydt.vala config.vala simple_iq.vala muc.vala muc_log.vala muc_commands.vala version.vala
 
-iswydt-bot: iswydt.vala config.vala muc.vala muc_log.vala
+version.vala: .
+	echo "static const string IswydtVersion = \"$$(hg id -bnit)\";" > version.vala
+iswydt-bot: $(SOURCES)
 	$(VALAC) $(VFLAGS) $(VALALIBS) -o $@ $^
 
-cfiles: iswydt.vala config.vala muc.vala muc_log.vala
+cfiles: $(SOURCES) 
 	$(VALAC) $(VFLAGS) $(VALALIBS) -C $^
 	mkdir -p cfiles
 	mv *.c cfiles/
--- a/iswydt.vala	Mon Nov 05 23:53:52 2012 +0400
+++ b/iswydt.vala	Mon Nov 05 23:54:44 2012 +0400
@@ -167,7 +167,9 @@
     });
     checktimer.attach(loop.get_context());
 
+    account.add_module(new ModuleIq(cfg, account));
     account.add_module(new ModuleMuc(cfg, account));
+    account.add_module(new ModuleMucCommands(cfg, account));
     account.add_module(new ModuleMucLog(cfg, account));
 
     Posix.sigaction_t action = Posix.sigaction_t();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/muc_commands.vala	Mon Nov 05 23:54:44 2012 +0400
@@ -0,0 +1,94 @@
+using Gee;
+
+class ModuleMucCommands : Module {
+    protected weak ModuleMuc muc;
+    public delegate void CommandHandler(ModuleMuc.Conference conf, ModuleMuc.Occupant user, string command, string? arguments);
+    public class Command : Object {
+        public weak Module mod;
+        public CommandHandler hnd;
+    }
+    protected HashMap<string,Command> commands;
+
+    public string getconf(string jid, string key, string? def) {
+        var res = cfg["muc "+jid, key];
+        if (res==null) res = cfg["muc", key];
+        if (res==null) res = def;
+        return res;
+    }
+    public bool register(string command, Module mod, CommandHandler handler) {
+        var cmd = new Command();
+        cmd.mod = mod; /* this will cause "copying delegates is discouraged" warning. that's okay, this delegate's data needs no destroy notify */
+        cmd.hnd = handler;
+        if (commands.has_key(command))
+            log("muc_commands", LogLevelFlags.LEVEL_WARNING, "Command '%s' defined by '%s' was redefined by '%s'.",
+                command, commands[command].mod.name(), mod.name());
+        commands[command] = cmd;
+        return true;
+    }
+    public bool unregister(string command) {
+        return commands.unset(command);
+    }
+
+    protected void hnd_modules(ModuleMuc.Conference conf, ModuleMuc.Occupant user, string command, string? arguments) {
+        var sb = new StringBuilder();
+        sb.append("Loaded modules:");
+        muc.name();
+        foreach (var mod in conn.modules)
+            sb.append(" "+mod.name());
+        user.public_message(sb.str);
+    }
+
+    protected void hnd_status(ModuleMuc.Conference conf, ModuleMuc.Occupant user, string command, string? arguments) {
+        var sb = new StringBuilder();
+        sb.append("Status:");
+        foreach (var room in muc.rooms.values) {
+            sb.append(" ");
+            sb.append(room.jid.split("@",2)[0]);
+            sb.append("[");
+            sb.append(room.enabled ? "EN":"DIS");
+            sb.append(":");
+            switch (room.state) {
+                case ModuleMuc.State.CONNECTED: sb.append("C"); break;
+                case ModuleMuc.State.DISCOVERING: sb.append("DS"); break;
+                case ModuleMuc.State.CONNECTING: sb.append(">C"); break;
+                case ModuleMuc.State.DISCONNECTING: sb.append(">D"); break;
+                case ModuleMuc.State.DISCONNECTED: sb.append("D"); break;
+            }
+            sb.append("]");
+        }
+        user.public_message(sb.str);
+    }
+
+    public ModuleMucCommands(Config cfg, Connection conn) {
+        base(cfg, conn);
+        commands = new HashMap<string,Command>();
+        foreach (var module in conn.modules) {
+            if (module.name()=="muc")
+                muc = (ModuleMuc)module;
+        }
+        if (muc==null)
+            log("muc_log", LogLevelFlags.LEVEL_ERROR, "Module 'muc' is not loaded");
+
+        muc.on_message.connect( (conf, user, message, body) => {
+            if ((user!=null)&&(body!=null)&&(message.get_child("delay")==null)) {
+                if (getconf(conf.jid, "commands", "no")!="yes")
+                    return;
+                if (body.has_prefix(conf.nick)) {
+                    var txt = body[conf.nick.length:body.length];
+                    if (txt.has_prefix(": ")||txt.has_prefix(", ")) {
+                        var command_n_args = txt[2:txt.length].split(" ",2);
+                        var command = commands[command_n_args[0]];
+                        if (command!=null)
+                            command.hnd(conf, user, command_n_args[0], (command_n_args.length > 1) ? command_n_args[1] : null);
+                    }
+                }
+            }
+        });
+        
+        register("modules", this, hnd_modules);
+        register("status", this, hnd_status);
+    }
+    public override string name() {
+        return "muc_commands";
+    }
+}
--- a/muc_log.vala	Mon Nov 05 23:53:52 2012 +0400
+++ b/muc_log.vala	Mon Nov 05 23:54:44 2012 +0400
@@ -35,12 +35,26 @@
             }
             return ((sum ^ m)+l)%10;
         }
+
+        protected void real_write(Time time, string _class, string nick, string str) {
+            var id = getid(time);
+            var times = time.format("%H:%M:%S");
+            var nicklass = (_class=="message") ? (" nick%u".printf(nick_hash(nick))) : "";
+
+            file.printf("<tr id='l_%s' class='%s'><td class='time'><a id='i_%s' href='#i_%s'>%s</a></td>", id, _class, id, id, times);
+            file.printf("<td class='nick%s'>%s</td><td class='text'>%s</td></tr>\n", nicklass, nick, str);
+            file.flush();
+        }
+
         public void write(Time time, string _class, string nick, string str) {
-
             if ((lastday != time.day)||(lastmonth != time.month)||(lastyear!=time.year)) {
                 var fname = time.format(logpath).replace("<muc>",jid);
                 log("muc_log", LogLevelFlags.LEVEL_INFO, "Switching log file '%s' to '%s'", filename, fname);
-                if (file!=null) file.flush();
+                bool wasntnull = false;
+                if (file!=null) {
+                    wasntnull = true;
+                    real_write(time, "logstop", "", "Log stopped. See you in the next episode.");
+                }
                 //try {
                     file = FileStream.open(fname,"a");
                 if (file==null) {
@@ -79,15 +93,11 @@
                 }
                 filename = fname;
                 lastyear = time.year; lastmonth = time.month; lastday = time.day;
+                if (wasntnull)
+                    real_write(time, "logstart", "", "Log started. This soap opera will never end.");
             }
-            
-            var id = getid(time);
-            var times = time.format("%H:%M:%S");
-            var nicklass = (_class=="message") ? (" nick%u".printf(nick_hash(nick))) : "";
 
-            file.printf("<tr id='l_%s' class='%s'><td class='time'><a id='i_%s' href='#i_%s'>%s</a></td>", id, _class, id, id, times);
-            file.printf("<td class='nick%s'>%s</td><td class='text'>%s</td></tr>\n", nicklass, nick, str);
-            file.flush();
+            real_write(time, _class, nick, str);
         }
             
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/simple_iq.vala	Mon Nov 05 23:54:44 2012 +0400
@@ -0,0 +1,41 @@
+using Gee, Lm;
+
+class ModuleIq : Module {
+    const string NS_IQ_VERSION = "jabber:iq:version";
+    public static delegate void Callback(string id, MessageNode request, MessageNode response);
+    protected HashMap<string, Callback> callbacks;
+    public ModuleIq(Config cfg, Connection conn) {
+        base(cfg, conn);
+        var iq_handler = new Lm.MessageHandler((handler, connection, message) => {
+            var node = message.node;
+
+            var query = node.get_child("query");
+            if (query == null) return Lm.HandlerResult.ALLOW_MORE_HANDLERS;
+
+            var from = node.get_attribute("from");
+            var id = node.get_attribute("id");
+
+            var response = new Lm.Message(from, Lm.MessageType.IQ);
+            response.node.set_attribute("type","result");
+            if (id!=null)
+                response.node.set_attribute("id",id);
+            var rquery = response.node.add_child("query",null);
+            
+            switch (query.get_attribute("xmlns")) {
+                case NS_IQ_VERSION:
+                    rquery.set_attribute("xmlns", NS_IQ_VERSION);
+                    rquery.add_child("name", "iswydt");
+                    rquery.add_child("version", IswydtVersion);
+                    stderr.printf("RQ: %s\n",rquery.to_string());
+                    stderr.printf("RS: %s\n",response.node.to_string());
+                    this.conn.cn.send(response);
+                    return Lm.HandlerResult.REMOVE_MESSAGE;
+            }
+            return Lm.HandlerResult.ALLOW_MORE_HANDLERS;
+        }, null);
+        conn.cn.register_message_handler(iq_handler, Lm.MessageType.IQ, Lm.HandlerPriority.NORMAL);
+    }
+    public override string name() {
+        return "iq";
+    }
+}