64 public signal void on_join(Conference conf, Occupant occupant); |
66 public signal void on_join(Conference conf, Occupant occupant); |
65 public signal void on_part(Conference conf, Occupant occupant); |
67 public signal void on_part(Conference conf, Occupant occupant); |
66 public signal void on_role(Conference conf, Occupant occupant, Role prev); |
68 public signal void on_role(Conference conf, Occupant occupant, Role prev); |
67 public signal void on_affil(Conference conf, Occupant occupant, Affiliation prev); |
69 public signal void on_affil(Conference conf, Occupant occupant, Affiliation prev); |
68 public signal void on_nick(Conference conf, Occupant occupant, string prev); |
70 public signal void on_nick(Conference conf, Occupant occupant, string prev); |
|
71 public signal void on_message(Conference conf, Occupant occupant, Lm.MessageNode message, string body); |
69 public signal void on_subject(Conference conf); |
72 public signal void on_subject(Conference conf); |
70 |
73 |
71 public class Conference : Object { |
74 public class Conference : Object { |
72 public string jid; |
75 public string jid; |
73 public string nick; |
76 public string nick; |
74 public string desired_nick; |
77 public string desired_nick; |
|
78 public bool enabled; |
75 public string subject; |
79 public string subject; |
76 |
80 |
77 protected State _state; |
81 protected State _state; |
78 public Time time; |
82 public Time time; |
79 public State state { get { return _state; } } |
83 public State state { get { return _state; } } |
85 var old_state = this._state; |
89 var old_state = this._state; |
86 if (old_state != new_state) { |
90 if (old_state != new_state) { |
87 this._state = new_state; |
91 this._state = new_state; |
88 stderr.printf("MUC State changed %s -> %s : %s\n",old_state.to_string(), new_state.to_string(), description); |
92 stderr.printf("MUC State changed %s -> %s : %s\n",old_state.to_string(), new_state.to_string(), description); |
89 module.state_changed(this, old_state, new_state, description); |
93 module.state_changed(this, old_state, new_state, description); |
|
94 if (new_state == State.DISCONNECTED) |
|
95 occupants.clear(); |
90 } else |
96 } else |
91 stderr.printf("MUC State not changed %s : %s\n",old_state.to_string(), description); |
97 stderr.printf("MUC State not changed %s : %s\n",old_state.to_string(), description); |
92 } |
98 } |
93 |
99 |
94 public Conference(ModuleMuc module, string jid) { |
100 public Conference(ModuleMuc module, string jid) { |
95 this.module = module; |
101 this.module = module; |
96 var section = "muc "+jid; |
102 var section = "muc "+jid; |
97 this.desired_nick = module.cfg[section,"nick"]; |
103 this.desired_nick = module.cfg.get_default(section,"nick",module.cfg.get_default("muc","nick",Random.next_int().to_string())); |
98 this.nick = this.desired_nick; |
104 this.nick = this.desired_nick; |
99 this.jid = jid; |
105 this.jid = jid; |
100 this._state = State.DISCONNECTED; |
106 this._state = State.DISCONNECTED; |
101 this.occupants = new Gee.HashMap<string,Occupant>(); |
107 this.occupants = new Gee.HashMap<string,Occupant>(); |
102 } |
108 } |
106 presence_join_id = jid+"_"+Random.next_int().to_string(); |
112 presence_join_id = jid+"_"+Random.next_int().to_string(); |
107 prs.node.set_attribute("id",presence_join_id); |
113 prs.node.set_attribute("id",presence_join_id); |
108 prs.node.add_child("x",null).set_attribute("xmlns","http://jabber.org/protocol/muc"); |
114 prs.node.add_child("x",null).set_attribute("xmlns","http://jabber.org/protocol/muc"); |
109 module.conn.cn.send(prs); |
115 module.conn.cn.send(prs); |
110 nick = desired_nick; |
116 nick = desired_nick; |
111 _change_state(State.CONNECTING, "requested to join"); |
117 _change_state(State.CONNECTING, "requested to join: "+desc); |
112 } |
118 } |
113 } |
119 } |
114 |
120 |
115 public Lm.HandlerResult muc_handler(Lm.MessageHandler handler, Lm.Connection connection, Lm.Message message) { |
121 public Lm.HandlerResult muc_handler(Lm.MessageHandler handler, Lm.Connection connection, Lm.Message message) { |
116 var node = message.node; |
122 var node = message.node; |
121 switch (type) { |
127 switch (type) { |
122 case null: |
128 case null: |
123 case "unavailable": |
129 case "unavailable": |
124 if (from.length==2) { |
130 if (from.length==2) { |
125 var statuses = new Gee.HashSet<int>(); |
131 var statuses = new Gee.HashSet<int>(); |
126 |
132 var occupant = occupants[from[1]]; |
127 var x = node.get_child("x"); |
133 var affil = Affiliation.NONE; |
128 var child = x!=null ? x.children : null; |
134 var role = Role.NONE; |
129 while (child != null) { |
135 string prs_nick = null; |
130 stdout.printf("Child %s %s\n", child.name, child.get_attribute("code")); |
136 |
131 if (child.name == "status") { |
137 var chn = node.children; |
132 var code = child.get_attribute("code"); |
138 while (chn != null) { |
133 if (code!=null) |
139 switch (chn.name) { |
134 statuses.add(code.to_int()); |
140 |
|
141 case "x": |
|
142 switch (chn.get_attribute("xmlns")) { |
|
143 case NS_MUC_USER: |
|
144 var child = chn.children; |
|
145 while (child != null) { |
|
146 stdout.printf("Child %s %s\n", child.name, child.get_attribute("code")); |
|
147 if (child.name == "status") { |
|
148 var code = child.get_attribute("code"); |
|
149 if (code!=null) |
|
150 statuses.add(code.to_int()); |
|
151 } |
|
152 child = child.next; |
|
153 } |
|
154 var item = chn.get_child("item"); |
|
155 if (item == null) |
|
156 log("Muc", LogLevelFlags.LEVEL_ERROR, "Your MUC server is shit. No role and affiliation info in presences: %s", node.to_string()); |
|
157 affil = affil_from_string(item.get_attribute("affiliation")); |
|
158 role = role_from_string(item.get_attribute("role")); |
|
159 prs_nick = item.get_attribute("nick"); |
|
160 break; |
|
161 } |
|
162 break; |
135 } |
163 } |
136 child = child.next; |
164 chn = chn.next; |
137 } |
165 } |
138 |
166 |
139 if (statuses.contains(110) && (_state == State.CONNECTED)) |
167 if (statuses.contains(110) && (_state == State.CONNECTED)) |
140 log("Muc", LogLevelFlags.LEVEL_INFO, "Joined a room which I was already in: %s", from[0]); |
168 log("Muc", LogLevelFlags.LEVEL_INFO, "Joined a room which I was already in: %s", from[0]); |
141 |
169 |
142 var occupant = occupants[from[1]]; |
|
143 var item = x != null ? x.get_child("item") : null; |
|
144 var affil = Affiliation.NONE; |
|
145 var role = Role.NONE; |
|
146 string nick = null; |
|
147 if (item != null) { |
|
148 affil = affil_from_string(item.get_attribute("affiliation")); |
|
149 role = role_from_string(item.get_attribute("role")); |
|
150 nick = item.get_attribute("nick"); |
|
151 } else |
|
152 log("Muc", LogLevelFlags.LEVEL_ERROR, "Your MUC server is shit. No role and affiliation info in presences: %s", node.to_string()); |
|
153 if (occupant != null) { |
170 if (occupant != null) { |
154 if (role == Role.NONE) { |
171 if (role == Role.NONE) { |
155 occupants.unset(from[1]); |
172 occupants.unset(from[1]); |
156 log("Muc", LogLevelFlags.LEVEL_INFO, "MUC<%s> %s has parted.", this.jid, from[1]); |
173 log("Muc", LogLevelFlags.LEVEL_INFO, "MUC<%s> %s has parted.", this.jid, from[1]); |
157 module.on_part(this, occupant); |
174 module.on_part(this, occupant); |
158 if (from[1]==this.nick) { |
175 if (occupant.isme) { |
159 _change_state(State.DISCONNECTED, "we became unavailable"); |
176 _change_state(State.DISCONNECTED, "we became unavailable"); |
160 occupants.clear(); |
|
161 } |
177 } |
162 } else { |
178 } else { |
163 if (affil != occupant.affil) { |
179 if (affil != occupant.affil) { |
164 var prev = occupant.affil; |
180 var prev = occupant.affil; |
165 occupant.affil = affil; |
181 occupant.affil = affil; |
168 if (role != occupant.role) { |
184 if (role != occupant.role) { |
169 var prev = occupant.role; |
185 var prev = occupant.role; |
170 occupant.role = role; |
186 occupant.role = role; |
171 module.on_role(this, occupant, prev); |
187 module.on_role(this, occupant, prev); |
172 } |
188 } |
173 if (statuses.contains(303) && (nick!=null)) { |
189 if (statuses.contains(303) && (prs_nick!=null)) { |
174 occupants[nick] = occupant; |
190 occupants[prs_nick] = occupant; |
175 occupants.unset(from[1]); |
191 occupants.unset(from[1]); |
176 occupant.nick = nick; |
192 occupant.nick = prs_nick; |
177 module.on_nick(this, occupant, from[1]); |
193 module.on_nick(this, occupant, from[1]); |
178 } |
194 } |
179 } |
195 } |
180 } else { |
196 } else { |
181 assert( role!= Role.NONE); |
197 assert( role!= Role.NONE); |
184 occupant.affil = affil; |
200 occupant.affil = affil; |
185 occupant.nick = from[1]; |
201 occupant.nick = from[1]; |
186 occupants[from[1]] = occupant; |
202 occupants[from[1]] = occupant; |
187 occupant.isme = statuses.contains(110); |
203 occupant.isme = statuses.contains(110); |
188 log("Muc", LogLevelFlags.LEVEL_INFO, "MUC<%s> %s has joined as %s/%s.", this.jid, from[1], affil.to_string(), role.to_string()); |
204 log("Muc", LogLevelFlags.LEVEL_INFO, "MUC<%s> %s has joined as %s/%s.", this.jid, from[1], affil.to_string(), role.to_string()); |
189 if (statuses.contains(110)) |
205 if (statuses.contains(110)) { |
|
206 this.nick = from[1]; |
190 _change_state(State.CONNECTED, "got own presence. we are "+this.nick); |
207 _change_state(State.CONNECTED, "got own presence. we are "+this.nick); |
|
208 } |
191 module.on_join(this, occupant); |
209 module.on_join(this, occupant); |
192 } |
210 } |
193 |
211 |
194 stdout.printf("User list: "); |
212 stdout.printf("User list: "); |
195 foreach (var a in occupants.keys) |
213 foreach (var a in occupants.keys) |
212 if (subj != null) { |
230 if (subj != null) { |
213 if (subj != this.subject) { |
231 if (subj != this.subject) { |
214 this.subject = subj; |
232 this.subject = subj; |
215 module.on_subject(this); |
233 module.on_subject(this); |
216 } |
234 } |
|
235 } else { |
|
236 var occupant = (from.length > 1) ? occupants[from[1]] : null; |
|
237 var body = node.find_child("body"); |
|
238 module.on_message(this, occupant, node, (body!=null) ? body.get_value() : null); |
217 } |
239 } |
218 } |
240 } |
219 return Lm.HandlerResult.ALLOW_MORE_HANDLERS; |
241 return Lm.HandlerResult.ALLOW_MORE_HANDLERS; |
220 } |
242 } |
221 public void part(string desc) { |
243 public void part(string desc) { |
|
244 if (_state != State.DISCONNECTED) { |
|
245 var prs = new Lm.Message(jid+"/"+desired_nick, Lm.MessageType.PRESENCE); |
|
246 presence_join_id = jid+"_"+Random.next_int().to_string(); |
|
247 prs.node.set_attribute("type","unavailable"); |
|
248 prs.node.add_child("x",null).set_attribute("xmlns","http://jabber.org/protocol/muc"); |
|
249 module.conn.cn.send(prs); |
|
250 nick = desired_nick; |
|
251 } |
|
252 } |
|
253 |
|
254 public void connection_lost() { |
|
255 _change_state(State.DISCONNECTED, "connection lost"); |
222 } |
256 } |
223 } |
257 } |
224 |
258 |
225 public override string name() { return "muc"; } |
259 public override string name() { return "muc"; } |
226 |
260 |
239 return rooms[froms[0]].muc_handler(handler, connection, message); |
273 return rooms[froms[0]].muc_handler(handler, connection, message); |
240 } |
274 } |
241 } |
275 } |
242 return Lm.HandlerResult.ALLOW_MORE_HANDLERS; |
276 return Lm.HandlerResult.ALLOW_MORE_HANDLERS; |
243 }, null); |
277 }, null); |
|
278 var names = cfg.get_default("muc","mucs","").split(" "); |
|
279 foreach (var name in names) { |
|
280 var room = new Conference(this, name); //, "Ζαλυπα"); |
|
281 //room.join("Oh hai"); |
|
282 room.enabled = true; |
|
283 this.rooms[room.jid] = room; |
|
284 } |
244 conn.cn.register_message_handler(muc_handler, Lm.MessageType.MESSAGE, Lm.HandlerPriority.NORMAL); |
285 conn.cn.register_message_handler(muc_handler, Lm.MessageType.MESSAGE, Lm.HandlerPriority.NORMAL); |
245 conn.cn.register_message_handler(muc_handler, Lm.MessageType.PRESENCE, Lm.HandlerPriority.NORMAL); |
286 conn.cn.register_message_handler(muc_handler, Lm.MessageType.PRESENCE, Lm.HandlerPriority.NORMAL); |
246 conn.cn.register_message_handler(muc_handler, Lm.MessageType.IQ, Lm.HandlerPriority.NORMAL); |
287 conn.cn.register_message_handler(muc_handler, Lm.MessageType.IQ, Lm.HandlerPriority.NORMAL); |
247 conn.state_changed.connect( (olds, news, desc) => { |
288 conn.state_changed.connect( (olds, news, desc) => { |
248 if (news == Connection.State.CONNECTED) { |
289 switch (news) { |
249 var room = new Conference(this, "говнохост@conference.blasux.ru"); //, "Ζαλυπα"); |
290 case Connection.State.CONNECTED: |
250 room.join("Oh hai"); |
291 break; |
251 this.rooms[room.jid] = room; |
292 case Connection.State.DISCONNECTED: |
|
293 foreach(var room in rooms.values) |
|
294 room.connection_lost(); |
|
295 break; |
252 } |
296 } |
253 }); |
297 }); |
|
298 conn.check_time.connect( () => { |
|
299 if (conn.state == Connection.State.CONNECTED) |
|
300 foreach (var room in rooms.values) { |
|
301 if (room.enabled) { |
|
302 if (room.state == State.DISCONNECTED) |
|
303 room.join("Reconnect"); |
|
304 } else { |
|
305 if (room.state == State.CONNECTED) |
|
306 room.part("Disabled"); |
|
307 } |
|
308 } |
|
309 }); |
254 } |
310 } |
255 } |
311 } |