# HG changeset patch # User Stiletto # Date 1351021828 -14400 # Node ID dd7a02c6d476794004fa459148d56a27f5820839 # Parent 4e050075fab9a7cf74beb8f130d95c5d6ea43a32 muc log, updated example config diff -r 4e050075fab9 -r dd7a02c6d476 Makefile --- a/Makefile Tue Oct 23 18:33:49 2012 +0400 +++ b/Makefile Tue Oct 23 23:50:28 2012 +0400 @@ -1,10 +1,10 @@ all: iswydt-bot VALAC = valac -LIBS := gee-1.0 loudmouth-1.0 +LIBS := gee-1.0 loudmouth-1.0 posix VALALIBS := $(patsubst %, --pkg %, $(LIBS)) -VFLAGS = +VFLAGS = -g -iswydt-bot: iswydt.vala config.vala muc.vala +iswydt-bot: iswydt.vala config.vala muc.vala muc_log.vala $(VALAC) $(VFLAGS) $(VALALIBS) -o $@ $^ diff -r 4e050075fab9 -r dd7a02c6d476 config.ini.example --- a/config.ini.example Tue Oct 23 18:33:49 2012 +0400 +++ b/config.ini.example Tue Oct 23 23:50:28 2012 +0400 @@ -1,4 +1,4 @@ -[default] +[server] jid=fuck@example.com password=shit server=talk.example.com @@ -6,3 +6,12 @@ port=5222 ssl=yes +[muc] +mucs=example1@conference.blasux.ru example2@conference.blasux.ru +nick=Govnupa +log-head=log_head.html +log-path=logs/%Y/%m/.html + +[muc example1@conference.blasux.ru] +nick=Ζαλυπα +log=yes diff -r 4e050075fab9 -r dd7a02c6d476 iswydt.vala --- a/iswydt.vala Tue Oct 23 18:33:49 2012 +0400 +++ b/iswydt.vala Tue Oct 23 23:50:28 2012 +0400 @@ -21,7 +21,7 @@ get { return _state; } } - public Module[] modules; + public Gee.ArrayList modules; public signal void state_changed(State old_state, State new_state, string description); public signal void check_time(); @@ -36,7 +36,7 @@ } public Connection(Config cfg) { - this.modules = new Module[10]; + this.modules = new Gee.ArrayList(); this.jid = cfg["server","jid"]; this.password = cfg["server","password"]; @@ -81,8 +81,6 @@ cn.register_message_handler(muc_handler, Lm.MessageType.MESSAGE, Lm.HandlerPriority.NORMAL); cn.register_message_handler(muc_handler, Lm.MessageType.PRESENCE, Lm.HandlerPriority.NORMAL); cn.register_message_handler(muc_handler, Lm.MessageType.IQ, Lm.HandlerPriority.NORMAL);*/ - var module = new ModuleMuc(cfg, this); - modules = {module}; state_changed.connect( (olds, news, desc) => { if (news == Connection.State.CONNECTED) { cn.send_raw("ТХБ"); @@ -96,6 +94,9 @@ open(); }); } + public void add_module(Module module) { + modules.add(module); + } public void open() { stderr.printf("Connecting to %s:%d as %s\n",server,port,jid); @@ -126,10 +127,15 @@ _change_state(State.DISCONNECTED, e.message); } } - + public void close() { + cn.close(); + } } +static Connection account; +static MainLoop loop; + int main(string[] args) { if (args.length<2) { stderr.printf("Usage: %s \n",args[0]); @@ -138,10 +144,13 @@ Log.set_handler("Muc", (LogLevelFlags)65535, (domain, levels, message) => { stderr.printf("--- %s\n", message); }); + Log.set_handler("muc_log", (LogLevelFlags)65535, (domain, levels, message) => { + stderr.printf("--- %s\n", message); + }); log("LM", LogLevelFlags.LEVEL_DEBUG, "HATE HATE"); var cfg = new Config.from_file(args[1]); - var loop = new MainLoop(); - var account = new Connection(cfg); + loop = new MainLoop(); + account = new Connection(cfg); //account.open(); stdout.printf("Fuck yeah\n"); var checktimer = new TimeoutSource(2000); @@ -151,6 +160,24 @@ return true; }); checktimer.attach(loop.get_context()); + + account.add_module(new ModuleMuc(cfg, account)); + account.add_module(new ModuleMucLog(cfg, account)); + + Posix.sigaction_t action = Posix.sigaction_t(); + action.sa_handler = ((i) => { + if (account.state != Connection.State.CONNECTED) + loop.quit(); + else { + account.state_changed.connect( (olds, news, desc) => { + if (news == Connection.State.DISCONNECTED) + loop.quit(); + }); + account.close(); + } + }); + Posix.sigaction(Posix.SIGINT, action, null); + loop.run(); return 0; } diff -r 4e050075fab9 -r dd7a02c6d476 log_head.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/log_head.html Tue Oct 23 23:50:28 2012 +0400 @@ -0,0 +1,25 @@ + + + + + + + + + + Log for <muc>, <date> + + + + +

