Mercurial > pidgin
annotate src/protocols/silc/buddy.c @ 13253:87a7c3077c19
[gaim-migrate @ 15619]
More cleaning up of oscar. Renamed some functions to be more clear.
Got rid of some stuff that wasn't used. Inlined some small things
in conn.c that were only used once.
The goals of all this are
1. Non-blocking I/O for all connections
2. p2p stuff won't use the same struct as oscar connections, because
that's stupid
3. The oscar PRPL should be less scary
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Sun, 12 Feb 2006 21:27:04 +0000 |
| parents | ec9b92104904 |
| children |
| rev | line source |
|---|---|
| 8849 | 1 /* |
| 2 | |
| 3 silcgaim_buddy.c | |
| 4 | |
| 5 Author: Pekka Riikonen <priikone@silcnet.org> | |
| 6 | |
| 7 Copyright (C) 2004 Pekka Riikonen | |
| 8 | |
| 9 This program is free software; you can redistribute it and/or modify | |
| 10 it under the terms of the GNU General Public License as published by | |
| 11 the Free Software Foundation; version 2 of the License. | |
| 12 | |
| 13 This program is distributed in the hope that it will be useful, | |
| 14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 GNU General Public License for more details. | |
| 17 | |
| 18 */ | |
| 19 | |
| 20 #include "silcincludes.h" | |
| 21 #include "silcclient.h" | |
| 22 #include "silcgaim.h" | |
| 12058 | 23 #include "wb.h" |
| 8849 | 24 |
| 25 /***************************** Key Agreement *********************************/ | |
| 26 | |
| 27 static void | |
| 9060 | 28 silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data); |
| 29 | |
| 30 static void | |
| 31 silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, | |
| 32 gboolean force_local); | |
| 8849 | 33 |
| 34 typedef struct { | |
| 35 char *nick; | |
| 36 GaimConnection *gc; | |
| 37 } *SilcGaimResolve; | |
| 38 | |
| 39 static void | |
| 40 silcgaim_buddy_keyagr_resolved(SilcClient client, | |
| 41 SilcClientConnection conn, | |
| 42 SilcClientEntry *clients, | |
| 43 SilcUInt32 clients_count, | |
| 44 void *context) | |
| 45 { | |
| 46 GaimConnection *gc = client->application; | |
| 47 SilcGaimResolve r = context; | |
| 48 char tmp[256]; | |
| 49 | |
| 50 if (!clients) { | |
| 51 g_snprintf(tmp, sizeof(tmp), | |
| 52 _("User %s is not present in the network"), r->nick); | |
| 53 gaim_notify_error(gc, _("Key Agreement"), | |
| 54 _("Cannot perform the key agreement"), tmp); | |
| 55 silc_free(r->nick); | |
| 56 silc_free(r); | |
| 57 return; | |
| 58 } | |
| 59 | |
| 9060 | 60 silcgaim_buddy_keyagr_do(gc, r->nick, FALSE); |
| 8849 | 61 silc_free(r->nick); |
| 62 silc_free(r); | |
| 63 } | |
| 64 | |
| 65 typedef struct { | |
| 66 gboolean responder; | |
| 67 } *SilcGaimKeyAgr; | |
| 68 | |
| 69 static void | |
| 70 silcgaim_buddy_keyagr_cb(SilcClient client, | |
| 71 SilcClientConnection conn, | |
| 72 SilcClientEntry client_entry, | |
| 73 SilcKeyAgreementStatus status, | |
| 74 SilcSKEKeyMaterial *key, | |
| 75 void *context) | |
| 76 { | |
| 77 GaimConnection *gc = client->application; | |
| 78 SilcGaim sg = gc->proto_data; | |
| 79 SilcGaimKeyAgr a = context; | |
| 80 | |
| 81 if (!sg->conn) | |
| 82 return; | |
| 83 | |
| 84 switch (status) { | |
| 85 case SILC_KEY_AGREEMENT_OK: | |
| 86 { | |
| 87 GaimConversation *convo; | |
| 88 char tmp[128]; | |
| 89 | |
| 90 /* Set the private key for this client */ | |
| 91 silc_client_del_private_message_key(client, conn, client_entry); | |
| 92 silc_client_add_private_message_key_ske(client, conn, client_entry, | |
| 93 NULL, NULL, key, a->responder); | |
| 94 silc_ske_free_key_material(key); | |
| 95 | |
| 11586 | 96 |
| 8849 | 97 /* Open IM window */ |
| 11338 | 98 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, |
| 10246 | 99 client_entry->nickname, sg->account); |
| 11586 | 100 if (convo) { |
| 101 /* we don't have windows in the core anymore...but we may want to | |
| 102 * provide some method for asking the UI to show the window | |
| 8849 | 103 gaim_conv_window_show(gaim_conversation_get_window(convo)); |
| 11586 | 104 */ |
| 105 } else { | |
| 11338 | 106 convo = gaim_conversation_new(GAIM_CONV_TYPE_IM, sg->account, |
| 8849 | 107 client_entry->nickname); |
| 11586 | 108 } |
| 8849 | 109 g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); |
| 110 gaim_conversation_set_title(convo, tmp); | |
| 111 } | |
| 112 break; | |
| 113 | |
| 114 case SILC_KEY_AGREEMENT_ERROR: | |
| 115 gaim_notify_error(gc, _("Key Agreement"), | |
| 116 _("Error occurred during key agreement"), NULL); | |
| 117 break; | |
| 118 | |
| 119 case SILC_KEY_AGREEMENT_FAILURE: | |
| 120 gaim_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); | |
| 121 break; | |
| 122 | |
| 123 case SILC_KEY_AGREEMENT_TIMEOUT: | |
| 124 gaim_notify_error(gc, _("Key Agreement"), | |
| 125 _("Timeout during key agreement"), NULL); | |
| 126 break; | |
| 127 | |
| 128 case SILC_KEY_AGREEMENT_ABORTED: | |
| 129 gaim_notify_error(gc, _("Key Agreement"), | |
| 130 _("Key agreement was aborted"), NULL); | |
| 131 break; | |
| 132 | |
| 133 case SILC_KEY_AGREEMENT_ALREADY_STARTED: | |
| 134 gaim_notify_error(gc, _("Key Agreement"), | |
| 135 _("Key agreement is already started"), NULL); | |
| 136 break; | |
| 137 | |
| 138 case SILC_KEY_AGREEMENT_SELF_DENIED: | |
| 139 gaim_notify_error(gc, _("Key Agreement"), | |
| 140 _("Key agreement cannot be started with yourself"), | |
| 141 NULL); | |
| 142 break; | |
| 143 | |
| 144 default: | |
| 145 break; | |
| 146 } | |
| 147 | |
| 148 silc_free(a); | |
| 149 } | |
| 150 | |
| 151 static void | |
| 152 silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, | |
| 153 gboolean force_local) | |
| 154 { | |
| 155 SilcGaim sg = gc->proto_data; | |
| 156 SilcClientEntry *clients; | |
| 157 SilcUInt32 clients_count; | |
| 8910 | 158 char *local_ip = NULL, *remote_ip = NULL; |
| 8849 | 159 gboolean local = TRUE; |
| 160 char *nickname; | |
| 161 SilcGaimKeyAgr a; | |
| 162 | |
| 163 if (!sg->conn || !name) | |
| 164 return; | |
| 165 | |
| 166 if (!silc_parse_userfqdn(name, &nickname, NULL)) | |
| 167 return; | |
| 168 | |
| 169 /* Find client entry */ | |
| 170 clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, | |
| 171 &clients_count); | |
| 172 if (!clients) { | |
| 173 /* Resolve unknown user */ | |
| 174 SilcGaimResolve r = silc_calloc(1, sizeof(*r)); | |
| 175 if (!r) | |
| 176 return; | |
| 177 r->nick = g_strdup(name); | |
| 178 r->gc = gc; | |
| 179 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, | |
| 180 silcgaim_buddy_keyagr_resolved, r); | |
| 181 silc_free(nickname); | |
| 182 return; | |
| 183 } | |
| 184 | |
| 185 /* Resolve the local IP from the outgoing socket connection. We resolve | |
| 186 it to check whether we have a private range IP address or public IP | |
| 187 address. If we have public then we will assume that we are not behind | |
| 188 NAT and will provide automatically the point of connection to the | |
| 189 agreement. If we have private range address we assume that we are | |
| 190 behind NAT and we let the responder provide the point of connection. | |
| 191 | |
| 192 The algorithm also checks the remote IP address of server connection. | |
| 193 If it is private range address and we have private range address we | |
| 194 assume that we are chatting in LAN and will provide the point of | |
| 195 connection. | |
| 196 | |
| 197 Naturally this algorithm does not always get things right. */ | |
| 198 | |
| 199 if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { | |
| 200 /* Check if the IP is private */ | |
| 201 if (!force_local && silcgaim_ip_is_private(local_ip)) { | |
| 202 local = FALSE; | |
| 203 | |
| 204 /* Local IP is private, resolve the remote server IP to see whether | |
| 205 we are talking to Internet or just on LAN. */ | |
| 206 if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, | |
| 207 &remote_ip)) | |
| 208 if (silcgaim_ip_is_private(remote_ip)) | |
| 209 /* We assume we are in LAN. Let's provide | |
| 210 the connection point. */ | |
| 211 local = TRUE; | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 if (force_local) | |
| 216 local = TRUE; | |
| 217 | |
| 218 if (local && !local_ip) | |
| 219 local_ip = silc_net_localip(); | |
| 220 | |
| 221 a = silc_calloc(1, sizeof(*a)); | |
| 222 if (!a) | |
| 223 return; | |
| 224 a->responder = local; | |
| 225 | |
| 226 /* Send the key agreement request */ | |
| 227 silc_client_send_key_agreement(sg->client, sg->conn, clients[0], | |
| 228 local ? local_ip : NULL, NULL, 0, 60, | |
| 229 silcgaim_buddy_keyagr_cb, a); | |
| 230 | |
| 231 silc_free(local_ip); | |
| 232 silc_free(remote_ip); | |
| 233 silc_free(clients); | |
| 234 } | |
| 235 | |
| 236 typedef struct { | |
| 237 SilcClient client; | |
| 238 SilcClientConnection conn; | |
| 239 SilcClientID client_id; | |
| 240 char *hostname; | |
| 241 SilcUInt16 port; | |
| 242 } *SilcGaimKeyAgrAsk; | |
| 243 | |
| 244 static void | |
| 245 silcgaim_buddy_keyagr_request_cb(SilcGaimKeyAgrAsk a, gint id) | |
| 246 { | |
| 247 SilcGaimKeyAgr ai; | |
| 248 SilcClientEntry client_entry; | |
| 249 | |
| 250 if (id != 1) | |
| 251 goto out; | |
| 252 | |
| 253 /* Get the client entry. */ | |
| 254 client_entry = silc_client_get_client_by_id(a->client, a->conn, | |
| 255 &a->client_id); | |
| 256 if (!client_entry) { | |
| 257 gaim_notify_error(a->client->application, _("Key Agreement"), | |
| 258 _("The remote user is not present in the network any more"), | |
| 259 NULL); | |
| 260 goto out; | |
| 261 } | |
| 262 | |
| 263 /* If the hostname was provided by the requestor perform the key agreement | |
| 264 now. Otherwise, we will send him a request to connect to us. */ | |
| 265 if (a->hostname) { | |
| 266 ai = silc_calloc(1, sizeof(*ai)); | |
| 267 if (!ai) | |
| 268 goto out; | |
| 269 ai->responder = FALSE; | |
| 270 silc_client_perform_key_agreement(a->client, a->conn, client_entry, | |
| 271 a->hostname, a->port, | |
| 272 silcgaim_buddy_keyagr_cb, ai); | |
| 273 } else { | |
| 274 /* Send request. Force us as the point of connection since requestor | |
| 275 did not provide the point of connection. */ | |
| 276 silcgaim_buddy_keyagr_do(a->client->application, | |
| 277 client_entry->nickname, TRUE); | |
| 278 } | |
| 279 | |
| 280 out: | |
| 281 silc_free(a->hostname); | |
| 282 silc_free(a); | |
| 283 } | |
| 284 | |
| 285 void silcgaim_buddy_keyagr_request(SilcClient client, | |
| 286 SilcClientConnection conn, | |
| 287 SilcClientEntry client_entry, | |
| 288 const char *hostname, SilcUInt16 port) | |
| 289 { | |
| 290 char tmp[128], tmp2[128]; | |
| 291 SilcGaimKeyAgrAsk a; | |
| 292 | |
| 293 g_snprintf(tmp, sizeof(tmp), | |
| 294 _("Key agreement request received from %s. Would you like to " | |
| 295 "perform the key agreement?"), client_entry->nickname); | |
| 296 if (hostname) | |
| 297 g_snprintf(tmp2, sizeof(tmp2), | |
| 298 _("The remote user is waiting key agreement on:\n" | |
| 299 "Remote host: %s\nRemote port: %d"), hostname, port); | |
| 300 | |
| 301 a = silc_calloc(1, sizeof(*a)); | |
| 302 if (!a) | |
| 303 return; | |
| 304 a->client = client; | |
| 305 a->conn = conn; | |
| 306 a->client_id = *client_entry->id; | |
| 307 if (hostname) | |
| 308 a->hostname = strdup(hostname); | |
| 309 a->port = port; | |
| 310 | |
| 11201 | 311 gaim_request_action(client->application, _("Key Agreement Request"), tmp, |
| 8849 | 312 hostname ? tmp2 : NULL, 1, a, 2, |
| 313 _("Yes"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb), | |
| 314 _("No"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb)); | |
| 315 } | |
| 316 | |
| 317 static void | |
| 9060 | 318 silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data) |
| 8849 | 319 { |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
320 GaimBuddy *buddy; |
| 9060 | 321 |
| 322 buddy = (GaimBuddy *)node; | |
| 323 silcgaim_buddy_keyagr_do(buddy->account->gc, buddy->name, FALSE); | |
| 8849 | 324 } |
| 325 | |
| 326 | |
| 327 /**************************** Static IM Key **********************************/ | |
| 328 | |
| 329 static void | |
| 9030 | 330 silcgaim_buddy_resetkey(GaimBlistNode *node, gpointer data) |
| 8849 | 331 { |
| 9030 | 332 GaimBuddy *b; |
| 333 GaimConnection *gc; | |
| 334 SilcGaim sg; | |
| 8849 | 335 char *nickname; |
| 336 SilcClientEntry *clients; | |
| 337 SilcUInt32 clients_count; | |
| 338 | |
| 9030 | 339 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
| 340 | |
| 341 b = (GaimBuddy *) node; | |
| 342 gc = gaim_account_get_connection(b->account); | |
| 343 sg = gc->proto_data; | |
| 344 | |
| 345 if (!silc_parse_userfqdn(b->name, &nickname, NULL)) | |
| 8849 | 346 return; |
| 347 | |
| 348 /* Find client entry */ | |
| 349 clients = silc_client_get_clients_local(sg->client, sg->conn, | |
| 9030 | 350 nickname, b->name, |
| 8849 | 351 &clients_count); |
| 352 if (!clients) { | |
| 353 silc_free(nickname); | |
| 354 return; | |
| 355 } | |
| 356 | |
| 357 clients[0]->prv_resp = FALSE; | |
| 358 silc_client_del_private_message_key(sg->client, sg->conn, | |
| 359 clients[0]); | |
| 360 silc_free(clients); | |
| 361 silc_free(nickname); | |
| 362 } | |
| 363 | |
| 364 typedef struct { | |
| 365 SilcClient client; | |
| 366 SilcClientConnection conn; | |
| 367 SilcClientID client_id; | |
| 368 } *SilcGaimPrivkey; | |
| 369 | |
| 370 static void | |
| 371 silcgaim_buddy_privkey(GaimConnection *gc, const char *name); | |
| 372 | |
| 373 static void | |
| 374 silcgaim_buddy_privkey_cb(SilcGaimPrivkey p, const char *passphrase) | |
| 375 { | |
| 376 SilcClientEntry client_entry; | |
| 377 | |
| 378 if (!passphrase || !(*passphrase)) { | |
| 379 silc_free(p); | |
| 380 return; | |
| 381 } | |
| 382 | |
| 383 /* Get the client entry. */ | |
| 384 client_entry = silc_client_get_client_by_id(p->client, p->conn, | |
| 385 &p->client_id); | |
| 386 if (!client_entry) { | |
| 387 gaim_notify_error(p->client->application, _("IM With Password"), | |
| 388 _("The remote user is not present in the network any more"), | |
| 389 NULL); | |
| 390 silc_free(p); | |
| 391 return; | |
| 392 } | |
| 393 | |
| 394 /* Set the private message key */ | |
| 395 silc_client_del_private_message_key(p->client, p->conn, | |
| 396 client_entry); | |
| 397 silc_client_add_private_message_key(p->client, p->conn, | |
| 398 client_entry, NULL, NULL, | |
| 399 (unsigned char *)passphrase, | |
| 400 strlen(passphrase), FALSE, | |
| 401 client_entry->prv_resp); | |
| 402 if (!client_entry->prv_resp) | |
| 403 silc_client_send_private_message_key_request(p->client, | |
| 404 p->conn, | |
| 405 client_entry); | |
| 406 silc_free(p); | |
| 407 } | |
| 408 | |
| 409 static void | |
| 410 silcgaim_buddy_privkey_resolved(SilcClient client, | |
| 411 SilcClientConnection conn, | |
| 412 SilcClientEntry *clients, | |
| 413 SilcUInt32 clients_count, | |
| 414 void *context) | |
| 415 { | |
| 416 char tmp[256]; | |
| 417 | |
| 418 if (!clients) { | |
| 419 g_snprintf(tmp, sizeof(tmp), | |
| 420 _("User %s is not present in the network"), | |
| 421 (const char *)context); | |
| 422 gaim_notify_error(client->application, _("IM With Password"), | |
| 423 _("Cannot set IM key"), tmp); | |
| 424 g_free(context); | |
| 425 return; | |
| 426 } | |
| 427 | |
| 428 silcgaim_buddy_privkey(client->application, context); | |
| 429 silc_free(context); | |
| 430 } | |
| 431 | |
| 432 static void | |
| 9038 | 433 silcgaim_buddy_privkey(GaimConnection *gc, const char *name) |
| 8849 | 434 { |
| 9038 | 435 SilcGaim sg = gc->proto_data; |
| 8849 | 436 char *nickname; |
| 437 SilcGaimPrivkey p; | |
| 438 SilcClientEntry *clients; | |
| 439 SilcUInt32 clients_count; | |
| 440 | |
| 9038 | 441 if (!name) |
| 442 return; | |
| 443 if (!silc_parse_userfqdn(name, &nickname, NULL)) | |
| 8849 | 444 return; |
| 445 | |
| 446 /* Find client entry */ | |
| 447 clients = silc_client_get_clients_local(sg->client, sg->conn, | |
| 9038 | 448 nickname, name, |
| 8849 | 449 &clients_count); |
| 450 if (!clients) { | |
| 451 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, | |
| 452 silcgaim_buddy_privkey_resolved, | |
| 9038 | 453 g_strdup(name)); |
| 8849 | 454 silc_free(nickname); |
| 455 return; | |
| 456 } | |
| 457 | |
| 458 p = silc_calloc(1, sizeof(*p)); | |
| 459 if (!p) | |
| 460 return; | |
| 461 p->client = sg->client; | |
| 462 p->conn = sg->conn; | |
| 463 p->client_id = *clients[0]->id; | |
| 11201 | 464 gaim_request_input(gc, _("IM With Password"), NULL, |
| 8849 | 465 _("Set IM Password"), NULL, FALSE, TRUE, NULL, |
| 466 _("OK"), G_CALLBACK(silcgaim_buddy_privkey_cb), | |
| 467 _("Cancel"), G_CALLBACK(silcgaim_buddy_privkey_cb), | |
| 468 p); | |
| 469 | |
| 470 silc_free(clients); | |
| 471 silc_free(nickname); | |
| 472 } | |
| 473 | |
| 9038 | 474 static void |
| 475 silcgaim_buddy_privkey_menu(GaimBlistNode *node, gpointer data) | |
| 476 { | |
| 477 GaimBuddy *buddy; | |
| 478 GaimConnection *gc; | |
| 479 | |
| 480 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 481 | |
| 482 buddy = (GaimBuddy *) node; | |
| 483 gc = gaim_account_get_connection(buddy->account); | |
| 484 | |
| 485 silcgaim_buddy_privkey(gc, buddy->name); | |
| 486 } | |
| 487 | |
| 8849 | 488 |
| 489 /**************************** Get Public Key *********************************/ | |
| 490 | |
| 491 typedef struct { | |
| 492 SilcClient client; | |
| 493 SilcClientConnection conn; | |
| 494 SilcClientID client_id; | |
| 495 } *SilcGaimBuddyGetkey; | |
| 496 | |
| 497 static void | |
| 498 silcgaim_buddy_getkey(GaimConnection *gc, const char *name); | |
| 499 | |
| 500 static void | |
| 501 silcgaim_buddy_getkey_cb(SilcGaimBuddyGetkey g, | |
| 502 SilcClientCommandReplyContext cmd) | |
| 503 { | |
| 504 SilcClientEntry client_entry; | |
| 505 unsigned char *pk; | |
| 506 SilcUInt32 pk_len; | |
| 507 | |
| 508 /* Get the client entry. */ | |
| 509 client_entry = silc_client_get_client_by_id(g->client, g->conn, | |
| 510 &g->client_id); | |
| 511 if (!client_entry) { | |
| 512 gaim_notify_error(g->client->application, _("Get Public Key"), | |
| 513 _("The remote user is not present in the network any more"), | |
| 514 NULL); | |
| 515 silc_free(g); | |
| 516 return; | |
| 517 } | |
| 518 | |
| 519 if (!client_entry->public_key) { | |
| 520 silc_free(g); | |
| 521 return; | |
| 522 } | |
| 523 | |
| 524 /* Now verify the public key */ | |
| 525 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); | |
| 526 silcgaim_verify_public_key(g->client, g->conn, client_entry->nickname, | |
| 527 SILC_SOCKET_TYPE_CLIENT, | |
| 528 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 529 NULL, NULL); | |
| 530 silc_free(pk); | |
| 531 silc_free(g); | |
| 532 } | |
| 533 | |
| 534 static void | |
| 535 silcgaim_buddy_getkey_resolved(SilcClient client, | |
| 536 SilcClientConnection conn, | |
| 537 SilcClientEntry *clients, | |
| 538 SilcUInt32 clients_count, | |
| 539 void *context) | |
| 540 { | |
| 541 char tmp[256]; | |
| 542 | |
| 543 if (!clients) { | |
| 544 g_snprintf(tmp, sizeof(tmp), | |
| 545 _("User %s is not present in the network"), | |
| 546 (const char *)context); | |
| 547 gaim_notify_error(client->application, _("Get Public Key"), | |
| 548 _("Cannot fetch the public key"), tmp); | |
| 549 g_free(context); | |
| 550 return; | |
| 551 } | |
| 552 | |
| 553 silcgaim_buddy_getkey(client->application, context); | |
| 554 silc_free(context); | |
| 555 } | |
| 556 | |
| 557 static void | |
| 9038 | 558 silcgaim_buddy_getkey(GaimConnection *gc, const char *name) |
| 8849 | 559 { |
| 9038 | 560 SilcGaim sg = gc->proto_data; |
| 561 SilcClient client = sg->client; | |
| 562 SilcClientConnection conn = sg->conn; | |
| 8849 | 563 SilcClientEntry *clients; |
| 564 SilcUInt32 clients_count; | |
| 565 SilcGaimBuddyGetkey g; | |
| 566 char *nickname; | |
| 567 | |
| 9038 | 568 if (!name) |
| 569 return; | |
| 8849 | 570 |
| 9038 | 571 if (!silc_parse_userfqdn(name, &nickname, NULL)) |
| 8849 | 572 return; |
| 573 | |
| 574 /* Find client entry */ | |
| 9038 | 575 clients = silc_client_get_clients_local(client, conn, nickname, name, |
| 576 &clients_count); | |
| 8849 | 577 if (!clients) { |
| 578 silc_client_get_clients(client, conn, nickname, NULL, | |
| 579 silcgaim_buddy_getkey_resolved, | |
| 9038 | 580 g_strdup(name)); |
| 8849 | 581 silc_free(nickname); |
| 582 return; | |
| 583 } | |
| 584 | |
| 585 /* Call GETKEY */ | |
| 586 g = silc_calloc(1, sizeof(*g)); | |
| 587 if (!g) | |
| 588 return; | |
| 589 g->client = client; | |
| 590 g->conn = conn; | |
| 591 g->client_id = *clients[0]->id; | |
| 592 silc_client_command_call(client, conn, NULL, "GETKEY", | |
| 593 clients[0]->nickname, NULL); | |
| 594 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 595 conn->cmd_ident, | |
| 596 (SilcCommandCb)silcgaim_buddy_getkey_cb, g); | |
| 597 silc_free(clients); | |
| 598 silc_free(nickname); | |
| 599 } | |
| 600 | |
| 601 static void | |
| 9038 | 602 silcgaim_buddy_getkey_menu(GaimBlistNode *node, gpointer data) |
| 603 { | |
| 604 GaimBuddy *buddy; | |
| 605 GaimConnection *gc; | |
| 606 | |
| 607 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 608 | |
| 609 buddy = (GaimBuddy *) node; | |
| 610 gc = gaim_account_get_connection(buddy->account); | |
| 611 | |
| 12761 | 612 silcgaim_buddy_getkey(gc, buddy->name); |
| 9038 | 613 } |
| 614 | |
| 615 static void | |
| 9030 | 616 silcgaim_buddy_showkey(GaimBlistNode *node, gpointer data) |
| 8849 | 617 { |
| 9030 | 618 GaimBuddy *b; |
| 619 GaimConnection *gc; | |
| 620 SilcGaim sg; | |
| 8849 | 621 SilcPublicKey public_key; |
| 622 const char *pkfile; | |
| 9030 | 623 |
| 624 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 8849 | 625 |
| 9030 | 626 b = (GaimBuddy *) node; |
| 627 gc = gaim_account_get_connection(b->account); | |
| 628 sg = gc->proto_data; | |
| 8849 | 629 |
| 9038 | 630 pkfile = gaim_blist_node_get_string(node, "public-key"); |
| 8849 | 631 if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && |
| 632 !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { | |
| 633 gaim_notify_error(gc, | |
| 634 _("Show Public Key"), | |
| 635 _("Could not load public key"), NULL); | |
| 636 return; | |
| 637 } | |
| 638 | |
| 9030 | 639 silcgaim_show_public_key(sg, b->name, public_key, NULL, NULL); |
| 8849 | 640 silc_pkcs_public_key_free(public_key); |
| 641 } | |
| 642 | |
| 643 | |
| 644 /**************************** Buddy routines *********************************/ | |
| 645 | |
| 646 /* The buddies are implemented by using the WHOIS and WATCH commands that | |
| 647 can be used to search users by their public key. Since nicknames aren't | |
| 648 unique in SILC we cannot trust the buddy list using their nickname. We | |
| 649 associate public keys to buddies and use those to search and watch | |
| 650 in the network. | |
| 651 | |
| 652 The problem is that Gaim does not return GaimBuddy contexts to the | |
| 653 callbacks but the buddy names. Naturally, this is not going to work | |
| 654 with SILC. But, for now, we have to do what we can... */ | |
| 655 | |
| 656 typedef struct { | |
| 657 SilcClient client; | |
| 658 SilcClientConnection conn; | |
| 659 SilcClientID client_id; | |
| 660 GaimBuddy *b; | |
| 661 unsigned char *offline_pk; | |
| 662 SilcUInt32 offline_pk_len; | |
| 663 unsigned int offline : 1; | |
| 664 unsigned int pubkey_search : 1; | |
| 665 unsigned int init : 1; | |
| 666 } *SilcGaimBuddyRes; | |
| 667 | |
| 668 static void | |
| 669 silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id); | |
| 670 static void | |
| 671 silcgaim_add_buddy_resolved(SilcClient client, | |
| 672 SilcClientConnection conn, | |
| 673 SilcClientEntry *clients, | |
| 674 SilcUInt32 clients_count, | |
| 675 void *context); | |
| 676 | |
| 677 void silcgaim_get_info(GaimConnection *gc, const char *who) | |
| 678 { | |
| 679 SilcGaim sg = gc->proto_data; | |
| 680 SilcClient client = sg->client; | |
| 681 SilcClientConnection conn = sg->conn; | |
| 682 SilcClientEntry client_entry; | |
| 683 GaimBuddy *b; | |
| 684 const char *filename, *nick = who; | |
| 685 char tmp[256]; | |
| 686 | |
| 687 if (!who) | |
| 688 return; | |
| 689 if (strlen(who) > 1 && who[0] == '@') | |
| 690 nick = who + 1; | |
| 691 if (strlen(who) > 1 && who[0] == '*') | |
| 692 nick = who + 1; | |
| 693 if (strlen(who) > 2 && who[0] == '*' && who[1] == '@') | |
| 694 nick = who + 2; | |
| 695 | |
| 696 b = gaim_find_buddy(gc->account, nick); | |
| 697 if (b) { | |
| 698 /* See if we have this buddy's public key. If we do use that | |
| 699 to search the details. */ | |
| 700 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 701 if (filename) { | |
| 702 /* Call WHOIS. The user info is displayed in the WHOIS | |
| 703 command reply. */ | |
| 704 silc_client_command_call(client, conn, NULL, "WHOIS", | |
| 705 "-details", "-pubkey", filename, NULL); | |
| 706 return; | |
| 707 } | |
| 708 | |
| 709 if (!b->proto_data) { | |
| 710 g_snprintf(tmp, sizeof(tmp), | |
| 711 _("User %s is not present in the network"), b->name); | |
| 712 gaim_notify_error(gc, _("User Information"), | |
| 713 _("Cannot get user information"), tmp); | |
| 714 return; | |
| 715 } | |
| 716 | |
| 717 client_entry = silc_client_get_client_by_id(client, conn, b->proto_data); | |
| 718 if (client_entry) { | |
| 719 /* Call WHOIS. The user info is displayed in the WHOIS | |
| 720 command reply. */ | |
| 721 silc_client_command_call(client, conn, NULL, "WHOIS", | |
| 722 client_entry->nickname, "-details", NULL); | |
| 723 } | |
| 724 } else { | |
| 725 /* Call WHOIS just with nickname. */ | |
| 726 silc_client_command_call(client, conn, NULL, "WHOIS", nick, NULL); | |
| 727 } | |
| 728 } | |
| 729 | |
| 730 static void | |
| 731 silcgaim_add_buddy_pk_no(SilcGaimBuddyRes r) | |
| 732 { | |
| 733 char tmp[512]; | |
| 734 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), | |
| 735 r->b->name); | |
| 736 gaim_notify_error(r->client->application, _("Add Buddy"), tmp, | |
| 8910 | 737 _("You cannot receive buddy notifications until you " |
| 738 "import his/her public key. You can use the Get Public Key " | |
| 8849 | 739 "command to get the public key.")); |
| 10050 | 740 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); |
| 8849 | 741 } |
| 742 | |
| 743 static void | |
| 744 silcgaim_add_buddy_save(bool success, void *context) | |
| 745 { | |
| 746 SilcGaimBuddyRes r = context; | |
| 747 GaimBuddy *b = r->b; | |
| 748 SilcClient client = r->client; | |
| 749 SilcClientEntry client_entry; | |
| 750 SilcAttributePayload attr; | |
| 751 SilcAttribute attribute; | |
| 752 SilcVCardStruct vcard; | |
| 753 SilcAttributeObjMime message, extension; | |
| 12761 | 754 #ifdef SILC_ATTRIBUTE_USER_ICON |
| 755 SilcAttributeObjMime usericon; | |
| 756 #endif | |
| 8849 | 757 SilcAttributeObjPk serverpk, usersign, serversign; |
| 758 gboolean usign_success = TRUE, ssign_success = TRUE; | |
| 11165 | 759 char filename[512], filename2[512], *fingerprint = NULL, *tmp; |
| 8849 | 760 SilcUInt32 len; |
| 761 int i; | |
| 762 | |
| 763 if (!success) { | |
| 764 /* The user did not trust the public key. */ | |
| 765 silcgaim_add_buddy_pk_no(r); | |
| 766 silc_free(r); | |
| 767 return; | |
| 768 } | |
| 769 | |
| 770 if (r->offline) { | |
| 771 /* User is offline. Associate the imported public key with | |
| 772 this user. */ | |
| 773 fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, | |
| 774 r->offline_pk_len); | |
| 775 for (i = 0; i < strlen(fingerprint); i++) | |
| 776 if (fingerprint[i] == ' ') | |
| 777 fingerprint[i] = '_'; | |
| 778 g_snprintf(filename, sizeof(filename) - 1, | |
| 779 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 780 silcgaim_silcdir(), fingerprint); | |
| 781 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 10050 | 782 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); |
| 8849 | 783 silc_free(fingerprint); |
| 784 silc_free(r->offline_pk); | |
| 785 silc_free(r); | |
| 786 return; | |
| 787 } | |
| 788 | |
| 789 /* Get the client entry. */ | |
| 790 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 791 &r->client_id); | |
| 792 if (!client_entry) { | |
| 793 silc_free(r); | |
| 794 return; | |
| 795 } | |
| 796 | |
| 797 memset(&vcard, 0, sizeof(vcard)); | |
| 798 memset(&message, 0, sizeof(message)); | |
| 799 memset(&extension, 0, sizeof(extension)); | |
| 12761 | 800 #ifdef SILC_ATTRIBUTE_USER_ICON |
| 801 memset(&usericon, 0, sizeof(usericon)); | |
| 802 #endif | |
| 8849 | 803 memset(&serverpk, 0, sizeof(serverpk)); |
| 804 memset(&usersign, 0, sizeof(usersign)); | |
| 805 memset(&serversign, 0, sizeof(serversign)); | |
| 806 | |
| 807 /* Now that we have the public key and we trust it now we | |
| 808 save the attributes of the buddy and update its status. */ | |
| 809 | |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
810 if (client_entry->attrs) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
811 silc_dlist_start(client_entry->attrs); |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
812 while ((attr = silc_dlist_get(client_entry->attrs)) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
813 != SILC_LIST_END) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
814 attribute = silc_attribute_get_attribute(attr); |
| 8849 | 815 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
816 switch (attribute) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
817 case SILC_ATTRIBUTE_USER_INFO: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
818 if (!silc_attribute_get_object(attr, (void *)&vcard, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
819 sizeof(vcard))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
820 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
821 break; |
| 8849 | 822 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
823 case SILC_ATTRIBUTE_STATUS_MESSAGE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
824 if (!silc_attribute_get_object(attr, (void *)&message, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
825 sizeof(message))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
826 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
827 break; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
828 |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
829 case SILC_ATTRIBUTE_EXTENSION: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
830 if (!silc_attribute_get_object(attr, (void *)&extension, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
831 sizeof(extension))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
832 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
833 break; |
| 8849 | 834 |
| 12761 | 835 #ifdef SILC_ATTRIBUTE_USER_ICON |
| 836 case SILC_ATTRIBUTE_USER_ICON: | |
| 837 if (!silc_attribute_get_object(attr, (void *)&usericon, | |
| 838 sizeof(usericon))) | |
| 839 continue; | |
| 840 break; | |
| 841 #endif | |
| 842 | |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
843 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
844 if (serverpk.type) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
845 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
846 if (!silc_attribute_get_object(attr, (void *)&serverpk, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
847 sizeof(serverpk))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
848 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
849 break; |
| 8849 | 850 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
851 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
852 if (usersign.data) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
853 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
854 if (!silc_attribute_get_object(attr, (void *)&usersign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
855 sizeof(usersign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
856 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
857 break; |
| 8849 | 858 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
859 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
860 if (serversign.data) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
861 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
862 if (!silc_attribute_get_object(attr, (void *)&serversign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
863 sizeof(serversign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
864 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
865 break; |
| 8849 | 866 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
867 default: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
868 break; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
869 } |
| 8849 | 870 } |
| 871 } | |
| 872 | |
| 873 /* Verify the attribute signatures */ | |
| 874 | |
| 875 if (usersign.data) { | |
| 876 SilcPKCS pkcs; | |
| 877 unsigned char *verifyd; | |
| 878 SilcUInt32 verify_len; | |
| 879 | |
| 11488 | 880 silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); |
| 8849 | 881 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 882 FALSE, &verify_len); | |
| 883 if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ | |
| 884 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 885 usersign.data, | |
| 886 usersign.data_len, | |
| 887 verifyd, verify_len)) | |
| 888 usign_success = FALSE; | |
| 889 } | |
| 890 silc_free(verifyd); | |
| 891 } | |
| 892 | |
| 893 if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { | |
| 894 SilcPublicKey public_key; | |
| 895 SilcPKCS pkcs; | |
| 896 unsigned char *verifyd; | |
| 897 SilcUInt32 verify_len; | |
| 898 | |
| 899 if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, | |
| 900 &public_key)) { | |
| 11488 | 901 silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); |
| 8849 | 902 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 903 TRUE, &verify_len); | |
| 904 if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { | |
| 905 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 906 serversign.data, | |
| 907 serversign.data_len, | |
| 908 verifyd, verify_len)) | |
| 909 ssign_success = FALSE; | |
| 910 } | |
| 911 silc_pkcs_public_key_free(public_key); | |
| 912 silc_free(verifyd); | |
| 913 } | |
| 914 } | |
| 915 | |
| 916 fingerprint = silc_fingerprint(client_entry->fingerprint, | |
| 917 client_entry->fingerprint_len); | |
| 918 for (i = 0; i < strlen(fingerprint); i++) | |
| 919 if (fingerprint[i] == ' ') | |
| 920 fingerprint[i] = '_'; | |
| 921 | |
| 922 if (usign_success || ssign_success) { | |
| 923 struct passwd *pw; | |
| 924 struct stat st; | |
| 925 | |
| 926 memset(filename2, 0, sizeof(filename2)); | |
| 927 | |
| 928 /* Filename for dir */ | |
| 929 tmp = fingerprint + strlen(fingerprint) - 9; | |
| 930 g_snprintf(filename, sizeof(filename) - 1, | |
| 931 "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", | |
| 932 silcgaim_silcdir(), tmp); | |
| 933 | |
| 934 pw = getpwuid(getuid()); | |
| 935 if (!pw) | |
| 936 return; | |
| 937 | |
| 938 /* Create dir if it doesn't exist */ | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
939 if ((g_stat(filename, &st)) == -1) { |
| 8849 | 940 if (errno == ENOENT) { |
| 941 if (pw->pw_uid == geteuid()) | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
942 g_mkdir(filename, 0755); |
| 8849 | 943 } |
| 944 } | |
| 945 | |
| 946 /* Save VCard */ | |
| 947 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 948 "%s" G_DIR_SEPARATOR_S "vcard", filename); | |
| 949 if (vcard.full_name) { | |
| 11488 | 950 tmp = (char *)silc_vcard_encode(&vcard, &len); |
| 8849 | 951 silc_file_writefile(filename2, tmp, len); |
| 952 silc_free(tmp); | |
| 953 } | |
| 954 | |
| 955 /* Save status message */ | |
| 956 if (message.mime) { | |
| 957 memset(filename2, 0, sizeof(filename2)); | |
| 958 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 959 "%s" G_DIR_SEPARATOR_S "status_message.mime", | |
| 960 filename); | |
| 11488 | 961 silc_file_writefile(filename2, (char *)message.mime, |
| 8849 | 962 message.mime_len); |
| 963 } | |
| 964 | |
| 965 /* Save extension data */ | |
| 966 if (extension.mime) { | |
| 967 memset(filename2, 0, sizeof(filename2)); | |
| 968 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 969 "%s" G_DIR_SEPARATOR_S "extension.mime", | |
| 970 filename); | |
| 11488 | 971 silc_file_writefile(filename2, (char *)extension.mime, |
| 8849 | 972 extension.mime_len); |
| 973 } | |
| 12761 | 974 |
| 975 #ifdef SILC_ATTRIBUTE_USER_ICON | |
| 976 /* Save user icon */ | |
| 977 if (usericon.mime) { | |
| 978 SilcMime m = silc_mime_decode(usericon.mime, | |
| 979 usericon.mime_len); | |
| 980 if (m) { | |
| 981 const char *type = silc_mime_get_field(m, "Content-Type"); | |
| 982 if (!strcmp(type, "image/jpeg") || | |
| 983 !strcmp(type, "image/gif") || | |
| 984 !strcmp(type, "image/bmp") || | |
| 985 !strcmp(type, "image/png")) { | |
| 986 const unsigned char *data; | |
| 987 SilcUInt32 data_len; | |
| 988 data = silc_mime_get_data(m, &data_len); | |
| 989 if (data) | |
| 990 gaim_buddy_icons_set_for_user(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), (void *)data, data_len); | |
| 991 } | |
| 992 silc_mime_free(m); | |
| 993 } | |
| 994 } | |
| 995 #endif | |
| 8849 | 996 } |
| 997 | |
| 998 /* Save the public key path to buddy properties, as it is used | |
| 999 to identify the buddy in the network (and not the nickname). */ | |
| 1000 memset(filename, 0, sizeof(filename)); | |
| 1001 g_snprintf(filename, sizeof(filename) - 1, | |
| 1002 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 1003 silcgaim_silcdir(), fingerprint); | |
| 1004 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 1005 | |
| 10050 | 1006 /* Update online status */ |
| 11522 | 1007 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_AVAILABLE, NULL); |
| 8849 | 1008 |
| 1009 /* Finally, start watching this user so we receive its status | |
| 1010 changes from the server */ | |
| 1011 g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); | |
| 1012 silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", | |
| 1013 filename2, NULL); | |
| 1014 | |
| 1015 silc_free(fingerprint); | |
| 1016 silc_free(r); | |
| 1017 } | |
| 1018 | |
| 1019 static void | |
| 1020 silcgaim_add_buddy_ask_import(void *user_data, const char *name) | |
| 1021 { | |
| 1022 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 1023 SilcPublicKey public_key; | |
| 1024 | |
| 1025 /* Load the public key */ | |
| 1026 if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && | |
| 1027 !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { | |
| 1028 silcgaim_add_buddy_ask_pk_cb(r, 0); | |
| 1029 gaim_notify_error(r->client->application, | |
| 1030 _("Add Buddy"), _("Could not load public key"), NULL); | |
| 1031 return; | |
| 1032 } | |
| 1033 | |
| 1034 /* Now verify the public key */ | |
| 1035 r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); | |
| 1036 silcgaim_verify_public_key(r->client, r->conn, r->b->name, | |
| 1037 SILC_SOCKET_TYPE_CLIENT, | |
| 1038 r->offline_pk, r->offline_pk_len, | |
| 1039 SILC_SKE_PK_TYPE_SILC, | |
| 1040 silcgaim_add_buddy_save, r); | |
| 1041 } | |
| 1042 | |
| 1043 static void | |
| 1044 silcgaim_add_buddy_ask_pk_cancel(void *user_data, const char *name) | |
| 1045 { | |
| 1046 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 1047 | |
| 1048 /* The user did not import public key. The buddy is unusable. */ | |
| 1049 silcgaim_add_buddy_pk_no(r); | |
| 1050 silc_free(r); | |
| 1051 } | |
| 1052 | |
| 1053 static void | |
| 1054 silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id) | |
| 1055 { | |
| 1056 if (id != 0) { | |
| 1057 /* The user did not import public key. The buddy is unusable. */ | |
| 1058 silcgaim_add_buddy_pk_no(r); | |
| 1059 silc_free(r); | |
| 1060 return; | |
| 1061 } | |
| 1062 | |
| 1063 /* Open file selector to select the public key. */ | |
| 11201 | 1064 gaim_request_file(r->client->application, _("Open..."), NULL, FALSE, |
| 8849 | 1065 G_CALLBACK(silcgaim_add_buddy_ask_import), |
| 1066 G_CALLBACK(silcgaim_add_buddy_ask_pk_cancel), r); | |
| 1067 } | |
| 1068 | |
| 1069 static void | |
| 1070 silcgaim_add_buddy_ask_pk(SilcGaimBuddyRes r) | |
| 1071 { | |
| 1072 char tmp[512]; | |
| 1073 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), | |
| 1074 r->b->name); | |
| 11201 | 1075 gaim_request_action(r->client->application, _("Add Buddy"), tmp, |
| 8910 | 1076 _("To add the buddy you must import his/her public key. " |
| 8849 | 1077 "Press Import to import a public key."), 0, r, 2, |
| 1078 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb), | |
|
12603
e4e47871c373
[gaim-migrate @ 14938]
Richard Laager <rlaager@wiktel.com>
parents:
12167
diff
changeset
|
1079 _("_Import..."), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb)); |
| 8849 | 1080 } |
| 1081 | |
| 1082 static void | |
| 1083 silcgaim_add_buddy_getkey_cb(SilcGaimBuddyRes r, | |
| 1084 SilcClientCommandReplyContext cmd) | |
| 1085 { | |
| 1086 SilcClientEntry client_entry; | |
| 1087 unsigned char *pk; | |
| 1088 SilcUInt32 pk_len; | |
| 1089 | |
| 1090 /* Get the client entry. */ | |
| 1091 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 1092 &r->client_id); | |
| 1093 if (!client_entry || !client_entry->public_key) { | |
| 1094 /* The buddy is offline/nonexistent. We will require user | |
| 1095 to associate a public key with the buddy or the buddy | |
| 1096 cannot be added. */ | |
| 1097 r->offline = TRUE; | |
| 1098 silcgaim_add_buddy_ask_pk(r); | |
| 1099 return; | |
| 1100 } | |
| 1101 | |
| 1102 /* Now verify the public key */ | |
| 1103 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); | |
| 1104 silcgaim_verify_public_key(r->client, r->conn, client_entry->nickname, | |
| 1105 SILC_SOCKET_TYPE_CLIENT, | |
| 1106 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1107 silcgaim_add_buddy_save, r); | |
| 1108 silc_free(pk); | |
| 1109 } | |
| 1110 | |
| 1111 static void | |
| 1112 silcgaim_add_buddy_select_cb(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1113 { | |
| 1114 GaimRequestField *f; | |
| 1115 const GList *list; | |
| 1116 SilcClientEntry client_entry; | |
| 1117 | |
| 1118 f = gaim_request_fields_get_field(fields, "list"); | |
| 1119 list = gaim_request_field_list_get_selected(f); | |
| 1120 if (!list) { | |
| 1121 /* The user did not select any user. */ | |
| 1122 silcgaim_add_buddy_pk_no(r); | |
| 1123 silc_free(r); | |
| 1124 return; | |
| 1125 } | |
| 1126 | |
| 1127 client_entry = gaim_request_field_list_get_data(f, list->data); | |
| 1128 silcgaim_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); | |
| 1129 } | |
| 1130 | |
| 1131 static void | |
| 1132 silcgaim_add_buddy_select_cancel(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1133 { | |
| 1134 /* The user did not select any user. */ | |
| 1135 silcgaim_add_buddy_pk_no(r); | |
| 1136 silc_free(r); | |
| 1137 } | |
| 1138 | |
| 1139 static void | |
| 1140 silcgaim_add_buddy_select(SilcGaimBuddyRes r, | |
| 1141 SilcClientEntry *clients, | |
| 1142 SilcUInt32 clients_count) | |
| 1143 { | |
| 1144 GaimRequestFields *fields; | |
| 1145 GaimRequestFieldGroup *g; | |
| 1146 GaimRequestField *f; | |
| 12167 | 1147 char tmp[512], tmp2[128]; |
| 8849 | 1148 int i; |
| 12167 | 1149 char *fingerprint; |
| 8849 | 1150 |
| 1151 fields = gaim_request_fields_new(); | |
| 1152 g = gaim_request_field_group_new(NULL); | |
| 1153 f = gaim_request_field_list_new("list", NULL); | |
| 1154 gaim_request_field_group_add_field(g, f); | |
| 1155 gaim_request_field_list_set_multi_select(f, FALSE); | |
| 1156 gaim_request_fields_add_group(fields, g); | |
| 1157 | |
| 1158 for (i = 0; i < clients_count; i++) { | |
| 12167 | 1159 fingerprint = NULL; |
| 1160 if (clients[i]->fingerprint) { | |
| 1161 fingerprint = silc_fingerprint(clients[i]->fingerprint, | |
| 1162 clients[i]->fingerprint_len); | |
| 1163 g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); | |
| 1164 } | |
| 1165 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", | |
| 8849 | 1166 clients[i]->realname, clients[i]->nickname, |
| 1167 clients[i]->username, clients[i]->hostname ? | |
| 12167 | 1168 clients[i]->hostname : "", |
| 1169 fingerprint ? tmp2 : ""); | |
| 8849 | 1170 gaim_request_field_list_add(f, tmp, clients[i]); |
| 12167 | 1171 silc_free(fingerprint); |
| 8849 | 1172 } |
| 1173 | |
| 11201 | 1174 gaim_request_fields(r->client->application, _("Add Buddy"), |
| 8891 | 1175 _("Select correct user"), |
| 1176 r->pubkey_search | |
| 1177 ? _("More than one user was found with the same public key. Select " | |
| 1178 "the correct user from the list to add to the buddy list.") | |
| 1179 : _("More than one user was found with the same name. Select " | |
| 1180 "the correct user from the list to add to the buddy list."), | |
| 1181 fields, | |
| 1182 _("OK"), G_CALLBACK(silcgaim_add_buddy_select_cb), | |
| 1183 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_select_cancel), r); | |
| 8849 | 1184 } |
| 1185 | |
| 1186 static void | |
| 1187 silcgaim_add_buddy_resolved(SilcClient client, | |
| 1188 SilcClientConnection conn, | |
| 1189 SilcClientEntry *clients, | |
| 1190 SilcUInt32 clients_count, | |
| 1191 void *context) | |
| 1192 { | |
| 1193 SilcGaimBuddyRes r = context; | |
| 1194 GaimBuddy *b = r->b; | |
| 1195 SilcAttributePayload pub; | |
| 1196 SilcAttributeObjPk userpk; | |
| 1197 unsigned char *pk; | |
| 1198 SilcUInt32 pk_len; | |
| 1199 const char *filename; | |
| 1200 | |
| 10029 | 1201 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); |
| 1202 | |
| 8849 | 1203 /* If the buddy is offline/nonexistent, we will require user |
| 1204 to associate a public key with the buddy or the buddy | |
| 1205 cannot be added. */ | |
| 1206 if (!clients_count) { | |
| 1207 if (r->init) { | |
| 1208 silc_free(r); | |
| 1209 return; | |
| 1210 } | |
| 1211 | |
| 1212 r->offline = TRUE; | |
| 10029 | 1213 /* If the user has already associated a public key, try loading it |
| 1214 * before prompting the user to load it again */ | |
| 1215 if (filename != NULL) | |
| 1216 silcgaim_add_buddy_ask_import(r, filename); | |
| 1217 else | |
| 1218 silcgaim_add_buddy_ask_pk(r); | |
| 8849 | 1219 return; |
| 1220 } | |
| 1221 | |
| 1222 /* If more than one client was found with nickname, we need to verify | |
| 1223 from user which one is the correct. */ | |
| 1224 if (clients_count > 1 && !r->pubkey_search) { | |
| 1225 if (r->init) { | |
| 1226 silc_free(r); | |
| 1227 return; | |
| 1228 } | |
| 1229 | |
| 1230 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1231 return; | |
| 1232 } | |
| 1233 | |
| 1234 /* If we searched using public keys and more than one entry was found | |
| 1235 the same person is logged on multiple times. */ | |
| 1236 if (clients_count > 1 && r->pubkey_search && b->name) { | |
| 1237 if (r->init) { | |
| 1238 /* Find the entry that closest matches to the | |
| 1239 buddy nickname. */ | |
| 1240 int i; | |
| 1241 for (i = 0; i < clients_count; i++) { | |
| 1242 if (!strncasecmp(b->name, clients[i]->nickname, | |
| 1243 strlen(b->name))) { | |
| 1244 clients[0] = clients[i]; | |
| 1245 break; | |
| 1246 } | |
| 1247 } | |
| 1248 } else { | |
| 1249 /* Verify from user which one is correct */ | |
| 1250 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1251 return; | |
| 1252 } | |
| 1253 } | |
| 1254 | |
| 1255 /* The client was found. Now get its public key and verify | |
| 1256 that before adding the buddy. */ | |
| 1257 memset(&userpk, 0, sizeof(userpk)); | |
| 1258 b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); | |
| 1259 r->client_id = *clients[0]->id; | |
| 1260 | |
| 1261 /* Get the public key from attributes, if not present then | |
| 1262 resolve it with GETKEY unless we have it cached already. */ | |
| 1263 if (clients[0]->attrs && !clients[0]->public_key) { | |
| 1264 pub = silcgaim_get_attr(clients[0]->attrs, | |
| 1265 SILC_ATTRIBUTE_USER_PUBLIC_KEY); | |
| 1266 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, | |
| 1267 sizeof(userpk))) { | |
| 1268 /* Get public key with GETKEY */ | |
| 1269 silc_client_command_call(client, conn, NULL, | |
| 1270 "GETKEY", clients[0]->nickname, NULL); | |
| 1271 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1272 conn->cmd_ident, | |
| 1273 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1274 r); | |
| 1275 return; | |
| 1276 } | |
| 1277 if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, | |
| 1278 &clients[0]->public_key)) | |
| 1279 return; | |
| 1280 silc_free(userpk.data); | |
| 1281 } else if (filename && !clients[0]->public_key) { | |
| 1282 if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1283 SILC_PKCS_FILE_PEM) && | |
| 1284 !silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1285 SILC_PKCS_FILE_BIN)) { | |
| 1286 /* Get public key with GETKEY */ | |
| 1287 silc_client_command_call(client, conn, NULL, | |
| 1288 "GETKEY", clients[0]->nickname, NULL); | |
| 1289 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1290 conn->cmd_ident, | |
| 1291 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1292 r); | |
| 1293 return; | |
| 1294 } | |
| 1295 } else if (!clients[0]->public_key) { | |
| 1296 /* Get public key with GETKEY */ | |
| 1297 silc_client_command_call(client, conn, NULL, | |
| 1298 "GETKEY", clients[0]->nickname, NULL); | |
| 1299 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1300 conn->cmd_ident, | |
| 1301 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1302 r); | |
| 1303 return; | |
| 1304 } | |
| 1305 | |
| 1306 /* We have the public key, verify it. */ | |
| 1307 pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); | |
| 1308 silcgaim_verify_public_key(client, conn, clients[0]->nickname, | |
| 1309 SILC_SOCKET_TYPE_CLIENT, | |
| 1310 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1311 silcgaim_add_buddy_save, r); | |
| 1312 silc_free(pk); | |
| 1313 } | |
| 1314 | |
| 1315 static void | |
| 1316 silcgaim_add_buddy_i(GaimConnection *gc, GaimBuddy *b, gboolean init) | |
| 1317 { | |
| 1318 SilcGaim sg = gc->proto_data; | |
| 1319 SilcClient client = sg->client; | |
| 1320 SilcClientConnection conn = sg->conn; | |
| 1321 SilcGaimBuddyRes r; | |
| 1322 SilcBuffer attrs; | |
| 1323 const char *filename, *name = b->name; | |
| 1324 | |
| 1325 r = silc_calloc(1, sizeof(*r)); | |
| 1326 if (!r) | |
| 1327 return; | |
| 1328 r->client = client; | |
| 1329 r->conn = conn; | |
| 1330 r->b = b; | |
| 1331 r->init = init; | |
| 1332 | |
| 1333 /* See if we have this buddy's public key. If we do use that | |
| 1334 to search the details. */ | |
| 1335 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 1336 if (filename) { | |
| 1337 SilcPublicKey public_key; | |
| 1338 SilcAttributeObjPk userpk; | |
| 1339 | |
| 1340 if (!silc_pkcs_load_public_key(filename, &public_key, | |
| 1341 SILC_PKCS_FILE_PEM) && | |
| 1342 !silc_pkcs_load_public_key(filename, &public_key, | |
| 1343 SILC_PKCS_FILE_BIN)) | |
| 1344 return; | |
| 1345 | |
| 1346 /* Get all attributes, and use the public key to search user */ | |
| 1347 name = NULL; | |
| 1348 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, | |
| 1349 SILC_ATTRIBUTE_SERVICE, | |
| 1350 SILC_ATTRIBUTE_STATUS_MOOD, | |
| 1351 SILC_ATTRIBUTE_STATUS_FREETEXT, | |
| 1352 SILC_ATTRIBUTE_STATUS_MESSAGE, | |
| 1353 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, | |
| 1354 SILC_ATTRIBUTE_PREFERRED_CONTACT, | |
| 1355 SILC_ATTRIBUTE_TIMEZONE, | |
| 1356 SILC_ATTRIBUTE_GEOLOCATION, | |
| 12761 | 1357 #ifdef SILC_ATTRIBUTE_USER_ICON |
| 1358 SILC_ATTRIBUTE_USER_ICON, | |
| 1359 #endif | |
| 8849 | 1360 SILC_ATTRIBUTE_DEVICE_INFO, 0); |
| 1361 userpk.type = "silc-rsa"; | |
| 1362 userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); | |
| 1363 attrs = silc_attribute_payload_encode(attrs, | |
| 1364 SILC_ATTRIBUTE_USER_PUBLIC_KEY, | |
| 1365 SILC_ATTRIBUTE_FLAG_VALID, | |
| 1366 &userpk, sizeof(userpk)); | |
| 1367 silc_free(userpk.data); | |
| 1368 silc_pkcs_public_key_free(public_key); | |
| 1369 r->pubkey_search = TRUE; | |
| 1370 } else { | |
| 1371 /* Get all attributes */ | |
| 1372 attrs = silc_client_attributes_request(0); | |
| 1373 } | |
| 1374 | |
| 1375 /* Resolve */ | |
| 1376 silc_client_get_clients_whois(client, conn, name, NULL, attrs, | |
| 1377 silcgaim_add_buddy_resolved, r); | |
| 1378 silc_buffer_free(attrs); | |
| 1379 } | |
| 1380 | |
| 9285 | 1381 void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
| 8849 | 1382 { |
| 9285 | 1383 silcgaim_add_buddy_i(gc, buddy, FALSE); |
| 8849 | 1384 } |
| 1385 | |
| 10869 | 1386 void silcgaim_send_buddylist(GaimConnection *gc) |
| 10341 | 1387 { |
| 10869 | 1388 GaimBuddyList *blist; |
| 1389 GaimBlistNode *gnode, *cnode, *bnode; | |
| 1390 GaimBuddy *buddy; | |
| 12111 | 1391 GaimAccount *account; |
| 1392 | |
| 1393 account = gaim_connection_get_account(gc); | |
| 10869 | 1394 |
| 1395 if ((blist = gaim_get_blist()) != NULL) | |
| 1396 { | |
| 1397 for (gnode = blist->root; gnode != NULL; gnode = gnode->next) | |
| 1398 { | |
| 1399 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 1400 continue; | |
| 1401 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) | |
| 1402 { | |
| 1403 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 1404 continue; | |
| 1405 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) | |
| 1406 { | |
| 1407 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 1408 continue; | |
| 1409 buddy = (GaimBuddy *)bnode; | |
| 12111 | 1410 if (gaim_buddy_get_account(buddy) == account) |
| 1411 silcgaim_add_buddy_i(gc, buddy, TRUE); | |
| 10869 | 1412 } |
| 1413 } | |
| 1414 } | |
| 10341 | 1415 } |
| 1416 } | |
| 1417 | |
| 9285 | 1418 void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
| 1419 GaimGroup *group) | |
| 8849 | 1420 { |
| 9285 | 1421 silc_free(buddy->proto_data); |
| 8849 | 1422 } |
| 1423 | |
| 1424 void silcgaim_idle_set(GaimConnection *gc, int idle) | |
| 1425 | |
| 1426 { | |
| 1427 SilcGaim sg = gc->proto_data; | |
| 1428 SilcClient client = sg->client; | |
| 1429 SilcClientConnection conn = sg->conn; | |
| 1430 SilcAttributeObjService service; | |
| 1431 const char *server; | |
| 1432 int port; | |
| 1433 | |
| 1434 server = gaim_account_get_string(sg->account, "server", | |
| 1435 "silc.silcnet.org"); | |
| 1436 port = gaim_account_get_int(sg->account, "port", 706), | |
| 1437 | |
| 1438 memset(&service, 0, sizeof(service)); | |
| 1439 silc_client_attribute_del(client, conn, | |
| 1440 SILC_ATTRIBUTE_SERVICE, NULL); | |
| 1441 service.port = port; | |
| 1442 g_snprintf(service.address, sizeof(service.address), "%s", server); | |
| 1443 service.idle = idle; | |
| 1444 silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, | |
| 1445 &service, sizeof(service)); | |
| 1446 } | |
| 1447 | |
| 1448 char *silcgaim_status_text(GaimBuddy *b) | |
| 1449 { | |
| 1450 SilcGaim sg = b->account->gc->proto_data; | |
| 1451 SilcClient client = sg->client; | |
| 1452 SilcClientConnection conn = sg->conn; | |
| 1453 SilcClientID *client_id = b->proto_data; | |
| 1454 SilcClientEntry client_entry; | |
| 1455 SilcAttributePayload attr; | |
| 1456 SilcAttributeMood mood = 0; | |
| 1457 | |
| 1458 /* Get the client entry. */ | |
| 1459 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1460 if (!client_entry) | |
| 1461 return NULL; | |
| 1462 | |
| 1463 /* If user is online, we show the mood status, if available. | |
| 1464 If user is offline or away that status is indicated. */ | |
| 1465 | |
| 1466 if (client_entry->mode & SILC_UMODE_DETACHED) | |
| 1467 return g_strdup(_("Detached")); | |
| 1468 if (client_entry->mode & SILC_UMODE_GONE) | |
| 1469 return g_strdup(_("Away")); | |
| 1470 if (client_entry->mode & SILC_UMODE_INDISPOSED) | |
| 1471 return g_strdup(_("Indisposed")); | |
| 1472 if (client_entry->mode & SILC_UMODE_BUSY) | |
| 1473 return g_strdup(_("Busy")); | |
| 1474 if (client_entry->mode & SILC_UMODE_PAGE) | |
| 1475 return g_strdup(_("Wake Me Up")); | |
| 1476 if (client_entry->mode & SILC_UMODE_HYPER) | |
| 1477 return g_strdup(_("Hyper Active")); | |
| 1478 if (client_entry->mode & SILC_UMODE_ROBOT) | |
| 1479 return g_strdup(_("Robot")); | |
| 1480 | |
| 1481 attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); | |
| 1482 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { | |
| 1483 /* The mood is a bit mask, so we could show multiple moods, | |
| 1484 but let's show only one for now. */ | |
| 1485 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) | |
| 1486 return g_strdup(_("Happy")); | |
| 1487 if (mood & SILC_ATTRIBUTE_MOOD_SAD) | |
| 1488 return g_strdup(_("Sad")); | |
| 1489 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) | |
| 1490 return g_strdup(_("Angry")); | |
| 1491 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) | |
| 1492 return g_strdup(_("Jealous")); | |
| 1493 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) | |
| 1494 return g_strdup(_("Ashamed")); | |
| 1495 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) | |
| 1496 return g_strdup(_("Invincible")); | |
| 1497 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) | |
| 1498 return g_strdup(_("In Love")); | |
| 1499 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) | |
| 1500 return g_strdup(_("Sleepy")); | |
| 1501 if (mood & SILC_ATTRIBUTE_MOOD_BORED) | |
| 1502 return g_strdup(_("Bored")); | |
| 1503 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) | |
| 1504 return g_strdup(_("Excited")); | |
| 1505 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) | |
| 1506 return g_strdup(_("Anxious")); | |
| 1507 } | |
| 1508 | |
| 1509 return NULL; | |
| 1510 } | |
| 1511 | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1512 void silcgaim_tooltip_text(GaimBuddy *b, GString *str, gboolean full) |
| 8849 | 1513 { |
| 1514 SilcGaim sg = b->account->gc->proto_data; | |
| 1515 SilcClient client = sg->client; | |
| 1516 SilcClientConnection conn = sg->conn; | |
| 1517 SilcClientID *client_id = b->proto_data; | |
| 1518 SilcClientEntry client_entry; | |
| 9488 | 1519 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; |
| 8849 | 1520 char tmp[256]; |
| 1521 | |
| 1522 /* Get the client entry. */ | |
| 1523 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1524 if (!client_entry) | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1525 return; |
| 8849 | 1526 |
| 1527 if (client_entry->nickname) | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1528 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Nickname"), |
| 8849 | 1529 client_entry->nickname); |
| 1530 if (client_entry->username && client_entry->hostname) | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1531 g_string_append_printf(str, "\n<b>%s:</b> %s@%s", _("Username"), |
| 8849 | 1532 client_entry->username, client_entry->hostname); |
| 1533 if (client_entry->mode) { | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1534 g_string_append_printf(str, "\n<b>%s:</b> ", _("User Modes")); |
| 8849 | 1535 memset(tmp, 0, sizeof(tmp)); |
| 1536 silcgaim_get_umode_string(client_entry->mode, | |
| 1537 tmp, sizeof(tmp) - strlen(tmp)); | |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1538 g_string_append_printf(str, "%s", tmp); |
| 8849 | 1539 } |
| 1540 | |
| 9488 | 1541 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1542 |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1543 if (statusstr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1544 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Message"), statusstr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1545 g_free(statusstr); |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1546 } |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1547 |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1548 if (full) { |
| 9488 | 1549 if (moodstr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1550 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Mood"), moodstr); |
| 9488 | 1551 g_free(moodstr); |
| 1552 } | |
| 8849 | 1553 |
| 9488 | 1554 if (contactstr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1555 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr); |
| 9488 | 1556 g_free(contactstr); |
| 1557 } | |
| 8849 | 1558 |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1559 if (langstr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1560 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Preferred Language"), langstr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1561 g_free(langstr); |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1562 } |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1563 |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1564 if (devicestr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1565 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Device"), devicestr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1566 g_free(devicestr); |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1567 } |
| 8849 | 1568 |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1569 if (tzstr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1570 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Timezone"), tzstr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1571 g_free(tzstr); |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1572 } |
| 8849 | 1573 |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1574 if (geostr) { |
|
12970
ec9b92104904
[gaim-migrate @ 15323]
Richard Laager <rlaager@wiktel.com>
parents:
12948
diff
changeset
|
1575 g_string_append_printf(str, "\n<b>%s:</b> %s", _("Geolocation"), geostr); |
|
12948
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1576 g_free(geostr); |
|
563fb4f1e9fc
[gaim-migrate @ 15301]
Richard Laager <rlaager@wiktel.com>
parents:
12947
diff
changeset
|
1577 } |
| 9488 | 1578 } |
| 8849 | 1579 } |
| 1580 | |
| 1581 static void | |
| 9038 | 1582 silcgaim_buddy_kill(GaimBlistNode *node, gpointer data) |
| 8849 | 1583 { |
| 9030 | 1584 GaimBuddy *b; |
| 1585 GaimConnection *gc; | |
| 1586 SilcGaim sg; | |
| 1587 | |
| 1588 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 1589 | |
| 1590 b = (GaimBuddy *) node; | |
| 1591 gc = gaim_account_get_connection(b->account); | |
| 1592 sg = gc->proto_data; | |
| 8849 | 1593 |
| 1594 /* Call KILL */ | |
| 9030 | 1595 silc_client_command_call(sg->client, sg->conn, NULL, "KILL", |
| 1596 b->name, "Killed by operator", NULL); | |
| 8849 | 1597 } |
| 1598 | |
| 12058 | 1599 typedef struct { |
| 1600 SilcGaim sg; | |
| 1601 SilcClientEntry client_entry; | |
| 1602 } *SilcGaimBuddyWb; | |
| 1603 | |
| 1604 static void | |
| 1605 silcgaim_buddy_wb(GaimBlistNode *node, gpointer data) | |
| 1606 { | |
| 1607 SilcGaimBuddyWb wb = data; | |
| 1608 silcgaim_wb_init(wb->sg, wb->client_entry); | |
| 1609 silc_free(wb); | |
| 1610 } | |
| 1611 | |
| 9030 | 1612 GList *silcgaim_buddy_menu(GaimBuddy *buddy) |
| 8849 | 1613 { |
| 9030 | 1614 GaimConnection *gc = gaim_account_get_connection(buddy->account); |
| 8849 | 1615 SilcGaim sg = gc->proto_data; |
| 1616 SilcClientConnection conn = sg->conn; | |
| 1617 const char *pkfile = NULL; | |
| 1618 SilcClientEntry client_entry = NULL; | |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1619 GaimMenuAction *act; |
| 9030 | 1620 GList *m = NULL; |
| 12058 | 1621 SilcGaimBuddyWb wb; |
| 8849 | 1622 |
| 9038 | 1623 pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); |
| 9030 | 1624 client_entry = silc_client_get_client_by_id(sg->client, |
| 1625 sg->conn, | |
| 9038 | 1626 buddy->proto_data); |
| 8849 | 1627 |
| 1628 if (client_entry && client_entry->send_key) { | |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1629 act = gaim_menu_action_new(_("Reset IM Key"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1630 GAIM_CALLBACK(silcgaim_buddy_resetkey), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1631 NULL, NULL); |
| 9030 | 1632 m = g_list_append(m, act); |
| 1633 | |
| 8849 | 1634 } else { |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1635 act = gaim_menu_action_new(_("IM with Key Exchange"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1636 GAIM_CALLBACK(silcgaim_buddy_keyagr), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1637 NULL, NULL); |
| 9030 | 1638 m = g_list_append(m, act); |
| 8849 | 1639 |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1640 act = gaim_menu_action_new(_("IM with Password"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1641 GAIM_CALLBACK(silcgaim_buddy_privkey_menu), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1642 NULL, NULL); |
| 9030 | 1643 m = g_list_append(m, act); |
| 8849 | 1644 } |
| 1645 | |
| 1646 if (pkfile) { | |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1647 act = gaim_menu_action_new(_("Show Public Key"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1648 GAIM_CALLBACK(silcgaim_buddy_showkey), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1649 NULL, NULL); |
| 9030 | 1650 m = g_list_append(m, act); |
| 1651 | |
| 8849 | 1652 } else { |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1653 act = gaim_menu_action_new(_("Get Public Key..."), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1654 GAIM_CALLBACK(silcgaim_buddy_getkey_menu), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1655 NULL, NULL); |
| 9030 | 1656 m = g_list_append(m, act); |
| 8849 | 1657 } |
| 1658 | |
| 1659 if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { | |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1660 act = gaim_menu_action_new(_("Kill User"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1661 GAIM_CALLBACK(silcgaim_buddy_kill), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1662 NULL, NULL); |
| 9030 | 1663 m = g_list_append(m, act); |
| 8849 | 1664 } |
| 1665 | |
| 12167 | 1666 if (client_entry) { |
| 1667 wb = silc_calloc(1, sizeof(*wb)); | |
| 1668 wb->sg = sg; | |
| 1669 wb->client_entry = client_entry; | |
|
12919
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1670 act = gaim_menu_action_new(_("Draw On Whiteboard"), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1671 GAIM_CALLBACK(silcgaim_buddy_wb), |
|
248b8b39c671
[gaim-migrate @ 15272]
Etan Reisner <pidgin@unreliablesource.net>
parents:
12761
diff
changeset
|
1672 (void *)wb, NULL); |
| 12167 | 1673 m = g_list_append(m, act); |
| 1674 } | |
| 8849 | 1675 return m; |
| 1676 } | |
| 12761 | 1677 |
| 1678 #ifdef SILC_ATTRIBUTE_USER_ICON | |
| 1679 void silcgaim_buddy_set_icon(GaimConnection *gc, const char *iconfile) | |
| 1680 { | |
| 1681 SilcGaim sg = gc->proto_data; | |
| 1682 SilcClient client = sg->client; | |
| 1683 SilcClientConnection conn = sg->conn; | |
| 1684 SilcMime mime; | |
| 1685 GaimBuddyIcon ic; | |
| 1686 char type[32]; | |
| 1687 unsigned char *icon; | |
| 1688 const char *t; | |
| 1689 struct stat st; | |
| 1690 FILE *fp; | |
| 1691 SilcAttributeObjMime obj; | |
| 1692 | |
| 1693 /* Remove */ | |
| 1694 if (!iconfile) { | |
| 1695 silc_client_attribute_del(client, conn, | |
| 1696 SILC_ATTRIBUTE_USER_ICON, NULL); | |
| 1697 return; | |
| 1698 } | |
| 1699 | |
| 1700 /* Add */ | |
| 1701 if (g_stat(iconfile, &st) < 0) | |
| 1702 return; | |
| 1703 fp = g_fopen(iconfile, "rb"); | |
| 1704 if (!fp) | |
| 1705 return; | |
| 1706 ic.data = g_malloc(st.st_size); | |
| 1707 if (!ic.data) | |
| 1708 return; | |
| 1709 ic.len = fread(ic.data, 1, st.st_size, fp); | |
| 1710 fclose(fp); | |
| 1711 | |
| 1712 mime = silc_mime_alloc(); | |
| 1713 if (!mime) { | |
| 1714 g_free(ic.data); | |
| 1715 return; | |
| 1716 } | |
| 1717 | |
| 1718 t = gaim_buddy_icon_get_type((const GaimBuddyIcon *)&ic); | |
| 1719 if (!t) { | |
| 1720 g_free(ic.data); | |
| 1721 silc_mime_free(mime); | |
| 1722 return; | |
| 1723 } | |
| 1724 if (!strcmp(t, "jpg")) | |
| 1725 t = "jpeg"; | |
| 1726 g_snprintf(type, sizeof(type), "image/%s", t); | |
| 1727 silc_mime_add_field(mime, "Content-Type", type); | |
| 1728 silc_mime_add_data(mime, ic.data, ic.len); | |
| 1729 | |
| 1730 obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); | |
| 1731 if (obj.mime) | |
| 1732 silc_client_attribute_add(client, conn, | |
| 1733 SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj)); | |
| 1734 | |
| 1735 silc_free(icon); | |
| 1736 g_free(ic.data); | |
| 1737 silc_mime_free(mime); | |
| 1738 } | |
| 1739 #endif |
