comparison libpurple/protocols/silc/chat.c @ 15373:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 32c366eeeb99
comparison
equal deleted inserted replaced
15372:f79e0f4df793 15373:5fe8042783c1
1 /*
2
3 silcgaim_chat.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 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 "silcincludes.h"
21 #include "silcclient.h"
22 #include "silcgaim.h"
23 #include "wb.h"
24
25 /***************************** Channel Routines ******************************/
26
27 GList *silcgaim_chat_info(GaimConnection *gc)
28 {
29 GList *ci = NULL;
30 struct proto_chat_entry *pce;
31
32 pce = g_new0(struct proto_chat_entry, 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(struct proto_chat_entry, 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 *silcgaim_chat_info_defaults(GaimConnection *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 silcgaim_chat_getinfo(GaimConnection *gc, GHashTable *components);
61
62 static void
63 silcgaim_chat_getinfo_res(SilcClient client,
64 SilcClientConnection conn,
65 SilcChannelEntry *channels,
66 SilcUInt32 channels_count,
67 void *context)
68 {
69 GHashTable *components = context;
70 GaimConnection *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 gaim_notify_error(gc, _("Channel Information"),
82 _("Cannot get channel information"), tmp);
83 return;
84 }
85
86 silcgaim_chat_getinfo(gc, components);
87 }
88
89
90 static void
91 silcgaim_chat_getinfo(GaimConnection *gc, GHashTable *components)
92 {
93 SilcGaim sg = gc->proto_data;
94 const char *chname;
95 char *buf, tmp[256], *tmp2;
96 GString *s;
97 SilcChannelEntry channel;
98 SilcHashTableList htl;
99 SilcChannelUser chu;
100
101 if (!components)
102 return;
103
104 chname = g_hash_table_lookup(components, "channel");
105 if (!chname)
106 return;
107 channel = silc_client_get_channel(sg->client, sg->conn,
108 (char *)chname);
109 if (!channel) {
110 silc_client_get_channel_resolve(sg->client, sg->conn,
111 (char *)chname,
112 silcgaim_chat_getinfo_res,
113 components);
114 return;
115 }
116
117 s = g_string_new("");
118 tmp2 = g_markup_escape_text(channel->channel_name, -1);
119 g_string_append_printf(s, _("<b>Channel Name:</b> %s"), tmp2);
120 g_free(tmp2);
121 if (channel->user_list && silc_hash_table_count(channel->user_list))
122 g_string_append_printf(s, _("<br><b>User Count:</b> %d"),
123 (int)silc_hash_table_count(channel->user_list));
124
125 silc_hash_table_list(channel->user_list, &htl);
126 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
127 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
128 tmp2 = g_markup_escape_text(chu->client->nickname, -1);
129 g_string_append_printf(s, _("<br><b>Channel Founder:</b> %s"),
130 tmp2);
131 g_free(tmp2);
132 break;
133 }
134 }
135 silc_hash_table_list_reset(&htl);
136
137 if (channel->channel_key)
138 g_string_append_printf(s, _("<br><b>Channel Cipher:</b> %s"),
139 silc_cipher_get_name(channel->channel_key));
140 if (channel->hmac)
141 /* Definition of HMAC: http://en.wikipedia.org/wiki/HMAC */
142 g_string_append_printf(s, _("<br><b>Channel HMAC:</b> %s"),
143 silc_hmac_get_name(channel->hmac));
144
145 if (channel->topic) {
146 tmp2 = g_markup_escape_text(channel->topic, -1);
147 g_string_append_printf(s, _("<br><b>Channel Topic:</b><br>%s"), tmp2);
148 g_free(tmp2);
149 }
150
151 if (channel->mode) {
152 g_string_append_printf(s, _("<br><b>Channel Modes:</b> "));
153 silcgaim_get_chmode_string(channel->mode, tmp, sizeof(tmp));
154 g_string_append(s, tmp);
155 }
156
157 if (channel->founder_key) {
158 char *fingerprint, *babbleprint;
159 unsigned char *pk;
160 SilcUInt32 pk_len;
161 pk = silc_pkcs_public_key_encode(channel->founder_key, &pk_len);
162 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
163 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
164
165 g_string_append_printf(s, _("<br><b>Founder Key Fingerprint:</b><br>%s"), fingerprint);
166 g_string_append_printf(s, _("<br><b>Founder Key Babbleprint:</b><br>%s"), babbleprint);
167
168 silc_free(fingerprint);
169 silc_free(babbleprint);
170 silc_free(pk);
171 }
172
173 buf = g_string_free(s, FALSE);
174 gaim_notify_formatted(gc, NULL, _("Channel Information"), NULL, buf, NULL, NULL);
175 g_free(buf);
176 }
177
178
179 static void
180 silcgaim_chat_getinfo_menu(GaimBlistNode *node, gpointer data)
181 {
182 GaimChat *chat = (GaimChat *)node;
183 silcgaim_chat_getinfo(chat->account->gc, chat->components);
184 }
185
186
187 #if 0 /* XXX For now these are not implemented. We need better
188 listview dialog from Gaim for these. */
189 /************************** Channel Invite List ******************************/
190
191 static void
192 silcgaim_chat_invitelist(GaimBlistNode *node, gpointer data);
193 {
194
195 }
196
197
198 /**************************** Channel Ban List *******************************/
199
200 static void
201 silcgaim_chat_banlist(GaimBlistNode *node, gpointer data);
202 {
203
204 }
205 #endif
206
207
208 /************************* Channel Authentication ****************************/
209
210 typedef struct {
211 SilcGaim sg;
212 SilcChannelEntry channel;
213 GaimChat *c;
214 SilcBuffer pubkeys;
215 } *SilcGaimChauth;
216
217 static void
218 silcgaim_chat_chpk_add(void *user_data, const char *name)
219 {
220 SilcGaimChauth sgc = (SilcGaimChauth)user_data;
221 SilcGaim sg = sgc->sg;
222 SilcClient client = sg->client;
223 SilcClientConnection conn = sg->conn;
224 SilcPublicKey public_key;
225 SilcBuffer chpks, pk, chidp;
226 unsigned char mode[4];
227 SilcUInt32 m;
228
229 /* Load the public key */
230 if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) &&
231 !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) {
232 silcgaim_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys);
233 silc_buffer_free(sgc->pubkeys);
234 silc_free(sgc);
235 gaim_notify_error(client->application,
236 _("Add Channel Public Key"),
237 _("Could not load public key"), NULL);
238 return;
239 }
240
241 pk = silc_pkcs_public_key_payload_encode(public_key);
242 chpks = silc_buffer_alloc_size(2);
243 SILC_PUT16_MSB(1, chpks->head);
244 chpks = silc_argument_payload_encode_one(chpks, pk->data,
245 pk->len, 0x00);
246 silc_buffer_free(pk);
247
248 m = sgc->channel->mode;
249 m |= SILC_CHANNEL_MODE_CHANNEL_AUTH;
250
251 /* Send CMODE */
252 SILC_PUT32_MSB(m, mode);
253 chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL);
254 silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
255 ++conn->cmd_ident, 3,
256 1, chidp->data, chidp->len,
257 2, mode, sizeof(mode),
258 9, chpks->data, chpks->len);
259 silc_buffer_free(chpks);
260 silc_buffer_free(chidp);
261 silc_buffer_free(sgc->pubkeys);
262 silc_free(sgc);
263 }
264
265 static void
266 silcgaim_chat_chpk_cancel(void *user_data, const char *name)
267 {
268 SilcGaimChauth sgc = (SilcGaimChauth)user_data;
269 silcgaim_chat_chauth_show(sgc->sg, sgc->channel, sgc->pubkeys);
270 silc_buffer_free(sgc->pubkeys);
271 silc_free(sgc);
272 }
273
274 static void
275 silcgaim_chat_chpk_cb(SilcGaimChauth sgc, GaimRequestFields *fields)
276 {
277 SilcGaim sg = sgc->sg;
278 SilcClient client = sg->client;
279 SilcClientConnection conn = sg->conn;
280 GaimRequestField *f;
281 const GList *list;
282 SilcPublicKey public_key;
283 SilcBuffer chpks, pk, chidp;
284 SilcUInt16 c = 0, ct;
285 unsigned char mode[4];
286 SilcUInt32 m;
287
288 f = gaim_request_fields_get_field(fields, "list");
289 if (!gaim_request_field_list_get_selected(f)) {
290 /* Add new public key */
291 gaim_request_file(sg->gc, _("Open Public Key..."), NULL, FALSE,
292 G_CALLBACK(silcgaim_chat_chpk_add),
293 G_CALLBACK(silcgaim_chat_chpk_cancel), sgc);
294 return;
295 }
296
297 list = gaim_request_field_list_get_items(f);
298 chpks = silc_buffer_alloc_size(2);
299
300 for (ct = 0; list; list = list->next, ct++) {
301 public_key = gaim_request_field_list_get_data(f, list->data);
302 if (gaim_request_field_list_is_selected(f, list->data)) {
303 /* Delete this public key */
304 pk = silc_pkcs_public_key_payload_encode(public_key);
305 chpks = silc_argument_payload_encode_one(chpks, pk->data,
306 pk->len, 0x01);
307 silc_buffer_free(pk);
308 c++;
309 }
310 silc_pkcs_public_key_free(public_key);
311 }
312 if (!c) {
313 silc_buffer_free(chpks);
314 return;
315 }
316 SILC_PUT16_MSB(c, chpks->head);
317
318 m = sgc->channel->mode;
319 if (ct == c)
320 m &= ~SILC_CHANNEL_MODE_CHANNEL_AUTH;
321
322 /* Send CMODE */
323 SILC_PUT32_MSB(m, mode);
324 chidp = silc_id_payload_encode(sgc->channel->id, SILC_ID_CHANNEL);
325 silc_client_command_send(client, conn, SILC_COMMAND_CMODE,
326 ++conn->cmd_ident, 3,
327 1, chidp->data, chidp->len,
328 2, mode, sizeof(mode),
329 9, chpks->data, chpks->len);
330 silc_buffer_free(chpks);
331 silc_buffer_free(chidp);
332 silc_buffer_free(sgc->pubkeys);
333 silc_free(sgc);
334 }
335
336 static void
337 silcgaim_chat_chauth_ok(SilcGaimChauth sgc, GaimRequestFields *fields)
338 {
339 SilcGaim sg = sgc->sg;
340 GaimRequestField *f;
341 const char *curpass, *val;
342 int set;
343
344 f = gaim_request_fields_get_field(fields, "passphrase");
345 val = gaim_request_field_string_get_value(f);
346 curpass = gaim_blist_node_get_string((GaimBlistNode *)sgc->c, "passphrase");
347
348 if (!val && curpass)
349 set = 0;
350 else if (val && !curpass)
351 set = 1;
352 else if (val && curpass && strcmp(val, curpass))
353 set = 1;
354 else
355 set = -1;
356
357 if (set == 1) {
358 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
359 sgc->channel->channel_name, "+a", val, NULL);
360 gaim_blist_node_set_string((GaimBlistNode *)sgc->c, "passphrase", val);
361 } else if (set == 0) {
362 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
363 sgc->channel->channel_name, "-a", NULL);
364 gaim_blist_node_remove_setting((GaimBlistNode *)sgc->c, "passphrase");
365 }
366
367 silc_buffer_free(sgc->pubkeys);
368 silc_free(sgc);
369 }
370
371 void silcgaim_chat_chauth_show(SilcGaim sg, SilcChannelEntry channel,
372 SilcBuffer channel_pubkeys)
373 {
374 SilcUInt16 argc;
375 SilcArgumentPayload chpks;
376 unsigned char *pk;
377 SilcUInt32 pk_len, type;
378 char *fingerprint, *babbleprint;
379 SilcPublicKey pubkey;
380 SilcPublicKeyIdentifier ident;
381 char tmp2[1024], t[512];
382 GaimRequestFields *fields;
383 GaimRequestFieldGroup *g;
384 GaimRequestField *f;
385 SilcGaimChauth sgc;
386 const char *curpass = NULL;
387
388 sgc = silc_calloc(1, sizeof(*sgc));
389 if (!sgc)
390 return;
391 sgc->sg = sg;
392 sgc->channel = channel;
393
394 fields = gaim_request_fields_new();
395
396 if (sgc->c)
397 curpass = gaim_blist_node_get_string((GaimBlistNode *)sgc->c, "passphrase");
398
399 g = gaim_request_field_group_new(NULL);
400 f = gaim_request_field_string_new("passphrase", _("Channel Passphrase"),
401 curpass, FALSE);
402 gaim_request_field_string_set_masked(f, TRUE);
403 gaim_request_field_group_add_field(g, f);
404 gaim_request_fields_add_group(fields, g);
405
406 g = gaim_request_field_group_new(NULL);
407 f = gaim_request_field_label_new("l1", _("Channel Public Keys List"));
408 gaim_request_field_group_add_field(g, f);
409 gaim_request_fields_add_group(fields, g);
410
411 g_snprintf(t, sizeof(t),
412 _("Channel authentication is used to secure the channel from "
413 "unauthorized access. The authentication may be based on "
414 "passphrase and digital signatures. If passphrase is set, it "
415 "is required to be able to join. If channel public keys are set "
416 "then only users whose public keys are listed are able to join."));
417
418 if (!channel_pubkeys) {
419 f = gaim_request_field_list_new("list", NULL);
420 gaim_request_field_group_add_field(g, f);
421 gaim_request_fields(sg->gc, _("Channel Authentication"),
422 _("Channel Authentication"), t, fields,
423 _("Add / Remove"), G_CALLBACK(silcgaim_chat_chpk_cb),
424 _("OK"), G_CALLBACK(silcgaim_chat_chauth_ok), sgc);
425 return;
426 }
427 sgc->pubkeys = silc_buffer_copy(channel_pubkeys);
428
429 g = gaim_request_field_group_new(NULL);
430 f = gaim_request_field_list_new("list", NULL);
431 gaim_request_field_group_add_field(g, f);
432 gaim_request_fields_add_group(fields, g);
433
434 SILC_GET16_MSB(argc, channel_pubkeys->data);
435 chpks = silc_argument_payload_parse(channel_pubkeys->data + 2,
436 channel_pubkeys->len - 2, argc);
437 if (!chpks)
438 return;
439
440 pk = silc_argument_get_first_arg(chpks, &type, &pk_len);
441 while (pk) {
442 fingerprint = silc_hash_fingerprint(NULL, pk + 4, pk_len - 4);
443 babbleprint = silc_hash_babbleprint(NULL, pk + 4, pk_len - 4);
444 silc_pkcs_public_key_payload_decode(pk, pk_len, &pubkey);
445 ident = silc_pkcs_decode_identifier(pubkey->identifier);
446
447 g_snprintf(tmp2, sizeof(tmp2), "%s\n %s\n %s",
448 ident->realname ? ident->realname : ident->username ?
449 ident->username : "", fingerprint, babbleprint);
450 gaim_request_field_list_add(f, tmp2, pubkey);
451
452 silc_free(fingerprint);
453 silc_free(babbleprint);
454 silc_pkcs_free_identifier(ident);
455 pk = silc_argument_get_next_arg(chpks, &type, &pk_len);
456 }
457
458 gaim_request_field_list_set_multi_select(f, FALSE);
459 gaim_request_fields(sg->gc, _("Channel Authentication"),
460 _("Channel Authentication"), t, fields,
461 _("Add / Remove"), G_CALLBACK(silcgaim_chat_chpk_cb),
462 _("OK"), G_CALLBACK(silcgaim_chat_chauth_ok), sgc);
463
464 silc_argument_payload_free(chpks);
465 }
466
467 static void
468 silcgaim_chat_chauth(GaimBlistNode *node, gpointer data)
469 {
470 GaimChat *chat;
471 GaimConnection *gc;
472 SilcGaim sg;
473
474 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
475
476 chat = (GaimChat *) node;
477 gc = gaim_account_get_connection(chat->account);
478 sg = gc->proto_data;
479
480 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
481 g_hash_table_lookup(chat->components, "channel"),
482 "+C", NULL);
483 }
484
485
486 /************************** Channel Private Groups **************************/
487
488 /* Private groups are "virtual" channels. They are groups inside a channel.
489 This is implemented by using channel private keys. By knowing a channel
490 private key user becomes part of that group and is able to talk on that
491 group. Other users, on the same channel, won't be able to see the
492 messages of that group. It is possible to have multiple groups inside
493 a channel - and thus having multiple private keys on the channel. */
494
495 typedef struct {
496 SilcGaim sg;
497 GaimChat *c;
498 const char *channel;
499 } *SilcGaimCharPrv;
500
501 static void
502 silcgaim_chat_prv_add(SilcGaimCharPrv p, GaimRequestFields *fields)
503 {
504 SilcGaim sg = p->sg;
505 char tmp[512];
506 GaimRequestField *f;
507 const char *name, *passphrase, *alias;
508 GHashTable *comp;
509 GaimGroup *g;
510 GaimChat *cn;
511
512 f = gaim_request_fields_get_field(fields, "name");
513 name = gaim_request_field_string_get_value(f);
514 if (!name) {
515 silc_free(p);
516 return;
517 }
518 f = gaim_request_fields_get_field(fields, "passphrase");
519 passphrase = gaim_request_field_string_get_value(f);
520 f = gaim_request_fields_get_field(fields, "alias");
521 alias = gaim_request_field_string_get_value(f);
522
523 /* Add private group to buddy list */
524 g_snprintf(tmp, sizeof(tmp), "%s [Private Group]", name);
525 comp = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
526 g_hash_table_replace(comp, g_strdup("channel"), g_strdup(tmp));
527 g_hash_table_replace(comp, g_strdup("passphrase"), g_strdup(passphrase));
528
529 cn = gaim_chat_new(sg->account, alias, comp);
530 g = (GaimGroup *)p->c->node.parent;
531 gaim_blist_add_chat(cn, g, (GaimBlistNode *)p->c);
532
533 /* Associate to a real channel */
534 gaim_blist_node_set_string((GaimBlistNode *)cn, "parentch", p->channel);
535
536 /* Join the group */
537 silcgaim_chat_join(sg->gc, comp);
538
539 silc_free(p);
540 }
541
542 static void
543 silcgaim_chat_prv_cancel(SilcGaimCharPrv p, GaimRequestFields *fields)
544 {
545 silc_free(p);
546 }
547
548 static void
549 silcgaim_chat_prv(GaimBlistNode *node, gpointer data)
550 {
551 GaimChat *chat;
552 GaimConnection *gc;
553 SilcGaim sg;
554
555 SilcGaimCharPrv p;
556 GaimRequestFields *fields;
557 GaimRequestFieldGroup *g;
558 GaimRequestField *f;
559 char tmp[512];
560
561 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
562
563 chat = (GaimChat *) node;
564 gc = gaim_account_get_connection(chat->account);
565 sg = gc->proto_data;
566
567 p = silc_calloc(1, sizeof(*p));
568 if (!p)
569 return;
570 p->sg = sg;
571
572 p->channel = g_hash_table_lookup(chat->components, "channel");
573 p->c = gaim_blist_find_chat(sg->account, p->channel);
574
575 fields = gaim_request_fields_new();
576
577 g = gaim_request_field_group_new(NULL);
578 f = gaim_request_field_string_new("name", _("Group Name"),
579 NULL, FALSE);
580 gaim_request_field_group_add_field(g, f);
581
582 f = gaim_request_field_string_new("passphrase", _("Passphrase"),
583 NULL, FALSE);
584 gaim_request_field_string_set_masked(f, TRUE);
585 gaim_request_field_group_add_field(g, f);
586
587 f = gaim_request_field_string_new("alias", _("Alias"),
588 NULL, FALSE);
589 gaim_request_field_group_add_field(g, f);
590 gaim_request_fields_add_group(fields, g);
591
592 g_snprintf(tmp, sizeof(tmp),
593 _("Please enter the %s channel private group name and passphrase."),
594 p->channel);
595 gaim_request_fields(gc, _("Add Channel Private Group"), NULL, tmp, fields,
596 _("Add"), G_CALLBACK(silcgaim_chat_prv_add),
597 _("Cancel"), G_CALLBACK(silcgaim_chat_prv_cancel), p);
598 }
599
600
601 /****************************** Channel Modes ********************************/
602
603 static void
604 silcgaim_chat_permanent_reset(GaimBlistNode *node, gpointer data)
605 {
606 GaimChat *chat;
607 GaimConnection *gc;
608 SilcGaim sg;
609
610 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
611
612 chat = (GaimChat *) node;
613 gc = gaim_account_get_connection(chat->account);
614 sg = gc->proto_data;
615
616 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
617 g_hash_table_lookup(chat->components, "channel"),
618 "-f", NULL);
619 }
620
621 static void
622 silcgaim_chat_permanent(GaimBlistNode *node, gpointer data)
623 {
624 GaimChat *chat;
625 GaimConnection *gc;
626 SilcGaim sg;
627 const char *channel;
628
629 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
630
631 chat = (GaimChat *) node;
632 gc = gaim_account_get_connection(chat->account);
633 sg = gc->proto_data;
634
635 if (!sg->conn)
636 return;
637
638 /* XXX we should have ability to define which founder
639 key to use. Now we use the user's own public key
640 (default key). */
641
642 /* Call CMODE */
643 channel = g_hash_table_lookup(chat->components, "channel");
644 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE", channel,
645 "+f", NULL);
646 }
647
648 typedef struct {
649 SilcGaim sg;
650 const char *channel;
651 } *SilcGaimChatInput;
652
653 static void
654 silcgaim_chat_ulimit_cb(SilcGaimChatInput s, const char *limit)
655 {
656 SilcChannelEntry channel;
657 int ulimit = 0;
658
659 channel = silc_client_get_channel(s->sg->client, s->sg->conn,
660 (char *)s->channel);
661 if (!channel)
662 return;
663 if (limit)
664 ulimit = atoi(limit);
665
666 if (!limit || !(*limit) || *limit == '0') {
667 if (limit && ulimit == channel->user_limit) {
668 silc_free(s);
669 return;
670 }
671 silc_client_command_call(s->sg->client, s->sg->conn, NULL, "CMODE",
672 s->channel, "-l", NULL);
673
674 silc_free(s);
675 return;
676 }
677
678 if (ulimit == channel->user_limit) {
679 silc_free(s);
680 return;
681 }
682
683 /* Call CMODE */
684 silc_client_command_call(s->sg->client, s->sg->conn, NULL, "CMODE",
685 s->channel, "+l", limit, NULL);
686
687 silc_free(s);
688 }
689
690 static void
691 silcgaim_chat_ulimit(GaimBlistNode *node, gpointer data)
692 {
693 GaimChat *chat;
694 GaimConnection *gc;
695 SilcGaim sg;
696
697 SilcGaimChatInput s;
698 SilcChannelEntry channel;
699 const char *ch;
700 char tmp[32];
701
702 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
703
704 chat = (GaimChat *) node;
705 gc = gaim_account_get_connection(chat->account);
706 sg = gc->proto_data;
707
708 if (!sg->conn)
709 return;
710
711 ch = g_strdup(g_hash_table_lookup(chat->components, "channel"));
712 channel = silc_client_get_channel(sg->client, sg->conn, (char *)ch);
713 if (!channel)
714 return;
715
716 s = silc_calloc(1, sizeof(*s));
717 if (!s)
718 return;
719 s->channel = ch;
720 s->sg = sg;
721 g_snprintf(tmp, sizeof(tmp), "%d", (int)channel->user_limit);
722 gaim_request_input(gc, _("User Limit"), NULL,
723 _("Set user limit on channel. Set to zero to reset user limit."),
724 tmp, FALSE, FALSE, NULL,
725 _("OK"), G_CALLBACK(silcgaim_chat_ulimit_cb),
726 _("Cancel"), G_CALLBACK(silcgaim_chat_ulimit_cb), s);
727 }
728
729 static void
730 silcgaim_chat_resettopic(GaimBlistNode *node, gpointer data)
731 {
732 GaimChat *chat;
733 GaimConnection *gc;
734 SilcGaim sg;
735
736 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
737
738 chat = (GaimChat *) node;
739 gc = gaim_account_get_connection(chat->account);
740 sg = gc->proto_data;
741
742 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
743 g_hash_table_lookup(chat->components, "channel"),
744 "-t", NULL);
745 }
746
747 static void
748 silcgaim_chat_settopic(GaimBlistNode *node, gpointer data)
749 {
750 GaimChat *chat;
751 GaimConnection *gc;
752 SilcGaim sg;
753
754 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
755
756 chat = (GaimChat *) node;
757 gc = gaim_account_get_connection(chat->account);
758 sg = gc->proto_data;
759
760 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
761 g_hash_table_lookup(chat->components, "channel"),
762 "+t", NULL);
763 }
764
765 static void
766 silcgaim_chat_resetprivate(GaimBlistNode *node, gpointer data)
767 {
768 GaimChat *chat;
769 GaimConnection *gc;
770 SilcGaim sg;
771
772 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
773
774 chat = (GaimChat *) node;
775 gc = gaim_account_get_connection(chat->account);
776 sg = gc->proto_data;
777
778 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
779 g_hash_table_lookup(chat->components, "channel"),
780 "-p", NULL);
781 }
782
783 static void
784 silcgaim_chat_setprivate(GaimBlistNode *node, gpointer data)
785 {
786 GaimChat *chat;
787 GaimConnection *gc;
788 SilcGaim sg;
789
790 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
791
792 chat = (GaimChat *) node;
793 gc = gaim_account_get_connection(chat->account);
794 sg = gc->proto_data;
795
796 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
797 g_hash_table_lookup(chat->components, "channel"),
798 "+p", NULL);
799 }
800
801 static void
802 silcgaim_chat_resetsecret(GaimBlistNode *node, gpointer data)
803 {
804 GaimChat *chat;
805 GaimConnection *gc;
806 SilcGaim sg;
807
808 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
809
810 chat = (GaimChat *) node;
811 gc = gaim_account_get_connection(chat->account);
812 sg = gc->proto_data;
813
814 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
815 g_hash_table_lookup(chat->components, "channel"),
816 "-s", NULL);
817 }
818
819 static void
820 silcgaim_chat_setsecret(GaimBlistNode *node, gpointer data)
821 {
822 GaimChat *chat;
823 GaimConnection *gc;
824 SilcGaim sg;
825
826 g_return_if_fail(GAIM_BLIST_NODE_IS_CHAT(node));
827
828 chat = (GaimChat *) node;
829 gc = gaim_account_get_connection(chat->account);
830 sg = gc->proto_data;
831
832 silc_client_command_call(sg->client, sg->conn, NULL, "CMODE",
833 g_hash_table_lookup(chat->components, "channel"),
834 "+s", NULL);
835 }
836
837 typedef struct {
838 SilcGaim sg;
839 SilcChannelEntry channel;
840 } *SilcGaimChatWb;
841
842 static void
843 silcgaim_chat_wb(GaimBlistNode *node, gpointer data)
844 {
845 SilcGaimChatWb wb = data;
846 silcgaim_wb_init_ch(wb->sg, wb->channel);
847 silc_free(wb);
848 }
849
850 GList *silcgaim_chat_menu(GaimChat *chat)
851 {
852 GHashTable *components = chat->components;
853 GaimConnection *gc = gaim_account_get_connection(chat->account);
854 SilcGaim sg = gc->proto_data;
855 SilcClientConnection conn = sg->conn;
856 const char *chname = NULL;
857 SilcChannelEntry channel = NULL;
858 SilcChannelUser chu = NULL;
859 SilcUInt32 mode = 0;
860
861 GList *m = NULL;
862 GaimMenuAction *act;
863
864 if (components)
865 chname = g_hash_table_lookup(components, "channel");
866 if (chname)
867 channel = silc_client_get_channel(sg->client, sg->conn,
868 (char *)chname);
869 if (channel) {
870 chu = silc_client_on_channel(channel, conn->local_entry);
871 if (chu)
872 mode = chu->mode;
873 }
874
875 if (strstr(chname, "[Private Group]"))
876 return NULL;
877
878 act = gaim_menu_action_new(_("Get Info"),
879 GAIM_CALLBACK(silcgaim_chat_getinfo_menu),
880 NULL, NULL);
881 m = g_list_append(m, act);
882
883 #if 0 /* XXX For now these are not implemented. We need better
884 listview dialog from Gaim for these. */
885 if (mode & SILC_CHANNEL_UMODE_CHANOP) {
886 act = gaim_menu_action_new(_("Invite List"),
887 GAIM_CALLBACK(silcgaim_chat_invitelist),
888 NULL, NULL);
889 m = g_list_append(m, act);
890
891 act = gaim_menu_action_new(_("Ban List"),
892 GAIM_CALLBACK(silcgaim_chat_banlist),
893 NULL, NULL);
894 m = g_list_append(m, act);
895 }
896 #endif
897
898 if (chu) {
899 act = gaim_menu_action_new(_("Add Private Group"),
900 GAIM_CALLBACK(silcgaim_chat_prv),
901 NULL, NULL);
902 m = g_list_append(m, act);
903 }
904
905 if (mode & SILC_CHANNEL_UMODE_CHANFO) {
906 act = gaim_menu_action_new(_("Channel Authentication"),
907 GAIM_CALLBACK(silcgaim_chat_chauth),
908 NULL, NULL);
909 m = g_list_append(m, act);
910
911 if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
912 act = gaim_menu_action_new(_("Reset Permanent"),
913 GAIM_CALLBACK(silcgaim_chat_permanent_reset),
914 NULL, NULL);
915 m = g_list_append(m, act);
916 } else {
917 act = gaim_menu_action_new(_("Set Permanent"),
918 GAIM_CALLBACK(silcgaim_chat_permanent),
919 NULL, NULL);
920 m = g_list_append(m, act);
921 }
922 }
923
924 if (mode & SILC_CHANNEL_UMODE_CHANOP) {
925 act = gaim_menu_action_new(_("Set User Limit"),
926 GAIM_CALLBACK(silcgaim_chat_ulimit),
927 NULL, NULL);
928 m = g_list_append(m, act);
929
930 if (channel->mode & SILC_CHANNEL_MODE_TOPIC) {
931 act = gaim_menu_action_new(_("Reset Topic Restriction"),
932 GAIM_CALLBACK(silcgaim_chat_resettopic),
933 NULL, NULL);
934 m = g_list_append(m, act);
935 } else {
936 act = gaim_menu_action_new(_("Set Topic Restriction"),
937 GAIM_CALLBACK(silcgaim_chat_settopic),
938 NULL, NULL);
939 m = g_list_append(m, act);
940 }
941
942 if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
943 act = gaim_menu_action_new(_("Reset Private Channel"),
944 GAIM_CALLBACK(silcgaim_chat_resetprivate),
945 NULL, NULL);
946 m = g_list_append(m, act);
947 } else {
948 act = gaim_menu_action_new(_("Set Private Channel"),
949 GAIM_CALLBACK(silcgaim_chat_setprivate),
950 NULL, NULL);
951 m = g_list_append(m, act);
952 }
953
954 if (channel->mode & SILC_CHANNEL_MODE_SECRET) {
955 act = gaim_menu_action_new(_("Reset Secret Channel"),
956 GAIM_CALLBACK(silcgaim_chat_resetsecret),
957 NULL, NULL);
958 m = g_list_append(m, act);
959 } else {
960 act = gaim_menu_action_new(_("Set Secret Channel"),
961 GAIM_CALLBACK(silcgaim_chat_setsecret),
962 NULL, NULL);
963 m = g_list_append(m, act);
964 }
965 }
966
967 if (channel) {
968 SilcGaimChatWb wb;
969 wb = silc_calloc(1, sizeof(*wb));
970 wb->sg = sg;
971 wb->channel = channel;
972 act = gaim_menu_action_new(_("Draw On Whiteboard"),
973 GAIM_CALLBACK(silcgaim_chat_wb),
974 (void *)wb, NULL);
975 m = g_list_append(m, act);
976 }
977
978 return m;
979 }
980
981
982 /******************************* Joining Etc. ********************************/
983
984 void silcgaim_chat_join_done(SilcClient client,
985 SilcClientConnection conn,
986 SilcClientEntry *clients,
987 SilcUInt32 clients_count,
988 void *context)
989 {
990 GaimConnection *gc = client->application;
991 SilcGaim sg = gc->proto_data;
992 SilcChannelEntry channel = context;
993 GaimConversation *convo;
994 SilcUInt32 retry = SILC_PTR_TO_32(channel->context);
995 SilcHashTableList htl;
996 SilcChannelUser chu;
997 GList *users = NULL, *flags = NULL;
998 char tmp[256];
999
1000 if (!clients && retry < 1) {
1001 /* Resolving users failed, try again. */
1002 channel->context = SILC_32_TO_PTR(retry + 1);
1003 silc_client_get_clients_by_channel(client, conn, channel,
1004 silcgaim_chat_join_done, channel);
1005 return;
1006 }
1007
1008 /* Add channel to Gaim */
1009 channel->context = SILC_32_TO_PTR(++sg->channel_ids);
1010 serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name);
1011 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
1012 channel->channel_name, sg->account);
1013 if (!convo)
1014 return;
1015
1016 /* Add all users to channel */
1017 silc_hash_table_list(channel->user_list, &htl);
1018 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1019 GaimConvChatBuddyFlags f = GAIM_CBFLAGS_NONE;
1020 if (!chu->client->nickname)
1021 continue;
1022 chu->context = SILC_32_TO_PTR(sg->channel_ids);
1023
1024 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1025 f |= GAIM_CBFLAGS_FOUNDER;
1026 if (chu->mode & SILC_CHANNEL_UMODE_CHANOP)
1027 f |= GAIM_CBFLAGS_OP;
1028 users = g_list_append(users, g_strdup(chu->client->nickname));
1029 flags = g_list_append(flags, GINT_TO_POINTER(f));
1030
1031 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
1032 if (chu->client == conn->local_entry)
1033 g_snprintf(tmp, sizeof(tmp),
1034 _("You are channel founder on <I>%s</I>"),
1035 channel->channel_name);
1036 else
1037 g_snprintf(tmp, sizeof(tmp),
1038 _("Channel founder on <I>%s</I> is <I>%s</I>"),
1039 channel->channel_name, chu->client->nickname);
1040
1041 gaim_conversation_write(convo, NULL, tmp,
1042 GAIM_MESSAGE_SYSTEM, time(NULL));
1043
1044 }
1045 }
1046 silc_hash_table_list_reset(&htl);
1047
1048 gaim_conv_chat_add_users(GAIM_CONV_CHAT(convo), users, NULL, flags, FALSE);
1049 g_list_free(users);
1050 g_list_free(flags);
1051
1052 /* Set topic */
1053 if (channel->topic)
1054 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo), NULL, channel->topic);
1055
1056 /* Set nick */
1057 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(convo), conn->local_entry->nickname);
1058 }
1059
1060 char *silcgaim_get_chat_name(GHashTable *data)
1061 {
1062 return g_strdup(g_hash_table_lookup(data, "channel"));
1063 }
1064
1065 void silcgaim_chat_join(GaimConnection *gc, GHashTable *data)
1066 {
1067 SilcGaim sg = gc->proto_data;
1068 SilcClient client = sg->client;
1069 SilcClientConnection conn = sg->conn;
1070 const char *channel, *passphrase, *parentch;
1071
1072 if (!conn)
1073 return;
1074
1075 channel = g_hash_table_lookup(data, "channel");
1076 passphrase = g_hash_table_lookup(data, "passphrase");
1077
1078 /* Check if we are joining a private group. Handle it
1079 purely locally as it's not a real channel */
1080 if (strstr(channel, "[Private Group]")) {
1081 SilcChannelEntry channel_entry;
1082 SilcChannelPrivateKey key;
1083 GaimChat *c;
1084 SilcGaimPrvgrp grp;
1085
1086 c = gaim_blist_find_chat(sg->account, channel);
1087 parentch = gaim_blist_node_get_string((GaimBlistNode *)c, "parentch");
1088 if (!parentch)
1089 return;
1090
1091 channel_entry = silc_client_get_channel(sg->client, sg->conn,
1092 (char *)parentch);
1093 if (!channel_entry ||
1094 !silc_client_on_channel(channel_entry, sg->conn->local_entry)) {
1095 char tmp[512];
1096 g_snprintf(tmp, sizeof(tmp),
1097 _("You have to join the %s channel before you are "
1098 "able to join the private group"), parentch);
1099 gaim_notify_error(gc, _("Join Private Group"),
1100 _("Cannot join private group"), tmp);
1101 return;
1102 }
1103
1104 /* Add channel private key */
1105 if (!silc_client_add_channel_private_key(client, conn,
1106 channel_entry, channel,
1107 NULL, NULL,
1108 (unsigned char *)passphrase,
1109 strlen(passphrase), &key))
1110 return;
1111
1112 /* Join the group */
1113 grp = silc_calloc(1, sizeof(*grp));
1114 if (!grp)
1115 return;
1116 grp->id = ++sg->channel_ids + SILCGAIM_PRVGRP;
1117 grp->chid = SILC_PTR_TO_32(channel_entry->context);
1118 grp->parentch = parentch;
1119 grp->channel = channel;
1120 grp->key = key;
1121 sg->grps = g_list_append(sg->grps, grp);
1122 serv_got_joined_chat(gc, grp->id, channel);
1123 return;
1124 }
1125
1126 /* XXX We should have other properties here as well:
1127 1. whether to try to authenticate to the channel
1128 1a. with default key,
1129 1b. with specific key.
1130 2. whether to try to authenticate to become founder.
1131 2a. with default key,
1132 2b. with specific key.
1133
1134 Since now such variety is not possible in the join dialog
1135 we always use -founder and -auth options, which try to
1136 do both 1 and 2 with default keys. */
1137
1138 /* Call JOIN */
1139 if ((passphrase != NULL) && (*passphrase != '\0'))
1140 silc_client_command_call(client, conn, NULL, "JOIN",
1141 channel, passphrase, "-auth", "-founder", NULL);
1142 else
1143 silc_client_command_call(client, conn, NULL, "JOIN",
1144 channel, "-auth", "-founder", NULL);
1145 }
1146
1147 void silcgaim_chat_invite(GaimConnection *gc, int id, const char *msg,
1148 const char *name)
1149 {
1150 SilcGaim sg = gc->proto_data;
1151 SilcClient client = sg->client;
1152 SilcClientConnection conn = sg->conn;
1153 SilcHashTableList htl;
1154 SilcChannelUser chu;
1155 gboolean found = FALSE;
1156
1157 if (!conn)
1158 return;
1159
1160 /* See if we are inviting on a private group. Invite
1161 to the actual channel */
1162 if (id > SILCGAIM_PRVGRP) {
1163 GList *l;
1164 SilcGaimPrvgrp prv;
1165
1166 for (l = sg->grps; l; l = l->next)
1167 if (((SilcGaimPrvgrp)l->data)->id == id)
1168 break;
1169 if (!l)
1170 return;
1171 prv = l->data;
1172 id = prv->chid;
1173 }
1174
1175 /* Find channel by id */
1176 silc_hash_table_list(conn->local_entry->channels, &htl);
1177 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1178 if (SILC_PTR_TO_32(chu->channel->context) == id ) {
1179 found = TRUE;
1180 break;
1181 }
1182 }
1183 silc_hash_table_list_reset(&htl);
1184 if (!found)
1185 return;
1186
1187 /* Call INVITE */
1188 silc_client_command_call(client, conn, NULL, "INVITE",
1189 chu->channel->channel_name,
1190 name, NULL);
1191 }
1192
1193 void silcgaim_chat_leave(GaimConnection *gc, int id)
1194 {
1195 SilcGaim sg = gc->proto_data;
1196 SilcClient client = sg->client;
1197 SilcClientConnection conn = sg->conn;
1198 SilcHashTableList htl;
1199 SilcChannelUser chu;
1200 gboolean found = FALSE;
1201 GList *l;
1202 SilcGaimPrvgrp prv;
1203
1204 if (!conn)
1205 return;
1206
1207 /* See if we are leaving a private group */
1208 if (id > SILCGAIM_PRVGRP) {
1209 SilcChannelEntry channel;
1210
1211 for (l = sg->grps; l; l = l->next)
1212 if (((SilcGaimPrvgrp)l->data)->id == id)
1213 break;
1214 if (!l)
1215 return;
1216 prv = l->data;
1217 channel = silc_client_get_channel(sg->client, sg->conn,
1218 (char *)prv->parentch);
1219 if (!channel)
1220 return;
1221 silc_client_del_channel_private_key(client, conn,
1222 channel, prv->key);
1223 silc_free(prv);
1224 sg->grps = g_list_remove(sg->grps, prv);
1225 serv_got_chat_left(gc, id);
1226 return;
1227 }
1228
1229 /* Find channel by id */
1230 silc_hash_table_list(conn->local_entry->channels, &htl);
1231 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1232 if (SILC_PTR_TO_32(chu->channel->context) == id ) {
1233 found = TRUE;
1234 break;
1235 }
1236 }
1237 silc_hash_table_list_reset(&htl);
1238 if (!found)
1239 return;
1240
1241 /* Call LEAVE */
1242 silc_client_command_call(client, conn, NULL, "LEAVE",
1243 chu->channel->channel_name, NULL);
1244
1245 serv_got_chat_left(gc, id);
1246
1247 /* Leave from private groups on this channel as well */
1248 for (l = sg->grps; l; l = l->next)
1249 if (((SilcGaimPrvgrp)l->data)->chid == id) {
1250 prv = l->data;
1251 silc_client_del_channel_private_key(client, conn,
1252 chu->channel,
1253 prv->key);
1254 serv_got_chat_left(gc, prv->id);
1255 silc_free(prv);
1256 sg->grps = g_list_remove(sg->grps, prv);
1257 if (!sg->grps)
1258 break;
1259 }
1260 }
1261
1262 int silcgaim_chat_send(GaimConnection *gc, int id, const char *msg, GaimMessageFlags msgflags)
1263 {
1264 SilcGaim sg = gc->proto_data;
1265 SilcClient client = sg->client;
1266 SilcClientConnection conn = sg->conn;
1267 SilcHashTableList htl;
1268 SilcChannelUser chu;
1269 SilcChannelEntry channel = NULL;
1270 SilcChannelPrivateKey key = NULL;
1271 SilcUInt32 flags;
1272 int ret;
1273 char *msg2, *tmp;
1274 gboolean found = FALSE;
1275 gboolean sign = gaim_account_get_bool(sg->account, "sign-verify", FALSE);
1276
1277 if (!msg || !conn)
1278 return 0;
1279
1280 flags = SILC_MESSAGE_FLAG_UTF8;
1281
1282 tmp = msg2 = gaim_unescape_html(msg);
1283
1284 if (!g_ascii_strncasecmp(msg2, "/me ", 4))
1285 {
1286 msg2 += 4;
1287 if (!*msg2) {
1288 g_free(tmp);
1289 return 0;
1290 }
1291 flags |= SILC_MESSAGE_FLAG_ACTION;
1292 } else if (strlen(msg) > 1 && msg[0] == '/') {
1293 if (!silc_client_command_call(client, conn, msg + 1))
1294 gaim_notify_error(gc, _("Call Command"), _("Cannot call command"),
1295 _("Unknown command"));
1296 g_free(tmp);
1297 return 0;
1298 }
1299
1300
1301 if (sign)
1302 flags |= SILC_MESSAGE_FLAG_SIGNED;
1303
1304 /* Get the channel private key if we are sending on
1305 private group */
1306 if (id > SILCGAIM_PRVGRP) {
1307 GList *l;
1308 SilcGaimPrvgrp prv;
1309
1310 for (l = sg->grps; l; l = l->next)
1311 if (((SilcGaimPrvgrp)l->data)->id == id)
1312 break;
1313 if (!l) {
1314 g_free(tmp);
1315 return 0;
1316 }
1317 prv = l->data;
1318 channel = silc_client_get_channel(sg->client, sg->conn,
1319 (char *)prv->parentch);
1320 if (!channel) {
1321 g_free(tmp);
1322 return 0;
1323 }
1324 key = prv->key;
1325 }
1326
1327 if (!channel) {
1328 /* Find channel by id */
1329 silc_hash_table_list(conn->local_entry->channels, &htl);
1330 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1331 if (SILC_PTR_TO_32(chu->channel->context) == id ) {
1332 found = TRUE;
1333 break;
1334 }
1335 }
1336 silc_hash_table_list_reset(&htl);
1337 if (!found) {
1338 g_free(tmp);
1339 return 0;
1340 }
1341 channel = chu->channel;
1342 }
1343
1344 /* Send channel message */
1345 ret = silc_client_send_channel_message(client, conn, channel, key,
1346 flags, (unsigned char *)msg2,
1347 strlen(msg2), TRUE);
1348 if (ret) {
1349 serv_got_chat_in(gc, id, gaim_connection_get_display_name(gc), 0, msg,
1350 time(NULL));
1351 }
1352 g_free(tmp);
1353
1354 return ret;
1355 }
1356
1357 void silcgaim_chat_set_topic(GaimConnection *gc, int id, const char *topic)
1358 {
1359 SilcGaim sg = gc->proto_data;
1360 SilcClient client = sg->client;
1361 SilcClientConnection conn = sg->conn;
1362 SilcHashTableList htl;
1363 SilcChannelUser chu;
1364 gboolean found = FALSE;
1365
1366 if (!conn)
1367 return;
1368
1369 /* See if setting topic on private group. Set it
1370 on the actual channel */
1371 if (id > SILCGAIM_PRVGRP) {
1372 GList *l;
1373 SilcGaimPrvgrp prv;
1374
1375 for (l = sg->grps; l; l = l->next)
1376 if (((SilcGaimPrvgrp)l->data)->id == id)
1377 break;
1378 if (!l)
1379 return;
1380 prv = l->data;
1381 id = prv->chid;
1382 }
1383
1384 /* Find channel by id */
1385 silc_hash_table_list(conn->local_entry->channels, &htl);
1386 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1387 if (SILC_PTR_TO_32(chu->channel->context) == id ) {
1388 found = TRUE;
1389 break;
1390 }
1391 }
1392 silc_hash_table_list_reset(&htl);
1393 if (!found)
1394 return;
1395
1396 /* Call TOPIC */
1397 silc_client_command_call(client, conn, NULL, "TOPIC",
1398 chu->channel->channel_name, topic, NULL);
1399 }
1400
1401 GaimRoomlist *silcgaim_roomlist_get_list(GaimConnection *gc)
1402 {
1403 SilcGaim sg = gc->proto_data;
1404 SilcClient client = sg->client;
1405 SilcClientConnection conn = sg->conn;
1406 GList *fields = NULL;
1407 GaimRoomlistField *f;
1408
1409 if (!conn)
1410 return NULL;
1411
1412 if (sg->roomlist)
1413 gaim_roomlist_unref(sg->roomlist);
1414
1415 sg->roomlist_canceled = FALSE;
1416
1417 sg->roomlist = gaim_roomlist_new(gaim_connection_get_account(gc));
1418 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "channel", TRUE);
1419 fields = g_list_append(fields, f);
1420 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_INT,
1421 _("Users"), "users", FALSE);
1422 fields = g_list_append(fields, f);
1423 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING,
1424 _("Topic"), "topic", FALSE);
1425 fields = g_list_append(fields, f);
1426 gaim_roomlist_set_fields(sg->roomlist, fields);
1427
1428 /* Call LIST */
1429 silc_client_command_call(client, conn, "LIST");
1430
1431 gaim_roomlist_set_in_progress(sg->roomlist, TRUE);
1432
1433 return sg->roomlist;
1434 }
1435
1436 void silcgaim_roomlist_cancel(GaimRoomlist *list)
1437 {
1438 GaimConnection *gc = gaim_account_get_connection(list->account);
1439 SilcGaim sg;
1440
1441 if (!gc)
1442 return;
1443 sg = gc->proto_data;
1444
1445 gaim_roomlist_set_in_progress(list, FALSE);
1446 if (sg->roomlist == list) {
1447 gaim_roomlist_unref(sg->roomlist);
1448 sg->roomlist = NULL;
1449 sg->roomlist_canceled = TRUE;
1450 }
1451 }