libpurple/protocols/silc/ops.c

changeset 17675
e7069bf1de1a
parent 16545
5188ffbaeb6e
child 17680
28241b48536e
equal deleted inserted replaced
17674:aafdd7bed36d 17675:e7069bf1de1a
2 2
3 silcpurple_ops.c 3 silcpurple_ops.c
4 4
5 Author: Pekka Riikonen <priikone@silcnet.org> 5 Author: Pekka Riikonen <priikone@silcnet.org>
6 6
7 Copyright (C) 2004 Pekka Riikonen 7 Copyright (C) 2004 - 2007 Pekka Riikonen
8 8
9 This program is free software; you can redistribute it and/or modify 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 10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License. 11 the Free Software Foundation; version 2 of the License.
12 12
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details. 16 GNU General Public License for more details.
17 17
18 */ 18 */
19 19
20 #include "silcincludes.h" 20 #include "silc.h"
21 #include "silcclient.h" 21 #include "silcclient.h"
22 #include "silcpurple.h" 22 #include "silcpurple.h"
23 #include "imgstore.h" 23 #include "imgstore.h"
24 #include "wb.h" 24 #include "wb.h"
25 25
26 static void 26 static void
27 silc_channel_message(SilcClient client, SilcClientConnection conn, 27 silc_channel_message(SilcClient client, SilcClientConnection conn,
28 SilcClientEntry sender, SilcChannelEntry channel, 28 SilcClientEntry sender, SilcChannelEntry channel,
29 SilcMessagePayload payload, SilcChannelPrivateKey key, 29 SilcMessagePayload payload,
30 SilcMessageFlags flags, const unsigned char *message, 30 SilcChannelPrivateKey key, SilcMessageFlags flags,
31 const unsigned char *message,
31 SilcUInt32 message_len); 32 SilcUInt32 message_len);
32 static void 33 static void
33 silc_private_message(SilcClient client, SilcClientConnection conn, 34 silc_private_message(SilcClient client, SilcClientConnection conn,
34 SilcClientEntry sender, SilcMessagePayload payload, 35 SilcClientEntry sender, SilcMessagePayload payload,
35 SilcMessageFlags flags, const unsigned char *message, 36 SilcMessageFlags flags, const unsigned char *message,
36 SilcUInt32 message_len); 37 SilcUInt32 message_len);
38 static void
39 silc_ask_passphrase(SilcClient client, SilcClientConnection conn,
40 SilcAskPassphrase completion, void *context);
37 41
38 /* Message sent to the application by library. `conn' associates the 42 /* Message sent to the application by library. `conn' associates the
39 message to a specific connection. `conn', however, may be NULL. 43 message to a specific connection. `conn', however, may be NULL.
40 The `type' indicates the type of the message sent by the library. 44 The `type' indicates the type of the message sent by the library.
41 The application can for example filter the message according the 45 The application can for example filter the message according the
42 type. */ 46 type. */
43 47
44 static void 48 void silc_say(SilcClient client, SilcClientConnection conn,
45 silc_say(SilcClient client, SilcClientConnection conn, 49 SilcClientMessageType type, char *msg, ...)
46 SilcClientMessageType type, char *msg, ...)
47 { 50 {
48 /* Nothing */ 51 if (type == SILC_CLIENT_MESSAGE_ERROR) {
52 char tmp[256];
53 va_list va;
54
55 va_start(va, msg);
56 silc_vsnprintf(tmp, sizeof(tmp), msg, va);
57 purple_notify_error(NULL, _("Error"), _("Error occurred"), tmp);
58
59 va_end(va);
60 return;
61 }
49 } 62 }
50 63
51 #ifdef HAVE_SILCMIME_H 64 #ifdef HAVE_SILCMIME_H
52 /* Processes incoming MIME message. Can be private message or channel 65 /* Processes incoming MIME message. Can be private message or channel
53 message. */ 66 message. Returns TRUE if the message `mime' was displayed. */
54 67
55 static void 68 static SilcBool
56 silcpurple_mime_message(SilcClient client, SilcClientConnection conn, 69 silcpurple_mime_message(SilcClient client, SilcClientConnection conn,
57 SilcClientEntry sender, SilcChannelEntry channel, 70 SilcClientEntry sender, SilcChannelEntry channel,
58 SilcMessagePayload payload, SilcChannelPrivateKey key, 71 SilcMessagePayload payload, SilcChannelPrivateKey key,
59 SilcMessageFlags flags, SilcMime mime, 72 SilcMessageFlags flags, SilcMime mime,
60 gboolean recursive) 73 gboolean recursive)
61 { 74 {
62 PurpleConnection *gc = client->application; 75 PurpleConnection *gc = client->application;
63 SilcPurple sg = gc->proto_data; 76 SilcPurple sg = gc->proto_data;
64 const char *type; 77 const char *type;
65 const unsigned char *data; 78 const unsigned char *data;
66 SilcUInt32 data_len; 79 SilcUInt32 data_len;
67 PurpleMessageFlags cflags = 0; 80 PurpleMessageFlags cflags = 0;
68 PurpleConversation *convo = NULL; 81 PurpleConversation *convo = NULL;
82 SilcBool ret = FALSE;
69 83
70 if (!mime) 84 if (!mime)
71 return; 85 return FALSE;
72 86
73 /* Check for fragmented MIME message */ 87 /* Check for fragmented MIME message */
74 if (silc_mime_is_partial(mime)) { 88 if (silc_mime_is_partial(mime)) {
75 if (!sg->mimeass) 89 if (!sg->mimeass)
76 sg->mimeass = silc_mime_assembler_alloc(); 90 sg->mimeass = silc_mime_assembler_alloc();
77 91
78 /* Defragment */ 92 /* Defragment */
79 mime = silc_mime_assemble(sg->mimeass, mime); 93 mime = silc_mime_assemble(sg->mimeass, mime);
80 if (!mime) 94 if (!mime)
81 /* More fragments to come */ 95 /* More fragments to come */
82 return; 96 return FALSE;
83 97
84 /* Process the complete message */ 98 /* Process the complete message */
85 silcpurple_mime_message(client, conn, sender, channel, 99 return silcpurple_mime_message(client, conn, sender, channel,
86 payload, key, flags, mime, FALSE); 100 payload, key, flags, mime,
87 return; 101 FALSE);
88 } 102 }
89 103
90 /* Check for multipart message */ 104 /* Check for multipart message */
91 if (silc_mime_is_multipart(mime)) { 105 if (silc_mime_is_multipart(mime)) {
92 SilcMime p; 106 SilcMime p;
93 const char *mtype; 107 const char *mtype;
94 SilcDList parts = silc_mime_get_multiparts(mime, &mtype); 108 SilcDList parts = silc_mime_get_multiparts(mime, &mtype);
95 109 SilcBool ret;
96 /* Only "mixed" type supported */ 110
97 if (strcmp(mtype, "mixed")) 111 if (!strcmp(mtype, "mixed")) {
98 goto out; 112 /* Contains multiple messages */
99 113 silc_dlist_start(parts);
100 silc_dlist_start(parts); 114 while ((p = silc_dlist_get(parts)) != SILC_LIST_END) {
101 while ((p = silc_dlist_get(parts)) != SILC_LIST_END) { 115 /* Recursively process parts */
102 /* Recursively process parts */ 116 ret = silcpurple_mime_message(client, conn, sender, channel,
103 silcpurple_mime_message(client, conn, sender, channel, 117 payload, key, flags, p, TRUE);
104 payload, key, flags, p, TRUE); 118 }
105 } 119 }
120
121 if (!strcmp(mtype, "alternative")) {
122 /* Same message in alternative formats. Kopete sends
123 these. Go in order from last to first. */
124 silc_dlist_end(parts);
125 while ((p = silc_dlist_get(parts)) != SILC_LIST_END) {
126 /* Go through the alternatives and display the first
127 one we support. */
128 if (silcpurple_mime_message(client, conn, sender, channel,
129 payload, key, flags, p, TRUE)) {
130 ret = TRUE;
131 break;
132 }
133 }
134 }
135
106 goto out; 136 goto out;
107 } 137 }
108 138
109 /* Get content type and MIME data */ 139 /* Get content type and MIME data */
110 type = silc_mime_get_field(mime, "Content-Type"); 140 type = silc_mime_get_field(mime, "Content-Type");
122 if (!strstr(type, "utf-8")) 152 if (!strstr(type, "utf-8"))
123 goto out; 153 goto out;
124 154
125 if (channel) 155 if (channel)
126 silc_channel_message(client, conn, sender, channel, 156 silc_channel_message(client, conn, sender, channel,
127 payload, key, 157 payload, key,
128 SILC_MESSAGE_FLAG_UTF8, data, 158 SILC_MESSAGE_FLAG_UTF8, data,
129 data_len); 159 data_len);
130 else 160 else
131 silc_private_message(client, conn, sender, payload, 161 silc_private_message(client, conn, sender, payload,
132 SILC_MESSAGE_FLAG_UTF8, data, 162 SILC_MESSAGE_FLAG_UTF8, data,
133 data_len); 163 data_len);
164 ret = TRUE;
134 goto out; 165 goto out;
135 } 166 }
136 167
137 /* Image */ 168 /* Image */
138 if (strstr(type, "image/png") || 169 if (strstr(type, "image/png") ||
155 break; 186 break;
156 } 187 }
157 } 188 }
158 if (channel && !convo) 189 if (channel && !convo)
159 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 190 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
160 channel->channel_name, sg->account); 191 channel->channel_name, sg->account);
161 if (channel && !convo) 192 if (channel && !convo)
162 goto out; 193 goto out;
163 194
164 imgid = purple_imgstore_add_with_id(g_memdup(data, data_len), data_len, ""); 195 imgid = purple_imgstore_add_with_id(g_memdup(data, data_len), data_len, "");
165 if (imgid) { 196 if (imgid) {
166 cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV; 197 cflags |= PURPLE_MESSAGE_IMAGES | PURPLE_MESSAGE_RECV;
167 g_snprintf(tmp, sizeof(tmp), "<IMG ID=\"%d\">", imgid); 198 g_snprintf(tmp, sizeof(tmp), "<IMG ID=\"%d\">", imgid);
168 199
169 if (channel) 200 if (channel)
170 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), 201 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
171 sender->nickname ? 202 sender->nickname ?
172 sender->nickname : 203 sender->nickname :
173 "<unknown>", cflags, 204 "<unknown>", cflags,
174 tmp, time(NULL)); 205 tmp, time(NULL));
175 else 206 else
176 serv_got_im(gc, sender->nickname ? 207 serv_got_im(gc, sender->nickname ?
177 sender->nickname : "<unknown>", 208 sender->nickname : "<unknown>",
178 tmp, cflags, time(NULL)); 209 tmp, cflags, time(NULL));
179 210
180 purple_imgstore_unref_by_id(imgid); 211 purple_imgstore_unref_by_id(imgid);
181 cflags = 0; 212 cflags = 0;
213 ret = TRUE;
182 } 214 }
183 goto out; 215 goto out;
184 } 216 }
185 217
186 /* Whiteboard message */ 218 /* Whiteboard message */
189 if (channel) 221 if (channel)
190 silcpurple_wb_receive_ch(client, conn, sender, channel, 222 silcpurple_wb_receive_ch(client, conn, sender, channel,
191 payload, flags, data, data_len); 223 payload, flags, data, data_len);
192 else 224 else
193 silcpurple_wb_receive(client, conn, sender, payload, 225 silcpurple_wb_receive(client, conn, sender, payload,
194 flags, data, data_len); 226 flags, data, data_len);
227 ret = TRUE;
195 goto out; 228 goto out;
196 } 229 }
197 230
198 out: 231 out:
199 if (!recursive) 232 if (!recursive)
200 silc_mime_free(mime); 233 silc_mime_free(mime);
234 return ret;
201 } 235 }
202 #endif /* HAVE_SILCMIME_H */ 236 #endif /* HAVE_SILCMIME_H */
203 237
204 /* Message for a channel. The `sender' is the sender of the message 238 /* Message for a channel. The `sender' is the sender of the message
205 The `channel' is the channel. The `message' is the message. Note 239 The `channel' is the channel. The `message' is the message. Note
208 (like it may tell the message is multimedia message). */ 242 (like it may tell the message is multimedia message). */
209 243
210 static void 244 static void
211 silc_channel_message(SilcClient client, SilcClientConnection conn, 245 silc_channel_message(SilcClient client, SilcClientConnection conn,
212 SilcClientEntry sender, SilcChannelEntry channel, 246 SilcClientEntry sender, SilcChannelEntry channel,
213 SilcMessagePayload payload, SilcChannelPrivateKey key, 247 SilcMessagePayload payload,
214 SilcMessageFlags flags, const unsigned char *message, 248 SilcChannelPrivateKey key, SilcMessageFlags flags,
249 const unsigned char *message,
215 SilcUInt32 message_len) 250 SilcUInt32 message_len)
216 { 251 {
217 PurpleConnection *gc = client->application; 252 PurpleConnection *gc = client->application;
218 SilcPurple sg = gc->proto_data; 253 SilcPurple sg = gc->proto_data;
219 PurpleConversation *convo = NULL; 254 PurpleConversation *convo = NULL;
234 break; 269 break;
235 } 270 }
236 } 271 }
237 if (!convo) 272 if (!convo)
238 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 273 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
239 channel->channel_name, sg->account); 274 channel->channel_name, sg->account);
240 if (!convo) 275 if (!convo)
241 return; 276 return;
242 277
243 if (flags & SILC_MESSAGE_FLAG_SIGNED && 278 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
244 purple_account_get_bool(sg->account, "sign-verify", FALSE)) { 279 purple_account_get_bool(sg->account, "sign-verify", FALSE)) {
247 282
248 if (flags & SILC_MESSAGE_FLAG_DATA) { 283 if (flags & SILC_MESSAGE_FLAG_DATA) {
249 /* Process MIME message */ 284 /* Process MIME message */
250 #ifdef HAVE_SILCMIME_H 285 #ifdef HAVE_SILCMIME_H
251 SilcMime mime; 286 SilcMime mime;
252 mime = silc_mime_decode(message, message_len); 287 mime = silc_mime_decode(NULL, message, message_len);
253 silcpurple_mime_message(client, conn, sender, channel, payload, 288 silcpurple_mime_message(client, conn, sender, channel, payload,
254 key, flags, mime, FALSE); 289 key, flags, mime, FALSE);
255 #else 290 #else
256 char type[128], enc[128]; 291 char type[128], enc[128];
257 unsigned char *data; 292 unsigned char *data;
258 SilcUInt32 data_len; 293 SilcUInt32 data_len;
259 294
281 return; 316 return;
282 317
283 tmp = g_markup_escape_text(msg, -1); 318 tmp = g_markup_escape_text(msg, -1);
284 /* Send to Purple */ 319 /* Send to Purple */
285 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), 320 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
286 sender->nickname ? 321 sender->nickname, 0, tmp, time(NULL));
287 sender->nickname : "<unknown>", 0,
288 tmp, time(NULL));
289 g_free(tmp); 322 g_free(tmp);
290 g_free(msg); 323 g_free(msg);
291 return; 324 return;
292 } 325 }
293 326
294 if (flags & SILC_MESSAGE_FLAG_NOTICE) { 327 if (flags & SILC_MESSAGE_FLAG_NOTICE) {
295 msg = g_strdup_printf("(notice) <I>%s</I> %s", 328 msg = g_strdup_printf("(notice) <I>%s</I> %s",
296 sender->nickname ? 329 sender->nickname, (const char *)message);
297 sender->nickname : "<unknown>",
298 (const char *)message);
299 if (!msg) 330 if (!msg)
300 return; 331 return;
301 332
302 /* Send to Purple */ 333 /* Send to Purple */
303 purple_conversation_write(convo, NULL, (const char *)msg, 334 purple_conversation_write(convo, NULL, (const char *)msg,
308 339
309 if (flags & SILC_MESSAGE_FLAG_UTF8) { 340 if (flags & SILC_MESSAGE_FLAG_UTF8) {
310 tmp = g_markup_escape_text((const char *)message, -1); 341 tmp = g_markup_escape_text((const char *)message, -1);
311 /* Send to Purple */ 342 /* Send to Purple */
312 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), 343 serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)),
313 sender->nickname ? 344 sender->nickname, 0, tmp, time(NULL));
314 sender->nickname : "<unknown>", 0,
315 tmp, time(NULL));
316 g_free(tmp); 345 g_free(tmp);
317 } 346 }
318 } 347 }
319 348
320 349
339 return; 368 return;
340 369
341 if (sender->nickname) 370 if (sender->nickname)
342 /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ 371 /* XXX - Should this be PURPLE_CONV_TYPE_IM? */
343 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, 372 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
344 sender->nickname, sg->account); 373 sender->nickname, sg->account);
345 374
346 if (flags & SILC_MESSAGE_FLAG_SIGNED && 375 if (flags & SILC_MESSAGE_FLAG_SIGNED &&
347 purple_account_get_bool(sg->account, "sign-verify", FALSE)) { 376 purple_account_get_bool(sg->account, "sign-verify", FALSE)) {
348 /* XXX */ 377 /* XXX */
349 } 378 }
350 379
351 if (flags & SILC_MESSAGE_FLAG_DATA) { 380 if (flags & SILC_MESSAGE_FLAG_DATA) {
352 #ifdef HAVE_SILCMIME_H 381 #ifdef HAVE_SILCMIME_H
353 /* Process MIME message */ 382 /* Process MIME message */
354 SilcMime mime; 383 SilcMime mime;
355 mime = silc_mime_decode(message, message_len); 384 mime = silc_mime_decode(NULL, message, message_len);
356 silcpurple_mime_message(client, conn, sender, NULL, payload, 385 silcpurple_mime_message(client, conn, sender, NULL, payload,
357 NULL, flags, mime, FALSE); 386 NULL, flags, mime, FALSE);
358 #else 387 #else
359 char type[128], enc[128]; 388 char type[128], enc[128];
360 unsigned char *data; 389 unsigned char *data;
362 391
363 memset(type, 0, sizeof(type)); 392 memset(type, 0, sizeof(type));
364 memset(enc, 0, sizeof(enc)); 393 memset(enc, 0, sizeof(enc));
365 394
366 if (!silc_mime_parse(message, message_len, NULL, 0, 395 if (!silc_mime_parse(message, message_len, NULL, 0,
367 type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data, 396 type, sizeof(type) - 1, enc, sizeof(enc) - 1, &data,
368 &data_len)) 397 &data_len))
369 return; 398 return;
370 399
371 if (!strcmp(type, "application/x-wb") && 400 if (!strcmp(type, "application/x-wb") &&
372 !strcmp(enc, "binary") && 401 !strcmp(enc, "binary") &&
381 msg = g_strdup_printf("/me %s", 410 msg = g_strdup_printf("/me %s",
382 (const char *)message); 411 (const char *)message);
383 if (!msg) 412 if (!msg)
384 return; 413 return;
385 414
415 /* Send to Purple */
386 tmp = g_markup_escape_text(msg, -1); 416 tmp = g_markup_escape_text(msg, -1);
387 /* Send to Purple */ 417 serv_got_im(gc, sender->nickname, tmp, 0, time(NULL));
388 serv_got_im(gc, sender->nickname ?
389 sender->nickname : "<unknown>",
390 tmp, 0, time(NULL));
391 g_free(msg); 418 g_free(msg);
392 g_free(tmp); 419 g_free(tmp);
393 return; 420 return;
394 } 421 }
395 422
396 if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) { 423 if (flags & SILC_MESSAGE_FLAG_NOTICE && convo) {
397 msg = g_strdup_printf("(notice) <I>%s</I> %s", 424 msg = g_strdup_printf("(notice) <I>%s</I> %s",
398 sender->nickname ? 425 sender->nickname, (const char *)message);
399 sender->nickname : "<unknown>",
400 (const char *)message);
401 if (!msg) 426 if (!msg)
402 return; 427 return;
403 428
404 /* Send to Purple */ 429 /* Send to Purple */
405 purple_conversation_write(convo, NULL, (const char *)msg, 430 purple_conversation_write(convo, NULL, (const char *)msg,
406 PURPLE_MESSAGE_SYSTEM, time(NULL)); 431 PURPLE_MESSAGE_SYSTEM, time(NULL));
407 g_free(msg); 432 g_free(msg);
408 return; 433 return;
409 } 434 }
410 435
411 if (flags & SILC_MESSAGE_FLAG_UTF8) { 436 if (flags & SILC_MESSAGE_FLAG_UTF8) {
412 tmp = g_markup_escape_text((const char *)message, -1); 437 tmp = g_markup_escape_text((const char *)message, -1);
413 /* Send to Purple */ 438 /* Send to Purple */
414 serv_got_im(gc, sender->nickname ? 439 serv_got_im(gc, sender->nickname, tmp, 0, time(NULL));
415 sender->nickname : "<unknown>",
416 tmp, 0, time(NULL));
417 g_free(tmp); 440 g_free(tmp);
418 } 441 }
419 } 442 }
420 443
421 444
445 SilcHashTableList htl; 468 SilcHashTableList htl;
446 SilcChannelUser chu; 469 SilcChannelUser chu;
447 char buf[512], buf2[512], *tmp, *name; 470 char buf[512], buf2[512], *tmp, *name;
448 SilcNotifyType notify; 471 SilcNotifyType notify;
449 PurpleBuddy *b; 472 PurpleBuddy *b;
473 SilcDList list;
450 int i; 474 int i;
451 475
452 va_start(va, type); 476 va_start(va, type);
453 memset(buf, 0, sizeof(buf)); 477 memset(buf, 0, sizeof(buf));
454 478
458 break; 482 break;
459 483
460 case SILC_NOTIFY_TYPE_INVITE: 484 case SILC_NOTIFY_TYPE_INVITE:
461 { 485 {
462 GHashTable *components; 486 GHashTable *components;
463 va_arg(va, SilcChannelEntry); 487 (void)va_arg(va, SilcChannelEntry);
464 name = va_arg(va, char *); 488 name = va_arg(va, char *);
465 client_entry = va_arg(va, SilcClientEntry); 489 client_entry = va_arg(va, SilcClientEntry);
466 490
467 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 491 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)); 492 g_hash_table_insert(components, strdup("channel"), strdup(name));
477 /* If we joined channel, do nothing */ 501 /* If we joined channel, do nothing */
478 if (client_entry == conn->local_entry) 502 if (client_entry == conn->local_entry)
479 break; 503 break;
480 504
481 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 505 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
482 channel->channel_name, sg->account); 506 channel->channel_name, sg->account);
483 if (!convo) 507 if (!convo)
484 break; 508 break;
485 509
486 /* Join user to channel */ 510 /* Join user to channel */
487 g_snprintf(buf, sizeof(buf), "%s@%s", 511 g_snprintf(buf, sizeof(buf), "%s@%s",
488 client_entry->username, client_entry->hostname); 512 client_entry->username, client_entry->hostname);
489 purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo), 513 purple_conv_chat_add_user(PURPLE_CONV_CHAT(convo),
490 g_strdup(client_entry->nickname), buf, PURPLE_CBFLAGS_NONE, TRUE); 514 g_strdup(client_entry->nickname), buf, PURPLE_CBFLAGS_NONE, TRUE);
491 515
492 break; 516 break;
493 517
494 case SILC_NOTIFY_TYPE_LEAVE: 518 case SILC_NOTIFY_TYPE_LEAVE:
495 client_entry = va_arg(va, SilcClientEntry); 519 client_entry = va_arg(va, SilcClientEntry);
496 channel = va_arg(va, SilcChannelEntry); 520 channel = va_arg(va, SilcChannelEntry);
497 521
498 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 522 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
499 channel->channel_name, sg->account); 523 channel->channel_name, sg->account);
500 if (!convo) 524 if (!convo)
501 break; 525 break;
502 526
503 /* Remove user from channel */ 527 /* Remove user from channel */
504 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), 528 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
505 client_entry->nickname, NULL); 529 client_entry->nickname, NULL);
506 530
507 break; 531 break;
508 532
509 case SILC_NOTIFY_TYPE_SIGNOFF: 533 case SILC_NOTIFY_TYPE_SIGNOFF:
510 client_entry = va_arg(va, SilcClientEntry); 534 client_entry = va_arg(va, SilcClientEntry);
511 tmp = va_arg(va, char *); 535 tmp = va_arg(va, char *);
512
513 if (!client_entry->nickname)
514 break;
515 536
516 /* Remove from all channels */ 537 /* Remove from all channels */
517 silc_hash_table_list(client_entry->channels, &htl); 538 silc_hash_table_list(client_entry->channels, &htl);
518 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { 539 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
519 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 540 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
520 chu->channel->channel_name, sg->account); 541 chu->channel->channel_name, sg->account);
521 if (!convo) 542 if (!convo)
522 continue; 543 continue;
523 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), 544 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
524 client_entry->nickname, 545 client_entry->nickname,
525 tmp); 546 tmp);
526 } 547 }
527 silc_hash_table_list_reset(&htl); 548 silc_hash_table_list_reset(&htl);
528 549
529 break; 550 break;
530 551
535 entry = va_arg(va, void *); 556 entry = va_arg(va, void *);
536 tmp = va_arg(va, char *); 557 tmp = va_arg(va, char *);
537 channel = va_arg(va, SilcChannelEntry); 558 channel = va_arg(va, SilcChannelEntry);
538 559
539 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 560 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
540 channel->channel_name, sg->account); 561 channel->channel_name, sg->account);
541 if (!convo) 562 if (!convo)
542 break; 563 break;
543 564
544 if (!tmp) 565 if (!tmp)
545 break; 566 break;
584 break; 605 break;
585 606
586 } 607 }
587 case SILC_NOTIFY_TYPE_NICK_CHANGE: 608 case SILC_NOTIFY_TYPE_NICK_CHANGE:
588 client_entry = va_arg(va, SilcClientEntry); 609 client_entry = va_arg(va, SilcClientEntry);
589 client_entry2 = va_arg(va, SilcClientEntry); 610 tmp = va_arg(va, char *); /* Old nick */
590 611 name = va_arg(va, char *); /* New nick */
591 if (!strcmp(client_entry->nickname, client_entry2->nickname)) 612
613 if (!strcmp(tmp, name))
592 break; 614 break;
593 615
594 /* Change nick on all channels */ 616 /* Change nick on all channels */
595 silc_hash_table_list(client_entry2->channels, &htl); 617 silc_hash_table_list(client_entry->channels, &htl);
596 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { 618 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
597 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 619 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
598 chu->channel->channel_name, sg->account); 620 chu->channel->channel_name, sg->account);
599 if (!convo) 621 if (!convo)
600 continue; 622 continue;
601 if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(convo), client_entry->nickname)) 623 if (purple_conv_chat_find_user(PURPLE_CONV_CHAT(convo), client_entry->nickname))
602 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), 624 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo),
603 client_entry->nickname, 625 tmp, name);
604 client_entry2->nickname);
605 } 626 }
606 silc_hash_table_list_reset(&htl); 627 silc_hash_table_list_reset(&htl);
607 628
608 break; 629 break;
609 630
613 mode = va_arg(va, SilcUInt32); 634 mode = va_arg(va, SilcUInt32);
614 (void)va_arg(va, char *); 635 (void)va_arg(va, char *);
615 (void)va_arg(va, char *); 636 (void)va_arg(va, char *);
616 (void)va_arg(va, char *); 637 (void)va_arg(va, char *);
617 (void)va_arg(va, SilcPublicKey); 638 (void)va_arg(va, SilcPublicKey);
618 (void)va_arg(va, SilcBuffer); 639 (void)va_arg(va, SilcDList);
619 channel = va_arg(va, SilcChannelEntry); 640 channel = va_arg(va, SilcChannelEntry);
620 641
621 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 642 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
622 channel->channel_name, sg->account); 643 channel->channel_name, sg->account);
623 if (!convo) 644 if (!convo)
624 break; 645 break;
625 646
626 if (idtype == SILC_ID_CLIENT) 647 if (idtype == SILC_ID_CLIENT)
627 name = ((SilcClientEntry)entry)->nickname; 648 name = ((SilcClientEntry)entry)->nickname;
641 g_snprintf(buf, sizeof(buf), 662 g_snprintf(buf, sizeof(buf),
642 _("<I>%s</I> removed all channel <I>%s</I> modes"), name, 663 _("<I>%s</I> removed all channel <I>%s</I> modes"), name,
643 channel->channel_name); 664 channel->channel_name);
644 } 665 }
645 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, 666 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name,
646 buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); 667 buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
647 break; 668 break;
648 669
649 case SILC_NOTIFY_TYPE_CUMODE_CHANGE: 670 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
650 { 671 {
651 PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE; 672 PurpleConvChatBuddyFlags flags = PURPLE_CBFLAGS_NONE;
654 mode = va_arg(va, SilcUInt32); 675 mode = va_arg(va, SilcUInt32);
655 client_entry2 = va_arg(va, SilcClientEntry); 676 client_entry2 = va_arg(va, SilcClientEntry);
656 channel = va_arg(va, SilcChannelEntry); 677 channel = va_arg(va, SilcChannelEntry);
657 678
658 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 679 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
659 channel->channel_name, sg->account); 680 channel->channel_name, sg->account);
660 if (!convo) 681 if (!convo)
661 break; 682 break;
662 683
663 if (idtype == SILC_ID_CLIENT) 684 if (idtype == SILC_ID_CLIENT)
664 name = ((SilcClientEntry)entry)->nickname; 685 name = ((SilcClientEntry)entry)->nickname;
670 break; 691 break;
671 692
672 if (mode) { 693 if (mode) {
673 silcpurple_get_chumode_string(mode, buf2, sizeof(buf2)); 694 silcpurple_get_chumode_string(mode, buf2, sizeof(buf2));
674 g_snprintf(buf, sizeof(buf), 695 g_snprintf(buf, sizeof(buf),
675 _("<I>%s</I> set <I>%s's</I> modes to: %s"), name, 696 _("<I>%s</I> set <I>%s's</I> modes to: %s"), name,
676 client_entry2->nickname, buf2); 697 client_entry2->nickname, buf2);
677 if (mode & SILC_CHANNEL_UMODE_CHANFO) 698 if (mode & SILC_CHANNEL_UMODE_CHANFO)
678 flags |= PURPLE_CBFLAGS_FOUNDER; 699 flags |= PURPLE_CBFLAGS_FOUNDER;
679 if (mode & SILC_CHANNEL_UMODE_CHANOP) 700 if (mode & SILC_CHANNEL_UMODE_CHANOP)
680 flags |= PURPLE_CBFLAGS_OP; 701 flags |= PURPLE_CBFLAGS_OP;
681 } else { 702 } else {
682 g_snprintf(buf, sizeof(buf), 703 g_snprintf(buf, sizeof(buf),
683 _("<I>%s</I> removed all <I>%s's</I> modes"), name, 704 _("<I>%s</I> removed all <I>%s's</I> modes"), name,
684 client_entry2->nickname); 705 client_entry2->nickname);
685 } 706 }
686 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name, 707 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), channel->channel_name,
687 buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); 708 buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
688 purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(convo), client_entry2->nickname, flags); 709 purple_conv_chat_user_set_flags(PURPLE_CONV_CHAT(convo), client_entry2->nickname, flags);
689 break; 710 break;
690 } 711 }
691 712
692 case SILC_NOTIFY_TYPE_MOTD: 713 case SILC_NOTIFY_TYPE_MOTD:
700 tmp = va_arg(va, char *); 721 tmp = va_arg(va, char *);
701 client_entry2 = va_arg(va, SilcClientEntry); 722 client_entry2 = va_arg(va, SilcClientEntry);
702 channel = va_arg(va, SilcChannelEntry); 723 channel = va_arg(va, SilcChannelEntry);
703 724
704 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 725 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
705 channel->channel_name, sg->account); 726 channel->channel_name, sg->account);
706 if (!convo) 727 if (!convo)
707 break; 728 break;
708 729
709 if (client_entry == conn->local_entry) { 730 if (client_entry == conn->local_entry) {
710 /* Remove us from channel */ 731 /* Remove us from channel */
711 g_snprintf(buf, sizeof(buf), 732 g_snprintf(buf, sizeof(buf),
712 _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"), 733 _("You have been kicked off <I>%s</I> by <I>%s</I> (%s)"),
713 channel->channel_name, client_entry2->nickname, 734 channel->channel_name, client_entry2->nickname,
714 tmp ? tmp : ""); 735 tmp ? tmp : "");
715 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, 736 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname,
716 buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); 737 buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
717 serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); 738 serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)));
718 } else { 739 } else {
719 /* Remove user from channel */ 740 /* Remove user from channel */
720 g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"), 741 g_snprintf(buf, sizeof(buf), _("Kicked by %s (%s)"),
721 client_entry2->nickname, tmp ? tmp : ""); 742 client_entry2->nickname, tmp ? tmp : "");
722 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), 743 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
723 client_entry->nickname, 744 client_entry->nickname,
724 buf); 745 buf);
725 } 746 }
726 747
727 break; 748 break;
728 749
729 case SILC_NOTIFY_TYPE_KILLED: 750 case SILC_NOTIFY_TYPE_KILLED:
730 client_entry = va_arg(va, SilcClientEntry); 751 client_entry = va_arg(va, SilcClientEntry);
731 tmp = va_arg(va, char *); 752 tmp = va_arg(va, char *);
732 idtype = va_arg(va, int); 753 idtype = va_arg(va, int);
733 entry = va_arg(va, SilcClientEntry); 754 entry = va_arg(va, SilcClientEntry);
734
735 if (!client_entry->nickname)
736 break;
737 755
738 if (client_entry == conn->local_entry) { 756 if (client_entry == conn->local_entry) {
739 if (idtype == SILC_ID_CLIENT) { 757 if (idtype == SILC_ID_CLIENT) {
740 client_entry2 = (SilcClientEntry)entry; 758 client_entry2 = (SilcClientEntry)entry;
741 g_snprintf(buf, sizeof(buf), 759 g_snprintf(buf, sizeof(buf),
759 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 777 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
760 chu->channel->channel_name, sg->account); 778 chu->channel->channel_name, sg->account);
761 if (!convo) 779 if (!convo)
762 continue; 780 continue;
763 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname, 781 purple_conv_chat_write(PURPLE_CONV_CHAT(convo), client_entry->nickname,
764 buf, PURPLE_MESSAGE_SYSTEM, time(NULL)); 782 buf, PURPLE_MESSAGE_SYSTEM, time(NULL));
765 serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo))); 783 serv_got_chat_left(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)));
766 } 784 }
767 silc_hash_table_list_reset(&htl); 785 silc_hash_table_list_reset(&htl);
768 786
769 } else { 787 } else {
790 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 808 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
791 chu->channel->channel_name, sg->account); 809 chu->channel->channel_name, sg->account);
792 if (!convo) 810 if (!convo)
793 continue; 811 continue;
794 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo), 812 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
795 client_entry->nickname, tmp); 813 client_entry->nickname, tmp);
796 } 814 }
797 silc_hash_table_list_reset(&htl); 815 silc_hash_table_list_reset(&htl);
798 } 816 }
799 817
800 break; 818 break;
801 819
802 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE: 820 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
803 break; 821 break;
804 822
805 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF: 823 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
806 { 824 (void)va_arg(va, void *);
807 int i; 825 list = va_arg(va, SilcDList);
808 SilcClientEntry *clients; 826
809 SilcUInt32 clients_count; 827 silc_dlist_start(list);
810 828 while ((client_entry = silc_dlist_get(list))) {
811 (void)va_arg(va, void *); 829 /* Remove from all channels */
812 clients = va_arg(va, SilcClientEntry *); 830 silc_hash_table_list(client_entry->channels, &htl);
813 clients_count = va_arg(va, SilcUInt32); 831 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
814 832 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
815 for (i = 0; i < clients_count; i++) { 833 chu->channel->channel_name, sg->account);
816 if (!clients[i]->nickname) 834 if (!convo)
817 break; 835 continue;
818 836 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
819 /* Remove from all channels */ 837 client_entry->nickname,
820 silc_hash_table_list(clients[i]->channels, &htl); 838 _("Server signoff"));
821 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { 839 }
822 convo = 840 silc_hash_table_list_reset(&htl);
823 purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
824 chu->channel->channel_name, sg->account);
825 if (!convo)
826 continue;
827 purple_conv_chat_remove_user(PURPLE_CONV_CHAT(convo),
828 clients[i]->nickname,
829 _("Server signoff"));
830 }
831 silc_hash_table_list_reset(&htl);
832 }
833 } 841 }
834 break; 842 break;
835 843
836 case SILC_NOTIFY_TYPE_ERROR: 844 case SILC_NOTIFY_TYPE_ERROR:
837 { 845 {
838 SilcStatus error = va_arg(va, int); 846 SilcStatus error = va_arg(va, int);
839 purple_notify_error(gc, "Error Notify", 847 purple_notify_error(gc, "Error Notify",
840 silc_get_status_message(error), 848 silc_get_status_message(error),
841 NULL); 849 NULL);
842 } 850 }
843 break; 851 break;
844 852
845 case SILC_NOTIFY_TYPE_WATCH: 853 case SILC_NOTIFY_TYPE_WATCH:
846 { 854 {
907 break; 915 break;
908 } 916 }
909 } 917 }
910 918
911 silc_free(b->proto_data); 919 silc_free(b->proto_data);
912 b->proto_data = silc_memdup(client_entry->id, 920 b->proto_data = silc_memdup(&client_entry->id,
913 sizeof(*client_entry->id)); 921 sizeof(client_entry->id));
914 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) { 922 if (notify == SILC_NOTIFY_TYPE_NICK_CHANGE) {
915 break; 923 break;
916 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) { 924 } else if (notify == SILC_NOTIFY_TYPE_UMODE_CHANGE) {
917 /* See if client was away and is now present */ 925 /* See if client was away and is now present */
918 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED | 926 if (!(mode & (SILC_UMODE_GONE | SILC_UMODE_INDISPOSED |
953 961
954 va_end(va); 962 va_end(va);
955 } 963 }
956 964
957 965
958 /* Command handler. This function is called always in the command function. 966 /* Command handler. This function is called always after application has
959 If error occurs it will be called as well. `conn' is the associated 967 called a command. It will be called to indicate that the command
960 client connection. `cmd_context' is the command context that was 968 was processed. It will also be called if error occurs while processing
961 originally sent to the command. `success' is FALSE if error occurred 969 the command. The `success' indicates whether the command was sent
962 during command. `command' is the command being processed. It must be 970 or if error occurred. The `status' indicates the actual error.
963 noted that this is not reply from server. This is merely called just 971 The `argc' and `argv' are the command line arguments sent to the
964 after application has called the command. Just to tell application 972 command by application. Note that, this is not reply to the command
965 that the command really was processed. */ 973 from server, this is merely and indication to application that the
974 command was processed. */
966 975
967 static void 976 static void
968 silc_command(SilcClient client, SilcClientConnection conn, 977 silc_command(SilcClient client, SilcClientConnection conn,
969 SilcClientCommandContext cmd_context, bool success, 978 SilcBool success, SilcCommand command, SilcStatus status,
970 SilcCommand command, SilcStatus status) 979 SilcUInt32 argc, unsigned char **argv)
971 { 980 {
972 PurpleConnection *gc = client->application; 981 PurpleConnection *gc = client->application;
973 SilcPurple sg = gc->proto_data; 982 SilcPurple sg = gc->proto_data;
974 983
975 switch (command) { 984 switch (command) {
976 985
977 case SILC_COMMAND_CMODE: 986 case SILC_COMMAND_CMODE:
978 if (cmd_context->argc == 3 && 987 if (argc == 3 && !strcmp((char *)argv[2], "+C"))
979 !strcmp((char *)cmd_context->argv[2], "+C"))
980 sg->chpk = TRUE; 988 sg->chpk = TRUE;
981 else 989 else
982 sg->chpk = FALSE; 990 sg->chpk = FALSE;
983 break; 991 break;
984 992
1088 buf); 1096 buf);
1089 g_free(buf); 1097 g_free(buf);
1090 } 1098 }
1091 #endif 1099 #endif
1092 1100
1093 /* Command reply handler. This function is called always in the command reply 1101
1094 function. If error occurs it will be called as well. Normal scenario 1102 /* Command reply handler. Delivers a reply to command that was sent
1095 is that it will be called after the received command data has been parsed 1103 earlier. The `conn' is the associated client connection. The `command'
1096 and processed. The function is used to pass the received command data to 1104 indicates the command reply type. If the `status' other than
1097 the application. 1105 SILC_STATUS_OK an error occurred. In this case the `error' will indicate
1098 1106 the error. It is possible to receive list of command replies and list
1099 `conn' is the associated client connection. `cmd_payload' is the command 1107 of errors. In this case the `status' will indicate it is an list entry
1100 payload data received from server and it can be ignored. It is provided 1108 (the `status' is SILC_STATUS_LIST_START, SILC_STATUS_LIST_ITEM and/or
1101 if the application would like to re-parse the received command data, 1109 SILC_STATUS_LIST_END).
1102 however, it must be noted that the data is parsed already by the library 1110
1103 thus the payload can be ignored. `success' is FALSE if error occurred. 1111 The arguments received in `ap' are command specific. See a separate
1104 In this case arguments are not sent to the application. The `status' is 1112 documentation in the Toolkit Reference Manual for the command reply
1105 the command reply status server returned. The `command' is the command 1113 arguments. */
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 1114
1110 static void 1115 static void
1111 silc_command_reply(SilcClient client, SilcClientConnection conn, 1116 silc_command_reply(SilcClient client, SilcClientConnection conn,
1112 SilcCommandPayload cmd_payload, bool success, 1117 SilcCommand command, SilcStatus status,
1113 SilcCommand command, SilcStatus status, ...) 1118 SilcStatus error, va_list ap)
1114 { 1119 {
1115 PurpleConnection *gc = client->application; 1120 PurpleConnection *gc = client->application;
1116 SilcPurple sg = gc->proto_data; 1121 SilcPurple sg = gc->proto_data;
1117 PurpleConversation *convo; 1122 PurpleConversation *convo;
1118 va_list vp;
1119
1120 va_start(vp, status);
1121 1123
1122 switch (command) { 1124 switch (command) {
1123 case SILC_COMMAND_JOIN: 1125 case SILC_COMMAND_JOIN:
1124 { 1126 {
1125 SilcChannelEntry channel_entry; 1127 SilcChannelEntry channel;
1126 1128 PurpleConversation *convo;
1127 if (!success) { 1129 SilcHashTableList *user_list;
1130 SilcChannelUser chu;
1131 GList *users = NULL, *flags = NULL;
1132 char tmp[256], *topic;
1133
1134 if (status != SILC_STATUS_OK) {
1128 purple_notify_error(gc, _("Join Chat"), _("Cannot join channel"), 1135 purple_notify_error(gc, _("Join Chat"), _("Cannot join channel"),
1129 silc_get_status_message(status)); 1136 silc_get_status_message(error));
1130 return; 1137 return;
1131 } 1138 }
1132 1139
1133 (void)va_arg(vp, char *); 1140 (void)va_arg(ap, char *);
1134 channel_entry = va_arg(vp, SilcChannelEntry); 1141 channel = va_arg(ap, SilcChannelEntry);
1135 1142 (void)va_arg(ap, SilcUInt32);
1136 /* Resolve users on channel */ 1143 user_list = va_arg(ap, SilcHashTableList *);
1137 silc_client_get_clients_by_channel(client, conn, channel_entry, 1144 topic = va_arg(ap, char *);
1138 silcpurple_chat_join_done, 1145
1139 channel_entry); 1146 /* Add channel to Purple */
1147 channel->context = SILC_32_TO_PTR(++sg->channel_ids);
1148 serv_got_joined_chat(gc, sg->channel_ids, channel->channel_name);
1149 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
1150 channel->channel_name, sg->account);
1151 if (!convo)
1152 return;
1153
1154 /* Add all users to channel */
1155 while (silc_hash_table_get(user_list, NULL, (void *)&chu)) {
1156 PurpleConvChatBuddyFlags f = PURPLE_CBFLAGS_NONE;
1157 chu->context = SILC_32_TO_PTR(sg->channel_ids);
1158
1159 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO)
1160 f |= PURPLE_CBFLAGS_FOUNDER;
1161 if (chu->mode & SILC_CHANNEL_UMODE_CHANOP)
1162 f |= PURPLE_CBFLAGS_OP;
1163 users = g_list_append(users, g_strdup(chu->client->nickname));
1164 flags = g_list_append(flags, GINT_TO_POINTER(f));
1165
1166 if (chu->mode & SILC_CHANNEL_UMODE_CHANFO) {
1167 if (chu->client == conn->local_entry)
1168 g_snprintf(tmp, sizeof(tmp),
1169 _("You are channel founder on <I>%s</I>"),
1170 channel->channel_name);
1171 else
1172 g_snprintf(tmp, sizeof(tmp),
1173 _("Channel founder on <I>%s</I> is <I>%s</I>"),
1174 channel->channel_name, chu->client->nickname);
1175
1176 purple_conversation_write(convo, NULL, tmp,
1177 PURPLE_MESSAGE_SYSTEM, time(NULL));
1178 }
1179 }
1180
1181 purple_conv_chat_add_users(PURPLE_CONV_CHAT(convo), users, NULL, flags, FALSE);
1182 g_list_free(users);
1183 g_list_free(flags);
1184
1185 /* Set topic */
1186 if (topic)
1187 purple_conv_chat_set_topic(PURPLE_CONV_CHAT(convo), NULL, topic);
1188
1189 /* Set nick */
1190 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), conn->local_entry->nickname);
1140 } 1191 }
1141 break; 1192 break;
1142 1193
1143 case SILC_COMMAND_LEAVE: 1194 case SILC_COMMAND_LEAVE:
1144 break; 1195 break;
1146 case SILC_COMMAND_USERS: 1197 case SILC_COMMAND_USERS:
1147 break; 1198 break;
1148 1199
1149 case SILC_COMMAND_WHOIS: 1200 case SILC_COMMAND_WHOIS:
1150 { 1201 {
1151 SilcUInt32 idle, mode; 1202 SilcUInt32 idle, *user_modes;
1152 SilcBuffer channels, user_modes; 1203 SilcDList channels;
1153 SilcClientEntry client_entry; 1204 SilcClientEntry client_entry;
1154 char tmp[1024], *tmp2; 1205 char tmp[1024], *tmp2;
1155 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; 1206 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr;
1156 PurpleNotifyUserInfo *user_info; 1207 PurpleNotifyUserInfo *user_info;
1157 1208
1158 if (!success) { 1209 if (status != SILC_STATUS_OK) {
1159 purple_notify_error(gc, _("User Information"), 1210 purple_notify_error(gc, _("User Information"),
1160 _("Cannot get user information"), 1211 _("Cannot get user information"),
1161 silc_get_status_message(status)); 1212 silc_get_status_message(error));
1162 break; 1213 break;
1163 } 1214 }
1164 1215
1165 client_entry = va_arg(vp, SilcClientEntry); 1216 client_entry = va_arg(ap, SilcClientEntry);
1166 if (!client_entry->nickname) 1217 (void)va_arg(ap, char *);
1167 break; 1218 (void)va_arg(ap, char *);
1168 (void)va_arg(vp, char *); 1219 (void)va_arg(ap, char *);
1169 (void)va_arg(vp, char *); 1220 channels = va_arg(ap, SilcDList);
1170 (void)va_arg(vp, char *); 1221 (void)va_arg(ap, SilcUInt32);
1171 channels = va_arg(vp, SilcBuffer); 1222 idle = va_arg(ap, SilcUInt32);
1172 mode = va_arg(vp, SilcUInt32); 1223 (void)va_arg(ap, unsigned char *);
1173 idle = va_arg(vp, SilcUInt32); 1224 user_modes = va_arg(ap, SilcUInt32 *);
1174 (void)va_arg(vp, unsigned char *);
1175 user_modes = va_arg(vp, SilcBuffer);
1176 1225
1177 user_info = purple_notify_user_info_new(); 1226 user_info = purple_notify_user_info_new();
1178 tmp2 = g_markup_escape_text(client_entry->nickname, -1); 1227 tmp2 = g_markup_escape_text(client_entry->nickname, -1);
1179 purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp2); 1228 purple_notify_user_info_add_pair(user_info, _("Nickname"), tmp2);
1180 g_free(tmp2); 1229 g_free(tmp2);
1181 if (client_entry->realname) { 1230 if (client_entry->realname) {
1182 tmp2 = g_markup_escape_text(client_entry->realname, -1); 1231 tmp2 = g_markup_escape_text(client_entry->realname, -1);
1183 purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp2); 1232 purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp2);
1184 g_free(tmp2); 1233 g_free(tmp2);
1185 } 1234 }
1186 if (client_entry->username) { 1235 tmp2 = g_markup_escape_text(client_entry->username, -1);
1187 tmp2 = g_markup_escape_text(client_entry->username, -1); 1236 if (*client_entry->hostname) {
1188 if (client_entry->hostname) { 1237 gchar *tmp3;
1189 gchar *tmp3; 1238 tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname);
1190 tmp3 = g_strdup_printf("%s@%s", tmp2, client_entry->hostname); 1239 purple_notify_user_info_add_pair(user_info, _("Username"), tmp3);
1191 purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); 1240 g_free(tmp3);
1192 g_free(tmp3); 1241 } else
1193 } else 1242 purple_notify_user_info_add_pair(user_info, _("Username"), tmp2);
1194 purple_notify_user_info_add_pair(user_info, _("Username"), tmp2); 1243 g_free(tmp2);
1195 g_free(tmp2);
1196 }
1197 1244
1198 if (client_entry->mode) { 1245 if (client_entry->mode) {
1199 memset(tmp, 0, sizeof(tmp)); 1246 memset(tmp, 0, sizeof(tmp));
1200 silcpurple_get_umode_string(client_entry->mode, 1247 silcpurple_get_umode_string(client_entry->mode,
1201 tmp, sizeof(tmp) - strlen(tmp)); 1248 tmp, sizeof(tmp) - strlen(tmp));
1202 purple_notify_user_info_add_pair(user_info, _("User Modes"), tmp); 1249 purple_notify_user_info_add_pair(user_info, _("User Modes"), tmp);
1203 } 1250 }
1204 1251
1205 silcpurple_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); 1252 silcpurple_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr);
1206 if (moodstr) { 1253 if (moodstr) {
1238 if (geostr) { 1285 if (geostr) {
1239 purple_notify_user_info_add_pair(user_info, _("Geolocation"), geostr); 1286 purple_notify_user_info_add_pair(user_info, _("Geolocation"), geostr);
1240 g_free(geostr); 1287 g_free(geostr);
1241 } 1288 }
1242 1289
1243 if (client_entry->server) 1290 if (*client_entry->server)
1244 purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); 1291 purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server);
1245 1292
1246 if (channels && user_modes) { 1293 if (channels && user_modes) {
1247 SilcUInt32 *umodes; 1294 SilcChannelPayload entry;
1248 SilcDList list = 1295 int i = 0;
1249 silc_channel_payload_parse_list(channels->data, 1296
1250 channels->len); 1297 memset(tmp, 0, sizeof(tmp));
1251 if (list && silc_get_mode_list(user_modes, 1298 silc_dlist_start(channels);
1252 silc_dlist_count(list), 1299 while ((entry = silc_dlist_get(channels))) {
1253 &umodes)) { 1300 SilcUInt32 name_len;
1254 SilcChannelPayload entry; 1301 char *m = silc_client_chumode_char(user_modes[i++]);
1255 int i = 0; 1302 char *name = (char *)silc_channel_get_name(entry, &name_len);
1256 1303 if (m)
1257 memset(tmp, 0, sizeof(tmp)); 1304 silc_strncat(tmp, sizeof(tmp) - 1, m, strlen(m));
1258 silc_dlist_start(list); 1305 silc_strncat(tmp, sizeof(tmp) - 1, name, name_len);
1259 while ((entry = silc_dlist_get(list)) 1306 silc_strncat(tmp, sizeof(tmp) - 1, " ", 1);
1260 != SILC_LIST_END) { 1307 silc_free(m);
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 purple_notify_user_info_add_pair(user_info, _("Currently on"), tmp2);
1273 g_free(tmp2);
1274 silc_free(umodes);
1275 } 1308 }
1309 tmp2 = g_markup_escape_text(tmp, -1);
1310 purple_notify_user_info_add_pair(user_info, _("Currently on"), tmp2);
1311 g_free(tmp2);
1276 } 1312 }
1277 1313
1278 if (client_entry->public_key) { 1314 if (client_entry->public_key) {
1279 char *fingerprint, *babbleprint; 1315 char *fingerprint, *babbleprint;
1280 unsigned char *pk; 1316 unsigned char *pk;
1295 _("User Information"), 1331 _("User Information"),
1296 buf, 1, client_entry, 2, 1332 buf, 1, client_entry, 2,
1297 _("OK"), G_CALLBACK(silcpurple_whois_more), 1333 _("OK"), G_CALLBACK(silcpurple_whois_more),
1298 _("_More..."), G_CALLBACK(silcpurple_whois_more), gc->account, NULL, NULL); 1334 _("_More..."), G_CALLBACK(silcpurple_whois_more), gc->account, NULL, NULL);
1299 else 1335 else
1300 #endif 1336 #endif /* 0 */
1301 purple_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL); 1337 purple_notify_userinfo(gc, client_entry->nickname, user_info, NULL, NULL);
1302 purple_notify_user_info_destroy(user_info); 1338 purple_notify_user_info_destroy(user_info);
1303 } 1339 }
1304 break; 1340 break;
1305 1341
1307 { 1343 {
1308 SilcClientEntry client_entry; 1344 SilcClientEntry client_entry;
1309 char *nickname, *realname, *username, *tmp; 1345 char *nickname, *realname, *username, *tmp;
1310 PurpleNotifyUserInfo *user_info; 1346 PurpleNotifyUserInfo *user_info;
1311 1347
1312 if (!success) { 1348 if (status != SILC_STATUS_OK) {
1313 purple_notify_error(gc, _("User Information"), 1349 purple_notify_error(gc, _("User Information"),
1314 _("Cannot get user information"), 1350 _("Cannot get user information"),
1315 silc_get_status_message(status)); 1351 silc_get_status_message(error));
1316 break; 1352 break;
1317 } 1353 }
1318 1354
1319 client_entry = va_arg(vp, SilcClientEntry); 1355 client_entry = va_arg(ap, SilcClientEntry);
1320 nickname = va_arg(vp, char *); 1356 nickname = va_arg(ap, char *);
1321 username = va_arg(vp, char *); 1357 username = va_arg(ap, char *);
1322 realname = va_arg(vp, char *); 1358 realname = va_arg(ap, char *);
1323 if (!nickname) 1359 if (!nickname)
1324 break; 1360 break;
1325 1361
1326 user_info = purple_notify_user_info_new(); 1362 user_info = purple_notify_user_info_new();
1327 tmp = g_markup_escape_text(nickname, -1); 1363 tmp = g_markup_escape_text(nickname, -1);
1332 purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp); 1368 purple_notify_user_info_add_pair(user_info, _("Real Name"), tmp);
1333 g_free(tmp); 1369 g_free(tmp);
1334 } 1370 }
1335 if (username) { 1371 if (username) {
1336 tmp = g_markup_escape_text(username, -1); 1372 tmp = g_markup_escape_text(username, -1);
1337 if (client_entry && client_entry->hostname) { 1373 if (client_entry && *client_entry->hostname) {
1338 gchar *tmp3; 1374 gchar *tmp3;
1339 tmp3 = g_strdup_printf("%s@%s", tmp, client_entry->hostname); 1375 tmp3 = g_strdup_printf("%s@%s", tmp, client_entry->hostname);
1340 purple_notify_user_info_add_pair(user_info, _("Username"), tmp3); 1376 purple_notify_user_info_add_pair(user_info, _("Username"), tmp3);
1341 g_free(tmp3); 1377 g_free(tmp3);
1342 } else 1378 } else
1343 purple_notify_user_info_add_pair(user_info, _("Username"), tmp); 1379 purple_notify_user_info_add_pair(user_info, _("Username"), tmp);
1344 g_free(tmp); 1380 g_free(tmp);
1345 } 1381 }
1346 if (client_entry && client_entry->server) 1382 if (client_entry && *client_entry->server)
1347 purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server); 1383 purple_notify_user_info_add_pair(user_info, _("Server"), client_entry->server);
1348 1384
1349 1385
1350 if (client_entry && client_entry->public_key) { 1386 if (client_entry && client_entry->public_key) {
1351 char *fingerprint, *babbleprint; 1387 char *fingerprint, *babbleprint;
1365 purple_notify_user_info_destroy(user_info); 1401 purple_notify_user_info_destroy(user_info);
1366 } 1402 }
1367 break; 1403 break;
1368 1404
1369 case SILC_COMMAND_DETACH: 1405 case SILC_COMMAND_DETACH:
1370 if (!success) { 1406 {
1371 purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"), 1407 const char *file;
1372 silc_get_status_message(status)); 1408 SilcBuffer detach_data;
1373 return; 1409
1410 if (status != SILC_STATUS_OK) {
1411 purple_notify_error(gc, _("Detach From Server"), _("Cannot detach"),
1412 silc_get_status_message(error));
1413 return;
1414 }
1415
1416 detach_data = va_arg(ap, SilcBuffer);
1417
1418 /* Save the detachment data to file. */
1419 file = silcpurple_session_file(purple_account_get_username(sg->account));
1420 g_unlink(file);
1421 silc_file_writefile(file, (const char *)silc_buffer_data(detach_data),
1422 silc_buffer_len(detach_data));
1374 } 1423 }
1375 break; 1424 break;
1376 1425
1377 case SILC_COMMAND_TOPIC: 1426 case SILC_COMMAND_TOPIC:
1378 { 1427 {
1379 SilcChannelEntry channel; 1428 SilcChannelEntry channel;
1380 1429
1381 if (!success) { 1430 if (status != SILC_STATUS_OK) {
1382 purple_notify_error(gc, _("Topic"), _("Cannot set topic"), 1431 purple_notify_error(gc, _("Topic"), _("Cannot set topic"),
1383 silc_get_status_message(status)); 1432 silc_get_status_message(error));
1384 return; 1433 return;
1385 } 1434 }
1386 1435
1387 channel = va_arg(vp, SilcChannelEntry); 1436 channel = va_arg(ap, SilcChannelEntry);
1388 1437
1389 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 1438 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
1390 channel->channel_name, sg->account); 1439 channel->channel_name, sg->account);
1391 if (!convo) { 1440 if (!convo) {
1392 purple_debug_error("silc", "Got a topic for %s, which doesn't exist\n", 1441 purple_debug_error("silc", "Got a topic for %s, which doesn't exist\n",
1393 channel->channel_name); 1442 channel->channel_name);
1394 break; 1443 break;
1395 } 1444 }
1396 1445
1397 /* Set topic */ 1446 /* Set topic */
1398 if (channel->topic) 1447 if (channel->topic)
1400 } 1449 }
1401 break; 1450 break;
1402 1451
1403 case SILC_COMMAND_NICK: 1452 case SILC_COMMAND_NICK:
1404 { 1453 {
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; 1454 SilcClientEntry local_entry;
1409 SilcHashTableList htl; 1455 SilcHashTableList htl;
1410 SilcChannelUser chu; 1456 SilcChannelUser chu;
1411 const char *oldnick; 1457 const char *oldnick, *newnick;
1412 1458
1413 if (!success) { 1459 if (status != SILC_STATUS_OK) {
1414 purple_notify_error(gc, _("Nick"), _("Failed to change nickname"), 1460 purple_notify_error(gc, _("Nick"), _("Failed to change nickname"),
1415 silc_get_status_message(status)); 1461 silc_get_status_message(error));
1416 return; 1462 return;
1417 } 1463 }
1418 1464
1419 local_entry = va_arg(vp, SilcClientEntry); 1465 local_entry = va_arg(ap, SilcClientEntry);
1466 newnick = va_arg(ap, char *);
1420 1467
1421 /* Change nick on all channels */ 1468 /* Change nick on all channels */
1422 silc_hash_table_list(local_entry->channels, &htl); 1469 silc_hash_table_list(local_entry->channels, &htl);
1423 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) { 1470 while (silc_hash_table_get(&htl, NULL, (void *)&chu)) {
1424 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, 1471 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT,
1425 chu->channel->channel_name, sg->account); 1472 chu->channel->channel_name, sg->account);
1426 if (!convo) 1473 if (!convo)
1427 continue; 1474 continue;
1428 oldnick = purple_conv_chat_get_nick(PURPLE_CONV_CHAT(convo)); 1475 oldnick = purple_conv_chat_get_nick(PURPLE_CONV_CHAT(convo));
1429 if (strcmp(oldnick, purple_normalize(purple_conversation_get_account(convo), local_entry->nickname))) { 1476 if (strcmp(oldnick, purple_normalize(purple_conversation_get_account(convo), newnick))) {
1430 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo), 1477 purple_conv_chat_rename_user(PURPLE_CONV_CHAT(convo),
1431 oldnick, local_entry->nickname); 1478 oldnick, newnick);
1432 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), local_entry->nickname); 1479 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(convo), newnick);
1433 } 1480 }
1434 } 1481 }
1435 silc_hash_table_list_reset(&htl); 1482 silc_hash_table_list_reset(&htl);
1436 1483
1437 purple_connection_set_display_name(gc, local_entry->nickname); 1484 purple_connection_set_display_name(gc, newnick);
1438 } 1485 }
1439 break; 1486 break;
1440 1487
1441 case SILC_COMMAND_LIST: 1488 case SILC_COMMAND_LIST:
1442 { 1489 {
1445 PurpleRoomlistRoom *room; 1492 PurpleRoomlistRoom *room;
1446 1493
1447 if (sg->roomlist_canceled) 1494 if (sg->roomlist_canceled)
1448 break; 1495 break;
1449 1496
1450 if (!success) { 1497 if (error != SILC_STATUS_OK) {
1451 purple_notify_error(gc, _("Error"), _("Error retrieving room list"), 1498 purple_notify_error(gc, _("Error"), _("Error retrieving room list"),
1452 silc_get_status_message(status)); 1499 silc_get_status_message(error));
1453 purple_roomlist_set_in_progress(sg->roomlist, FALSE); 1500 purple_roomlist_set_in_progress(sg->roomlist, FALSE);
1454 purple_roomlist_unref(sg->roomlist); 1501 purple_roomlist_unref(sg->roomlist);
1455 sg->roomlist = NULL; 1502 sg->roomlist = NULL;
1456 return; 1503 return;
1457 } 1504 }
1458 1505
1459 (void)va_arg(vp, SilcChannelEntry); 1506 (void)va_arg(ap, SilcChannelEntry);
1460 name = va_arg(vp, char *); 1507 name = va_arg(ap, char *);
1461 if (!name) { 1508 if (!name) {
1462 purple_notify_error(gc, _("Roomlist"), _("Cannot get room list"), 1509 purple_notify_error(gc, _("Roomlist"), _("Cannot get room list"),
1463 silc_get_status_message(status)); 1510 _("Network is empty"));
1464 purple_roomlist_set_in_progress(sg->roomlist, FALSE); 1511 purple_roomlist_set_in_progress(sg->roomlist, FALSE);
1465 purple_roomlist_unref(sg->roomlist); 1512 purple_roomlist_unref(sg->roomlist);
1466 sg->roomlist = NULL; 1513 sg->roomlist = NULL;
1467 return; 1514 return;
1468 } 1515 }
1469 topic = va_arg(vp, char *); 1516 topic = va_arg(ap, char *);
1470 usercount = va_arg(vp, int); 1517 usercount = va_arg(ap, int);
1471 1518
1472 room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL); 1519 room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL);
1473 purple_roomlist_room_add_field(sg->roomlist, room, name); 1520 purple_roomlist_room_add_field(sg->roomlist, room, name);
1474 purple_roomlist_room_add_field(sg->roomlist, room, 1521 purple_roomlist_room_add_field(sg->roomlist, room,
1475 SILC_32_TO_PTR(usercount)); 1522 SILC_32_TO_PTR(usercount));
1476 purple_roomlist_room_add_field(sg->roomlist, room, 1523 purple_roomlist_room_add_field(sg->roomlist, room,
1477 topic ? topic : ""); 1524 topic ? topic : "");
1478 purple_roomlist_room_add(sg->roomlist, room); 1525 purple_roomlist_room_add(sg->roomlist, room);
1479 1526
1480 if (status == SILC_STATUS_LIST_END || 1527 if (status == SILC_STATUS_LIST_END ||
1481 status == SILC_STATUS_OK) { 1528 status == SILC_STATUS_OK) {
1482 purple_roomlist_set_in_progress(sg->roomlist, FALSE); 1529 purple_roomlist_set_in_progress(sg->roomlist, FALSE);
1488 1535
1489 case SILC_COMMAND_GETKEY: 1536 case SILC_COMMAND_GETKEY:
1490 { 1537 {
1491 SilcPublicKey public_key; 1538 SilcPublicKey public_key;
1492 1539
1493 if (!success) { 1540 if (status != SILC_STATUS_OK) {
1494 purple_notify_error(gc, _("Get Public Key"), 1541 purple_notify_error(gc, _("Get Public Key"),
1495 _("Cannot fetch the public key"), 1542 _("Cannot fetch the public key"),
1496 silc_get_status_message(status)); 1543 silc_get_status_message(error));
1497 return; 1544 return;
1498 } 1545 }
1499 1546
1500 (void)va_arg(vp, SilcUInt32); 1547 (void)va_arg(ap, SilcUInt32);
1501 (void)va_arg(vp, void *); 1548 (void)va_arg(ap, void *);
1502 public_key = va_arg(vp, SilcPublicKey); 1549 public_key = va_arg(ap, SilcPublicKey);
1503 1550
1504 if (!public_key) 1551 if (!public_key)
1505 purple_notify_error(gc, _("Get Public Key"), 1552 purple_notify_error(gc, _("Get Public Key"),
1506 _("Cannot fetch the public key"), 1553 _("Cannot fetch the public key"),
1507 _("No public key was received")); 1554 _("No public key was received"));
1508 } 1555 }
1509 break; 1556 break;
1510 1557
1511 case SILC_COMMAND_INFO: 1558 case SILC_COMMAND_INFO:
1512 { 1559 {
1513 1560
1514 char *server_name; 1561 char *server_name;
1515 char *server_info; 1562 char *server_info;
1516 char tmp[256]; 1563 char tmp[256];
1517 1564
1518 if (!success) { 1565 if (status != SILC_STATUS_OK) {
1519 purple_notify_error(gc, _("Server Information"), 1566 purple_notify_error(gc, _("Server Information"),
1520 _("Cannot get server information"), 1567 _("Cannot get server information"),
1521 silc_get_status_message(status)); 1568 silc_get_status_message(error));
1522 return; 1569 return;
1523 } 1570 }
1524 1571
1525 (void)va_arg(vp, SilcServerEntry); 1572 (void)va_arg(ap, SilcServerEntry);
1526 server_name = va_arg(vp, char *); 1573 server_name = va_arg(ap, char *);
1527 server_info = va_arg(vp, char *); 1574 server_info = va_arg(ap, char *);
1528 1575
1529 if (server_name && server_info) { 1576 if (server_name && server_info) {
1530 g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s", 1577 g_snprintf(tmp, sizeof(tmp), "Server: %s\n%s",
1531 server_name, server_info); 1578 server_name, server_info);
1532 purple_notify_info(gc, NULL, _("Server Information"), tmp); 1579 purple_notify_info(gc, NULL, _("Server Information"), tmp);
1534 } 1581 }
1535 break; 1582 break;
1536 1583
1537 case SILC_COMMAND_STATS: 1584 case SILC_COMMAND_STATS:
1538 { 1585 {
1539 SilcUInt32 starttime, uptime, my_clients, my_channels, my_server_ops, 1586 SilcClientStats *stats;
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; 1587 char *msg;
1547 1588
1548 if (!success) { 1589 if (status != SILC_STATUS_OK) {
1549 purple_notify_error(gc, _("Server Statistics"), 1590 purple_notify_error(gc, _("Server Statistics"),
1550 _("Cannot get server statistics"), 1591 _("Cannot get server statistics"),
1551 silc_get_status_message(status)); 1592 silc_get_status_message(error));
1552 return; 1593 return;
1553 } 1594 }
1554 1595
1555 server_stats = va_arg(vp, unsigned char *); 1596 stats = va_arg(ap, SilcClientStats *);
1556 buffer_length = va_arg(vp, SilcUInt32);
1557 if (!server_stats || !buffer_length) {
1558 purple_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 1597
1581 msg = g_strdup_printf(_("Local server start time: %s\n" 1598 msg = g_strdup_printf(_("Local server start time: %s\n"
1582 "Local server uptime: %s\n" 1599 "Local server uptime: %s\n"
1583 "Local server clients: %d\n" 1600 "Local server clients: %d\n"
1584 "Local server channels: %d\n" 1601 "Local server channels: %d\n"
1585 "Local server operators: %d\n" 1602 "Local server operators: %d\n"
1586 "Local router operators: %d\n" 1603 "Local router operators: %d\n"
1587 "Local cell clients: %d\n" 1604 "Local cell clients: %d\n"
1588 "Local cell channels: %d\n" 1605 "Local cell channels: %d\n"
1589 "Local cell servers: %d\n" 1606 "Local cell servers: %d\n"
1590 "Total clients: %d\n" 1607 "Total clients: %d\n"
1591 "Total channels: %d\n" 1608 "Total channels: %d\n"
1592 "Total servers: %d\n" 1609 "Total servers: %d\n"
1593 "Total routers: %d\n" 1610 "Total routers: %d\n"
1594 "Total server operators: %d\n" 1611 "Total server operators: %d\n"
1595 "Total router operators: %d\n"), 1612 "Total router operators: %d\n"),
1596 silc_get_time(starttime), 1613 silc_time_string(stats->starttime),
1597 purple_str_seconds_to_string((int)uptime), 1614 purple_str_seconds_to_string((int)stats->uptime),
1598 (int)my_clients, (int)my_channels, (int)my_server_ops, (int)my_router_ops, 1615 (int)stats->my_clients,
1599 (int)cell_clients, (int)cell_channels, (int)cell_servers, 1616 (int)stats->my_channels,
1600 (int)clients, (int)channels, (int)servers, (int)routers, 1617 (int)stats->my_server_ops,
1601 (int)server_ops, (int)router_ops); 1618 (int)stats->my_router_ops,
1619 (int)stats->cell_clients,
1620 (int)stats->cell_channels,
1621 (int)stats->cell_servers,
1622 (int)stats->clients,
1623 (int)stats->channels,
1624 (int)stats->servers,
1625 (int)stats->routers,
1626 (int)stats->server_ops,
1627 (int)stats->router_ops);
1602 1628
1603 purple_notify_info(gc, NULL, 1629 purple_notify_info(gc, NULL,
1604 _("Network Statistics"), msg); 1630 _("Network Statistics"), msg);
1605 g_free(msg); 1631 g_free(msg);
1606 } 1632 }
1607 break; 1633 break;
1608 1634
1609 case SILC_COMMAND_PING: 1635 case SILC_COMMAND_PING:
1610 { 1636 {
1611 if (!success) { 1637 if (status != SILC_STATUS_OK) {
1612 purple_notify_error(gc, _("Ping"), _("Ping failed"), 1638 purple_notify_error(gc, _("Ping"), _("Ping failed"),
1613 silc_get_status_message(status)); 1639 silc_get_status_message(error));
1614 return; 1640 return;
1615 } 1641 }
1616 1642
1617 purple_notify_info(gc, _("Ping"), _("Ping reply received from server"), 1643 purple_notify_info(gc, _("Ping"), _("Ping reply received from server"),
1618 NULL); 1644 NULL);
1619 } 1645 }
1620 break; 1646 break;
1621 1647
1622 case SILC_COMMAND_KILL: 1648 case SILC_COMMAND_KILL:
1623 if (!success) { 1649 if (status != SILC_STATUS_OK) {
1624 purple_notify_error(gc, _("Kill User"), 1650 purple_notify_error(gc, _("Kill User"),
1625 _("Could not kill user"), 1651 _("Could not kill user"),
1626 silc_get_status_message(status)); 1652 silc_get_status_message(error));
1627 return; 1653 return;
1628 } 1654 }
1629 break; 1655 break;
1630 1656
1631 case SILC_COMMAND_CMODE: 1657 case SILC_COMMAND_CMODE:
1632 { 1658 {
1633 SilcChannelEntry channel_entry; 1659 SilcChannelEntry channel_entry;
1634 SilcBuffer channel_pubkeys; 1660 SilcDList channel_pubkeys, list;
1635 1661 SilcArgumentDecodedList e;
1636 if (!success) 1662
1663 if (status != SILC_STATUS_OK)
1637 return; 1664 return;
1638 1665
1639 channel_entry = va_arg(vp, SilcChannelEntry); 1666 channel_entry = va_arg(ap, SilcChannelEntry);
1640 (void)va_arg(vp, SilcUInt32); 1667 (void)va_arg(ap, SilcUInt32);
1641 (void)va_arg(vp, SilcPublicKey); 1668 (void)va_arg(ap, SilcPublicKey);
1642 channel_pubkeys = va_arg(vp, SilcBuffer); 1669 channel_pubkeys = va_arg(ap, SilcDList);
1643 1670
1644 if (sg->chpk) 1671 if (!sg->chpk)
1645 silcpurple_chat_chauth_show(sg, channel_entry, channel_pubkeys); 1672 break;
1673
1674 list = silc_dlist_init();
1675
1676 if (channel_pubkeys) {
1677 silc_dlist_start(channel_pubkeys);
1678 while ((e = silc_dlist_get(channel_pubkeys))) {
1679 if (e->arg_type == 0x00 ||
1680 e->arg_type == 0x03)
1681 silc_dlist_add(list, silc_pkcs_public_key_copy(e->argument));
1682 }
1683 }
1684 silcpurple_chat_chauth_show(sg, channel_entry, list);
1685 }
1686 break;
1687
1688 case SILC_COMMAND_WATCH:
1689 if (status != SILC_STATUS_OK) {
1690 purple_notify_error(gc, _("WATCH"), _("Cannot watch user"),
1691 silc_get_status_message(error));
1692 return;
1646 } 1693 }
1647 break; 1694 break;
1648 1695
1649 default: 1696 default:
1650 if (success) 1697 if (status == SILC_STATUS_OK)
1651 purple_debug_info("silc", "Unhandled command: %d (succeeded)\n", command); 1698 purple_debug_info("silc", "Unhandled command: %d (succeeded)\n", command);
1652 else 1699 else
1653 purple_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command, 1700 purple_debug_info("silc", "Unhandled command: %d (failed: %s)\n", command,
1654 silc_get_status_message(status)); 1701 silc_get_status_message(error));
1655 break; 1702 break;
1656 } 1703 }
1657
1658 va_end(vp);
1659 } 1704 }
1660 1705
1661 1706 /* Generic command reply callback for silc_client_command_send. Simply
1662 /* Called to indicate that connection was either successfully established 1707 calls the default command_reply client operation callback */
1663 or connecting failed. This is also the first time application receives 1708
1664 the SilcClientConnection object which it should save somewhere. 1709 SilcBool silcpurple_command_reply(SilcClient client, SilcClientConnection conn,
1665 If the `success' is FALSE the application must always call the function 1710 SilcCommand command, SilcStatus status,
1666 silc_client_close_connection. */ 1711 SilcStatus error, void *context, va_list ap)
1712 {
1713 silc_command_reply(client, conn, command, status, error, ap);
1714 return TRUE;
1715 }
1716
1717
1718 typedef struct {
1719 union {
1720 SilcAskPassphrase ask_pass;
1721 SilcGetAuthMeth get_auth;
1722 } u;
1723 void *context;
1724 } *SilcPurpleAskPassphrase;
1667 1725
1668 static void 1726 static void
1669 silc_connected(SilcClient client, SilcClientConnection conn, 1727 silc_ask_auth_password_cb(const unsigned char *passphrase,
1670 SilcClientConnectionStatus status) 1728 SilcUInt32 passphrase_len, void *context)
1671 { 1729 {
1672 PurpleConnection *gc = client->application; 1730 SilcPurpleAskPassphrase internal = context;
1673 SilcPurple sg; 1731
1674 gboolean reject_watch, block_invites, block_ims; 1732 if (!passphrase || !(*passphrase))
1675 1733 internal->u.get_auth(SILC_AUTH_NONE, NULL, 0, internal->context);
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 purple_connection_set_state(gc, PURPLE_CONNECTED);
1686
1687 /* Send the server our buddy list */
1688 silcpurple_send_buddylist(gc);
1689
1690 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
1691
1692 /* Send any UMODEs configured for account */
1693 reject_watch = purple_account_get_bool(sg->account, "reject-watch", FALSE);
1694 block_invites = purple_account_get_bool(sg->account, "block-invites", FALSE);
1695 block_ims = purple_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 purple_connection_error(gc, _("Error during connecting to SILC Server"));
1710 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
1711 break;
1712
1713 case SILC_CLIENT_CONN_ERROR_KE:
1714 purple_connection_error(gc, _("Key Exchange failed"));
1715 break;
1716
1717 case SILC_CLIENT_CONN_ERROR_AUTH:
1718 purple_connection_error(gc, _("Authentication failed"));
1719 break;
1720
1721 case SILC_CLIENT_CONN_ERROR_RESUME:
1722 purple_connection_error(gc,
1723 _("Resuming detached session failed. "
1724 "Press Reconnect to create new connection."));
1725 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
1726 break;
1727
1728 case SILC_CLIENT_CONN_ERROR_TIMEOUT:
1729 purple_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 PurpleConnection *gc = client->application;
1749 SilcPurple sg = gc->proto_data;
1750
1751 if (sg->resuming && !sg->detaching)
1752 g_unlink(silcpurple_session_file(purple_account_get_username(sg->account)));
1753
1754 sg->conn = NULL;
1755
1756 /* Close the connection */
1757 if (!sg->detaching)
1758 purple_connection_error(gc, _("Disconnected by server"));
1759 else 1734 else
1760 /* TODO: Does this work correctly? Maybe we need to set wants_to_die? */ 1735 internal->u.get_auth(SILC_AUTH_PASSWORD,
1761 purple_account_disconnect(purple_connection_get_account(gc)); 1736 (unsigned char *)passphrase,
1762 } 1737 passphrase_len, internal->context);
1763
1764
1765 typedef struct {
1766 SilcGetAuthMeth completion;
1767 void *context;
1768 } *SilcPurpleGetAuthMethod;
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 SilcPurpleGetAuthMethod 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); 1738 silc_free(internal);
1800 } 1739 }
1801 1740
1802 /* Find authentication method and authentication data by hostname and 1741 /* Find authentication method and authentication data by hostname and
1803 port. The hostname may be IP address as well. When the authentication 1742 port. The hostname may be IP address as well. The `auth_method' is
1804 method has been resolved the `completion' callback with the found 1743 the authentication method the remote connection requires. It is
1805 authentication method and authentication data is called. The `conn' 1744 however possible that remote accepts also some other authentication
1806 may be NULL. */ 1745 method. Application should use the method that may have been
1746 configured for this connection. If none has been configured it should
1747 use the required `auth_method'. If the `auth_method' is
1748 SILC_AUTH_NONE, server does not require any authentication or the
1749 required authentication method is not known. The `completion'
1750 callback must be called to deliver the chosen authentication method
1751 and data. The `conn' may be NULL. */
1807 1752
1808 static void 1753 static void
1809 silc_get_auth_method(SilcClient client, SilcClientConnection conn, 1754 silc_get_auth_method(SilcClient client, SilcClientConnection conn,
1810 char *hostname, SilcUInt16 port, 1755 char *hostname, SilcUInt16 port,
1756 SilcAuthMethod auth_method,
1811 SilcGetAuthMeth completion, void *context) 1757 SilcGetAuthMeth completion, void *context)
1812 { 1758 {
1813 PurpleConnection *gc = client->application; 1759 PurpleConnection *gc = client->application;
1814 SilcPurple sg = gc->proto_data; 1760 SilcPurple sg = gc->proto_data;
1815 SilcPurpleGetAuthMethod internal; 1761 SilcPurpleAskPassphrase internal;
1816 const char *password; 1762 const char *password;
1817 1763
1818 /* Progress */ 1764 /* Progress */
1819 if (sg->resuming) 1765 if (sg->resuming)
1820 purple_connection_update_progress(gc, _("Resuming session"), 4, 5); 1766 purple_connection_update_progress(gc, _("Resuming session"), 4, 5);
1821 else 1767 else
1822 purple_connection_update_progress(gc, _("Authenticating connection"), 4, 5); 1768 purple_connection_update_progress(gc, _("Authenticating connection"), 4, 5);
1823 1769
1824 /* Check configuration if we have this connection configured. If we 1770 /* Check configuration if we have this connection configured. */
1825 have then return that data immediately, as it's faster way. */ 1771 if (auth_method == SILC_AUTH_PUBLIC_KEY &&
1826 if (purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) { 1772 purple_account_get_bool(sg->account, "pubkey-auth", FALSE)) {
1827 completion(TRUE, SILC_AUTH_PUBLIC_KEY, NULL, 0, context); 1773 completion(SILC_AUTH_PUBLIC_KEY, NULL, 0, context);
1828 return; 1774 return;
1829 } 1775 }
1830 password = purple_connection_get_password(gc); 1776 if (auth_method == SILC_AUTH_PASSWORD) {
1831 if (password && *password) { 1777 password = purple_connection_get_password(gc);
1832 completion(TRUE, SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context); 1778 if (password && *password) {
1779 completion(SILC_AUTH_PASSWORD, (unsigned char *)password, strlen(password), context);
1780 return;
1781 }
1782
1783 /* Ask password from user */
1784 internal = silc_calloc(1, sizeof(*internal));
1785 if (!internal)
1786 return;
1787 internal->u.get_auth = completion;
1788 internal->context = context;
1789 silc_ask_passphrase(client, conn, silc_ask_auth_password_cb,
1790 internal);
1833 return; 1791 return;
1834 } 1792 }
1835 1793
1836 /* Resolve the authentication method from server, as we may not know it. */ 1794 completion(SILC_AUTH_NONE, NULL, 0, context);
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 } 1795 }
1846 1796
1847 1797
1848 /* Verifies received public key. The `conn_type' indicates which entity 1798 /* Called to verify received public key. The `conn_type' indicates which
1849 (server, client etc.) has sent the public key. If user decides to trust 1799 entity (server or client) has sent the public key. If user decides to
1850 the application may save the key as trusted public key for later 1800 trust the key the application may save the key as trusted public key for
1851 use. The `completion' must be called after the public key has been 1801 later use. The `completion' must be called after the public key has
1852 verified. */ 1802 been verified. */
1853 1803
1854 static void 1804 static void
1855 silc_verify_public_key(SilcClient client, SilcClientConnection conn, 1805 silc_verify_public_key(SilcClient client, SilcClientConnection conn,
1856 SilcSocketType conn_type, unsigned char *pk, 1806 SilcConnectionType conn_type,
1857 SilcUInt32 pk_len, SilcSKEPKType pk_type, 1807 SilcPublicKey public_key,
1858 SilcVerifyPublicKey completion, void *context) 1808 SilcVerifyPublicKey completion, void *context)
1859 { 1809 {
1860 PurpleConnection *gc = client->application; 1810 PurpleConnection *gc = client->application;
1861 SilcPurple sg = gc->proto_data; 1811 SilcPurple sg = gc->proto_data;
1862 1812
1863 if (!sg->conn && (conn_type == SILC_SOCKET_TYPE_SERVER || 1813 if (!sg->conn && (conn_type == SILC_CONN_SERVER ||
1864 conn_type == SILC_SOCKET_TYPE_ROUTER)) { 1814 conn_type == SILC_CONN_ROUTER)) {
1865 /* Progress */ 1815 /* Progress */
1866 if (sg->resuming) 1816 if (sg->resuming)
1867 purple_connection_update_progress(gc, _("Resuming session"), 3, 5); 1817 purple_connection_update_progress(gc, _("Resuming session"), 3, 5);
1868 else 1818 else
1869 purple_connection_update_progress(gc, _("Verifying server public key"), 1819 purple_connection_update_progress(gc, _("Verifying server public key"),
1870 3, 5); 1820 3, 5);
1871 } 1821 }
1872 1822
1873 /* Verify public key */ 1823 /* Verify public key */
1874 silcpurple_verify_public_key(client, conn, NULL, conn_type, pk, 1824 silcpurple_verify_public_key(client, conn, NULL, conn_type,
1875 pk_len, pk_type, completion, context); 1825 public_key, completion, context);
1876 } 1826 }
1877
1878 typedef struct {
1879 SilcAskPassphrase completion;
1880 void *context;
1881 } *SilcPurpleAskPassphrase;
1882 1827
1883 static void 1828 static void
1884 silc_ask_passphrase_cb(SilcPurpleAskPassphrase internal, const char *passphrase) 1829 silc_ask_passphrase_cb(SilcPurpleAskPassphrase internal, const char *passphrase)
1885 { 1830 {
1886 if (!passphrase || !(*passphrase)) 1831 if (!passphrase || !(*passphrase))
1887 internal->completion(NULL, 0, internal->context); 1832 internal->u.ask_pass(NULL, 0, internal->context);
1888 else 1833 else
1889 internal->completion((unsigned char *)passphrase, 1834 internal->u.ask_pass((unsigned char *)passphrase,
1890 strlen(passphrase), internal->context); 1835 strlen(passphrase), internal->context);
1891 silc_free(internal); 1836 silc_free(internal);
1892 } 1837 }
1893 1838
1894 /* Ask (interact, that is) a passphrase from user. The passphrase is 1839 /* Ask (interact, that is) a passphrase from user. The passphrase is
1903 PurpleConnection *gc = client->application; 1848 PurpleConnection *gc = client->application;
1904 SilcPurpleAskPassphrase internal = silc_calloc(1, sizeof(*internal)); 1849 SilcPurpleAskPassphrase internal = silc_calloc(1, sizeof(*internal));
1905 1850
1906 if (!internal) 1851 if (!internal)
1907 return; 1852 return;
1908 internal->completion = completion; 1853 internal->u.ask_pass = completion;
1909 internal->context = context; 1854 internal->context = context;
1910 purple_request_input(gc, _("Passphrase"), NULL, 1855 purple_request_input(gc, _("Passphrase"), NULL,
1911 _("Passphrase required"), NULL, FALSE, TRUE, NULL, 1856 _("Passphrase required"), NULL, FALSE, TRUE, NULL,
1912 _("OK"), G_CALLBACK(silc_ask_passphrase_cb), 1857 _("OK"), G_CALLBACK(silc_ask_passphrase_cb),
1913 _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb), 1858 _("Cancel"), G_CALLBACK(silc_ask_passphrase_cb),
1914 purple_connection_get_account(gc), NULL, NULL, internal); 1859 purple_connection_get_account(gc), NULL, NULL, internal);
1915 } 1860 }
1916 1861
1917 1862
1918 /* Notifies application that failure packet was received. This is called 1863 /* Called to indicate that incoming key agreement request has been
1919 if there is some protocol active in the client. The `protocol' is the 1864 received. If the application wants to perform key agreement it may
1920 protocol context. The `failure' is opaque pointer to the failure 1865 call silc_client_perform_key_agreement to initiate key agreement or
1921 indication. Note, that the `failure' is protocol dependant and 1866 silc_client_send_key_agreement to provide connection point to the
1922 application must explicitly cast it to correct type. Usually `failure' 1867 remote client in case the `hostname' is NULL. If key agreement is
1923 is 32 bit failure type (see protocol specs for all protocol failure 1868 not desired this request can be ignored. The `protocol' is either
1924 types). */ 1869 value 0 for TCP or value 1 for UDP. */
1925 1870
1926 static void 1871 static void
1927 silc_failure(SilcClient client, SilcClientConnection conn, 1872 silc_key_agreement(SilcClient client, SilcClientConnection conn,
1928 SilcProtocol protocol, void *failure) 1873 SilcClientEntry client_entry,
1874 const char *hostname, SilcUInt16 protocol,
1875 SilcUInt16 port)
1929 { 1876 {
1930 PurpleConnection *gc = client->application; 1877 silcpurple_buddy_keyagr_request(client, conn, client_entry,
1931 char buf[128]; 1878 hostname, port, protocol);
1932
1933 memset(buf, 0, sizeof(buf));
1934
1935 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
1936 SilcSKEStatus status = (SilcSKEStatus)SILC_PTR_TO_32(failure);
1937
1938 if (status == SILC_SKE_STATUS_BAD_VERSION)
1939 g_snprintf(buf, sizeof(buf),
1940 _("Failure: Version mismatch, upgrade your client"));
1941 if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY)
1942 g_snprintf(buf, sizeof(buf),
1943 _("Failure: Remote does not trust/support your public key"));
1944 if (status == SILC_SKE_STATUS_UNKNOWN_GROUP)
1945 g_snprintf(buf, sizeof(buf),
1946 _("Failure: Remote does not support proposed KE group"));
1947 if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER)
1948 g_snprintf(buf, sizeof(buf),
1949 _("Failure: Remote does not support proposed cipher"));
1950 if (status == SILC_SKE_STATUS_UNKNOWN_PKCS)
1951 g_snprintf(buf, sizeof(buf),
1952 _("Failure: Remote does not support proposed PKCS"));
1953 if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION)
1954 g_snprintf(buf, sizeof(buf),
1955 _("Failure: Remote does not support proposed hash function"));
1956 if (status == SILC_SKE_STATUS_UNKNOWN_HMAC)
1957 g_snprintf(buf, sizeof(buf),
1958 _("Failure: Remote does not support proposed HMAC"));
1959 if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE)
1960 g_snprintf(buf, sizeof(buf), _("Failure: Incorrect signature"));
1961 if (status == SILC_SKE_STATUS_INVALID_COOKIE)
1962 g_snprintf(buf, sizeof(buf), _("Failure: Invalid cookie"));
1963
1964 /* Show the error on the progress bar. A more generic error message
1965 is going to be showed to user after this in the silc_connected. */
1966 purple_connection_update_progress(gc, buf, 2, 5);
1967 }
1968
1969 if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
1970 SilcUInt32 err = SILC_PTR_TO_32(failure);
1971
1972 if (err == SILC_AUTH_FAILED)
1973 g_snprintf(buf, sizeof(buf), _("Failure: Authentication failed"));
1974
1975 /* Show the error on the progress bar. A more generic error message
1976 is going to be showed to user after this in the silc_connected. */
1977 purple_connection_update_progress(gc, buf, 4, 5);
1978 }
1979 }
1980
1981 /* Asks whether the user would like to perform the key agreement protocol.
1982 This is called after we have received an key agreement packet or an
1983 reply to our key agreement packet. This returns TRUE if the user wants
1984 the library to perform the key agreement protocol and FALSE if it is not
1985 desired (application may start it later by calling the function
1986 silc_client_perform_key_agreement). If TRUE is returned also the
1987 `completion' and `context' arguments must be set by the application. */
1988
1989 static bool
1990 silc_key_agreement(SilcClient client, SilcClientConnection conn,
1991 SilcClientEntry client_entry, const char *hostname,
1992 SilcUInt16 port, SilcKeyAgreementCallback *completion,
1993 void **context)
1994 {
1995 silcpurple_buddy_keyagr_request(client, conn, client_entry, hostname, port);
1996 *completion = NULL;
1997 *context = NULL;
1998 return FALSE;
1999 } 1879 }
2000 1880
2001 1881
2002 /* Notifies application that file transfer protocol session is being 1882 /* Notifies application that file transfer protocol session is being
2003 requested by the remote client indicated by the `client_entry' from 1883 requested by the remote client indicated by the `client_entry' from
2010 silc_ftp(SilcClient client, SilcClientConnection conn, 1890 silc_ftp(SilcClient client, SilcClientConnection conn,
2011 SilcClientEntry client_entry, SilcUInt32 session_id, 1891 SilcClientEntry client_entry, SilcUInt32 session_id,
2012 const char *hostname, SilcUInt16 port) 1892 const char *hostname, SilcUInt16 port)
2013 { 1893 {
2014 silcpurple_ftp_request(client, conn, client_entry, session_id, 1894 silcpurple_ftp_request(client, conn, client_entry, session_id,
2015 hostname, port); 1895 hostname, port);
2016 }
2017
2018
2019 /* Delivers SILC session detachment data indicated by `detach_data' to the
2020 application. If application has issued SILC_COMMAND_DETACH command
2021 the client session in the SILC network is not quit. The client remains
2022 in the network but is detached. The detachment data may be used later
2023 to resume the session in the SILC Network. The appliation is
2024 responsible of saving the `detach_data', to for example in a file.
2025
2026 The detachment data can be given as argument to the functions
2027 silc_client_connect_to_server, or silc_client_add_connection when
2028 creating connection to remote server, inside SilcClientConnectionParams
2029 structure. If it is provided the client library will attempt to resume
2030 the session in the network. After the connection is created
2031 successfully, the application is responsible of setting the user
2032 interface for user into the same state it was before detaching (showing
2033 same channels, channel modes, etc). It can do this by fetching the
2034 information (like joined channels) from the client library. */
2035
2036 static void
2037 silc_detach(SilcClient client, SilcClientConnection conn,
2038 const unsigned char *detach_data, SilcUInt32 detach_data_len)
2039 {
2040 PurpleConnection *gc = client->application;
2041 SilcPurple sg = gc->proto_data;
2042 const char *file;
2043
2044 /* Save the detachment data to file. */
2045 file = silcpurple_session_file(purple_account_get_username(sg->account));
2046 g_unlink(file);
2047 silc_file_writefile(file, (char *)detach_data, detach_data_len);
2048 } 1896 }
2049 1897
2050 SilcClientOperations ops = { 1898 SilcClientOperations ops = {
2051 silc_say, 1899 silc_say,
2052 silc_channel_message, 1900 silc_channel_message,
2053 silc_private_message, 1901 silc_private_message,
2054 silc_notify, 1902 silc_notify,
2055 silc_command, 1903 silc_command,
2056 silc_command_reply, 1904 silc_command_reply,
2057 silc_connected,
2058 silc_disconnected,
2059 silc_get_auth_method, 1905 silc_get_auth_method,
2060 silc_verify_public_key, 1906 silc_verify_public_key,
2061 silc_ask_passphrase, 1907 silc_ask_passphrase,
2062 silc_failure,
2063 silc_key_agreement, 1908 silc_key_agreement,
2064 silc_ftp, 1909 silc_ftp
2065 silc_detach
2066 }; 1910 };

mercurial