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