comparison libpurple/protocols/silc/ops.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_ops.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 "imgstore.h"
24 #include "wb.h"
25
26 static void
27 silc_channel_message(SilcClient client, SilcClientConnection conn,
28 SilcClientEntry sender, SilcChannelEntry channel,
29 SilcMessagePayload payload, SilcChannelPrivateKey key,
30 SilcMessageFlags flags, const unsigned char *message,
31 SilcUInt32 message_len);
32 static void
33 silc_private_message(SilcClient client, SilcClientConnection conn,
34 SilcClientEntry sender, SilcMessagePayload payload,
35 SilcMessageFlags flags, const unsigned char *message,
36 SilcUInt32 message_len);
37
38 /* Message sent to the application by library. `conn' associates the
39 message to a specific connection. `conn', however, may be NULL.
40 The `type' indicates the type of the message sent by the library.
41 The application can for example filter the message according the
42 type. */
43
44 static void
45 silc_say(SilcClient client, SilcClientConnection conn,
46 SilcClientMessageType type, char *msg, ...)
47 {
48 /* Nothing */
49 }
50
51 #ifdef HAVE_SILCMIME_H
52 /* Processes incoming MIME message. Can be private message or channel
53 message. */
54
55 static void
56 silcgaim_mime_message(SilcClient client, SilcClientConnection conn,
57 SilcClientEntry sender, SilcChannelEntry channel,
58 SilcMessagePayload payload, SilcChannelPrivateKey key,
59 SilcMessageFlags flags, SilcMime mime,
60 gboolean recursive)
61 {
62 GaimConnection *gc = client->application;
63 SilcGaim sg = gc->proto_data;
64 const char *type;
65 const unsigned char *data;
66 SilcUInt32 data_len;
67 GaimMessageFlags cflags = 0;
68 GaimConversation *convo = NULL;
69
70 if (!mime)
71 return;
72
73 /* Check for fragmented MIME message */
74 if (silc_mime_is_partial(mime)) {
75 if (!sg->mimeass)
76 sg->mimeass = silc_mime_assembler_alloc();
77
78 /* Defragment */
79 mime = silc_mime_assemble(sg->mimeass, mime);
80 if (!mime)
81 /* More fragments to come */
82 return;
83
84 /* Process the complete message */
85 silcgaim_mime_message(client, conn, sender, channel,
86 payload, key, flags, mime, FALSE);
87 return;
88 }
89
90 /* Check for multipart message */
91 if (silc_mime_is_multipart(mime)) {
92 SilcMime p;
93 const char *mtype;
94 SilcDList parts = silc_mime_get_multiparts(mime, &mtype);
95
96 /* Only "mixed" type supported */
97 if (strcmp(mtype, "mixed"))
98 goto out;
99
100 silc_dlist_start(parts);
101 while ((p = silc_dlist_get(parts)) != SILC_LIST_END) {
102 /* Recursively process parts */
103 silcgaim_mime_message(client, conn, sender, channel,
104 payload, key, flags, p, TRUE);
105 }
106 goto out;
107 }
108
109 /* Get content type and MIME data */
110 type = silc_mime_get_field(mime, "Content-Type");
111 if (!type)
112 goto out;
113 data = silc_mime_get_data(mime, &data_len);
114 if (!data)
115 goto out;
116
117 /* Process according to content type */
118
119 /* Plain text */
120 if (strstr(type, "text/plain")) {
121 /* Default is UTF-8, don't check for other charsets */
122 if (!strstr(type, "utf-8"))
123 goto out;
124
125 if (channel)
126 silc_channel_message(client, conn, sender, channel,
127 payload, key,
128 SILC_MESSAGE_FLAG_UTF8, data,
129 data_len);
130 else
131 silc_private_message(client, conn, sender, payload,
132 SILC_MESSAGE_FLAG_UTF8, data,
133 data_len);
134 goto out;
135 }
136
137 /* Image */
138 if (strstr(type, "image/png") ||
139 strstr(type, "image/jpeg") ||
140 strstr(type, "image/gif") ||
141 strstr(type, "image/tiff")) {
142 char tmp[32];
143 int imgid;
144
145 /* Get channel convo (if message is for channel) */
146 if (key && channel) {
147 GList *l;
148 SilcGaimPrvgrp prv;
149
150 for (l = sg->grps; l; l = l->next)
151 if (((SilcGaimPrvgrp)l->data)->key == key) {
152 prv = l->data;
153 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
154 prv->channel, sg->account);
155 break;
156 }
157 }
158 if (channel && !convo)
159 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
160 channel->channel_name, sg->account);
161 if (channel && !convo)
162 goto out;
163
164 imgid = gaim_imgstore_add(data, data_len, "");
165 if (imgid) {
166 cflags |= GAIM_MESSAGE_IMAGES | GAIM_MESSAGE_RECV;
167 g_snprintf(tmp, sizeof(tmp), "<IMG ID=\"%d\">", imgid);
168
169 if (channel)
170 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)),
171 sender->nickname ?
172 sender->nickname :
173 "<unknown>", cflags,
174 tmp, time(NULL));
175 else
176 serv_got_im(gc, sender->nickname ?
177 sender->nickname : "<unknown>",
178 tmp, cflags, time(NULL));
179
180 gaim_imgstore_unref(imgid);
181 cflags = 0;
182 }
183 goto out;
184 }
185
186 /* Whiteboard message */
187 if (strstr(type, "application/x-wb") &&
188 !gaim_account_get_bool(sg->account, "block-wb", FALSE)) {
189 if (channel)
190 silcgaim_wb_receive_ch(client, conn, sender, channel,
191 payload, flags, data, data_len);
192 else
193 silcgaim_wb_receive(client, conn, sender, payload,
194 flags, data, data_len);
195 goto out;
196 }
197
198 out:
199 if (!recursive)
200 silc_mime_free(mime);
201 }
202 #endif /* HAVE_SILCMIME_H */
203
204 /* Message for a channel. The `sender' is the sender of the message
205 The `channel' is the channel. The `message' is the message. Note
206 that `message' maybe NULL. The `flags' indicates message flags
207 and it is used to determine how the message can be interpreted
208 (like it may tell the message is multimedia message). */
209
210 static void
211 silc_channel_message(SilcClient client, SilcClientConnection conn,
212 SilcClientEntry sender, SilcChannelEntry channel,
213 SilcMessagePayload payload, SilcChannelPrivateKey key,
214 SilcMessageFlags flags, const unsigned char *message,
215 SilcUInt32 message_len)
216 {
217 GaimConnection *gc = client->application;
218 SilcGaim sg = gc->proto_data;
219 GaimConversation *convo = NULL;
220 char *msg, *tmp;
221
222 if (!message)
223 return;
224
225 if (key) {
226 GList *l;
227 SilcGaimPrvgrp prv;
228
229 for (l = sg->grps; l; l = l->next)
230 if (((SilcGaimPrvgrp)l->data)->key == key) {
231 prv = l->data;
232 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
233 prv->channel, sg->account);
234 break;
235 }
236 }
237 if (!convo)
238 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
239 channel->channel_name, sg->account);
240 if (!convo)
241 return;
242
243 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
244 gaim_account_get_bool(sg->account, "sign-verify", FALSE)) {
245 /* XXX */
246 }
247
248 if (flags & SILC_MESSAGE_FLAG_DATA) {
249 /* Process MIME message */
250 #ifdef HAVE_SILCMIME_H
251 SilcMime mime;
252 mime = silc_mime_decode(message, message_len);
253 silcgaim_mime_message(client, conn, sender, channel, payload,
254 key, flags, mime, FALSE);
255 #else
256 char type[128], enc[128];
257 unsigned char *data;
258 SilcUInt32 data_len;
259
260 memset(type, 0, sizeof(type));
261 memset(enc, 0, sizeof(enc));
262
263 if (!silc_mime_parse(message, message_len, NULL, 0,
264 type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data,
265 &data_len))
266 return;
267
268 if (!strcmp(type, "application/x-wb") &&
269 !strcmp(enc, "binary") &&
270 !gaim_account_get_bool(sg->account, "block-wb", FALSE))
271 silcgaim_wb_receive_ch(client, conn, sender, channel,
272 payload, flags, data, data_len);
273 #endif
274 return;
275 }
276
277 if (flags & SILC_MESSAGE_FLAG_ACTION) {
278 msg = g_strdup_printf("/me %s",
279 (const char *)message);
280 if (!msg)
281 return;
282
283 tmp = g_markup_escape_text(msg, -1);
284 /* Send to Gaim */
285 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)),
286 sender->nickname ?
287 sender->nickname : "<unknown>", 0,
288 tmp, time(NULL));
289 g_free(tmp);
290 g_free(msg);
291 return;
292 }
293
294 if (flags & SILC_MESSAGE_FLAG_NOTICE) {
295 msg = g_strdup_printf("(notice) <I>%s</I> %s",
296 sender->nickname ?
297 sender->nickname : "<unknown>",
298 (const char *)message);
299 if (!msg)
300 return;
301
302 /* Send to Gaim */
303 gaim_conversation_write(convo, NULL, (const char *)msg,
304 GAIM_MESSAGE_SYSTEM, time(NULL));
305 g_free(msg);
306 return;
307 }
308
309 if (flags & SILC_MESSAGE_FLAG_UTF8) {
310 tmp = g_markup_escape_text((const char *)message, -1);
311 /* Send to Gaim */
312 serv_got_chat_in(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)),
313 sender->nickname ?
314 sender->nickname : "<unknown>", 0,
315 tmp, time(NULL));
316 g_free(tmp);
317 }
318 }
319
320
321 /* Private message to the client. The `sender' is the sender of the
322 message. The message is `message'and maybe NULL. The `flags'
323 indicates message flags and it is used to determine how the message
324 can be interpreted (like it may tell the message is multimedia
325 message). */
326
327 static void
328 silc_private_message(SilcClient client, SilcClientConnection conn,
329 SilcClientEntry sender, SilcMessagePayload payload,
330 SilcMessageFlags flags, const unsigned char *message,
331 SilcUInt32 message_len)
332 {
333 GaimConnection *gc = client->application;
334 SilcGaim sg = gc->proto_data;
335 GaimConversation *convo = NULL;
336 char *msg, *tmp;
337
338 if (!message)
339 return;
340
341 if (sender->nickname)
342 /* XXX - Should this be GAIM_CONV_TYPE_IM? */
343 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY,
344 sender->nickname, sg->account);
345
346 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
347 gaim_account_get_bool(sg->account, "sign-verify", FALSE)) {
348 /* XXX */
349 }
350
351 if (flags & SILC_MESSAGE_FLAG_DATA) {
352 #ifdef HAVE_SILCMIME_H
353 /* Process MIME message */
354 SilcMime mime;
355 mime = silc_mime_decode(message, message_len);
356 silcgaim_mime_message(client, conn, sender, NULL, payload,
357 NULL, flags, mime, FALSE);
358 #else
359 char type[128], enc[128];
360 unsigned char *data;
361 SilcUInt32 data_len;
362
363 memset(type, 0, sizeof(type));
364 memset(enc, 0, sizeof(enc));
365
366 if (!silc_mime_parse(message, message_len, NULL, 0,
367 type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data,
368 &data_len))
369 return;
370
371 if (!strcmp(type, "application/x-wb") &&
372 !strcmp(enc, "binary") &&
373 !gaim_account_get_bool(sg->account, "block-wb", FALSE))
374 silcgaim_wb_receive(client, conn, sender, payload,
375 flags, data, data_len);
376 #endif
377 return;
378 }
379
380 if (flags & SILC_MESSAGE_FLAG_ACTION && convo) {
381 msg = g_strdup_printf("/me %s",
382 (const char *)message);
383 if (!msg)
384 return;
385
386 tmp = g_markup_escape_text(msg, -1);
387 /* Send to Gaim */
388 serv_got_im(gc, sender->nickname ?
389 sender->nickname : "<unknown>",
390 tmp, 0, time(NULL));
391 g_free(msg);
392 g_free(tmp);
393 return;
394 }
395
396 if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) {
397 msg = g_strdup_printf("(notice) <I>%s</I> %s",
398 sender->nickname ?
399 sender->nickname : "<unknown>",
400 (const char *)message);
401 if (!msg)
402 return;
403
404 /* Send to Gaim */
405 gaim_conversation_write(convo, NULL, (const char *)msg,
406 GAIM_MESSAGE_SYSTEM, time(NULL));
407 g_free(msg);
408 return;
409 }
410
411 if (flags & SILC_MESSAGE_FLAG_UTF8) {
412 tmp = g_markup_escape_text((const char *)message, -1);
413 /* Send to Gaim */
414 serv_got_im(gc, sender->nickname ?
415 sender->nickname : "<unknown>",
416 tmp, 0, time(NULL));
417 g_free(tmp);
418 }
419 }
420
421
422 /* Notify message to the client. The notify arguments are sent in the
423 same order as servers sends them. The arguments are same as received
424 from the server except for ID's. If ID is received application receives
425 the corresponding entry to the ID. For example, if Client ID is received
426 application receives SilcClientEntry. Also, if the notify type is
427 for channel the channel entry is sent to application (even if server
428 does not send it because client library gets the channel entry from
429 the Channel ID in the packet's header). */
430
431 static void
432 silc_notify(SilcClient client, SilcClientConnection conn,
433 SilcNotifyType type, ...)
434 {
435 va_list va;
436 GaimConnection *gc = client->application;
437 SilcGaim sg = gc->proto_data;
438 GaimConversation *convo;
439 SilcClientEntry client_entry, client_entry2;
440 SilcChannelEntry channel;
441 SilcServerEntry server_entry;
442 SilcIdType idtype;
443 void *entry;
444 SilcUInt32 mode;
445 SilcHashTableList htl;
446 SilcChannelUser chu;
447 char buf[512], buf2[512], *tmp, *name;
448 SilcNotifyType notify;
449 GaimBuddy *b;
450 int i;
451
452 va_start(va, type);
453 memset(buf, 0, sizeof(buf));
454
455 switch (type) {
456
457 case SILC_NOTIFY_TYPE_NONE:
458 break;
459
460 case SILC_NOTIFY_TYPE_INVITE:
461 {
462 GHashTable *components;
463 va_arg(va, SilcChannelEntry);
464 name = va_arg(va, char *);
465 client_entry = va_arg(va, SilcClientEntry);
466
467 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
468 g_hash_table_insert(components, strdup("channel"), strdup(name));
469 serv_got_chat_invite(gc, name, client_entry->nickname, NULL, components);
470 }
471 break;
472
473 case SILC_NOTIFY_TYPE_JOIN:
474 client_entry = va_arg(va, SilcClientEntry);
475 channel = va_arg(va, SilcChannelEntry);
476
477 /* If we joined channel, do nothing */
478 if (client_entry == conn->local_entry)
479 break;
480
481 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
482 channel->channel_name, sg->account);
483 if (!convo)
484 break;
485
486 /* Join user to channel */
487 g_snprintf(buf, sizeof(buf), "%s@%s",
488 client_entry->username, client_entry->hostname);
489 gaim_conv_chat_add_user(GAIM_CONV_CHAT(convo),
490 g_strdup(client_entry->nickname), buf, GAIM_CBFLAGS_NONE, TRUE);
491
492 break;
493
494 case SILC_NOTIFY_TYPE_LEAVE:
495 client_entry = va_arg(va, SilcClientEntry);
496 channel = va_arg(va, SilcChannelEntry);
497
498 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
499 channel->channel_name, sg->account);
500 if (!convo)
501 break;
502
503 /* Remove user from channel */
504 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
505 client_entry->nickname, NULL);
506
507 break;
508
509 case SILC_NOTIFY_TYPE_SIGNOFF:
510 client_entry = va_arg(va, SilcClientEntry);
511 tmp = va_arg(va, char *);
512
513 if (!client_entry->nickname)
514 break;
515
516 /* Remove from all channels */
517 silc_hash_table_list(client_entry->channels, &htl);
518 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
519 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
520 chu->channel->channel_name, sg->account);
521 if (!convo)
522 continue;
523 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
524 client_entry->nickname,
525 tmp);
526 }
527 silc_hash_table_list_reset(&htl);
528
529 break;
530
531 case SILC_NOTIFY_TYPE_TOPIC_SET:
532 {
533 char *esc, *tmp2;
534 idtype = va_arg(va, int);
535 entry = va_arg(va, void *);
536 tmp = va_arg(va, char *);
537 channel = va_arg(va, SilcChannelEntry);
538
539 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
540 channel->channel_name, sg->account);
541 if (!convo)
542 break;
543
544 if (!tmp)
545 break;
546
547 esc = g_markup_escape_text(tmp, -1);
548 tmp2 = gaim_markup_linkify(esc);
549 g_free(esc);
550
551 if (idtype == SILC_ID_CLIENT) {
552 client_entry = (SilcClientEntry)entry;
553 g_snprintf(buf, sizeof(buf),
554 _("%s has changed the topic of <I>%s</I> to: %s"),
555 client_entry->nickname, channel->channel_name, tmp2);
556 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
557 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
558 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
559 client_entry->nickname, tmp);
560 } else if (idtype == SILC_ID_SERVER) {
561 server_entry = (SilcServerEntry)entry;
562 g_snprintf(buf, sizeof(buf),
563 _("%s has changed the topic of <I>%s</I> to: %s"),
564 server_entry->server_name, channel->channel_name, tmp2);
565 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), server_entry->server_name,
566 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
567 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
568 server_entry->server_name, tmp);
569 } else if (idtype == SILC_ID_CHANNEL) {
570 channel = (SilcChannelEntry)entry;
571 g_snprintf(buf, sizeof(buf),
572 _("%s has changed the topic of <I>%s</I> to: %s"),
573 channel->channel_name, channel->channel_name, tmp2);
574 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
575 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
576 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo),
577 channel->channel_name, tmp);
578 } else {
579 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo), NULL, tmp);
580 }
581
582 g_free(tmp2);
583
584 break;
585
586 }
587 case SILC_NOTIFY_TYPE_NICK_CHANGE:
588 client_entry = va_arg(va, SilcClientEntry);
589 client_entry2 = va_arg(va, SilcClientEntry);
590
591 if (!strcmp(client_entry->nickname, client_entry2->nickname))
592 break;
593
594 /* Change nick on all channels */
595 silc_hash_table_list(client_entry2->channels, &htl);
596 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
597 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
598 chu->channel->channel_name, sg->account);
599 if (!convo)
600 continue;
601 if (gaim_conv_chat_find_user(GAIM_CONV_CHAT(convo), client_entry->nickname))
602 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(convo),
603 client_entry->nickname,
604 client_entry2->nickname);
605 }
606 silc_hash_table_list_reset(&htl);
607
608 break;
609
610 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
611 idtype = va_arg(va, int);
612 entry = va_arg(va, void *);
613 mode = va_arg(va, SilcUInt32);
614 (void)va_arg(va, char *);
615 (void)va_arg(va, char *);
616 (void)va_arg(va, char *);
617 (void)va_arg(va, SilcPublicKey);
618 (void)va_arg(va, SilcBuffer);
619 channel = va_arg(va, SilcChannelEntry);
620
621 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
622 channel->channel_name, sg->account);
623 if (!convo)
624 break;
625
626 if (idtype == SILC_ID_CLIENT)
627 name = ((SilcClientEntry)entry)->nickname;
628 else if (idtype == SILC_ID_SERVER)
629 name = ((SilcServerEntry)entry)->server_name;
630 else
631 name = ((SilcChannelEntry)entry)->channel_name;
632 if (!name)
633 break;
634
635 if (mode) {
636 silcgaim_get_chmode_string(mode, buf2, sizeof(buf2));
637 g_snprintf(buf, sizeof(buf),
638 _("<I>%s</I> set channel <I>%s</I> modes to: %s"), name,
639 channel->channel_name, buf2);
640 } else {
641 g_snprintf(buf, sizeof(buf),
642 _("<I>%s</I> removed all channel <I>%s</I> modes"), name,
643 channel->channel_name);
644 }
645 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
646 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
647 break;
648
649 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
650 {
651 GaimConvChatBuddyFlags flags = GAIM_CBFLAGS_NONE;
652 idtype = va_arg(va, int);
653 entry = va_arg(va, void *);
654 mode = va_arg(va, SilcUInt32);
655 client_entry2 = va_arg(va, SilcClientEntry);
656 channel = va_arg(va, SilcChannelEntry);
657
658 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
659 channel->channel_name, sg->account);
660 if (!convo)
661 break;
662
663 if (idtype == SILC_ID_CLIENT)
664 name = ((SilcClientEntry)entry)->nickname;
665 else if (idtype == SILC_ID_SERVER)
666 name = ((SilcServerEntry)entry)->server_name;
667 else
668 name = ((SilcChannelEntry)entry)->channel_name;
669 if (!name)
670 break;
671
672 if (mode) {
673 silcgaim_get_chumode_string(mode, buf2, sizeof(buf2));
674 g_snprintf(buf, sizeof(buf),
675 _("<I>%s</I> set <I>%s's</I> modes to: %s"), name,
676 client_entry2->nickname, buf2);
677 if (mode & SILC_CHANNEL_UMODE_CHANFO)
678 flags |= GAIM_CBFLAGS_FOUNDER;
679 if (mode & SILC_CHANNEL_UMODE_CHANOP)
680 flags |= GAIM_CBFLAGS_OP;
681 } else {
682 g_snprintf(buf, sizeof(buf),
683 _("<I>%s</I> removed all <I>%s's</I> modes"), name,
684 client_entry2->nickname);
685 }
686 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), channel->channel_name,
687 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
688 gaim_conv_chat_user_set_flags(GAIM_CONV_CHAT(convo), client_entry2->nickname, flags);
689 break;
690 }
691
692 case SILC_NOTIFY_TYPE_MOTD:
693 tmp = va_arg(va, char *);
694 silc_free(sg->motd);
695 sg->motd = silc_memdup(tmp, strlen(tmp));
696 break;
697
698 case SILC_NOTIFY_TYPE_KICKED:
699 client_entry = va_arg(va, SilcClientEntry);
700 tmp = va_arg(va, char *);
701 client_entry2 = va_arg(va, SilcClientEntry);
702 channel = va_arg(va, SilcChannelEntry);
703
704 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
705 channel->channel_name, sg->account);
706 if (!convo)
707 break;
708
709 if (client_entry == conn->local_entry) {
710 /* Remove us from channel */
711 g_snprintf(buf, sizeof(buf),
712 _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"),
713 channel->channel_name, client_entry2->nickname,
714 tmp ? tmp : "");
715 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
716 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
717 serv_got_chat_left(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)));
718 } else {
719 /* Remove user from channel */
720 g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"),
721 client_entry2->nickname, tmp ? tmp : "");
722 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
723 client_entry->nickname,
724 buf);
725 }
726
727 break;
728
729 case SILC_NOTIFY_TYPE_KILLED:
730 client_entry = va_arg(va, SilcClientEntry);
731 tmp = va_arg(va, char *);
732 idtype = va_arg(va, int);
733 entry = va_arg(va, SilcClientEntry);
734
735 if (!client_entry->nickname)
736 break;
737
738 if (client_entry == conn->local_entry) {
739 if (idtype == SILC_ID_CLIENT) {
740 client_entry2 = (SilcClientEntry)entry;
741 g_snprintf(buf, sizeof(buf),
742 _("You have been killed by %s (%s)"),
743 client_entry2->nickname, tmp ? tmp : "");
744 } else if (idtype == SILC_ID_SERVER) {
745 server_entry = (SilcServerEntry)entry;
746 g_snprintf(buf, sizeof(buf),
747 _("You have been killed by %s (%s)"),
748 server_entry->server_name, tmp ? tmp : "");
749 } else if (idtype == SILC_ID_CHANNEL) {
750 channel = (SilcChannelEntry)entry;
751 g_snprintf(buf, sizeof(buf),
752 _("You have been killed by %s (%s)"),
753 channel->channel_name, tmp ? tmp : "");
754 }
755
756 /* Remove us from all channels */
757 silc_hash_table_list(client_entry->channels, &htl);
758 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
759 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
760 chu->channel->channel_name, sg->account);
761 if (!convo)
762 continue;
763 gaim_conv_chat_write(GAIM_CONV_CHAT(convo), client_entry->nickname,
764 buf, GAIM_MESSAGE_SYSTEM, time(NULL));
765 serv_got_chat_left(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(convo)));
766 }
767 silc_hash_table_list_reset(&htl);
768
769 } else {
770 if (idtype == SILC_ID_CLIENT) {
771 client_entry2 = (SilcClientEntry)entry;
772 g_snprintf(buf, sizeof(buf),
773 _("Killed by %s (%s)"),
774 client_entry2->nickname, tmp ? tmp : "");
775 } else if (idtype == SILC_ID_SERVER) {
776 server_entry = (SilcServerEntry)entry;
777 g_snprintf(buf, sizeof(buf),
778 _("Killed by %s (%s)"),
779 server_entry->server_name, tmp ? tmp : "");
780 } else if (idtype == SILC_ID_CHANNEL) {
781 channel = (SilcChannelEntry)entry;
782 g_snprintf(buf, sizeof(buf),
783 _("Killed by %s (%s)"),
784 channel->channel_name, tmp ? tmp : "");
785 }
786
787 /* Remove user from all channels */
788 silc_hash_table_list(client_entry->channels, &htl);
789 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
790 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
791 chu->channel->channel_name, sg->account);
792 if (!convo)
793 continue;
794 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
795 client_entry->nickname, tmp);
796 }
797 silc_hash_table_list_reset(&htl);
798 }
799
800 break;
801
802 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
803 break;
804
805 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
806 {
807 int i;
808 SilcClientEntry *clients;
809 SilcUInt32 clients_count;
810
811 (void)va_arg(va, void *);
812 clients = va_arg(va, SilcClientEntry *);
813 clients_count = va_arg(va, SilcUInt32);
814
815 for (i = 0; i < clients_count; i++) {
816 if (!clients[i]->nickname)
817 break;
818
819 /* Remove from all channels */
820 silc_hash_table_list(clients[i]->channels, &htl);
821 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
822 convo =
823 gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
824 chu->channel->channel_name, sg->account);
825 if (!convo)
826 continue;
827 gaim_conv_chat_remove_user(GAIM_CONV_CHAT(convo),
828 clients[i]->nickname,
829 _("Server signoff"));
830 }
831 silc_hash_table_list_reset(&htl);
832 }
833 }
834 break;
835
836 case SILC_NOTIFY_TYPE_ERROR:
837 {
838 SilcStatus error = va_arg(va, int);
839 gaim_notify_error(gc, "Error Notify",
840 silc_get_status_message(error),
841 NULL);
842 }
843 break;
844
845 case SILC_NOTIFY_TYPE_WATCH:
846 {
847 SilcPublicKey public_key;
848 unsigned char *pk;
849 SilcUInt32 pk_len;
850 char *fingerprint;
851
852 client_entry = va_arg(va, SilcClientEntry);
853 (void)va_arg(va, char *);
854 mode = va_arg(va, SilcUInt32);
855 notify = va_arg(va, int);
856 public_key = va_arg(va, SilcPublicKey);
857
858 b = NULL;
859 if (public_key) {
860 GaimBlistNode *gnode, *cnode, *bnode;
861 const char *f;
862
863 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
864 if (!pk)
865 break;
866 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
867 for (i = 0; i < strlen(fingerprint); i++)
868 if (fingerprint[i] == ' ')
869 fingerprint[i] = '_';
870 g_snprintf(buf, sizeof(buf) - 1,
871 "%s" G_DIR_SEPARATOR_S "clientkeys"
872 G_DIR_SEPARATOR_S "clientkey_%s.pub",
873 silcgaim_silcdir(), fingerprint);
874 silc_free(fingerprint);
875 silc_free(pk);
876
877 /* Find buddy by associated public key */
878 for (gnode = gaim_get_blist()->root; gnode;
879 gnode = gnode->next) {
880 if (!GAIM_BLIST_NODE_IS_GROUP(gnode))
881 continue;
882 for (cnode = gnode->child; cnode; cnode = cnode->next) {
883 if( !GAIM_BLIST_NODE_IS_CONTACT(cnode))
884 continue;
885 for (bnode = cnode->child; bnode;
886 bnode = bnode->next) {
887 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode))
888 continue;
889 b = (GaimBuddy *)bnode;
890 if (b->account != gc->account)
891 continue;
892 f = gaim_blist_node_get_string(bnode, "public-key");
893 if (f && !strcmp(f, buf))
894 goto cont;
895 b = NULL;
896 }
897 }
898 }
899 }
900 cont:
901 if (!b) {
902 /* Find buddy by nickname */
903 b = gaim_find_buddy(sg->account, client_entry->nickname);
904 if (!b) {
905 gaim_debug_warning("silc", "WATCH for %s, unknown buddy",
906 client_entry->nickname);
907 break;
908 }
909 }
910
911 silc_free(b->proto_data);
912 b->proto_data = silc_memdup(client_entry->id,
913 sizeof(*client_entry->id));
914 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
915 break;
916 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
917 /* See if client was away and is now present */
918 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
919 SILC_UMODE_BUSY | SILC_UMODE_PAGE |
920 SILC_UMODE_DETACHED)) &&
921 (client_entry->mode & SILC_UMODE_GONE ||
922 client_entry->mode & SILC_UMODE_INDISPOSED ||
923 client_entry->mode & SILC_UMODE_BUSY ||
924 client_entry->mode & SILC_UMODE_PAGE ||
925 client_entry->mode & SILC_UMODE_DETACHED)) {
926 client_entry->mode = mode;
927 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_AVAILABLE, NULL);
928 }
929 else if ((mode & SILC_UMODE_GONE) ||
930 (mode & SILC_UMODE_INDISPOSED) ||
931 (mode & SILC_UMODE_BUSY) ||
932 (mode & SILC_UMODE_PAGE) ||
933 (mode & SILC_UMODE_DETACHED)) {
934 client_entry->mode = mode;
935 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_OFFLINE, NULL);
936 }
937 } else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
938 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
939 notify == SILC_NOTIFY_TYPE_KILLED) {
940 client_entry->mode = mode;
941 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_OFFLINE, NULL);
942 } else if (notify == SILC_NOTIFY_TYPE_NONE) {
943 client_entry->mode = mode;
944 gaim_prpl_got_user_status(gaim_buddy_get_account(b), gaim_buddy_get_name(b), SILCGAIM_STATUS_ID_AVAILABLE, NULL);
945 }
946 }
947 break;
948
949 default:
950 gaim_debug_info("silc", "Unhandled notification: %d\n", type);
951 break;
952 }
953
954 va_end(va);
955 }
956
957
958 /* Command handler. This function is called always in the command function.
959 If error occurs it will be called as well. `conn' is the associated
960 client connection. `cmd_context' is the command context that was
961 originally sent to the command. `success' is FALSE if error occurred
962 during command. `command' is the command being processed. It must be
963 noted that this is not reply from server. This is merely called just
964 after application has called the command. Just to tell application
965 that the command really was processed. */
966
967 static void
968 silc_command(SilcClient client, SilcClientConnection conn,
969 SilcClientCommandContext cmd_context, bool success,
970 SilcCommand command, SilcStatus status)
971 {
972 GaimConnection *gc = client->application;
973 SilcGaim sg = gc->proto_data;
974
975 switch (command) {
976
977 case SILC_COMMAND_CMODE:
978 if (cmd_context->argc == 3 &&
979 !strcmp((char *)cmd_context->argv[2], "+C"))
980 sg->chpk = TRUE;
981 else
982 sg->chpk = FALSE;
983 break;
984
985 default:
986 break;
987 }
988 }
989
990 #if 0
991 static void
992 silcgaim_whois_more(SilcClientEntry client_entry, gint id)
993 {
994 SilcAttributePayload attr;
995 SilcAttribute attribute;
996 char *buf;
997 GString *s;
998 SilcVCardStruct vcard;
999 int i;
1000
1001 if (id != 0)
1002 return;
1003
1004 memset(&vcard, 0, sizeof(vcard));
1005
1006 s = g_string_new("");
1007
1008 silc_dlist_start(client_entry->attrs);
1009 while ((attr = silc_dlist_get(client_entry->attrs)) != SILC_LIST_END) {
1010 attribute = silc_attribute_get_attribute(attr);
1011 switch (attribute) {
1012
1013 case SILC_ATTRIBUTE_USER_INFO:
1014 if (!silc_attribute_get_object(attr, (void *)&vcard,
1015 sizeof(vcard)))
1016 continue;
1017 g_string_append_printf(s, "%s:\n\n", _("Personal Information"));
1018 if (vcard.full_name)
1019 g_string_append_printf(s, "%s:\t\t%s\n",
1020 _("Full Name"),
1021 vcard.full_name);
1022 if (vcard.first_name)
1023 g_string_append_printf(s, "%s:\t%s\n",
1024 _("First Name"),
1025 vcard.first_name);
1026 if (vcard.middle_names)
1027 g_string_append_printf(s, "%s:\t%s\n",
1028 _("Middle Name"),
1029 vcard.middle_names);
1030 if (vcard.family_name)
1031 g_string_append_printf(s, "%s:\t%s\n",
1032 _("Family Name"),
1033 vcard.family_name);
1034 if (vcard.nickname)
1035 g_string_append_printf(s, "%s:\t\t%s\n",
1036 _("Nickname"),
1037 vcard.nickname);
1038 if (vcard.bday)
1039 g_string_append_printf(s, "%s:\t\t%s\n",
1040 _("Birth Day"),
1041 vcard.bday);
1042 if (vcard.title)
1043 g_string_append_printf(s, "%s:\t\t%s\n",
1044 _("Job Title"),
1045 vcard.title);
1046 if (vcard.role)
1047 g_string_append_printf(s, "%s:\t\t%s\n",
1048 _("Job Role"),
1049 vcard.role);
1050 if (vcard.org_name)
1051 g_string_append_printf(s, "%s:\t%s\n",
1052 _("Organization"),
1053 vcard.org_name);
1054 if (vcard.org_unit)
1055 g_string_append_printf(s, "%s:\t\t%s\n",
1056 _("Unit"),
1057 vcard.org_unit);
1058 if (vcard.url)
1059 g_string_append_printf(s, "%s:\t%s\n",
1060 _("Homepage"),
1061 vcard.url);
1062 if (vcard.label)
1063 g_string_append_printf(s, "%s:\t%s\n",
1064 _("Address"),
1065 vcard.label);
1066 for (i = 0; i < vcard.num_tels; i++) {
1067 if (vcard.tels[i].telnum)
1068 g_string_append_printf(s, "%s:\t\t\t%s\n",
1069 _("Phone"),
1070 vcard.tels[i].telnum);
1071 }
1072 for (i = 0; i < vcard.num_emails; i++) {
1073 if (vcard.emails[i].address)
1074 g_string_append_printf(s, "%s:\t\t%s\n",
1075 _("E-Mail"),
1076 vcard.emails[i].address);
1077 }
1078 if (vcard.note)
1079 g_string_append_printf(s, "\n%s:\t\t%s\n",
1080 _("Note"),
1081 vcard.note);
1082 break;
1083 }
1084 }
1085
1086 buf = g_string_free(s, FALSE);
1087 gaim_notify_info(NULL, _("User Information"), _("User Information"),
1088 buf);
1089 g_free(buf);
1090 }
1091 #endif
1092
1093 /* Command reply handler. This function is called always in the command reply
1094 function. If error occurs it will be called as well. Normal scenario
1095 is that it will be called after the received command data has been parsed
1096 and processed. The function is used to pass the received command data to
1097 the application.
1098
1099 `conn' is the associated client connection. `cmd_payload' is the command
1100 payload data received from server and it can be ignored. It is provided
1101 if the application would like to re-parse the received command data,
1102 however, it must be noted that the data is parsed already by the library
1103 thus the payload can be ignored. `success' is FALSE if error occurred.
1104 In this case arguments are not sent to the application. The `status' is
1105 the command reply status server returned. The `command' is the command
1106 reply being processed. The function has variable argument list and each
1107 command defines the number and type of arguments it passes to the
1108 application (on error they are not sent). */
1109
1110 static void
1111 silc_command_reply(SilcClient client, SilcClientConnection conn,
1112 SilcCommandPayload cmd_payload, bool success,
1113 SilcCommand command, SilcStatus status, ...)
1114 {
1115 GaimConnection *gc = client->application;
1116 SilcGaim sg = gc->proto_data;
1117 GaimConversation *convo;
1118 va_list vp;
1119
1120 va_start(vp, status);
1121
1122 switch (command) {
1123 case SILC_COMMAND_JOIN:
1124 {
1125 SilcChannelEntry channel_entry;
1126
1127 if (!success) {
1128 gaim_notify_error(gc, _("Join Chat"), _("Cannot join channel"),
1129 silc_get_status_message(status));
1130 return;
1131 }
1132
1133 (void)va_arg(vp, char *);
1134 channel_entry = va_arg(vp, SilcChannelEntry);
1135
1136 /* Resolve users on channel */
1137 silc_client_get_clients_by_channel(client, conn, channel_entry,
1138 silcgaim_chat_join_done,
1139 channel_entry);
1140 }
1141 break;
1142
1143 case SILC_COMMAND_LEAVE:
1144 break;
1145
1146 case SILC_COMMAND_USERS:
1147 break;
1148
1149 case SILC_COMMAND_WHOIS:
1150 {
1151 SilcUInt32 idle, mode;
1152 SilcBuffer channels, user_modes;
1153 SilcClientEntry client_entry;
1154 char tmp[1024], *tmp2;
1155 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
1156 GaimNotifyUserInfo *user_info;
1157
1158 if (!success) {
1159 gaim_notify_error(gc, _("User Information"),
1160 _("Cannot get user information"),
1161 silc_get_status_message(status));
1162 break;
1163 }
1164
1165 client_entry = va_arg(vp, SilcClientEntry);
1166 if (!client_entry->nickname)
1167 break;
1168 (void)va_arg(vp, char *);
1169 (void)va_arg(vp, char *);
1170 (void)va_arg(vp, char *);
1171 channels = va_arg(vp, SilcBuffer);
1172 mode = va_arg(vp, SilcUInt32);
1173 idle = va_arg(vp, SilcUInt32);
1174 (void)va_arg(vp, unsigned char *);
1175 user_modes = va_arg(vp, SilcBuffer);
1176
1177 user_info = gaim_notify_user_info_new();
1178 tmp2 = g_markup_escape_text(client_entry->nickname, -1);
1179 gaim_notify_user_info_add_pair(user_info, _("Nickname"), tmp2);
1180 g_free(tmp2);
1181 if (client_entry->realname) {
1182 tmp2 = g_markup_escape_text(client_entry->realname, -1);
1183 gaim_notify_user_info_add_pair(user_info, _("Real Name"), tmp2);
1184 g_free(tmp2);
1185 }
1186 if (client_entry->username) {
1187 tmp2 = g_markup_escape_text(client_entry->username, -1);
1188 if (client_entry->hostname) {
1189 gchar *tmp3;
1190 tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname);
1191 gaim_notify_user_info_add_pair(user_info, _("Username"), tmp3);
1192 g_free(tmp3);
1193 } else
1194 gaim_notify_user_info_add_pair(user_info, _("Username"), tmp2);
1195 g_free(tmp2);
1196 }
1197
1198 if (client_entry->mode) {
1199 memset(tmp, 0, sizeof(tmp));
1200 silcgaim_get_umode_string(client_entry->mode,
1201 tmp, sizeof(tmp) - strlen(tmp));
1202 gaim_notify_user_info_add_pair(user_info, _("User Modes"), tmp);
1203 }
1204
1205 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr);
1206 if (moodstr) {
1207 gaim_notify_user_info_add_pair(user_info, _("Mood"), moodstr);
1208 g_free(moodstr);
1209 }
1210
1211 if (statusstr) {
1212 tmp2 = g_markup_escape_text(statusstr, -1);
1213 gaim_notify_user_info_add_pair(user_info, _("Status Text"), tmp2);
1214 g_free(statusstr);
1215 g_free(tmp2);
1216 }
1217
1218 if (contactstr) {
1219 gaim_notify_user_info_add_pair(user_info, _("Preferred Contact"), contactstr);
1220 g_free(contactstr);
1221 }
1222
1223 if (langstr) {
1224 gaim_notify_user_info_add_pair(user_info, _("Preferred Language"), langstr);
1225 g_free(langstr);
1226 }
1227
1228 if (devicestr) {
1229 gaim_notify_user_info_add_pair(user_info, _("Device"), devicestr);
1230 g_free(devicestr);
1231 }
1232
1233 if (tzstr) {
1234 gaim_notify_user_info_add_pair(user_info, _("Timezone"), tzstr);
1235 g_free(tzstr);
1236 }
1237
1238 if (geostr) {
1239 gaim_notify_user_info_add_pair(user_info, _("Geolocation"), geostr);
1240 g_free(geostr);
1241 }
1242
1243 if (client_entry->server)
1244 gaim_notify_user_info_add_pair(user_info, _("Server"), client_entry->server);
1245
1246 if (channels && user_modes) {
1247 SilcUInt32 *umodes;
1248 SilcDList list =
1249 silc_channel_payload_parse_list(channels->data,
1250 channels->len);
1251 if (list && silc_get_mode_list(user_modes,
1252 silc_dlist_count(list),
1253 &umodes)) {
1254 SilcChannelPayload entry;
1255 int i = 0;
1256
1257 memset(tmp, 0, sizeof(tmp));
1258 silc_dlist_start(list);
1259 while ((entry = silc_dlist_get(list))
1260 != SILC_LIST_END) {
1261 SilcUInt32 name_len;
1262 char *m = silc_client_chumode_char(umodes[i++]);
1263 char *name = (char *)silc_channel_get_name(entry, &name_len);
1264 if (m)
1265 silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m));
1266 silc_strncat(tmp, sizeof(tmp) - 1, name, name_len);
1267 silc_strncat(tmp, sizeof(tmp) - 1, " ", 1);
1268 silc_free(m);
1269
1270 }
1271 tmp2 = g_markup_escape_text(tmp, -1);
1272 gaim_notify_user_info_add_pair(user_info, _("Currently on"), tmp2);
1273 g_free(tmp2);
1274 silc_free(umodes);
1275 }
1276 }
1277
1278 if (client_entry->public_key) {
1279 char *fingerprint, *babbleprint;
1280 unsigned char *pk;
1281 SilcUInt32 pk_len;
1282 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
1283 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1284 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1285 gaim_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
1286 gaim_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
1287 silc_free(fingerprint);
1288 silc_free(babbleprint);
1289 silc_free(pk);
1290 }
1291
1292 #if 0 /* XXX for now, let's not show attrs here */
1293 if (client_entry->attrs)
1294 gaim_request_action(gc, _("User Information"),
1295 _("User Information"),
1296 buf, 1, client_entry, 2,
1297 _("OK"), G_CALLBACK(silcgaim_whois_more),
1298 _("_More..."), G_CALLBACK(silcgaim_whois_more));
1299 else
1300 #endif
1301 gaim_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL);
1302 gaim_notify_user_info_destroy(user_info);
1303 }
1304 break;
1305
1306 case SILC_COMMAND_WHOWAS:
1307 {
1308 SilcClientEntry client_entry;
1309 char *nickname, *realname, *username, *tmp;
1310 GaimNotifyUserInfo *user_info;
1311
1312 if (!success) {
1313 gaim_notify_error(gc, _("User Information"),
1314 _("Cannot get user information"),
1315 silc_get_status_message(status));
1316 break;
1317 }
1318
1319 client_entry = va_arg(vp, SilcClientEntry);
1320 nickname = va_arg(vp, char *);
1321 username = va_arg(vp, char *);
1322 realname = va_arg(vp, char *);
1323 if (!nickname)
1324 break;
1325
1326 user_info = gaim_notify_user_info_new();
1327 tmp = g_markup_escape_text(nickname, -1);
1328 gaim_notify_user_info_add_pair(user_info, _("Nickname"), tmp);
1329 g_free(tmp);
1330 if (realname) {
1331 tmp = g_markup_escape_text(realname, -1);
1332 gaim_notify_user_info_add_pair(user_info, _("Real Name"), tmp);
1333 g_free(tmp);
1334 }
1335 if (username) {
1336 tmp = g_markup_escape_text(username, -1);
1337 if (client_entry && client_entry->hostname) {
1338 gchar *tmp3;
1339 tmp3 = g_strdup_printf("%s@%s", tmp, client_entry->hostname);
1340 gaim_notify_user_info_add_pair(user_info, _("Username"), tmp3);
1341 g_free(tmp3);
1342 } else
1343 gaim_notify_user_info_add_pair(user_info, _("Username"), tmp);
1344 g_free(tmp);
1345 }
1346 if (client_entry && client_entry->server)
1347 gaim_notify_user_info_add_pair(user_info, _("Server"), client_entry->server);
1348
1349
1350 if (client_entry && client_entry->public_key) {
1351 char *fingerprint, *babbleprint;
1352 unsigned char *pk;
1353 SilcUInt32 pk_len;
1354 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
1355 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
1356 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
1357 gaim_notify_user_info_add_pair(user_info, _("Public Key Fingerprint"), fingerprint);
1358 gaim_notify_user_info_add_pair(user_info, _("Public Key Babbleprint"), babbleprint);
1359 silc_free(fingerprint);
1360 silc_free(babbleprint);
1361 silc_free(pk);
1362 }
1363
1364 gaim_notify_userinfo(gc, nickname, user_info, NULL, NULL);
1365 gaim_notify_user_info_destroy(user_info);
1366 }
1367 break;
1368
1369 case SILC_COMMAND_DETACH:
1370 if (!success) {
1371 gaim_notify_error(gc, _("Detach From Server"), _("Cannot detach"),
1372 silc_get_status_message(status));
1373 return;
1374 }
1375 break;
1376
1377 case SILC_COMMAND_TOPIC:
1378 {
1379 SilcChannelEntry channel;
1380
1381 if (!success) {
1382 gaim_notify_error(gc, _("Topic"), _("Cannot set topic"),
1383 silc_get_status_message(status));
1384 return;
1385 }
1386
1387 channel = va_arg(vp, SilcChannelEntry);
1388
1389 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
1390 channel->channel_name, sg->account);
1391 if (!convo) {
1392 gaim_debug_error("silc", "Got a topic for %s, which doesn't exist\n",
1393 channel->channel_name);
1394 break;
1395 }
1396
1397 /* Set topic */
1398 if (channel->topic)
1399 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(convo), NULL, channel->topic);
1400 }
1401 break;
1402
1403 case SILC_COMMAND_NICK:
1404 {
1405 /* I don't think we should need to do this because the server should
1406 * be sending a SILC_NOTIFY_TYPE_NICK_CHANGE when we change our own
1407 * nick, but it isn't, so we deal with it here instead. Stu. */
1408 SilcClientEntry local_entry;
1409 SilcHashTableList htl;
1410 SilcChannelUser chu;
1411 const char *oldnick;
1412
1413 if (!success) {
1414 gaim_notify_error(gc, _("Nick"), _("Failed to change nickname"),
1415 silc_get_status_message(status));
1416 return;
1417 }
1418
1419 local_entry = va_arg(vp, SilcClientEntry);
1420
1421 /* Change nick on all channels */
1422 silc_hash_table_list(local_entry->channels, &htl);
1423 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1424 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_CHAT,
1425 chu->channel->channel_name, sg->account);
1426 if (!convo)
1427 continue;
1428 oldnick = gaim_conv_chat_get_nick(GAIM_CONV_CHAT(convo));
1429 if (strcmp(oldnick, gaim_normalize(gaim_conversation_get_account(convo), local_entry->nickname))) {
1430 gaim_conv_chat_rename_user(GAIM_CONV_CHAT(convo),
1431 oldnick, local_entry->nickname);
1432 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(convo), local_entry->nickname);
1433 }
1434 }
1435 silc_hash_table_list_reset(&htl);
1436
1437 gaim_connection_set_display_name(gc, local_entry->nickname);
1438 }
1439 break;
1440
1441 case SILC_COMMAND_LIST:
1442 {
1443 char *topic, *name;
1444 int usercount;
1445 GaimRoomlistRoom *room;
1446
1447 if (sg->roomlist_canceled)
1448 break;
1449
1450 if (!success) {
1451 gaim_notify_error(gc, _("Error"), _("Error retrieving room list"),
1452 silc_get_status_message(status));
1453 gaim_roomlist_set_in_progress(sg->roomlist, FALSE);
1454 gaim_roomlist_unref(sg->roomlist);
1455 sg->roomlist = NULL;
1456 return;
1457 }
1458
1459 (void)va_arg(vp, SilcChannelEntry);
1460 name = va_arg(vp, char *);
1461 if (!name) {
1462 gaim_notify_error(gc, _("Roomlist"), _("Cannot get room list"),
1463 silc_get_status_message(status));
1464 gaim_roomlist_set_in_progress(sg->roomlist, FALSE);
1465 gaim_roomlist_unref(sg->roomlist);
1466 sg->roomlist = NULL;
1467 return;
1468 }
1469 topic = va_arg(vp, char *);
1470 usercount = va_arg(vp, int);
1471
1472 room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, name, NULL);
1473 gaim_roomlist_room_add_field(sg->roomlist, room, name);
1474 gaim_roomlist_room_add_field(sg->roomlist, room,
1475 SILC_32_TO_PTR(usercount));
1476 gaim_roomlist_room_add_field(sg->roomlist, room,
1477 topic ? topic : "");
1478 gaim_roomlist_room_add(sg->roomlist, room);
1479
1480 if (status == SILC_STATUS_LIST_END ||
1481 status == SILC_STATUS_OK) {
1482 gaim_roomlist_set_in_progress(sg->roomlist, FALSE);
1483 gaim_roomlist_unref(sg->roomlist);
1484 sg->roomlist = NULL;
1485 }
1486 }
1487 break;
1488
1489 case SILC_COMMAND_GETKEY:
1490 {
1491 SilcPublicKey public_key;
1492
1493 if (!success) {
1494 gaim_notify_error(gc, _("Get Public Key"),
1495 _("Cannot fetch the public key"),
1496 silc_get_status_message(status));
1497 return;
1498 }
1499
1500 (void)va_arg(vp, SilcUInt32);
1501 (void)va_arg(vp, void *);
1502 public_key = va_arg(vp, SilcPublicKey);
1503
1504 if (!public_key)
1505 gaim_notify_error(gc, _("Get Public Key"),
1506 _("Cannot fetch the public key"),
1507 _("No public key was received"));
1508 }
1509 break;
1510
1511 case SILC_COMMAND_INFO:
1512 {
1513
1514 char *server_name;
1515 char *server_info;
1516 char tmp[256];
1517
1518 if (!success) {
1519 gaim_notify_error(gc, _("Server Information"),
1520 _("Cannot get server information"),
1521 silc_get_status_message(status));
1522 return;
1523 }
1524
1525 (void)va_arg(vp, SilcServerEntry);
1526 server_name = va_arg(vp, char *);
1527 server_info = va_arg(vp, char *);
1528
1529 if (server_name && server_info) {
1530 g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s",
1531 server_name, server_info);
1532 gaim_notify_info(gc, NULL, _("Server Information"), tmp);
1533 }
1534 }
1535 break;
1536
1537 case SILC_COMMAND_STATS:
1538 {
1539 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops,
1540 my_router_ops, cell_clients, cell_channels, cell_servers,
1541 clients, channels, servers, routers, server_ops, router_ops;
1542 SilcUInt32 buffer_length;
1543 SilcBufferStruct buf;
1544
1545 unsigned char *server_stats;
1546 char *msg;
1547
1548 if (!success) {
1549 gaim_notify_error(gc, _("Server Statistics"),
1550 _("Cannot get server statistics"),
1551 silc_get_status_message(status));
1552 return;
1553 }
1554
1555 server_stats = va_arg(vp, unsigned char *);
1556 buffer_length = va_arg(vp, SilcUInt32);
1557 if (!server_stats || !buffer_length) {
1558 gaim_notify_error(gc, _("Server Statistics"),
1559 _("No server statistics available"), NULL);
1560 break;
1561 }
1562 silc_buffer_set(&buf, server_stats, buffer_length);
1563 silc_buffer_unformat(&buf,
1564 SILC_STR_UI_INT(&starttime),
1565 SILC_STR_UI_INT(&uptime),
1566 SILC_STR_UI_INT(&my_clients),
1567 SILC_STR_UI_INT(&my_channels),
1568 SILC_STR_UI_INT(&my_server_ops),
1569 SILC_STR_UI_INT(&my_router_ops),
1570 SILC_STR_UI_INT(&cell_clients),
1571 SILC_STR_UI_INT(&cell_channels),
1572 SILC_STR_UI_INT(&cell_servers),
1573 SILC_STR_UI_INT(&clients),
1574 SILC_STR_UI_INT(&channels),
1575 SILC_STR_UI_INT(&servers),
1576 SILC_STR_UI_INT(&routers),
1577 SILC_STR_UI_INT(&server_ops),
1578 SILC_STR_UI_INT(&router_ops),
1579 SILC_STR_END);
1580
1581 msg = g_strdup_printf(_("Local server start time: %s\n"
1582 "Local server uptime: %s\n"
1583 "Local server clients: %d\n"
1584 "Local server channels: %d\n"
1585 "Local server operators: %d\n"
1586 "Local router operators: %d\n"
1587 "Local cell clients: %d\n"
1588 "Local cell channels: %d\n"
1589 "Local cell servers: %d\n"
1590 "Total clients: %d\n"
1591 "Total channels: %d\n"
1592 "Total servers: %d\n"
1593 "Total routers: %d\n"
1594 "Total server operators: %d\n"
1595 "Total router operators: %d\n"),
1596 silc_get_time(starttime),
1597 gaim_str_seconds_to_string((int)uptime),
1598 (int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops,
1599 (int)cell_clients, (int)cell_channels, (int)cell_servers,
1600 (int)clients, (int)channels, (int)servers, (int)routers,
1601 (int)server_ops, (int)router_ops);
1602
1603 gaim_notify_info(gc, NULL,
1604 _("Network Statistics"), msg);
1605 g_free(msg);
1606 }
1607 break;
1608
1609 case SILC_COMMAND_PING:
1610 {
1611 if (!success) {
1612 gaim_notify_error(gc, _("Ping"), _("Ping failed"),
1613 silc_get_status_message(status));
1614 return;
1615 }
1616
1617 gaim_notify_info(gc, _("Ping"), _("Ping reply received from server"),
1618 NULL);
1619 }
1620 break;
1621
1622 case SILC_COMMAND_KILL:
1623 if (!success) {
1624 gaim_notify_error(gc, _("Kill User"),
1625 _("Could not kill user"),
1626 silc_get_status_message(status));
1627 return;
1628 }
1629 break;
1630
1631 case SILC_COMMAND_CMODE:
1632 {
1633 SilcChannelEntry channel_entry;
1634 SilcBuffer channel_pubkeys;
1635
1636 if (!success)
1637 return;
1638
1639 channel_entry = va_arg(vp, SilcChannelEntry);
1640 (void)va_arg(vp, SilcUInt32);
1641 (void)va_arg(vp, SilcPublicKey);
1642 channel_pubkeys = va_arg(vp, SilcBuffer);
1643
1644 if (sg->chpk)
1645 silcgaim_chat_chauth_show(sg, channel_entry, channel_pubkeys);
1646 }
1647 break;
1648
1649 default:
1650 if (success)
1651 gaim_debug_info("silc", "Unhandled command: %d (succeeded)\n", command);
1652 else
1653 gaim_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command,
1654 silc_get_status_message(status));
1655 break;
1656 }
1657
1658 va_end(vp);
1659 }
1660
1661
1662 /* Called to indicate that connection was either successfully established
1663 or connecting failed. This is also the first time application receives
1664 the SilcClientConnection object which it should save somewhere.
1665 If the `success' is FALSE the application must always call the function
1666 silc_client_close_connection. */
1667
1668 static void
1669 silc_connected(SilcClient client, SilcClientConnection conn,
1670 SilcClientConnectionStatus status)
1671 {
1672 GaimConnection *gc = client->application;
1673 SilcGaim sg;
1674 gboolean reject_watch, block_invites, block_ims;
1675
1676 if (gc == NULL) {
1677 silc_client_close_connection(client, conn);
1678 return;
1679 }
1680 sg = gc->proto_data;
1681
1682 switch (status) {
1683 case SILC_CLIENT_CONN_SUCCESS:
1684 case SILC_CLIENT_CONN_SUCCESS_RESUME:
1685 gaim_connection_set_state(gc, GAIM_CONNECTED);
1686
1687 /* Send the server our buddy list */
1688 silcgaim_send_buddylist(gc);
1689
1690 g_unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
1691
1692 /* Send any UMODEs configured for account */
1693 reject_watch = gaim_account_get_bool(sg->account, "reject-watch", FALSE);
1694 block_invites = gaim_account_get_bool(sg->account, "block-invites", FALSE);
1695 block_ims = gaim_account_get_bool(sg->account, "block-ims", FALSE);
1696 if (reject_watch || block_invites || block_ims) {
1697 char m[5];
1698 g_snprintf(m, sizeof(m), "+%s%s%s",
1699 reject_watch ? "w" : "",
1700 block_invites ? "I" : "",
1701 block_ims ? "P" : "");
1702 silc_client_command_call(sg->client, sg->conn, NULL,
1703 "UMODE", m, NULL);
1704 }
1705
1706 return;
1707 break;
1708 case SILC_CLIENT_CONN_ERROR:
1709 gaim_connection_error(gc, _("Error during connecting to SILC Server"));
1710 g_unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
1711 break;
1712
1713 case SILC_CLIENT_CONN_ERROR_KE:
1714 gaim_connection_error(gc, _("Key Exchange failed"));
1715 break;
1716
1717 case SILC_CLIENT_CONN_ERROR_AUTH:
1718 gaim_connection_error(gc, _("Authentication failed"));
1719 break;
1720
1721 case SILC_CLIENT_CONN_ERROR_RESUME:
1722 gaim_connection_error(gc,
1723 _("Resuming detached session failed. "
1724 "Press Reconnect to create new connection."));
1725 g_unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
1726 break;
1727
1728 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
1729 gaim_connection_error(gc, _("Connection Timeout"));
1730 break;
1731 }
1732
1733 /* Error */
1734 sg->conn = NULL;
1735 silc_client_close_connection(client, conn);
1736 }
1737
1738
1739 /* Called to indicate that connection was disconnected to the server.
1740 The `status' may tell the reason of the disconnection, and if the
1741 `message' is non-NULL it may include the disconnection message
1742 received from server. */
1743
1744 static void
1745 silc_disconnected(SilcClient client, SilcClientConnection conn,
1746 SilcStatus status, const char *message)
1747 {
1748 GaimConnection *gc = client->application;
1749 SilcGaim sg = gc->proto_data;
1750
1751 if (sg->resuming && !sg->detaching)
1752 g_unlink(silcgaim_session_file(gaim_account_get_username(sg->account)));
1753
1754 sg->conn = NULL;
1755
1756 /* Close the connection */
1757 if (!sg->detaching)
1758 gaim_connection_error(gc, _("Disconnected by server"));
1759 else
1760 /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */
1761 gaim_account_disconnect(gaim_connection_get_account(gc));
1762 }
1763
1764
1765 typedef struct {
1766 SilcGetAuthMeth completion;
1767 void *context;
1768 } *SilcGaimGetAuthMethod;
1769
1770 /* Callback called when we've received the authentication method information
1771 from the server after we've requested it. */
1772
1773 static void silc_get_auth_method_callback(SilcClient client,
1774 SilcClientConnection conn,
1775 SilcAuthMethod auth_meth,
1776 void *context)
1777 {
1778 SilcGaimGetAuthMethod internal = context;
1779
1780 switch (auth_meth) {
1781 case SILC_AUTH_NONE:
1782 /* No authentication required. */
1783 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1784 break;
1785
1786 case SILC_AUTH_PASSWORD:
1787 /* By returning NULL here the library will ask the passphrase from us
1788 by calling the silc_ask_passphrase. */
1789 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1790 break;
1791
1792 case SILC_AUTH_PUBLIC_KEY:
1793 /* Do not get the authentication data now, the library will generate
1794 it using our default key, if we do not provide it here. */
1795 (*internal->completion)(TRUE, auth_meth, NULL, 0, internal->context);
1796 break;
1797 }
1798
1799 silc_free(internal);
1800 }
1801
1802 /* Find authentication method and authentication data by hostname and
1803 port. The hostname may be IP address as well. When the authentication
1804 method has been resolved the `completion' callback with the found
1805 authentication method and authentication data is called. The `conn'
1806 may be NULL. */
1807
1808 static void
1809 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1810 char *hostname, SilcUInt16 port,
1811 SilcGetAuthMeth completion, void *context)
1812 {
1813 GaimConnection *gc = client->application;
1814 SilcGaim sg = gc->proto_data;
1815 SilcGaimGetAuthMethod internal;
1816 const char *password;
1817
1818 /* Progress */
1819 if (sg->resuming)
1820 gaim_connection_update_progress(gc, _("Resuming session"), 4, 5);
1821 else
1822 gaim_connection_update_progress(gc, _("Authenticating connection"), 4, 5);
1823
1824 /* Check configuration if we have this connection configured. If we
1825 have then return that data immediately, as it's faster way. */
1826 if (gaim_account_get_bool(sg->account, "pubkey-auth", FALSE)) {
1827 completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
1828 return;
1829 }
1830 password = gaim_connection_get_password(gc);
1831 if (password && *password) {
1832 completion(TRUE, SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context);
1833 return;
1834 }
1835
1836 /* Resolve the authentication method from server, as we may not know it. */
1837 internal = silc_calloc(1, sizeof(*internal));
1838 if (!internal)
1839 return;
1840 internal->completion = completion;
1841 internal->context = context;
1842 silc_client_request_authentication_method(client, conn,
1843 silc_get_auth_method_callback,
1844 internal);
1845 }
1846
1847
1848 /* Verifies received public key. The `conn_type' indicates which entity
1849 (server, client etc.) has sent the public key. If user decides to trust
1850 the application may save the key as trusted public key for later
1851 use. The `completion' must be called after the public key has been
1852 verified. */
1853
1854 static void
1855 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1856 SilcSocketType conn_type, unsigned char *pk,
1857 SilcUInt32 pk_len, SilcSKEPKType pk_type,
1858 SilcVerifyPublicKey completion, void *context)
1859 {
1860 GaimConnection *gc = client->application;
1861 SilcGaim sg = gc->proto_data;
1862
1863 if (!sg->conn && (conn_type == SILC_SOCKET_TYPE_SERVER ||
1864 conn_type == SILC_SOCKET_TYPE_ROUTER)) {
1865 /* Progress */
1866 if (sg->resuming)
1867 gaim_connection_update_progress(gc, _("Resuming session"), 3, 5);
1868 else
1869 gaim_connection_update_progress(gc, _("Verifying server public key"),
1870 3, 5);
1871 }
1872
1873 /* Verify public key */
1874 silcgaim_verify_public_key(client, conn, NULL, conn_type, pk,
1875 pk_len, pk_type, completion, context);
1876 }
1877
1878 typedef struct {
1879 SilcAskPassphrase completion;
1880 void *context;
1881 } *SilcGaimAskPassphrase;
1882
1883 static void
1884 silc_ask_passphrase_cb(SilcGaimAskPassphrase internal, const char *passphrase)
1885 {
1886 if (!passphrase || !(*passphrase))
1887 internal->completion(NULL, 0, internal->context);
1888 else
1889 internal->completion((unsigned char *)passphrase,
1890 strlen(passphrase), internal->context);
1891 silc_free(internal);
1892 }
1893
1894 /* Ask (interact, that is) a passphrase from user. The passphrase is
1895 returned to the library by calling the `completion' callback with
1896 the `context'. The returned passphrase SHOULD be in UTF-8 encoded,
1897 if not then the library will attempt to encode. */
1898
1899 static void
1900 silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
1901 SilcAskPassphrase completion, void *context)
1902 {
1903 SilcGaimAskPassphrase internal = silc_calloc(1, sizeof(*internal));
1904
1905 if (!internal)
1906 return;
1907 internal->completion = completion;
1908 internal->context = context;
1909 gaim_request_input(client->application, _("Passphrase"), NULL,
1910 _("Passphrase required"), NULL, FALSE, TRUE, NULL,
1911 _("OK"), G_CALLBACK(silc_ask_passphrase_cb),
1912 _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb),
1913 internal);
1914 }
1915
1916
1917 /* Notifies application that failure packet was received. This is called
1918 if there is some protocol active in the client. The `protocol' is the
1919 protocol context. The `failure' is opaque pointer to the failure
1920 indication. Note, that the `failure' is protocol dependant and
1921 application must explicitly cast it to correct type. Usually `failure'
1922 is 32 bit failure type (see protocol specs for all protocol failure
1923 types). */
1924
1925 static void
1926 silc_failure(SilcClient client, SilcClientConnection conn,
1927 SilcProtocol protocol, void *failure)
1928 {
1929 GaimConnection *gc = client->application;
1930 char buf[128];
1931
1932 memset(buf, 0, sizeof(buf));
1933
1934 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1935 SilcSKEStatus status = (SilcSKEStatus)SILC_PTR_TO_32(failure);
1936
1937 if (status == SILC_SKE_STATUS_BAD_VERSION)
1938 g_snprintf(buf, sizeof(buf),
1939 _("Failure: Version mismatch, upgrade your client"));
1940 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1941 g_snprintf(buf, sizeof(buf),
1942 _("Failure: Remote does not trust/support your public key"));
1943 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1944 g_snprintf(buf, sizeof(buf),
1945 _("Failure: Remote does not support proposed KE group"));
1946 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1947 g_snprintf(buf, sizeof(buf),
1948 _("Failure: Remote does not support proposed cipher"));
1949 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1950 g_snprintf(buf, sizeof(buf),
1951 _("Failure: Remote does not support proposed PKCS"));
1952 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1953 g_snprintf(buf, sizeof(buf),
1954 _("Failure: Remote does not support proposed hash function"));
1955 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1956 g_snprintf(buf, sizeof(buf),
1957 _("Failure: Remote does not support proposed HMAC"));
1958 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1959 g_snprintf(buf, sizeof(buf), _("Failure: Incorrect signature"));
1960 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1961 g_snprintf(buf, sizeof(buf), _("Failure: Invalid cookie"));
1962
1963 /* Show the error on the progress bar. A more generic error message
1964 is going to be showed to user after this in the silc_connected. */
1965 gaim_connection_update_progress(gc, buf, 2, 5);
1966 }
1967
1968 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1969 SilcUInt32 err = SILC_PTR_TO_32(failure);
1970
1971 if (err == SILC_AUTH_FAILED)
1972 g_snprintf(buf, sizeof(buf), _("Failure: Authentication failed"));
1973
1974 /* Show the error on the progress bar. A more generic error message
1975 is going to be showed to user after this in the silc_connected. */
1976 gaim_connection_update_progress(gc, buf, 4, 5);
1977 }
1978 }
1979
1980 /* Asks whether the user would like to perform the key agreement protocol.
1981 This is called after we have received an key agreement packet or an
1982 reply to our key agreement packet. This returns TRUE if the user wants
1983 the library to perform the key agreement protocol and FALSE if it is not
1984 desired (application may start it later by calling the function
1985 silc_client_perform_key_agreement). If TRUE is returned also the
1986 `completion' and `context' arguments must be set by the application. */
1987
1988 static bool
1989 silc_key_agreement(SilcClient client, SilcClientConnection conn,
1990 SilcClientEntry client_entry, const char *hostname,
1991 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1992 void **context)
1993 {
1994 silcgaim_buddy_keyagr_request(client, conn, client_entry, hostname, port);
1995 *completion = NULL;
1996 *context = NULL;
1997 return FALSE;
1998 }
1999
2000
2001 /* Notifies application that file transfer protocol session is being
2002 requested by the remote client indicated by the `client_entry' from
2003 the `hostname' and `port'. The `session_id' is the file transfer
2004 session and it can be used to either accept or reject the file
2005 transfer request, by calling the silc_client_file_receive or
2006 silc_client_file_close, respectively. */
2007
2008 static void
2009 silc_ftp(SilcClient client, SilcClientConnection conn,
2010 SilcClientEntry client_entry, SilcUInt32 session_id,
2011 const char *hostname, SilcUInt16 port)
2012 {
2013 silcgaim_ftp_request(client, conn, client_entry, session_id,
2014 hostname, port);
2015 }
2016
2017
2018 /* Delivers SILC session detachment data indicated by `detach_data' to the
2019 application. If application has issued SILC_COMMAND_DETACH command
2020 the client session in the SILC network is not quit. The client remains
2021 in the network but is detached. The detachment data may be used later
2022 to resume the session in the SILC Network. The appliation is
2023 responsible of saving the `detach_data', to for example in a file.
2024
2025 The detachment data can be given as argument to the functions
2026 silc_client_connect_to_server, or silc_client_add_connection when
2027 creating connection to remote server, inside SilcClientConnectionParams
2028 structure. If it is provided the client library will attempt to resume
2029 the session in the network. After the connection is created
2030 successfully, the application is responsible of setting the user
2031 interface for user into the same state it was before detaching (showing
2032 same channels, channel modes, etc). It can do this by fetching the
2033 information (like joined channels) from the client library. */
2034
2035 static void
2036 silc_detach(SilcClient client, SilcClientConnection conn,
2037 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2038 {
2039 GaimConnection *gc = client->application;
2040 SilcGaim sg = gc->proto_data;
2041 const char *file;
2042
2043 /* Save the detachment data to file. */
2044 file = silcgaim_session_file(gaim_account_get_username(sg->account));
2045 g_unlink(file);
2046 silc_file_writefile(file, (char *)detach_data, detach_data_len);
2047 }
2048
2049 SilcClientOperations ops = {
2050 silc_say,
2051 silc_channel_message,
2052 silc_private_message,
2053 silc_notify,
2054 silc_command,
2055 silc_command_reply,
2056 silc_connected,
2057 silc_disconnected,
2058 silc_get_auth_method,
2059 silc_verify_public_key,
2060 silc_ask_passphrase,
2061 silc_failure,
2062 silc_key_agreement,
2063 silc_ftp,
2064 silc_detach
2065 };