Log for ,

+ +

All times shown according to UTC.

+ + + + + + diff -r 4e050075fab9 -r dd7a02c6d476 logs/script.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/logs/script.js Tue Oct 23 23:50:28 2012 +0400 @@ -0,0 +1,19 @@ +window.onload = function () { + var log = document.getElementById("log"); + var rows = log.getElementsByTagName("tr"); + var rownum = rows.length; + for (var i = 0; i < rownum; i++) { + var row = rows[i]; + if (row.getAttribute("class") == "message") { + var nicktd = row.getElementsByClassName("nick")[0]; + if (nicktd) { + var nick = nicktd.textContent; + var sum = 0; + for( var j = 0, iTop = nick.length; j < iTop; j++ ) { + sum += 0x56 ^ nick.charCodeAt(j); + } + nicktd.setAttribute("class","nick nick"+(sum % 10)); + } + } + } +}; diff -r 4e050075fab9 -r dd7a02c6d476 logs/style.css --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/logs/style.css Tue Oct 23 23:50:28 2012 +0400 @@ -0,0 +1,130 @@ +body { + background-color: white; + color: black; +} + +h1, h2, h3, #footer * { + color: #70709f; + clear: left; +} + + +#footer { + background-color: #ececef; + border-color: #c0c0ff; + color: inherit; + border-top: 2px solid; + border-bottom: 2px solid; + margin-bottom: 0.2em; + padding-top: 0.75ex; + padding-bottom: 0.75ex; + min-height: 4.7ex; + clear: left; +} + +#footer * { + background-color: inherit; + font-size: 92%; +} + +tr, td { + vertical-align: top; +} + +.dark { + background-color: #efefef; +} + +.special { + font-size: 80%; +} +.special * { + color: gray; +} + +#log { + border-collapse: collapse; + width: 100%; + border: 1px solid #efefef; +} + +#log tr { border-top: 1px solid #efefef; } +#log tr.head, #log tr.dark.new { border-top-style: none; } +#log tr.dark { border-top: 1px solid #dfdfdf; } +#log tr td.text { width: 90%; } + +#log td, th { + font-family: Consolas, "Lucida Console", "Courier New", monospace; + padding: 0.2em 0.4em; + width: 1px; +} + +#log th { border-bottom: 1px solid #C0C0C0; } + +#log .nick { + text-align: right; + border-right: 1px solid #C0C0C0; +} +#log .time a { color: #333; text-decoration: none; } +#log .time a:hover { color: #000; text-decoration: underline; } + +#log .time { border-left: 1px solid #efefef; } +#log .msg { border-right: 1px solid #efefef; line-height: 1.3em; } +#log .act { font-style: italic; } + +.log-index li { + display: inline; +} + +label,input { + display: block; + width: 10em; + float: left; + margin-bottom: 2ex; +} + +label { + text-align: right; + width: 8em; + padding-right: 2ex; +} + +br { + clear: left; +} + +/* index page */ + +.calendar { + float: left; +} + +/* most important channel members. This is subjective, if you have a different + * opinion, feel free to change */ +.nick_timtoady { color: green; font-weight: bold; } +.nick_audreyt { color: red; font-weight: bold;} + + +/* all "active" bots, (svnbot6, lambdabot, specbot etc.) */ +.bots {color: #FFA500; font-style: italic} + +/* The rest gets dynamically allocated colors */ +.nick1 { color: #00AA33; } +.nick2 { color: #AA0000; } +.nick3 { color: #005500; } +.nick4 { color: #FF0077; } +.nick5 { color: blue; } +.nick6 { color: #8B008B; } +.nick7 { color: #50507f; } +.nick8 { color: #00008B; } +.nick9 { color: #222222; } + +abbr { cursor: help; } + +.search_found { + font-weight: bold; +} + +tr.logstart td.text { + color: #3f0; +} diff -r 4e050075fab9 -r dd7a02c6d476 muc.vala --- a/muc.vala Tue Oct 23 18:33:49 2012 +0400 +++ b/muc.vala Tue Oct 23 23:50:28 2012 +0400 @@ -29,18 +29,18 @@ static Role role_from_string(string role) { switch (role) { - case "moderator": return Role.MODERATOR; break; - case "participant": return Role.PARTICIPANT; break; - case "visitor": return Role.VISITOR; break; + case "moderator": return Role.MODERATOR; + case "participant": return Role.PARTICIPANT; + case "visitor": return Role.VISITOR; } return Role.NONE; } static Affiliation affil_from_string(string affil) { switch (affil) { - case "owner": return Affiliation.OWNER; break; - case "admin": return Affiliation.ADMIN; break; - case "member": return Affiliation.MEMBER; break; - case "outcast": return Affiliation.OUTCAST; break; + case "owner": return Affiliation.OWNER; + case "admin": return Affiliation.ADMIN; + case "member": return Affiliation.MEMBER; + case "outcast": return Affiliation.OUTCAST; } return Affiliation.NONE; } @@ -68,8 +68,8 @@ public signal void on_role(Conference conf, Occupant occupant, Role prev); public signal void on_affil(Conference conf, Occupant occupant, Affiliation prev); public signal void on_nick(Conference conf, Occupant occupant, string prev); - public signal void on_message(Conference conf, Occupant occupant, Lm.MessageNode message, string body); - public signal void on_subject(Conference conf); + public signal void on_message(Conference conf, Occupant? occupant, Lm.MessageNode message, string? body); + public signal void on_subject(Conference conf, Occupant? occupant); public class Conference : Object { public string jid; @@ -227,13 +227,13 @@ } } else if ((message.get_type()==Lm.MessageType.MESSAGE)&&(type=="groupchat")) { var subj = node.get_attribute("subject"); + var occupant = (from.length > 1) ? occupants[from[1]] : null; if (subj != null) { if (subj != this.subject) { this.subject = subj; - module.on_subject(this); + module.on_subject(this, occupant); } } else { - var occupant = (from.length > 1) ? occupants[from[1]] : null; var body = node.find_child("body"); module.on_message(this, occupant, node, (body!=null) ? body.get_value() : null); } diff -r 4e050075fab9 -r dd7a02c6d476 muc_log.vala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/muc_log.vala Tue Oct 23 23:50:28 2012 +0400 @@ -0,0 +1,124 @@ +using Gee; + +class ModuleMucLog : Module { + protected weak ModuleMuc muc; + protected HashMap rooms; + class RoomLog : Object { + public string jid; + public string logpath; + public string filename; + protected weak ModuleMucLog muclog; + protected FileStream file; + public string getid(Time time) { + return time.format("%s"); + } + protected int lastday; + protected int lastyear; + protected int lastmonth; + + public RoomLog(ModuleMucLog muclog, string jid) { + this.jid = jid; + this.muclog = muclog; + logpath = muclog.getconf(jid, "log-path", null); + filename = null; + write(Time.local(new time_t()), "logstart", "", "Log started"); + } + ~RoomLog() { + write(Time.local(new time_t()), "logstop", "", "Log stopped"); + 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("",jid); + log("muc_log", LogLevelFlags.LEVEL_INFO, "Switching log file '%s' to '%s'", filename, fname); + if (file!=null) file.flush(); + //try { + file = FileStream.open(fname,"a"); + if (file==null) { + int start = 0; + int length = fname.length; + while (true) { + var pos = fname.index_of("/", start); + if (pos==-1) + break; + stderr.printf("--------------------- %s\n", fname[0:pos]); + Posix.mkdir(fname[0:pos],0777); + start = pos+1; + } + + file = FileStream.open(fname,"a"); + if (file == null) { + log("muc_log", LogLevelFlags.LEVEL_WARNING, "Failed to create log file '%s'", fname); + return; + } + } + + if (file.tell()==0) { + var loghead = muclog.getconf(jid, "log-head",null); + if (loghead!="null") { + try { + var headfile = new IOChannel.file(loghead,"r"); + string head; + size_t length; + headfile.read_to_end(out head, out length); + headfile.shutdown(false); + file.printf("%s\n", head.replace("",jid).replace("",time.format("%d.%m.%Y"))); + } catch (FileError fe) { + log("muc_log", LogLevelFlags.LEVEL_WARNING, "Failed to read head"); + } + } + } + filename = fname; + lastyear = time.year; lastmonth = time.month; lastday = time.day; + } + + var id = getid(time); + var times = time.format("%H:%M:%S"); + file.printf("", id, _class, id, id, times); + file.printf("\n", nick, str); + } + + } + 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 ModuleMucLog(Config cfg, Connection conn) { + base(cfg, conn); + rooms = new HashMap(); + muc = null; + 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.state_changed.connect( (conf, olds, news, desc) => { + switch (news) { + case ModuleMuc.State.CONNECTED: + if (getconf(conf.jid, "log", "no")=="yes") { + rooms[conf.jid] = new RoomLog(this, conf.jid); + } + break; + case ModuleMuc.State.DISCONNECTED: + rooms.unset(conf.jid); + break; + } + }); + muc.on_message.connect( (conf, user, message, body) => { + if ((user!=null)&&(body!=null)&&(message.get_child("delay")==null)) { + var room = rooms[conf.jid]; + if (room!=null) { + var nick = Markup.escape_text(user.nick).replace(" "," "); + room.write(Time.local(new time_t()), "message", nick, Markup.escape_text(body).replace("\n","
")); + } + } + }); + } + public override string name() { + return "muc_log"; + } +}
TimeNickMessage
%s%s%s