libpurple/protocols/silc/chat.c

changeset 41832
63f39d354a73
parent 41831
596940e90c68
child 41833
a6a511564c1b
equal deleted inserted replaced
41831:596940e90c68 41832:63f39d354a73
1 /*
2
3 silcpurple_chat.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 - 2007 Pekka Riikonen
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include <glib/gi18n-lib.h>
21
22 #include "silcpurple.h"
23 #include "wb.h"
24
25 /***************************** Channel Routines ******************************/
26
27 GList *silcpurple_chat_info(PurpleProtocolChat *protocol_chat, PurpleConnection *gc)
28 {
29 GList *ci = NULL;
30 PurpleProtocolChatEntry *pce;
31
32 pce = g_new0(PurpleProtocolChatEntry, 1);
33 pce->label = _("_Channel:");
34 pce->identifier = "channel";
35 pce->required = TRUE;
36 ci = g_list_append(ci, pce);
37
38 pce = g_new0(PurpleProtocolChatEntry, 1);
39 pce->label = _("_Passphrase:");
40 pce->identifier = "passphrase";
41 pce->secret = TRUE;
42 ci = g_list_append(ci, pce);
43
44 return ci;
45 }
46
47 GHashTable *silcpurple_chat_info_defaults(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, const char *chat_name)
48 {
49 GHashTable *defaults;
50
51 defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
52
53 if (chat_name != NULL)
54 g_hash_table_insert(defaults, "channel", g_strdup(chat_name));
55
56 return defaults;
57 }
58
59 static void
60 silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components);
61
62 static void
63 silcpurple_chat_getinfo_res(SilcClient client,
64 SilcClientConnection conn,
65 SilcStatus status,
66 SilcDList channels,
67 void *context)
68 {
69 GHashTable *components = context;
70 PurpleConnection *gc = client->application;
71 const char *chname;
72 char tmp[256];
73
74 chname = g_hash_table_lookup(components, "channel");
75 if (!chname)
76 return;
77
78 if (!channels) {
79 g_snprintf(tmp, sizeof(tmp),
80 _("Channel %s does not exist in the network"), chname);
81 purple_notify_error(gc, _("Channel Information"),
82 _("Cannot get channel information"), tmp,
83 purple_request_cpar_from_connection(gc));
84 return;
85 }
86
87 silcpurple_chat_getinfo(gc, components);
88 }
89
90
91 static void
92 silcpurple_chat_getinfo(PurpleConnection *gc, GHashTable *components)
93 {
94 SilcPurple sg = purple_connection_get_protocol_data(gc);
95 const char *chname;
96 char tmp[256], *tmp2;
97 GString *s;
98 SilcChannelEntry channel;
99 SilcHashTableList htl;
100 SilcChannelUser chu;
101
102 if (!components)
103 return;
104
105 chname = g_hash_table_lookup(components, "channel");
106 if (!chname)
107 return;
108 channel = silc_client_get_channel(sg->client, sg->conn,
109 (char *)chname);
110 if (!channel) {
111 silc_client_get_channel_resolve(sg->client, sg->conn,
112 (char *)chname,
113 silcpurple_chat_getinfo_res,
114 components);
115 return;
116 }
117
118 s = g_string_new("");
119 tmp2 = g_markup_escape_text(channel->channel_name, -1);
120 g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2);
121 g_free(tmp2);
122 if (channel->user_list && silc_hash_table_count(channel->user_list))
123 g_string_append_printf(s, _("<br><b>User Count:</b> %d"),
124 (int)silc_hash_table_count(channel->user_list));
125
126 silc_hash_table_list(channel->user_list, &htl);
127 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
128 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
129 tmp2 = g_markup_escape_text(chu->client->nickname, -1);
130 g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"),
131 tmp2);
132 g_free(tmp2);
133 break;
134 }
135 }
136 silc_hash_table_list_reset(&htl);
137
138 if (channel->cipher)
139 g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"),
140 channel->cipher);
141
142 if (channel->hmac)
143 /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */
144 g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"),
145 channel->hmac);
146
147 if (channel->topic) {
148 tmp2 = g_markup_escape_text(channel->topic, -1);
149 g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2);
150 g_free(tmp2);
151 }
152
153 if (channel->mode) {
154 g_string_append(s, _("<br><b>Channel Modes:</b> "));
155 silcpurple_get_chmode_string(channel->mode, tmp, sizeof(tmp));
156 g_string_append(s, tmp);
157 }
158
159 if (channel->founder_key) {
160 char *fingerprint, *babbleprint;
161 unsigned char *pk;
162 SilcUInt32 pk_len;
163 pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len);
164 if (pk) {
165 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
166 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
167
168 g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
169 g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);
170
171 silc_free(fingerprint);
172 silc_free(babbleprint);
173 silc_free(pk);
174 }
175 }
176
177 purple_notify_formatted(gc, NULL, _("Channel Information"), NULL, s->str, NULL, NULL);
178 g_string_free(s, TRUE);
179 }
180
181
182 static void
183 silcpurple_chat_getinfo_menu(PurpleBlistNode *node, gpointer data)
184 {
185 PurpleChat *chat = (PurpleChat *)node;
186 PurpleAccount *account = purple_chat_get_account(chat);
187 silcpurple_chat_getinfo(purple_account_get_connection(account),
188 purple_chat_get_components(chat));
189 }
190
191
192 /************************* Channel Authentication ****************************/
193
194 typedef struct {
195 SilcPurple sg;
196 SilcChannelEntry channel;
197 PurpleChat *c;
198 SilcDList pubkeys;
199 } *SilcPurpleChauth;
200
201 static void
202 silcpurple_chat_chpk_add(void *user_data, const char *name)
203 {
204 SilcPurpleChauth sgc = (SilcPurpleChauth)user_data;
205 SilcPurple sg = sgc->sg;
206 SilcClient client = sg->client;
207 SilcClientConnection conn = sg->conn;
208 SilcPublicKey public_key;
209 SilcBuffer chpks, pk, chidp;
210 unsigned char mode[4];
211 SilcUInt32 m;
212
213 /* Load the public key */
214 if (!silc_pkcs_load_public_key(name, &public_key)) {
215 silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys);
216 silc_dlist_uninit(sgc->pubkeys);
217 silc_free(sgc);
218 purple_notify_error(client->application,
219 _("Add Channel Public Key"),
220 _("Could not load public key"), NULL, NULL);
221 return;
222 }
223
224 pk = silc_public_key_payload_encode(public_key);
225 chpks = silc_buffer_alloc_size(2);
226 SILC_PUT16_MSB(1, chpks->head);
227 chpks = silc_argument_payload_encode_one(chpks, pk->data,
228 silc_buffer_len(pk), 0x00);
229 silc_buffer_free(pk);
230
231 m = sgc->channel->mode;
232 m |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
233
234 /* Send CMODE */
235 SILC_PUT32_MSB(m, mode);
236 chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL);
237 silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
238 silcpurple_command_reply, NULL, 3,
239 1, chidp->data, silc_buffer_len(chidp),
240 2, mode, sizeof(mode),
241 9, chpks->data, silc_buffer_len(chpks));
242 silc_buffer_free(chpks);
243 silc_buffer_free(chidp);
244 if (sgc->pubkeys) {
245 silc_dlist_start(sgc->pubkeys);
246 while ((public_key = silc_dlist_get(sgc->pubkeys)))
247 silc_pkcs_public_key_free(public_key);
248 silc_dlist_uninit(sgc->pubkeys);
249 }
250 silc_free(sgc);
251 }
252
253 static void
254 silcpurple_chat_chpk_cancel(void *user_data, const char *name)
255 {
256 SilcPurpleChauth sgc = (SilcPurpleChauth)user_data;
257 SilcPublicKey public_key;
258
259 silcpurple_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys);
260
261 if (sgc->pubkeys) {
262 silc_dlist_start(sgc->pubkeys);
263 while ((public_key = silc_dlist_get(sgc->pubkeys)))
264 silc_pkcs_public_key_free(public_key);
265 silc_dlist_uninit(sgc->pubkeys);
266 }
267 silc_free(sgc);
268 }
269
270 static void
271 silcpurple_chat_chpk_cb(SilcPurpleChauth sgc, PurpleRequestFields *fields)
272 {
273 SilcPurple sg = sgc->sg;
274 SilcClient client = sg->client;
275 SilcClientConnection conn = sg->conn;
276 PurpleRequestField *f;
277 GList *list;
278 SilcPublicKey public_key;
279 SilcBuffer chpks, pk, chidp;
280 SilcUInt16 c = 0, ct;
281 unsigned char mode[4];
282 SilcUInt32 m;
283
284 f = purple_request_fields_get_field(fields, "list");
285 if (!purple_request_field_list_get_selected(f)) {
286 /* Add new public key */
287 purple_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE,
288 G_CALLBACK(silcpurple_chat_chpk_add),
289 G_CALLBACK(silcpurple_chat_chpk_cancel),
290 purple_request_cpar_from_connection(sg->gc), sgc);
291 return;
292 }
293
294 list = purple_request_field_list_get_items(f);
295 chpks = silc_buffer_alloc_size(2);
296
297 for (ct = 0; list; list = list->next, ct++) {
298 PurpleKeyValuePair *item = list->data;
299
300 public_key = purple_request_field_list_get_data(f, item->key);
301 if (purple_request_field_list_is_selected(f, item->key)) {
302 /* Delete this public key */
303 pk = silc_public_key_payload_encode(public_key);
304 chpks = silc_argument_payload_encode_one(chpks, pk->data,
305 silc_buffer_len(pk), 0x01);
306 silc_buffer_free(pk);
307 c++;
308 }
309 }
310 if (!c) {
311 silc_buffer_free(chpks);
312 return;
313 }
314 SILC_PUT16_MSB(c, chpks->head);
315
316 m = sgc->channel->mode;
317 if (ct == c)
318 m &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
319
320 /* Send CMODE */
321 SILC_PUT32_MSB(m, mode);
322 chidp = silc_id_payload_encode(&sgc->channel->id, SILC_ID_CHANNEL);
323 silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
324 silcpurple_command_reply, NULL, 3,
325 1, chidp->data, silc_buffer_len(chidp),
326 2, mode, sizeof(mode),
327 9, chpks->data, silc_buffer_len(chpks));
328 silc_buffer_free(chpks);
329 silc_buffer_free(chidp);
330 if (sgc->pubkeys) {
331 silc_dlist_start(sgc->pubkeys);
332 while ((public_key = silc_dlist_get(sgc->pubkeys)))
333 silc_pkcs_public_key_free(public_key);
334 silc_dlist_uninit(sgc->pubkeys);
335 }
336 silc_free(sgc);
337 }
338
339 static void
340 silcpurple_chat_chauth_ok(SilcPurpleChauth sgc, PurpleRequestFields *fields)
341 {
342 SilcPurple sg = sgc->sg;
343 PurpleRequestField *f;
344 SilcPublicKey public_key;
345 const char *curpass, *val;
346 int set;
347
348 f = purple_request_fields_get_field(fields, "passphrase");
349 val = purple_request_field_string_get_value(f);
350 curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase");
351
352 if (!val && curpass)
353 set = 0;
354 else if (val && !curpass)
355 set = 1;
356 else if (val && curpass && !purple_strequal(val, curpass))
357 set = 1;
358 else
359 set = -1;
360
361 if (set == 1) {
362 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
363 sgc->channel->channel_name, "+a", val, NULL);
364 purple_blist_node_set_string((PurpleBlistNode *)sgc->c, "passphrase", val);
365 } else if (set == 0) {
366 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
367 sgc->channel->channel_name, "-a", NULL);
368 purple_blist_node_remove_setting((PurpleBlistNode *)sgc->c, "passphrase");
369 }
370
371 if (sgc->pubkeys) {
372 silc_dlist_start(sgc->pubkeys);
373 while ((public_key = silc_dlist_get(sgc->pubkeys)))
374 silc_pkcs_public_key_free(public_key);
375 silc_dlist_uninit(sgc->pubkeys);
376 }
377 silc_free(sgc);
378 }
379
380 void silcpurple_chat_chauth_show(SilcPurple sg, SilcChannelEntry channel,
381 SilcDList channel_pubkeys)
382 {
383 SilcPublicKey public_key;
384 SilcSILCPublicKey silc_pubkey;
385 unsigned char *pk;
386 SilcUInt32 pk_len;
387 char *fingerprint, *babbleprint;
388 SilcPublicKeyIdentifier ident;
389 char tmp2[1024];
390 const gchar *t;
391 PurpleRequestFields *fields;
392 PurpleRequestFieldGroup *g;
393 PurpleRequestField *f;
394 SilcPurpleChauth sgc;
395 const char *curpass = NULL;
396
397 sgc = silc_calloc(1, sizeof(*sgc));
398 if (!sgc)
399 return;
400 sgc->sg = sg;
401 sgc->channel = channel;
402
403 fields = purple_request_fields_new();
404
405 if (sgc->c)
406 curpass = purple_blist_node_get_string((PurpleBlistNode *)sgc->c, "passphrase");
407
408 g = purple_request_field_group_new(NULL);
409 f = purple_request_field_string_new("passphrase", _("Channel Passphrase"),
410 curpass, FALSE);
411 purple_request_field_string_set_masked(f, TRUE);
412 purple_request_field_group_add_field(g, f);
413 purple_request_fields_add_group(fields, g);
414
415 g = purple_request_field_group_new(NULL);
416 f = purple_request_field_label_new("l1", _("Channel Public Keys List"));
417 purple_request_field_group_add_field(g, f);
418 purple_request_fields_add_group(fields, g);
419
420 t = _("Channel authentication is used to secure the channel from "
421 "unauthorized access. The authentication may be based on "
422 "passphrase and digital signatures. If passphrase is set, it "
423 "is required to be able to join. If channel public keys are set "
424 "then only users whose public keys are listed are able to join.");
425
426 if (!channel_pubkeys || !silc_dlist_count(channel_pubkeys)) {
427 f = purple_request_field_list_new("list", NULL);
428 purple_request_field_group_add_field(g, f);
429 purple_request_fields(sg->gc, _("Channel Authentication"),
430 _("Channel Authentication"), t, fields,
431 _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb),
432 _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok),
433 purple_request_cpar_from_connection(sg->gc), sgc);
434 if (channel_pubkeys)
435 silc_dlist_uninit(channel_pubkeys);
436 return;
437 }
438 sgc->pubkeys = channel_pubkeys;
439
440 g = purple_request_field_group_new(NULL);
441 f = purple_request_field_list_new("list", NULL);
442 purple_request_field_group_add_field(g, f);
443 purple_request_fields_add_group(fields, g);
444
445 silc_dlist_start(channel_pubkeys);
446 while ((public_key = silc_dlist_get(channel_pubkeys))) {
447 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
448 if (!pk)
449 continue;
450 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
451 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
452
453 silc_pubkey = silc_pkcs_get_context(SILC_PKCS_SILC, public_key);
454 ident = &silc_pubkey->identifier;
455
456 g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s",
457 ident->realname ? ident->realname : ident->username ?
458 ident->username : "", fingerprint, babbleprint);
459 purple_request_field_list_add_icon(f, tmp2, NULL, public_key);
460
461 silc_free(fingerprint);
462 silc_free(babbleprint);
463 }
464
465 purple_request_field_list_set_multi_select(f, FALSE);
466 purple_request_fields(sg->gc, _("Channel Authentication"),
467 _("Channel Authentication"), t, fields,
468 _("Add / Remove"), G_CALLBACK(silcpurple_chat_chpk_cb),
469 _("OK"), G_CALLBACK(silcpurple_chat_chauth_ok),
470 purple_request_cpar_from_connection(sg->gc), sgc);
471 }
472
473 static void
474 silcpurple_chat_chauth(PurpleBlistNode *node, gpointer data)
475 {
476 PurpleChat *chat;
477 PurpleConnection *gc;
478 SilcPurple sg;
479
480 g_return_if_fail(PURPLE_IS_CHAT(node));
481
482 chat = (PurpleChat *) node;
483 gc = purple_account_get_connection(purple_chat_get_account(chat));
484 sg = purple_connection_get_protocol_data(gc);
485
486 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
487 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
488 "+C", NULL);
489 }
490
491
492 /************************** Channel Private Groups **************************/
493
494 /* Private groups are "virtual" channels. They are groups inside a channel.
495 This is implemented by using channel private keys. By knowing a channel
496 private key user becomes part of that group and is able to talk on that
497 group. Other users, on the same channel, won't be able to see the
498 messages of that group. It is possible to have multiple groups inside
499 a channel - and thus having multiple private keys on the channel. */
500
501 typedef struct {
502 SilcPurple sg;
503 PurpleChat *c;
504 const char *channel;
505 } *SilcPurpleCharPrv;
506
507 static void
508 silcpurple_chat_prv_add(SilcPurpleCharPrv p, PurpleRequestFields *fields)
509 {
510 SilcPurple sg = p->sg;
511 gchar *tmp;
512 PurpleRequestField *f;
513 const char *name, *passphrase, *alias;
514 GHashTable *comp;
515 PurpleGroup *g;
516 PurpleChat *cn;
517
518 f = purple_request_fields_get_field(fields, "name");
519 name = purple_request_field_string_get_value(f);
520 if (!name) {
521 silc_free(p);
522 return;
523 }
524 f = purple_request_fields_get_field(fields, "passphrase");
525 passphrase = purple_request_field_string_get_value(f);
526 f = purple_request_fields_get_field(fields, "alias");
527 alias = purple_request_field_string_get_value(f);
528
529 /* Add private group to buddy list */
530 tmp = g_strdup_printf("%s [Private Group]", name);
531 comp = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
532 g_hash_table_replace(comp, "channel", tmp);
533 g_hash_table_replace(comp, "passphrase", g_strdup(passphrase));
534
535 cn = purple_chat_new(sg->account, alias, comp);
536 g = purple_chat_get_group(p->c);
537 purple_blist_add_chat(cn, g, (PurpleBlistNode *)p->c);
538
539 /* Associate to a real channel */
540 purple_blist_node_set_string((PurpleBlistNode *)cn, "parentch", p->channel);
541
542 /* Join the group */
543 silcpurple_chat_join(NULL, sg->gc, comp);
544
545 silc_free(p);
546 }
547
548 static void
549 silcpurple_chat_prv_cancel(SilcPurpleCharPrv p, PurpleRequestFields *fields)
550 {
551 silc_free(p);
552 }
553
554 static void
555 silcpurple_chat_prv(PurpleBlistNode *node, gpointer data)
556 {
557 PurpleChat *chat;
558 PurpleConnection *gc;
559 SilcPurple sg;
560
561 SilcPurpleCharPrv p;
562 PurpleRequestFields *fields;
563 PurpleRequestFieldGroup *g;
564 PurpleRequestField *f;
565 char tmp[512];
566
567 g_return_if_fail(PURPLE_IS_CHAT(node));
568
569 chat = (PurpleChat *) node;
570 gc = purple_account_get_connection(purple_chat_get_account(chat));
571 sg = purple_connection_get_protocol_data(gc);
572
573 p = silc_calloc(1, sizeof(*p));
574 if (!p)
575 return;
576 p->sg = sg;
577
578 p->channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel");
579 p->c = purple_blist_find_chat(sg->account, p->channel);
580
581 fields = purple_request_fields_new();
582
583 g = purple_request_field_group_new(NULL);
584 f = purple_request_field_string_new("name", _("Group Name"),
585 NULL, FALSE);
586 purple_request_field_group_add_field(g, f);
587
588 f = purple_request_field_string_new("passphrase", _("Passphrase"),
589 NULL, FALSE);
590 purple_request_field_string_set_masked(f, TRUE);
591 purple_request_field_group_add_field(g, f);
592
593 f = purple_request_field_string_new("alias", _("Alias"),
594 NULL, FALSE);
595 purple_request_field_group_add_field(g, f);
596 purple_request_fields_add_group(fields, g);
597
598 g_snprintf(tmp, sizeof(tmp),
599 _("Please enter the %s channel private group name and passphrase."),
600 p->channel);
601 purple_request_fields(gc, _("Add Channel Private Group"), NULL, tmp, fields,
602 _("Add"), G_CALLBACK(silcpurple_chat_prv_add),
603 _("Cancel"), G_CALLBACK(silcpurple_chat_prv_cancel),
604 purple_request_cpar_from_connection(gc), p);
605 }
606
607
608 /****************************** Channel Modes ********************************/
609
610 static void
611 silcpurple_chat_permanent_reset(PurpleBlistNode *node, gpointer data)
612 {
613 PurpleChat *chat;
614 PurpleConnection *gc;
615 SilcPurple sg;
616
617 g_return_if_fail(PURPLE_IS_CHAT(node));
618
619 chat = (PurpleChat *) node;
620 gc = purple_account_get_connection(purple_chat_get_account(chat));
621 sg = purple_connection_get_protocol_data(gc);
622
623 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
624 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
625 "-f", NULL);
626 }
627
628 static void
629 silcpurple_chat_permanent(PurpleBlistNode *node, gpointer data)
630 {
631 PurpleChat *chat;
632 PurpleConnection *gc;
633 SilcPurple sg;
634 const char *channel;
635
636 g_return_if_fail(PURPLE_IS_CHAT(node));
637
638 chat = (PurpleChat *) node;
639 gc = purple_account_get_connection(purple_chat_get_account(chat));
640 sg = purple_connection_get_protocol_data(gc);
641
642 if (!sg->conn)
643 return;
644
645 /* XXX we should have ability to define which founder
646 key to use. Now we use the user's own public key
647 (default key). */
648
649 /* Call CMODE */
650 channel = g_hash_table_lookup(purple_chat_get_components(chat), "channel");
651 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", channel,
652 "+f", NULL);
653 }
654
655 static void
656 silcpurple_chat_ulimit_cb(PurpleKeyValuePair *s, const char *limit)
657 {
658 SilcPurple sg = s->value;
659 SilcChannelEntry channel;
660 guint ulimit = 0;
661
662 channel = silc_client_get_channel(sg->client, sg->conn, s->key);
663 if (!channel)
664 return;
665 if (limit)
666 ulimit = strtoul(limit, NULL, 10);
667
668 if (!limit || !(*limit) || *limit == '0') {
669 if (!limit || ulimit != channel->user_limit) {
670 silc_client_command_call(sg->client, sg->conn, NULL,
671 "CMODE", s->key, "-l", NULL);
672 }
673 } else if (ulimit != channel->user_limit) {
674 /* Call CMODE */
675 silc_client_command_call(sg->client, sg->conn, NULL,
676 "CMODE", s->key, "+l", limit, NULL);
677 }
678
679 purple_key_value_pair_free(s);
680 }
681
682 static void
683 silcpurple_chat_ulimit(PurpleBlistNode *node, gpointer data)
684 {
685 PurpleChat *chat;
686 PurpleConnection *gc;
687 SilcPurple sg;
688
689 PurpleKeyValuePair *s;
690 SilcChannelEntry channel;
691 char *ch;
692 char tmp[32];
693
694 g_return_if_fail(PURPLE_IS_CHAT(node));
695
696 chat = (PurpleChat *) node;
697 gc = purple_account_get_connection(purple_chat_get_account(chat));
698 sg = purple_connection_get_protocol_data(gc);
699
700 if (!sg->conn)
701 return;
702
703 ch = g_hash_table_lookup(purple_chat_get_components(chat), "channel");
704 channel = silc_client_get_channel(sg->client, sg->conn, ch);
705 if (!channel)
706 return;
707
708 s = purple_key_value_pair_new(ch, sg);
709 g_snprintf(tmp, sizeof(tmp), "%d", (int)channel->user_limit);
710 purple_request_input(gc, _("User Limit"), NULL,
711 _("Set user limit on channel. Set to zero to reset user limit."),
712 tmp, FALSE, FALSE, NULL,
713 _("OK"), G_CALLBACK(silcpurple_chat_ulimit_cb),
714 _("Cancel"), G_CALLBACK(silcpurple_chat_ulimit_cb),
715 purple_request_cpar_from_connection(gc), s);
716 }
717
718 static void
719 silcpurple_chat_resettopic(PurpleBlistNode *node, gpointer data)
720 {
721 PurpleChat *chat;
722 PurpleConnection *gc;
723 SilcPurple sg;
724
725 g_return_if_fail(PURPLE_IS_CHAT(node));
726
727 chat = (PurpleChat *) node;
728 gc = purple_account_get_connection(purple_chat_get_account(chat));
729 sg = purple_connection_get_protocol_data(gc);
730
731 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
732 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
733 "-t", NULL);
734 }
735
736 static void
737 silcpurple_chat_settopic(PurpleBlistNode *node, gpointer data)
738 {
739 PurpleChat *chat;
740 PurpleConnection *gc;
741 SilcPurple sg;
742
743 g_return_if_fail(PURPLE_IS_CHAT(node));
744
745 chat = (PurpleChat *) node;
746 gc = purple_account_get_connection(purple_chat_get_account(chat));
747 sg = purple_connection_get_protocol_data(gc);
748
749 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
750 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
751 "+t", NULL);
752 }
753
754 static void
755 silcpurple_chat_resetprivate(PurpleBlistNode *node, gpointer data)
756 {
757 PurpleChat *chat;
758 PurpleConnection *gc;
759 SilcPurple sg;
760
761 g_return_if_fail(PURPLE_IS_CHAT(node));
762
763 chat = (PurpleChat *) node;
764 gc = purple_account_get_connection(purple_chat_get_account(chat));
765 sg = purple_connection_get_protocol_data(gc);
766
767 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
768 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
769 "-p", NULL);
770 }
771
772 static void
773 silcpurple_chat_setprivate(PurpleBlistNode *node, gpointer data)
774 {
775 PurpleChat *chat;
776 PurpleConnection *gc;
777 SilcPurple sg;
778
779 g_return_if_fail(PURPLE_IS_CHAT(node));
780
781 chat = (PurpleChat *) node;
782 gc = purple_account_get_connection(purple_chat_get_account(chat));
783 sg = purple_connection_get_protocol_data(gc);
784
785 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
786 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
787 "+p", NULL);
788 }
789
790 static void
791 silcpurple_chat_resetsecret(PurpleBlistNode *node, gpointer data)
792 {
793 PurpleChat *chat;
794 PurpleConnection *gc;
795 SilcPurple sg;
796
797 g_return_if_fail(PURPLE_IS_CHAT(node));
798
799 chat = (PurpleChat *) node;
800 gc = purple_account_get_connection(purple_chat_get_account(chat));
801 sg = purple_connection_get_protocol_data(gc);
802
803 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
804 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
805 "-s", NULL);
806 }
807
808 static void
809 silcpurple_chat_setsecret(PurpleBlistNode *node, gpointer data)
810 {
811 PurpleChat *chat;
812 PurpleConnection *gc;
813 SilcPurple sg;
814
815 g_return_if_fail(PURPLE_IS_CHAT(node));
816
817 chat = (PurpleChat *) node;
818 gc = purple_account_get_connection(purple_chat_get_account(chat));
819 sg = purple_connection_get_protocol_data(gc);
820
821 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
822 g_hash_table_lookup(purple_chat_get_components(chat), "channel"),
823 "+s", NULL);
824 }
825
826 typedef struct {
827 SilcPurple sg;
828 SilcChannelEntry channel;
829 } *SilcPurpleChatWb;
830
831 static void
832 silcpurple_chat_wb(PurpleBlistNode *node, gpointer data)
833 {
834 SilcPurpleChatWb wb = data;
835 silcpurple_wb_init_ch(wb->sg, wb->channel);
836 silc_free(wb);
837 }
838
839 GList *silcpurple_chat_menu(PurpleChat *chat)
840 {
841 GHashTable *components = purple_chat_get_components(chat);
842 PurpleConnection *gc = purple_account_get_connection(purple_chat_get_account(chat));
843 SilcPurple sg = purple_connection_get_protocol_data(gc);
844 SilcClientConnection conn = sg->conn;
845 const char *chname = NULL;
846 SilcChannelEntry channel = NULL;
847 SilcChannelUser chu = NULL;
848 SilcUInt32 mode = 0;
849
850 GList *m = NULL;
851 PurpleActionMenu *act;
852
853 if (components)
854 chname = g_hash_table_lookup(components, "channel");
855 if (!chname)
856 return NULL;
857 channel = silc_client_get_channel(sg->client, sg->conn,
858 (char *)chname);
859 if (channel) {
860 chu = silc_client_on_channel(channel, conn->local_entry);
861 if (chu)
862 mode = chu->mode;
863 }
864
865 if (strstr(chname, "[Private Group]"))
866 return NULL;
867
868 act = purple_action_menu_new(_("Get Info"),
869 G_CALLBACK(silcpurple_chat_getinfo_menu),
870 NULL, NULL);
871 m = g_list_append(m, act);
872
873 if (chu) {
874 act = purple_action_menu_new(_("Add Private Group"),
875 G_CALLBACK(silcpurple_chat_prv),
876 NULL, NULL);
877 m = g_list_append(m, act);
878 }
879
880 if (chu && mode & SILC_CHANNEL_UMODE_CHANFO) {
881 act = purple_action_menu_new(_("Channel Authentication"),
882 G_CALLBACK(silcpurple_chat_chauth),
883 NULL, NULL);
884 m = g_list_append(m, act);
885
886 if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
887 act = purple_action_menu_new(_("Reset Permanent"),
888 G_CALLBACK(silcpurple_chat_permanent_reset),
889 NULL, NULL);
890 m = g_list_append(m, act);
891 } else {
892 act = purple_action_menu_new(_("Set Permanent"),
893 G_CALLBACK(silcpurple_chat_permanent),
894 NULL, NULL);
895 m = g_list_append(m, act);
896 }
897 }
898
899 if (chu && mode & SILC_CHANNEL_UMODE_CHANOP) {
900 act = purple_action_menu_new(_("Set User Limit"),
901 G_CALLBACK(silcpurple_chat_ulimit),
902 NULL, NULL);
903 m = g_list_append(m, act);
904
905 if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
906 act = purple_action_menu_new(_("Reset Topic Restriction"),
907 G_CALLBACK(silcpurple_chat_resettopic),
908 NULL, NULL);
909 m = g_list_append(m, act);
910 } else {
911 act = purple_action_menu_new(_("Set Topic Restriction"),
912 G_CALLBACK(silcpurple_chat_settopic),
913 NULL, NULL);
914 m = g_list_append(m, act);
915 }
916
917 if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
918 act = purple_action_menu_new(_("Reset Private Channel"),
919 G_CALLBACK(silcpurple_chat_resetprivate),
920 NULL, NULL);
921 m = g_list_append(m, act);
922 } else {
923 act = purple_action_menu_new(_("Set Private Channel"),
924 G_CALLBACK(silcpurple_chat_setprivate),
925 NULL, NULL);
926 m = g_list_append(m, act);
927 }
928
929 if (channel->mode & SILC_CHANNEL_MODE_SECRET) {
930 act = purple_action_menu_new(_("Reset Secret Channel"),
931 G_CALLBACK(silcpurple_chat_resetsecret),
932 NULL, NULL);
933 m = g_list_append(m, act);
934 } else {
935 act = purple_action_menu_new(_("Set Secret Channel"),
936 G_CALLBACK(silcpurple_chat_setsecret),
937 NULL, NULL);
938 m = g_list_append(m, act);
939 }
940 }
941
942 if (chu && channel) {
943 SilcPurpleChatWb wb;
944 wb = silc_calloc(1, sizeof(*wb));
945 wb->sg = sg;
946 wb->channel = channel;
947 act = purple_action_menu_new(_("Draw On Whiteboard"),
948 G_CALLBACK(silcpurple_chat_wb),
949 (void *)wb, NULL);
950 m = g_list_append(m, act);
951 }
952
953 return m;
954 }
955
956
957 /******************************* Joining Etc. ********************************/
958
959 char *silcpurple_get_chat_name(PurpleProtocolChat *protocol_chat, GHashTable *data)
960 {
961 return g_strdup(g_hash_table_lookup(data, "channel"));
962 }
963
964 void silcpurple_chat_join(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, GHashTable *data)
965 {
966 SilcPurple sg = purple_connection_get_protocol_data(gc);
967 SilcClient client = sg->client;
968 SilcClientConnection conn = sg->conn;
969 const char *channel, *passphrase, *parentch;
970
971 if (!conn)
972 return;
973
974 channel = g_hash_table_lookup(data, "channel");
975 passphrase = g_hash_table_lookup(data, "passphrase");
976
977 /* Check if we are joining a private group. Handle it
978 purely locally as it's not a real channel */
979 if (strstr(channel, "[Private Group]")) {
980 SilcChannelEntry channel_entry;
981 SilcChannelPrivateKey key;
982 PurpleChat *c;
983 SilcPurplePrvgrp grp;
984
985 c = purple_blist_find_chat(sg->account, channel);
986 parentch = purple_blist_node_get_string((PurpleBlistNode *)c, "parentch");
987 if (!parentch)
988 return;
989
990 channel_entry = silc_client_get_channel(sg->client, sg->conn,
991 (char *)parentch);
992 if (!channel_entry ||
993 !silc_client_on_channel(channel_entry, sg->conn->local_entry)) {
994 char tmp[512];
995 g_snprintf(tmp, sizeof(tmp),
996 _("You have to join the %s channel before you are "
997 "able to join the private group"), parentch);
998 purple_notify_error(gc, _("Join Private Group"),
999 _("Cannot join private group"), tmp,
1000 purple_request_cpar_from_connection(gc));
1001 return;
1002 }
1003
1004 /* Add channel private key */
1005 if (!silc_client_add_channel_private_key(client, conn,
1006 channel_entry, channel,
1007 NULL, NULL,
1008 (unsigned char *)passphrase,
1009 strlen(passphrase), &key))
1010 return;
1011
1012 /* Join the group */
1013 grp = silc_calloc(1, sizeof(*grp));
1014 if (!grp)
1015 return;
1016 grp->id = ++sg->channel_ids + SILCPURPLE_PRVGRP;
1017 grp->chid = SILC_PTR_TO_32(channel_entry->context);
1018 grp->parentch = parentch;
1019 grp->channel = channel;
1020 grp->key = key;
1021 sg->grps = g_list_append(sg->grps, grp);
1022 purple_serv_got_joined_chat(gc, grp->id, channel);
1023 return;
1024 }
1025
1026 /* XXX We should have other properties here as well:
1027 1. whether to try to authenticate to the channel
1028 1a. with default key,
1029 1b. with specific key.
1030 2. whether to try to authenticate to become founder.
1031 2a. with default key,
1032 2b. with specific key.
1033
1034 Since now such variety is not possible in the join dialog
1035 we always use -founder and -auth options, which try to
1036 do both 1 and 2 with default keys. */
1037
1038 /* Call JOIN */
1039 if ((passphrase != NULL) && (*passphrase != '\0'))
1040 silc_client_command_call(client, conn, NULL, "JOIN",
1041 channel, passphrase, "-auth", "-founder", NULL);
1042 else
1043 silc_client_command_call(client, conn, NULL, "JOIN",
1044 channel, "-auth", "-founder", NULL);
1045 }
1046
1047 void silcpurple_chat_invite(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *msg,
1048 const char *name)
1049 {
1050 SilcPurple sg = purple_connection_get_protocol_data(gc);
1051 SilcClient client = sg->client;
1052 SilcClientConnection conn = sg->conn;
1053 SilcHashTableList htl;
1054 SilcChannelUser chu;
1055 gboolean found = FALSE;
1056
1057 if (!conn)
1058 return;
1059
1060 /* See if we are inviting on a private group. Invite
1061 to the actual channel */
1062 if (id > SILCPURPLE_PRVGRP) {
1063 GList *l;
1064 SilcPurplePrvgrp prv;
1065
1066 for (l = sg->grps; l; l = l->next)
1067 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id)
1068 break;
1069 if (!l)
1070 return;
1071 prv = l->data;
1072 id = prv->chid;
1073 }
1074
1075 /* Find channel by id */
1076 silc_hash_table_list(conn->local_entry->channels, &htl);
1077 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1078 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) {
1079 found = TRUE;
1080 break;
1081 }
1082 }
1083 silc_hash_table_list_reset(&htl);
1084 if (!found)
1085 return;
1086
1087 /* Call INVITE */
1088 silc_client_command_call(client, conn, NULL, "INVITE",
1089 chu->channel->channel_name,
1090 name, NULL);
1091 }
1092
1093 void silcpurple_chat_leave(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id)
1094 {
1095 SilcPurple sg = purple_connection_get_protocol_data(gc);
1096 SilcClient client = sg->client;
1097 SilcClientConnection conn = sg->conn;
1098 SilcHashTableList htl;
1099 SilcChannelUser chu;
1100 gboolean found = FALSE;
1101 GList *l;
1102 SilcPurplePrvgrp prv;
1103
1104 if (!conn)
1105 return;
1106
1107 /* See if we are leaving a private group */
1108 if (id > SILCPURPLE_PRVGRP) {
1109 SilcChannelEntry channel;
1110
1111 for (l = sg->grps; l; l = l->next)
1112 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id)
1113 break;
1114 if (!l)
1115 return;
1116 prv = l->data;
1117 channel = silc_client_get_channel(sg->client, sg->conn,
1118 (char *)prv->parentch);
1119 if (!channel)
1120 return;
1121 silc_client_del_channel_private_key(client, conn,
1122 channel, prv->key);
1123 silc_free(prv);
1124 sg->grps = g_list_delete_link(sg->grps, l);
1125 purple_serv_got_chat_left(gc, id);
1126 return;
1127 }
1128
1129 /* Find channel by id */
1130 silc_hash_table_list(conn->local_entry->channels, &htl);
1131 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1132 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) {
1133 found = TRUE;
1134 break;
1135 }
1136 }
1137 silc_hash_table_list_reset(&htl);
1138 if (!found)
1139 return;
1140
1141 /* Call LEAVE */
1142 silc_client_command_call(client, conn, NULL, "LEAVE",
1143 chu->channel->channel_name, NULL);
1144
1145 purple_serv_got_chat_left(gc, id);
1146
1147 /* Leave from private groups on this channel as well */
1148 for (l = sg->grps; l; l = l->next)
1149 if (((SilcPurplePrvgrp)l->data)->chid == (gulong)id) {
1150 prv = l->data;
1151 silc_client_del_channel_private_key(client, conn,
1152 chu->channel,
1153 prv->key);
1154 purple_serv_got_chat_left(gc, prv->id);
1155 silc_free(prv);
1156 sg->grps = g_list_delete_link(sg->grps, l);
1157 if (!sg->grps)
1158 break;
1159 }
1160 }
1161
1162 int silcpurple_chat_send(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, PurpleMessage *pmsg)
1163 {
1164 SilcPurple sg = purple_connection_get_protocol_data(gc);
1165 SilcClient client = sg->client;
1166 SilcClientConnection conn = sg->conn;
1167 SilcHashTableList htl;
1168 SilcChannelUser chu;
1169 SilcChannelEntry channel = NULL;
1170 SilcChannelPrivateKey key = NULL;
1171 SilcMessageFlags flags;
1172 int ret = 0;
1173 const gchar *msg = purple_message_get_contents(pmsg);
1174 char *msg2, *tmp;
1175 gboolean found = FALSE;
1176 gboolean sign = purple_account_get_bool(sg->account, "sign-verify", FALSE);
1177 SilcDList list;
1178 PurpleMessageFlags msgflags = purple_message_get_flags(pmsg);
1179
1180 if (!msg || !conn)
1181 return 0;
1182
1183 flags = SILC_MESSAGE_FLAG_UTF8;
1184
1185 tmp = msg2 = purple_unescape_html(msg);
1186
1187 if (!g_ascii_strncasecmp(msg2, "/me ", 4))
1188 {
1189 msg2 += 4;
1190 if (!*msg2) {
1191 g_free(tmp);
1192 return 0;
1193 }
1194 flags |= SILC_MESSAGE_FLAG_ACTION;
1195 } else if (strlen(msg) > 1 && msg[0] == '/') {
1196 if (!silc_client_command_call(client, conn, msg + 1)) {
1197 purple_notify_error(gc, _("Call Command"),
1198 _("Cannot call command"), _("Unknown command"),
1199 purple_request_cpar_from_connection(gc));
1200 }
1201 g_free(tmp);
1202 return 0;
1203 }
1204
1205
1206 if (sign)
1207 flags |= SILC_MESSAGE_FLAG_SIGNED;
1208
1209 /* Get the channel private key if we are sending on
1210 private group */
1211 if (id > SILCPURPLE_PRVGRP) {
1212 GList *l;
1213 SilcPurplePrvgrp prv;
1214
1215 for (l = sg->grps; l; l = l->next)
1216 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id)
1217 break;
1218 if (!l) {
1219 g_free(tmp);
1220 return 0;
1221 }
1222 prv = l->data;
1223 channel = silc_client_get_channel(sg->client, sg->conn,
1224 (char *)prv->parentch);
1225 if (!channel) {
1226 g_free(tmp);
1227 return 0;
1228 }
1229 key = prv->key;
1230 }
1231
1232 if (!channel) {
1233 /* Find channel by id */
1234 silc_hash_table_list(conn->local_entry->channels, &htl);
1235 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1236 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) {
1237 found = TRUE;
1238 break;
1239 }
1240 }
1241 silc_hash_table_list_reset(&htl);
1242 if (!found) {
1243 g_free(tmp);
1244 return 0;
1245 }
1246 channel = chu->channel;
1247 }
1248
1249 /* Check for images */
1250 if (msgflags & PURPLE_MESSAGE_IMAGES) {
1251 list = silcpurple_image_message(msg, &flags);
1252 if (list) {
1253 /* Send one or more MIME message. If more than one, they
1254 are MIME fragments due to over large message */
1255 SilcBuffer buf;
1256
1257 silc_dlist_start(list);
1258 while ((buf = silc_dlist_get(list)) != SILC_LIST_END)
1259 ret =
1260 silc_client_send_channel_message(client, conn,
1261 channel, key,
1262 flags, sg->sha1hash,
1263 buf->data,
1264 silc_buffer_len(buf));
1265 silc_mime_partial_free(list);
1266 g_free(tmp);
1267
1268 if (ret)
1269 purple_serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), msgflags, msg, time(NULL));
1270 return ret;
1271 }
1272 }
1273
1274 /* Send channel message */
1275 ret = silc_client_send_channel_message(client, conn, channel, key,
1276 flags, sg->sha1hash,
1277 (unsigned char *)msg2,
1278 strlen(msg2));
1279 if (ret) {
1280 purple_serv_got_chat_in(gc, id, purple_connection_get_display_name(gc), msgflags, msg,
1281 time(NULL));
1282 }
1283 g_free(tmp);
1284
1285 return ret;
1286 }
1287
1288 void silcpurple_chat_set_topic(PurpleProtocolChat *protocol_chat, PurpleConnection *gc, int id, const char *topic)
1289 {
1290 SilcPurple sg = purple_connection_get_protocol_data(gc);
1291 SilcClient client = sg->client;
1292 SilcClientConnection conn = sg->conn;
1293 SilcHashTableList htl;
1294 SilcChannelUser chu;
1295 gboolean found = FALSE;
1296
1297 if (!conn)
1298 return;
1299
1300 /* See if setting topic on private group. Set it
1301 on the actual channel */
1302 if (id > SILCPURPLE_PRVGRP) {
1303 GList *l;
1304 SilcPurplePrvgrp prv;
1305
1306 for (l = sg->grps; l; l = l->next)
1307 if (((SilcPurplePrvgrp)l->data)->id == (gulong)id)
1308 break;
1309 if (!l)
1310 return;
1311 prv = l->data;
1312 id = prv->chid;
1313 }
1314
1315 /* Find channel by id */
1316 silc_hash_table_list(conn->local_entry->channels, &htl);
1317 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1318 if (SILC_PTR_TO_32(chu->channel->context) == (gulong)id ) {
1319 found = TRUE;
1320 break;
1321 }
1322 }
1323 silc_hash_table_list_reset(&htl);
1324 if (!found)
1325 return;
1326
1327 /* Call TOPIC */
1328 silc_client_command_call(client, conn, NULL, "TOPIC",
1329 chu->channel->channel_name, topic, NULL);
1330 }
1331
1332 PurpleRoomlist *
1333 silcpurple_roomlist_get_list(PurpleProtocolRoomlist *protocol_roomlist,
1334 PurpleConnection *gc)
1335 {
1336 SilcPurple sg = purple_connection_get_protocol_data(gc);
1337 SilcClient client = sg->client;
1338 SilcClientConnection conn = sg->conn;
1339
1340 if (!conn)
1341 return NULL;
1342
1343 if (sg->roomlist)
1344 g_object_unref(sg->roomlist);
1345
1346 sg->roomlist_cancelled = FALSE;
1347
1348 sg->roomlist = purple_roomlist_new(purple_connection_get_account(gc));
1349
1350 /* Call LIST */
1351 silc_client_command_call(client, conn, "LIST");
1352
1353 purple_roomlist_set_in_progress(sg->roomlist, TRUE);
1354
1355 return sg->roomlist;
1356 }
1357
1358 void
1359 silcpurple_roomlist_cancel(PurpleProtocolRoomlist *protocol_roomlist,
1360 PurpleRoomlist *list)
1361 {
1362 PurpleAccount *account = purple_roomlist_get_account(list);
1363 PurpleConnection *gc = purple_account_get_connection(account);
1364 SilcPurple sg;
1365
1366 if (!gc)
1367 return;
1368 sg = purple_connection_get_protocol_data(gc);
1369
1370 purple_roomlist_set_in_progress(list, FALSE);
1371 if (sg->roomlist == list) {
1372 g_object_unref(sg->roomlist);
1373 sg->roomlist = NULL;
1374 sg->roomlist_cancelled = TRUE;
1375 }
1376 }

mercurial