Mercurial > pidgin
annotate src/protocols/silc/buddy.c @ 11986:bfbb1798535e
[gaim-migrate @ 14279]
Switch to using the unicode character 0x25cf instead of an asterisk as
our password masking character.
In the words of the great Christian Hammond, "By the way, isn't it
about time we replace the asterisk in masked entries with that unicode
character for the round filled circle ("?")? The asterisk is so 1980s."
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Sat, 05 Nov 2005 23:42:35 +0000 |
| parents | 03cd74ca2562 |
| children | d5daff460913 |
| 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" | |
| 23 | |
| 24 /***************************** Key Agreement *********************************/ | |
| 25 | |
| 26 static void | |
| 9060 | 27 silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data); |
| 28 | |
| 29 static void | |
| 30 silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, | |
| 31 gboolean force_local); | |
| 8849 | 32 |
| 33 typedef struct { | |
| 34 char *nick; | |
| 35 GaimConnection *gc; | |
| 36 } *SilcGaimResolve; | |
| 37 | |
| 38 static void | |
| 39 silcgaim_buddy_keyagr_resolved(SilcClient client, | |
| 40 SilcClientConnection conn, | |
| 41 SilcClientEntry *clients, | |
| 42 SilcUInt32 clients_count, | |
| 43 void *context) | |
| 44 { | |
| 45 GaimConnection *gc = client->application; | |
| 46 SilcGaimResolve r = context; | |
| 47 char tmp[256]; | |
| 48 | |
| 49 if (!clients) { | |
| 50 g_snprintf(tmp, sizeof(tmp), | |
| 51 _("User %s is not present in the network"), r->nick); | |
| 52 gaim_notify_error(gc, _("Key Agreement"), | |
| 53 _("Cannot perform the key agreement"), tmp); | |
| 54 silc_free(r->nick); | |
| 55 silc_free(r); | |
| 56 return; | |
| 57 } | |
| 58 | |
| 9060 | 59 silcgaim_buddy_keyagr_do(gc, r->nick, FALSE); |
| 8849 | 60 silc_free(r->nick); |
| 61 silc_free(r); | |
| 62 } | |
| 63 | |
| 64 typedef struct { | |
| 65 gboolean responder; | |
| 66 } *SilcGaimKeyAgr; | |
| 67 | |
| 68 static void | |
| 69 silcgaim_buddy_keyagr_cb(SilcClient client, | |
| 70 SilcClientConnection conn, | |
| 71 SilcClientEntry client_entry, | |
| 72 SilcKeyAgreementStatus status, | |
| 73 SilcSKEKeyMaterial *key, | |
| 74 void *context) | |
| 75 { | |
| 76 GaimConnection *gc = client->application; | |
| 77 SilcGaim sg = gc->proto_data; | |
| 78 SilcGaimKeyAgr a = context; | |
| 79 | |
| 80 if (!sg->conn) | |
| 81 return; | |
| 82 | |
| 83 switch (status) { | |
| 84 case SILC_KEY_AGREEMENT_OK: | |
| 85 { | |
| 86 GaimConversation *convo; | |
| 87 char tmp[128]; | |
| 88 | |
| 89 /* Set the private key for this client */ | |
| 90 silc_client_del_private_message_key(client, conn, client_entry); | |
| 91 silc_client_add_private_message_key_ske(client, conn, client_entry, | |
| 92 NULL, NULL, key, a->responder); | |
| 93 silc_ske_free_key_material(key); | |
| 94 | |
| 11586 | 95 |
| 8849 | 96 /* Open IM window */ |
| 11338 | 97 convo = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, |
| 10246 | 98 client_entry->nickname, sg->account); |
| 11586 | 99 if (convo) { |
| 100 /* we don't have windows in the core anymore...but we may want to | |
| 101 * provide some method for asking the UI to show the window | |
| 8849 | 102 gaim_conv_window_show(gaim_conversation_get_window(convo)); |
| 11586 | 103 */ |
| 104 } else { | |
| 11338 | 105 convo = gaim_conversation_new(GAIM_CONV_TYPE_IM, sg->account, |
| 8849 | 106 client_entry->nickname); |
| 11586 | 107 } |
| 8849 | 108 g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); |
| 109 gaim_conversation_set_title(convo, tmp); | |
| 110 } | |
| 111 break; | |
| 112 | |
| 113 case SILC_KEY_AGREEMENT_ERROR: | |
| 114 gaim_notify_error(gc, _("Key Agreement"), | |
| 115 _("Error occurred during key agreement"), NULL); | |
| 116 break; | |
| 117 | |
| 118 case SILC_KEY_AGREEMENT_FAILURE: | |
| 119 gaim_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); | |
| 120 break; | |
| 121 | |
| 122 case SILC_KEY_AGREEMENT_TIMEOUT: | |
| 123 gaim_notify_error(gc, _("Key Agreement"), | |
| 124 _("Timeout during key agreement"), NULL); | |
| 125 break; | |
| 126 | |
| 127 case SILC_KEY_AGREEMENT_ABORTED: | |
| 128 gaim_notify_error(gc, _("Key Agreement"), | |
| 129 _("Key agreement was aborted"), NULL); | |
| 130 break; | |
| 131 | |
| 132 case SILC_KEY_AGREEMENT_ALREADY_STARTED: | |
| 133 gaim_notify_error(gc, _("Key Agreement"), | |
| 134 _("Key agreement is already started"), NULL); | |
| 135 break; | |
| 136 | |
| 137 case SILC_KEY_AGREEMENT_SELF_DENIED: | |
| 138 gaim_notify_error(gc, _("Key Agreement"), | |
| 139 _("Key agreement cannot be started with yourself"), | |
| 140 NULL); | |
| 141 break; | |
| 142 | |
| 143 default: | |
| 144 break; | |
| 145 } | |
| 146 | |
| 147 silc_free(a); | |
| 148 } | |
| 149 | |
| 150 static void | |
| 151 silcgaim_buddy_keyagr_do(GaimConnection *gc, const char *name, | |
| 152 gboolean force_local) | |
| 153 { | |
| 154 SilcGaim sg = gc->proto_data; | |
| 155 SilcClientEntry *clients; | |
| 156 SilcUInt32 clients_count; | |
| 8910 | 157 char *local_ip = NULL, *remote_ip = NULL; |
| 8849 | 158 gboolean local = TRUE; |
| 159 char *nickname; | |
| 160 SilcGaimKeyAgr a; | |
| 161 | |
| 162 if (!sg->conn || !name) | |
| 163 return; | |
| 164 | |
| 165 if (!silc_parse_userfqdn(name, &nickname, NULL)) | |
| 166 return; | |
| 167 | |
| 168 /* Find client entry */ | |
| 169 clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, | |
| 170 &clients_count); | |
| 171 if (!clients) { | |
| 172 /* Resolve unknown user */ | |
| 173 SilcGaimResolve r = silc_calloc(1, sizeof(*r)); | |
| 174 if (!r) | |
| 175 return; | |
| 176 r->nick = g_strdup(name); | |
| 177 r->gc = gc; | |
| 178 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, | |
| 179 silcgaim_buddy_keyagr_resolved, r); | |
| 180 silc_free(nickname); | |
| 181 return; | |
| 182 } | |
| 183 | |
| 184 /* Resolve the local IP from the outgoing socket connection. We resolve | |
| 185 it to check whether we have a private range IP address or public IP | |
| 186 address. If we have public then we will assume that we are not behind | |
| 187 NAT and will provide automatically the point of connection to the | |
| 188 agreement. If we have private range address we assume that we are | |
| 189 behind NAT and we let the responder provide the point of connection. | |
| 190 | |
| 191 The algorithm also checks the remote IP address of server connection. | |
| 192 If it is private range address and we have private range address we | |
| 193 assume that we are chatting in LAN and will provide the point of | |
| 194 connection. | |
| 195 | |
| 196 Naturally this algorithm does not always get things right. */ | |
| 197 | |
| 198 if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { | |
| 199 /* Check if the IP is private */ | |
| 200 if (!force_local && silcgaim_ip_is_private(local_ip)) { | |
| 201 local = FALSE; | |
| 202 | |
| 203 /* Local IP is private, resolve the remote server IP to see whether | |
| 204 we are talking to Internet or just on LAN. */ | |
| 205 if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, | |
| 206 &remote_ip)) | |
| 207 if (silcgaim_ip_is_private(remote_ip)) | |
| 208 /* We assume we are in LAN. Let's provide | |
| 209 the connection point. */ | |
| 210 local = TRUE; | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 if (force_local) | |
| 215 local = TRUE; | |
| 216 | |
| 217 if (local && !local_ip) | |
| 218 local_ip = silc_net_localip(); | |
| 219 | |
| 220 a = silc_calloc(1, sizeof(*a)); | |
| 221 if (!a) | |
| 222 return; | |
| 223 a->responder = local; | |
| 224 | |
| 225 /* Send the key agreement request */ | |
| 226 silc_client_send_key_agreement(sg->client, sg->conn, clients[0], | |
| 227 local ? local_ip : NULL, NULL, 0, 60, | |
| 228 silcgaim_buddy_keyagr_cb, a); | |
| 229 | |
| 230 silc_free(local_ip); | |
| 231 silc_free(remote_ip); | |
| 232 silc_free(clients); | |
| 233 } | |
| 234 | |
| 235 typedef struct { | |
| 236 SilcClient client; | |
| 237 SilcClientConnection conn; | |
| 238 SilcClientID client_id; | |
| 239 char *hostname; | |
| 240 SilcUInt16 port; | |
| 241 } *SilcGaimKeyAgrAsk; | |
| 242 | |
| 243 static void | |
| 244 silcgaim_buddy_keyagr_request_cb(SilcGaimKeyAgrAsk a, gint id) | |
| 245 { | |
| 246 SilcGaimKeyAgr ai; | |
| 247 SilcClientEntry client_entry; | |
| 248 | |
| 249 if (id != 1) | |
| 250 goto out; | |
| 251 | |
| 252 /* Get the client entry. */ | |
| 253 client_entry = silc_client_get_client_by_id(a->client, a->conn, | |
| 254 &a->client_id); | |
| 255 if (!client_entry) { | |
| 256 gaim_notify_error(a->client->application, _("Key Agreement"), | |
| 257 _("The remote user is not present in the network any more"), | |
| 258 NULL); | |
| 259 goto out; | |
| 260 } | |
| 261 | |
| 262 /* If the hostname was provided by the requestor perform the key agreement | |
| 263 now. Otherwise, we will send him a request to connect to us. */ | |
| 264 if (a->hostname) { | |
| 265 ai = silc_calloc(1, sizeof(*ai)); | |
| 266 if (!ai) | |
| 267 goto out; | |
| 268 ai->responder = FALSE; | |
| 269 silc_client_perform_key_agreement(a->client, a->conn, client_entry, | |
| 270 a->hostname, a->port, | |
| 271 silcgaim_buddy_keyagr_cb, ai); | |
| 272 } else { | |
| 273 /* Send request. Force us as the point of connection since requestor | |
| 274 did not provide the point of connection. */ | |
| 275 silcgaim_buddy_keyagr_do(a->client->application, | |
| 276 client_entry->nickname, TRUE); | |
| 277 } | |
| 278 | |
| 279 out: | |
| 280 silc_free(a->hostname); | |
| 281 silc_free(a); | |
| 282 } | |
| 283 | |
| 284 void silcgaim_buddy_keyagr_request(SilcClient client, | |
| 285 SilcClientConnection conn, | |
| 286 SilcClientEntry client_entry, | |
| 287 const char *hostname, SilcUInt16 port) | |
| 288 { | |
| 289 char tmp[128], tmp2[128]; | |
| 290 SilcGaimKeyAgrAsk a; | |
| 291 | |
| 292 g_snprintf(tmp, sizeof(tmp), | |
| 293 _("Key agreement request received from %s. Would you like to " | |
| 294 "perform the key agreement?"), client_entry->nickname); | |
| 295 if (hostname) | |
| 296 g_snprintf(tmp2, sizeof(tmp2), | |
| 297 _("The remote user is waiting key agreement on:\n" | |
| 298 "Remote host: %s\nRemote port: %d"), hostname, port); | |
| 299 | |
| 300 a = silc_calloc(1, sizeof(*a)); | |
| 301 if (!a) | |
| 302 return; | |
| 303 a->client = client; | |
| 304 a->conn = conn; | |
| 305 a->client_id = *client_entry->id; | |
| 306 if (hostname) | |
| 307 a->hostname = strdup(hostname); | |
| 308 a->port = port; | |
| 309 | |
| 11201 | 310 gaim_request_action(client->application, _("Key Agreement Request"), tmp, |
| 8849 | 311 hostname ? tmp2 : NULL, 1, a, 2, |
| 312 _("Yes"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb), | |
| 313 _("No"), G_CALLBACK(silcgaim_buddy_keyagr_request_cb)); | |
| 314 } | |
| 315 | |
| 316 static void | |
| 9060 | 317 silcgaim_buddy_keyagr(GaimBlistNode *node, gpointer data) |
| 8849 | 318 { |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
319 GaimBuddy *buddy; |
| 9060 | 320 |
| 321 buddy = (GaimBuddy *)node; | |
| 322 silcgaim_buddy_keyagr_do(buddy->account->gc, buddy->name, FALSE); | |
| 8849 | 323 } |
| 324 | |
| 325 | |
| 326 /**************************** Static IM Key **********************************/ | |
| 327 | |
| 328 static void | |
| 9030 | 329 silcgaim_buddy_resetkey(GaimBlistNode *node, gpointer data) |
| 8849 | 330 { |
| 9030 | 331 GaimBuddy *b; |
| 332 GaimConnection *gc; | |
| 333 SilcGaim sg; | |
| 8849 | 334 char *nickname; |
| 335 SilcClientEntry *clients; | |
| 336 SilcUInt32 clients_count; | |
| 337 | |
| 9030 | 338 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); |
| 339 | |
| 340 b = (GaimBuddy *) node; | |
| 341 gc = gaim_account_get_connection(b->account); | |
| 342 sg = gc->proto_data; | |
| 343 | |
| 344 if (!silc_parse_userfqdn(b->name, &nickname, NULL)) | |
| 8849 | 345 return; |
| 346 | |
| 347 /* Find client entry */ | |
| 348 clients = silc_client_get_clients_local(sg->client, sg->conn, | |
| 9030 | 349 nickname, b->name, |
| 8849 | 350 &clients_count); |
| 351 if (!clients) { | |
| 352 silc_free(nickname); | |
| 353 return; | |
| 354 } | |
| 355 | |
| 356 clients[0]->prv_resp = FALSE; | |
| 357 silc_client_del_private_message_key(sg->client, sg->conn, | |
| 358 clients[0]); | |
| 359 silc_free(clients); | |
| 360 silc_free(nickname); | |
| 361 } | |
| 362 | |
| 363 typedef struct { | |
| 364 SilcClient client; | |
| 365 SilcClientConnection conn; | |
| 366 SilcClientID client_id; | |
| 367 } *SilcGaimPrivkey; | |
| 368 | |
| 369 static void | |
| 370 silcgaim_buddy_privkey(GaimConnection *gc, const char *name); | |
| 371 | |
| 372 static void | |
| 373 silcgaim_buddy_privkey_cb(SilcGaimPrivkey p, const char *passphrase) | |
| 374 { | |
| 375 SilcClientEntry client_entry; | |
| 376 | |
| 377 if (!passphrase || !(*passphrase)) { | |
| 378 silc_free(p); | |
| 379 return; | |
| 380 } | |
| 381 | |
| 382 /* Get the client entry. */ | |
| 383 client_entry = silc_client_get_client_by_id(p->client, p->conn, | |
| 384 &p->client_id); | |
| 385 if (!client_entry) { | |
| 386 gaim_notify_error(p->client->application, _("IM With Password"), | |
| 387 _("The remote user is not present in the network any more"), | |
| 388 NULL); | |
| 389 silc_free(p); | |
| 390 return; | |
| 391 } | |
| 392 | |
| 393 /* Set the private message key */ | |
| 394 silc_client_del_private_message_key(p->client, p->conn, | |
| 395 client_entry); | |
| 396 silc_client_add_private_message_key(p->client, p->conn, | |
| 397 client_entry, NULL, NULL, | |
| 398 (unsigned char *)passphrase, | |
| 399 strlen(passphrase), FALSE, | |
| 400 client_entry->prv_resp); | |
| 401 if (!client_entry->prv_resp) | |
| 402 silc_client_send_private_message_key_request(p->client, | |
| 403 p->conn, | |
| 404 client_entry); | |
| 405 silc_free(p); | |
| 406 } | |
| 407 | |
| 408 static void | |
| 409 silcgaim_buddy_privkey_resolved(SilcClient client, | |
| 410 SilcClientConnection conn, | |
| 411 SilcClientEntry *clients, | |
| 412 SilcUInt32 clients_count, | |
| 413 void *context) | |
| 414 { | |
| 415 char tmp[256]; | |
| 416 | |
| 417 if (!clients) { | |
| 418 g_snprintf(tmp, sizeof(tmp), | |
| 419 _("User %s is not present in the network"), | |
| 420 (const char *)context); | |
| 421 gaim_notify_error(client->application, _("IM With Password"), | |
| 422 _("Cannot set IM key"), tmp); | |
| 423 g_free(context); | |
| 424 return; | |
| 425 } | |
| 426 | |
| 427 silcgaim_buddy_privkey(client->application, context); | |
| 428 silc_free(context); | |
| 429 } | |
| 430 | |
| 431 static void | |
| 9038 | 432 silcgaim_buddy_privkey(GaimConnection *gc, const char *name) |
| 8849 | 433 { |
| 9038 | 434 SilcGaim sg = gc->proto_data; |
| 8849 | 435 char *nickname; |
| 436 SilcGaimPrivkey p; | |
| 437 SilcClientEntry *clients; | |
| 438 SilcUInt32 clients_count; | |
| 439 | |
| 9038 | 440 if (!name) |
| 441 return; | |
| 442 if (!silc_parse_userfqdn(name, &nickname, NULL)) | |
| 8849 | 443 return; |
| 444 | |
| 445 /* Find client entry */ | |
| 446 clients = silc_client_get_clients_local(sg->client, sg->conn, | |
| 9038 | 447 nickname, name, |
| 8849 | 448 &clients_count); |
| 449 if (!clients) { | |
| 450 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, | |
| 451 silcgaim_buddy_privkey_resolved, | |
| 9038 | 452 g_strdup(name)); |
| 8849 | 453 silc_free(nickname); |
| 454 return; | |
| 455 } | |
| 456 | |
| 457 p = silc_calloc(1, sizeof(*p)); | |
| 458 if (!p) | |
| 459 return; | |
| 460 p->client = sg->client; | |
| 461 p->conn = sg->conn; | |
| 462 p->client_id = *clients[0]->id; | |
| 11201 | 463 gaim_request_input(gc, _("IM With Password"), NULL, |
| 8849 | 464 _("Set IM Password"), NULL, FALSE, TRUE, NULL, |
| 465 _("OK"), G_CALLBACK(silcgaim_buddy_privkey_cb), | |
| 466 _("Cancel"), G_CALLBACK(silcgaim_buddy_privkey_cb), | |
| 467 p); | |
| 468 | |
| 469 silc_free(clients); | |
| 470 silc_free(nickname); | |
| 471 } | |
| 472 | |
| 9038 | 473 static void |
| 474 silcgaim_buddy_privkey_menu(GaimBlistNode *node, gpointer data) | |
| 475 { | |
| 476 GaimBuddy *buddy; | |
| 477 GaimConnection *gc; | |
| 478 | |
| 479 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 480 | |
| 481 buddy = (GaimBuddy *) node; | |
| 482 gc = gaim_account_get_connection(buddy->account); | |
| 483 | |
| 484 silcgaim_buddy_privkey(gc, buddy->name); | |
| 485 } | |
| 486 | |
| 8849 | 487 |
| 488 /**************************** Get Public Key *********************************/ | |
| 489 | |
| 490 typedef struct { | |
| 491 SilcClient client; | |
| 492 SilcClientConnection conn; | |
| 493 SilcClientID client_id; | |
| 494 } *SilcGaimBuddyGetkey; | |
| 495 | |
| 496 static void | |
| 497 silcgaim_buddy_getkey(GaimConnection *gc, const char *name); | |
| 498 | |
| 499 static void | |
| 500 silcgaim_buddy_getkey_cb(SilcGaimBuddyGetkey g, | |
| 501 SilcClientCommandReplyContext cmd) | |
| 502 { | |
| 503 SilcClientEntry client_entry; | |
| 504 unsigned char *pk; | |
| 505 SilcUInt32 pk_len; | |
| 506 | |
| 507 /* Get the client entry. */ | |
| 508 client_entry = silc_client_get_client_by_id(g->client, g->conn, | |
| 509 &g->client_id); | |
| 510 if (!client_entry) { | |
| 511 gaim_notify_error(g->client->application, _("Get Public Key"), | |
| 512 _("The remote user is not present in the network any more"), | |
| 513 NULL); | |
| 514 silc_free(g); | |
| 515 return; | |
| 516 } | |
| 517 | |
| 518 if (!client_entry->public_key) { | |
| 519 silc_free(g); | |
| 520 return; | |
| 521 } | |
| 522 | |
| 523 /* Now verify the public key */ | |
| 524 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); | |
| 525 silcgaim_verify_public_key(g->client, g->conn, client_entry->nickname, | |
| 526 SILC_SOCKET_TYPE_CLIENT, | |
| 527 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 528 NULL, NULL); | |
| 529 silc_free(pk); | |
| 530 silc_free(g); | |
| 531 } | |
| 532 | |
| 533 static void | |
| 534 silcgaim_buddy_getkey_resolved(SilcClient client, | |
| 535 SilcClientConnection conn, | |
| 536 SilcClientEntry *clients, | |
| 537 SilcUInt32 clients_count, | |
| 538 void *context) | |
| 539 { | |
| 540 char tmp[256]; | |
| 541 | |
| 542 if (!clients) { | |
| 543 g_snprintf(tmp, sizeof(tmp), | |
| 544 _("User %s is not present in the network"), | |
| 545 (const char *)context); | |
| 546 gaim_notify_error(client->application, _("Get Public Key"), | |
| 547 _("Cannot fetch the public key"), tmp); | |
| 548 g_free(context); | |
| 549 return; | |
| 550 } | |
| 551 | |
| 552 silcgaim_buddy_getkey(client->application, context); | |
| 553 silc_free(context); | |
| 554 } | |
| 555 | |
| 556 static void | |
| 9038 | 557 silcgaim_buddy_getkey(GaimConnection *gc, const char *name) |
| 8849 | 558 { |
| 9038 | 559 SilcGaim sg = gc->proto_data; |
| 560 SilcClient client = sg->client; | |
| 561 SilcClientConnection conn = sg->conn; | |
| 8849 | 562 SilcClientEntry *clients; |
| 563 SilcUInt32 clients_count; | |
| 564 SilcGaimBuddyGetkey g; | |
| 565 char *nickname; | |
| 566 | |
| 9038 | 567 if (!name) |
| 568 return; | |
| 8849 | 569 |
| 9038 | 570 if (!silc_parse_userfqdn(name, &nickname, NULL)) |
| 8849 | 571 return; |
| 572 | |
| 573 /* Find client entry */ | |
| 9038 | 574 clients = silc_client_get_clients_local(client, conn, nickname, name, |
| 575 &clients_count); | |
| 8849 | 576 if (!clients) { |
| 577 silc_client_get_clients(client, conn, nickname, NULL, | |
| 578 silcgaim_buddy_getkey_resolved, | |
| 9038 | 579 g_strdup(name)); |
| 8849 | 580 silc_free(nickname); |
| 581 return; | |
| 582 } | |
| 583 | |
| 584 /* Call GETKEY */ | |
| 585 g = silc_calloc(1, sizeof(*g)); | |
| 586 if (!g) | |
| 587 return; | |
| 588 g->client = client; | |
| 589 g->conn = conn; | |
| 590 g->client_id = *clients[0]->id; | |
| 591 silc_client_command_call(client, conn, NULL, "GETKEY", | |
| 592 clients[0]->nickname, NULL); | |
| 593 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 594 conn->cmd_ident, | |
| 595 (SilcCommandCb)silcgaim_buddy_getkey_cb, g); | |
| 596 silc_free(clients); | |
| 597 silc_free(nickname); | |
| 598 } | |
| 599 | |
| 600 static void | |
| 9038 | 601 silcgaim_buddy_getkey_menu(GaimBlistNode *node, gpointer data) |
| 602 { | |
| 603 GaimBuddy *buddy; | |
| 604 GaimConnection *gc; | |
| 605 | |
| 606 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 607 | |
| 608 buddy = (GaimBuddy *) node; | |
| 609 gc = gaim_account_get_connection(buddy->account); | |
| 610 | |
| 611 silcgaim_buddy_privkey(gc, buddy->name); | |
| 612 | |
| 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; | |
| 754 SilcAttributeObjPk serverpk, usersign, serversign; | |
| 755 gboolean usign_success = TRUE, ssign_success = TRUE; | |
| 11165 | 756 char filename[512], filename2[512], *fingerprint = NULL, *tmp; |
| 8849 | 757 SilcUInt32 len; |
| 758 int i; | |
| 759 | |
| 760 if (!success) { | |
| 761 /* The user did not trust the public key. */ | |
| 762 silcgaim_add_buddy_pk_no(r); | |
| 763 silc_free(r); | |
| 764 return; | |
| 765 } | |
| 766 | |
| 767 if (r->offline) { | |
| 768 /* User is offline. Associate the imported public key with | |
| 769 this user. */ | |
| 770 fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, | |
| 771 r->offline_pk_len); | |
| 772 for (i = 0; i < strlen(fingerprint); i++) | |
| 773 if (fingerprint[i] == ' ') | |
| 774 fingerprint[i] = '_'; | |
| 775 g_snprintf(filename, sizeof(filename) - 1, | |
| 776 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 777 silcgaim_silcdir(), fingerprint); | |
| 778 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 10050 | 779 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); |
| 8849 | 780 silc_free(fingerprint); |
| 781 silc_free(r->offline_pk); | |
| 782 silc_free(r); | |
| 783 return; | |
| 784 } | |
| 785 | |
| 786 /* Get the client entry. */ | |
| 787 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 788 &r->client_id); | |
| 789 if (!client_entry) { | |
| 790 silc_free(r); | |
| 791 return; | |
| 792 } | |
| 793 | |
| 794 memset(&vcard, 0, sizeof(vcard)); | |
| 795 memset(&message, 0, sizeof(message)); | |
| 796 memset(&extension, 0, sizeof(extension)); | |
| 797 memset(&serverpk, 0, sizeof(serverpk)); | |
| 798 memset(&usersign, 0, sizeof(usersign)); | |
| 799 memset(&serversign, 0, sizeof(serversign)); | |
| 800 | |
| 801 /* Now that we have the public key and we trust it now we | |
| 802 save the attributes of the buddy and update its status. */ | |
| 803 | |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
804 if (client_entry->attrs) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
805 silc_dlist_start(client_entry->attrs); |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
806 while ((attr = silc_dlist_get(client_entry->attrs)) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
807 != SILC_LIST_END) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
808 attribute = silc_attribute_get_attribute(attr); |
| 8849 | 809 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
810 switch (attribute) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
811 case SILC_ATTRIBUTE_USER_INFO: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
812 if (!silc_attribute_get_object(attr, (void *)&vcard, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
813 sizeof(vcard))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
814 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
815 break; |
| 8849 | 816 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
817 case SILC_ATTRIBUTE_STATUS_MESSAGE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
818 if (!silc_attribute_get_object(attr, (void *)&message, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
819 sizeof(message))) |
|
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; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
822 |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
823 case SILC_ATTRIBUTE_EXTENSION: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
824 if (!silc_attribute_get_object(attr, (void *)&extension, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
825 sizeof(extension))) |
|
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; |
| 8849 | 828 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
829 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
830 if (serverpk.type) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
831 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
832 if (!silc_attribute_get_object(attr, (void *)&serverpk, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
833 sizeof(serverpk))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
834 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
835 break; |
| 8849 | 836 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
837 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
838 if (usersign.data) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
839 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
840 if (!silc_attribute_get_object(attr, (void *)&usersign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
841 sizeof(usersign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
842 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
843 break; |
| 8849 | 844 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
845 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
846 if (serversign.data) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
847 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
848 if (!silc_attribute_get_object(attr, (void *)&serversign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
849 sizeof(serversign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
850 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
851 break; |
| 8849 | 852 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
853 default: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
854 break; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
855 } |
| 8849 | 856 } |
| 857 } | |
| 858 | |
| 859 /* Verify the attribute signatures */ | |
| 860 | |
| 861 if (usersign.data) { | |
| 862 SilcPKCS pkcs; | |
| 863 unsigned char *verifyd; | |
| 864 SilcUInt32 verify_len; | |
| 865 | |
| 11488 | 866 silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); |
| 8849 | 867 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 868 FALSE, &verify_len); | |
| 869 if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ | |
| 870 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 871 usersign.data, | |
| 872 usersign.data_len, | |
| 873 verifyd, verify_len)) | |
| 874 usign_success = FALSE; | |
| 875 } | |
| 876 silc_free(verifyd); | |
| 877 } | |
| 878 | |
| 879 if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { | |
| 880 SilcPublicKey public_key; | |
| 881 SilcPKCS pkcs; | |
| 882 unsigned char *verifyd; | |
| 883 SilcUInt32 verify_len; | |
| 884 | |
| 885 if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, | |
| 886 &public_key)) { | |
| 11488 | 887 silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); |
| 8849 | 888 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 889 TRUE, &verify_len); | |
| 890 if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { | |
| 891 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 892 serversign.data, | |
| 893 serversign.data_len, | |
| 894 verifyd, verify_len)) | |
| 895 ssign_success = FALSE; | |
| 896 } | |
| 897 silc_pkcs_public_key_free(public_key); | |
| 898 silc_free(verifyd); | |
| 899 } | |
| 900 } | |
| 901 | |
| 902 fingerprint = silc_fingerprint(client_entry->fingerprint, | |
| 903 client_entry->fingerprint_len); | |
| 904 for (i = 0; i < strlen(fingerprint); i++) | |
| 905 if (fingerprint[i] == ' ') | |
| 906 fingerprint[i] = '_'; | |
| 907 | |
| 908 if (usign_success || ssign_success) { | |
| 909 struct passwd *pw; | |
| 910 struct stat st; | |
| 911 | |
| 912 memset(filename2, 0, sizeof(filename2)); | |
| 913 | |
| 914 /* Filename for dir */ | |
| 915 tmp = fingerprint + strlen(fingerprint) - 9; | |
| 916 g_snprintf(filename, sizeof(filename) - 1, | |
| 917 "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", | |
| 918 silcgaim_silcdir(), tmp); | |
| 919 | |
| 920 pw = getpwuid(getuid()); | |
| 921 if (!pw) | |
| 922 return; | |
| 923 | |
| 924 /* Create dir if it doesn't exist */ | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
925 if ((g_stat(filename, &st)) == -1) { |
| 8849 | 926 if (errno == ENOENT) { |
| 927 if (pw->pw_uid == geteuid()) | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
928 g_mkdir(filename, 0755); |
| 8849 | 929 } |
| 930 } | |
| 931 | |
| 932 /* Save VCard */ | |
| 933 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 934 "%s" G_DIR_SEPARATOR_S "vcard", filename); | |
| 935 if (vcard.full_name) { | |
| 11488 | 936 tmp = (char *)silc_vcard_encode(&vcard, &len); |
| 8849 | 937 silc_file_writefile(filename2, tmp, len); |
| 938 silc_free(tmp); | |
| 939 } | |
| 940 | |
| 941 /* Save status message */ | |
| 942 if (message.mime) { | |
| 943 memset(filename2, 0, sizeof(filename2)); | |
| 944 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 945 "%s" G_DIR_SEPARATOR_S "status_message.mime", | |
| 946 filename); | |
| 11488 | 947 silc_file_writefile(filename2, (char *)message.mime, |
| 8849 | 948 message.mime_len); |
| 949 } | |
| 950 | |
| 951 /* Save extension data */ | |
| 952 if (extension.mime) { | |
| 953 memset(filename2, 0, sizeof(filename2)); | |
| 954 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 955 "%s" G_DIR_SEPARATOR_S "extension.mime", | |
| 956 filename); | |
| 11488 | 957 silc_file_writefile(filename2, (char *)extension.mime, |
| 8849 | 958 extension.mime_len); |
| 959 } | |
| 960 } | |
| 961 | |
| 962 /* Save the public key path to buddy properties, as it is used | |
| 963 to identify the buddy in the network (and not the nickname). */ | |
| 964 memset(filename, 0, sizeof(filename)); | |
| 965 g_snprintf(filename, sizeof(filename) - 1, | |
| 966 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 967 silcgaim_silcdir(), fingerprint); | |
| 968 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 969 | |
| 10050 | 970 /* Update online status */ |
| 11522 | 971 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_AVAILABLE, NULL); |
| 8849 | 972 |
| 973 /* Finally, start watching this user so we receive its status | |
| 974 changes from the server */ | |
| 975 g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); | |
| 976 silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", | |
| 977 filename2, NULL); | |
| 978 | |
| 979 silc_free(fingerprint); | |
| 980 silc_free(r); | |
| 981 } | |
| 982 | |
| 983 static void | |
| 984 silcgaim_add_buddy_ask_import(void *user_data, const char *name) | |
| 985 { | |
| 986 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 987 SilcPublicKey public_key; | |
| 988 | |
| 989 /* Load the public key */ | |
| 990 if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && | |
| 991 !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { | |
| 992 silcgaim_add_buddy_ask_pk_cb(r, 0); | |
| 993 gaim_notify_error(r->client->application, | |
| 994 _("Add Buddy"), _("Could not load public key"), NULL); | |
| 995 return; | |
| 996 } | |
| 997 | |
| 998 /* Now verify the public key */ | |
| 999 r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); | |
| 1000 silcgaim_verify_public_key(r->client, r->conn, r->b->name, | |
| 1001 SILC_SOCKET_TYPE_CLIENT, | |
| 1002 r->offline_pk, r->offline_pk_len, | |
| 1003 SILC_SKE_PK_TYPE_SILC, | |
| 1004 silcgaim_add_buddy_save, r); | |
| 1005 } | |
| 1006 | |
| 1007 static void | |
| 1008 silcgaim_add_buddy_ask_pk_cancel(void *user_data, const char *name) | |
| 1009 { | |
| 1010 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 1011 | |
| 1012 /* The user did not import public key. The buddy is unusable. */ | |
| 1013 silcgaim_add_buddy_pk_no(r); | |
| 1014 silc_free(r); | |
| 1015 } | |
| 1016 | |
| 1017 static void | |
| 1018 silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id) | |
| 1019 { | |
| 1020 if (id != 0) { | |
| 1021 /* The user did not import public key. The buddy is unusable. */ | |
| 1022 silcgaim_add_buddy_pk_no(r); | |
| 1023 silc_free(r); | |
| 1024 return; | |
| 1025 } | |
| 1026 | |
| 1027 /* Open file selector to select the public key. */ | |
| 11201 | 1028 gaim_request_file(r->client->application, _("Open..."), NULL, FALSE, |
| 8849 | 1029 G_CALLBACK(silcgaim_add_buddy_ask_import), |
| 1030 G_CALLBACK(silcgaim_add_buddy_ask_pk_cancel), r); | |
| 1031 } | |
| 1032 | |
| 1033 static void | |
| 1034 silcgaim_add_buddy_ask_pk(SilcGaimBuddyRes r) | |
| 1035 { | |
| 1036 char tmp[512]; | |
| 1037 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), | |
| 1038 r->b->name); | |
| 11201 | 1039 gaim_request_action(r->client->application, _("Add Buddy"), tmp, |
| 8910 | 1040 _("To add the buddy you must import his/her public key. " |
| 8849 | 1041 "Press Import to import a public key."), 0, r, 2, |
| 1042 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb), | |
| 1043 _("Import..."), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb)); | |
| 1044 } | |
| 1045 | |
| 1046 static void | |
| 1047 silcgaim_add_buddy_getkey_cb(SilcGaimBuddyRes r, | |
| 1048 SilcClientCommandReplyContext cmd) | |
| 1049 { | |
| 1050 SilcClientEntry client_entry; | |
| 1051 unsigned char *pk; | |
| 1052 SilcUInt32 pk_len; | |
| 1053 | |
| 1054 /* Get the client entry. */ | |
| 1055 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 1056 &r->client_id); | |
| 1057 if (!client_entry || !client_entry->public_key) { | |
| 1058 /* The buddy is offline/nonexistent. We will require user | |
| 1059 to associate a public key with the buddy or the buddy | |
| 1060 cannot be added. */ | |
| 1061 r->offline = TRUE; | |
| 1062 silcgaim_add_buddy_ask_pk(r); | |
| 1063 return; | |
| 1064 } | |
| 1065 | |
| 1066 /* Now verify the public key */ | |
| 1067 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); | |
| 1068 silcgaim_verify_public_key(r->client, r->conn, client_entry->nickname, | |
| 1069 SILC_SOCKET_TYPE_CLIENT, | |
| 1070 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1071 silcgaim_add_buddy_save, r); | |
| 1072 silc_free(pk); | |
| 1073 } | |
| 1074 | |
| 1075 static void | |
| 1076 silcgaim_add_buddy_select_cb(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1077 { | |
| 1078 GaimRequestField *f; | |
| 1079 const GList *list; | |
| 1080 SilcClientEntry client_entry; | |
| 1081 | |
| 1082 f = gaim_request_fields_get_field(fields, "list"); | |
| 1083 list = gaim_request_field_list_get_selected(f); | |
| 1084 if (!list) { | |
| 1085 /* The user did not select any user. */ | |
| 1086 silcgaim_add_buddy_pk_no(r); | |
| 1087 silc_free(r); | |
| 1088 return; | |
| 1089 } | |
| 1090 | |
| 1091 client_entry = gaim_request_field_list_get_data(f, list->data); | |
| 1092 silcgaim_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); | |
| 1093 } | |
| 1094 | |
| 1095 static void | |
| 1096 silcgaim_add_buddy_select_cancel(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1097 { | |
| 1098 /* The user did not select any user. */ | |
| 1099 silcgaim_add_buddy_pk_no(r); | |
| 1100 silc_free(r); | |
| 1101 } | |
| 1102 | |
| 1103 static void | |
| 1104 silcgaim_add_buddy_select(SilcGaimBuddyRes r, | |
| 1105 SilcClientEntry *clients, | |
| 1106 SilcUInt32 clients_count) | |
| 1107 { | |
| 1108 GaimRequestFields *fields; | |
| 1109 GaimRequestFieldGroup *g; | |
| 1110 GaimRequestField *f; | |
| 1111 char tmp[512]; | |
| 1112 int i; | |
| 1113 | |
| 1114 fields = gaim_request_fields_new(); | |
| 1115 g = gaim_request_field_group_new(NULL); | |
| 1116 f = gaim_request_field_list_new("list", NULL); | |
| 1117 gaim_request_field_group_add_field(g, f); | |
| 1118 gaim_request_field_list_set_multi_select(f, FALSE); | |
| 1119 gaim_request_fields_add_group(fields, g); | |
| 1120 | |
| 1121 for (i = 0; i < clients_count; i++) { | |
| 1122 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)", | |
| 1123 clients[i]->realname, clients[i]->nickname, | |
| 1124 clients[i]->username, clients[i]->hostname ? | |
| 1125 clients[i]->hostname : ""); | |
| 1126 gaim_request_field_list_add(f, tmp, clients[i]); | |
| 1127 } | |
| 1128 | |
| 11201 | 1129 gaim_request_fields(r->client->application, _("Add Buddy"), |
| 8891 | 1130 _("Select correct user"), |
| 1131 r->pubkey_search | |
| 1132 ? _("More than one user was found with the same public key. Select " | |
| 1133 "the correct user from the list to add to the buddy list.") | |
| 1134 : _("More than one user was found with the same name. Select " | |
| 1135 "the correct user from the list to add to the buddy list."), | |
| 1136 fields, | |
| 1137 _("OK"), G_CALLBACK(silcgaim_add_buddy_select_cb), | |
| 1138 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_select_cancel), r); | |
| 8849 | 1139 } |
| 1140 | |
| 1141 static void | |
| 1142 silcgaim_add_buddy_resolved(SilcClient client, | |
| 1143 SilcClientConnection conn, | |
| 1144 SilcClientEntry *clients, | |
| 1145 SilcUInt32 clients_count, | |
| 1146 void *context) | |
| 1147 { | |
| 1148 SilcGaimBuddyRes r = context; | |
| 1149 GaimBuddy *b = r->b; | |
| 1150 SilcAttributePayload pub; | |
| 1151 SilcAttributeObjPk userpk; | |
| 1152 unsigned char *pk; | |
| 1153 SilcUInt32 pk_len; | |
| 1154 const char *filename; | |
| 1155 | |
| 10029 | 1156 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); |
| 1157 | |
| 8849 | 1158 /* If the buddy is offline/nonexistent, we will require user |
| 1159 to associate a public key with the buddy or the buddy | |
| 1160 cannot be added. */ | |
| 1161 if (!clients_count) { | |
| 1162 if (r->init) { | |
| 1163 silc_free(r); | |
| 1164 return; | |
| 1165 } | |
| 1166 | |
| 1167 r->offline = TRUE; | |
| 10029 | 1168 /* If the user has already associated a public key, try loading it |
| 1169 * before prompting the user to load it again */ | |
| 1170 if (filename != NULL) | |
| 1171 silcgaim_add_buddy_ask_import(r, filename); | |
| 1172 else | |
| 1173 silcgaim_add_buddy_ask_pk(r); | |
| 8849 | 1174 return; |
| 1175 } | |
| 1176 | |
| 1177 /* If more than one client was found with nickname, we need to verify | |
| 1178 from user which one is the correct. */ | |
| 1179 if (clients_count > 1 && !r->pubkey_search) { | |
| 1180 if (r->init) { | |
| 1181 silc_free(r); | |
| 1182 return; | |
| 1183 } | |
| 1184 | |
| 1185 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1186 return; | |
| 1187 } | |
| 1188 | |
| 1189 /* If we searched using public keys and more than one entry was found | |
| 1190 the same person is logged on multiple times. */ | |
| 1191 if (clients_count > 1 && r->pubkey_search && b->name) { | |
| 1192 if (r->init) { | |
| 1193 /* Find the entry that closest matches to the | |
| 1194 buddy nickname. */ | |
| 1195 int i; | |
| 1196 for (i = 0; i < clients_count; i++) { | |
| 1197 if (!strncasecmp(b->name, clients[i]->nickname, | |
| 1198 strlen(b->name))) { | |
| 1199 clients[0] = clients[i]; | |
| 1200 break; | |
| 1201 } | |
| 1202 } | |
| 1203 } else { | |
| 1204 /* Verify from user which one is correct */ | |
| 1205 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1206 return; | |
| 1207 } | |
| 1208 } | |
| 1209 | |
| 1210 /* The client was found. Now get its public key and verify | |
| 1211 that before adding the buddy. */ | |
| 1212 memset(&userpk, 0, sizeof(userpk)); | |
| 1213 b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); | |
| 1214 r->client_id = *clients[0]->id; | |
| 1215 | |
| 1216 /* Get the public key from attributes, if not present then | |
| 1217 resolve it with GETKEY unless we have it cached already. */ | |
| 1218 if (clients[0]->attrs && !clients[0]->public_key) { | |
| 1219 pub = silcgaim_get_attr(clients[0]->attrs, | |
| 1220 SILC_ATTRIBUTE_USER_PUBLIC_KEY); | |
| 1221 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, | |
| 1222 sizeof(userpk))) { | |
| 1223 /* Get public key with GETKEY */ | |
| 1224 silc_client_command_call(client, conn, NULL, | |
| 1225 "GETKEY", clients[0]->nickname, NULL); | |
| 1226 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1227 conn->cmd_ident, | |
| 1228 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1229 r); | |
| 1230 return; | |
| 1231 } | |
| 1232 if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, | |
| 1233 &clients[0]->public_key)) | |
| 1234 return; | |
| 1235 silc_free(userpk.data); | |
| 1236 } else if (filename && !clients[0]->public_key) { | |
| 1237 if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1238 SILC_PKCS_FILE_PEM) && | |
| 1239 !silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1240 SILC_PKCS_FILE_BIN)) { | |
| 1241 /* Get public key with GETKEY */ | |
| 1242 silc_client_command_call(client, conn, NULL, | |
| 1243 "GETKEY", clients[0]->nickname, NULL); | |
| 1244 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1245 conn->cmd_ident, | |
| 1246 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1247 r); | |
| 1248 return; | |
| 1249 } | |
| 1250 } else if (!clients[0]->public_key) { | |
| 1251 /* Get public key with GETKEY */ | |
| 1252 silc_client_command_call(client, conn, NULL, | |
| 1253 "GETKEY", clients[0]->nickname, NULL); | |
| 1254 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1255 conn->cmd_ident, | |
| 1256 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1257 r); | |
| 1258 return; | |
| 1259 } | |
| 1260 | |
| 1261 /* We have the public key, verify it. */ | |
| 1262 pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); | |
| 1263 silcgaim_verify_public_key(client, conn, clients[0]->nickname, | |
| 1264 SILC_SOCKET_TYPE_CLIENT, | |
| 1265 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1266 silcgaim_add_buddy_save, r); | |
| 1267 silc_free(pk); | |
| 1268 } | |
| 1269 | |
| 1270 static void | |
| 1271 silcgaim_add_buddy_i(GaimConnection *gc, GaimBuddy *b, gboolean init) | |
| 1272 { | |
| 1273 SilcGaim sg = gc->proto_data; | |
| 1274 SilcClient client = sg->client; | |
| 1275 SilcClientConnection conn = sg->conn; | |
| 1276 SilcGaimBuddyRes r; | |
| 1277 SilcBuffer attrs; | |
| 1278 const char *filename, *name = b->name; | |
| 1279 | |
| 1280 r = silc_calloc(1, sizeof(*r)); | |
| 1281 if (!r) | |
| 1282 return; | |
| 1283 r->client = client; | |
| 1284 r->conn = conn; | |
| 1285 r->b = b; | |
| 1286 r->init = init; | |
| 1287 | |
| 1288 /* See if we have this buddy's public key. If we do use that | |
| 1289 to search the details. */ | |
| 1290 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 1291 if (filename) { | |
| 1292 SilcPublicKey public_key; | |
| 1293 SilcAttributeObjPk userpk; | |
| 1294 | |
| 1295 if (!silc_pkcs_load_public_key(filename, &public_key, | |
| 1296 SILC_PKCS_FILE_PEM) && | |
| 1297 !silc_pkcs_load_public_key(filename, &public_key, | |
| 1298 SILC_PKCS_FILE_BIN)) | |
| 1299 return; | |
| 1300 | |
| 1301 /* Get all attributes, and use the public key to search user */ | |
| 1302 name = NULL; | |
| 1303 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, | |
| 1304 SILC_ATTRIBUTE_SERVICE, | |
| 1305 SILC_ATTRIBUTE_STATUS_MOOD, | |
| 1306 SILC_ATTRIBUTE_STATUS_FREETEXT, | |
| 1307 SILC_ATTRIBUTE_STATUS_MESSAGE, | |
| 1308 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, | |
| 1309 SILC_ATTRIBUTE_PREFERRED_CONTACT, | |
| 1310 SILC_ATTRIBUTE_TIMEZONE, | |
| 1311 SILC_ATTRIBUTE_GEOLOCATION, | |
| 1312 SILC_ATTRIBUTE_DEVICE_INFO, 0); | |
| 1313 userpk.type = "silc-rsa"; | |
| 1314 userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); | |
| 1315 attrs = silc_attribute_payload_encode(attrs, | |
| 1316 SILC_ATTRIBUTE_USER_PUBLIC_KEY, | |
| 1317 SILC_ATTRIBUTE_FLAG_VALID, | |
| 1318 &userpk, sizeof(userpk)); | |
| 1319 silc_free(userpk.data); | |
| 1320 silc_pkcs_public_key_free(public_key); | |
| 1321 r->pubkey_search = TRUE; | |
| 1322 } else { | |
| 1323 /* Get all attributes */ | |
| 1324 attrs = silc_client_attributes_request(0); | |
| 1325 } | |
| 1326 | |
| 1327 /* Resolve */ | |
| 1328 silc_client_get_clients_whois(client, conn, name, NULL, attrs, | |
| 1329 silcgaim_add_buddy_resolved, r); | |
| 1330 silc_buffer_free(attrs); | |
| 1331 } | |
| 1332 | |
| 9285 | 1333 void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
| 8849 | 1334 { |
| 9285 | 1335 silcgaim_add_buddy_i(gc, buddy, FALSE); |
| 8849 | 1336 } |
| 1337 | |
| 10869 | 1338 void silcgaim_send_buddylist(GaimConnection *gc) |
| 10341 | 1339 { |
| 10869 | 1340 GaimBuddyList *blist; |
| 1341 GaimBlistNode *gnode, *cnode, *bnode; | |
| 1342 GaimBuddy *buddy; | |
| 1343 | |
| 1344 if ((blist = gaim_get_blist()) != NULL) | |
| 1345 { | |
| 1346 for (gnode = blist->root; gnode != NULL; gnode = gnode->next) | |
| 1347 { | |
| 1348 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 1349 continue; | |
| 1350 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) | |
| 1351 { | |
| 1352 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 1353 continue; | |
| 1354 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) | |
| 1355 { | |
| 1356 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 1357 continue; | |
| 1358 buddy = (GaimBuddy *)bnode; | |
| 1359 silcgaim_add_buddy_i(gc, buddy, TRUE); | |
| 1360 } | |
| 1361 } | |
| 1362 } | |
| 10341 | 1363 } |
| 1364 } | |
| 1365 | |
| 9285 | 1366 void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
| 1367 GaimGroup *group) | |
| 8849 | 1368 { |
| 9285 | 1369 silc_free(buddy->proto_data); |
| 8849 | 1370 } |
| 1371 | |
| 1372 void silcgaim_idle_set(GaimConnection *gc, int idle) | |
| 1373 | |
| 1374 { | |
| 1375 SilcGaim sg = gc->proto_data; | |
| 1376 SilcClient client = sg->client; | |
| 1377 SilcClientConnection conn = sg->conn; | |
| 1378 SilcAttributeObjService service; | |
| 1379 const char *server; | |
| 1380 int port; | |
| 1381 | |
| 1382 server = gaim_account_get_string(sg->account, "server", | |
| 1383 "silc.silcnet.org"); | |
| 1384 port = gaim_account_get_int(sg->account, "port", 706), | |
| 1385 | |
| 1386 memset(&service, 0, sizeof(service)); | |
| 1387 silc_client_attribute_del(client, conn, | |
| 1388 SILC_ATTRIBUTE_SERVICE, NULL); | |
| 1389 service.port = port; | |
| 1390 g_snprintf(service.address, sizeof(service.address), "%s", server); | |
| 1391 service.idle = idle; | |
| 1392 silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, | |
| 1393 &service, sizeof(service)); | |
| 1394 } | |
| 1395 | |
| 1396 char *silcgaim_status_text(GaimBuddy *b) | |
| 1397 { | |
| 1398 SilcGaim sg = b->account->gc->proto_data; | |
| 1399 SilcClient client = sg->client; | |
| 1400 SilcClientConnection conn = sg->conn; | |
| 1401 SilcClientID *client_id = b->proto_data; | |
| 1402 SilcClientEntry client_entry; | |
| 1403 SilcAttributePayload attr; | |
| 1404 SilcAttributeMood mood = 0; | |
| 1405 | |
| 1406 /* Get the client entry. */ | |
| 1407 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1408 if (!client_entry) | |
| 1409 return NULL; | |
| 1410 | |
| 1411 /* If user is online, we show the mood status, if available. | |
| 1412 If user is offline or away that status is indicated. */ | |
| 1413 | |
| 1414 if (client_entry->mode & SILC_UMODE_DETACHED) | |
| 1415 return g_strdup(_("Detached")); | |
| 1416 if (client_entry->mode & SILC_UMODE_GONE) | |
| 1417 return g_strdup(_("Away")); | |
| 1418 if (client_entry->mode & SILC_UMODE_INDISPOSED) | |
| 1419 return g_strdup(_("Indisposed")); | |
| 1420 if (client_entry->mode & SILC_UMODE_BUSY) | |
| 1421 return g_strdup(_("Busy")); | |
| 1422 if (client_entry->mode & SILC_UMODE_PAGE) | |
| 1423 return g_strdup(_("Wake Me Up")); | |
| 1424 if (client_entry->mode & SILC_UMODE_HYPER) | |
| 1425 return g_strdup(_("Hyper Active")); | |
| 1426 if (client_entry->mode & SILC_UMODE_ROBOT) | |
| 1427 return g_strdup(_("Robot")); | |
| 1428 | |
| 1429 attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); | |
| 1430 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { | |
| 1431 /* The mood is a bit mask, so we could show multiple moods, | |
| 1432 but let's show only one for now. */ | |
| 1433 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) | |
| 1434 return g_strdup(_("Happy")); | |
| 1435 if (mood & SILC_ATTRIBUTE_MOOD_SAD) | |
| 1436 return g_strdup(_("Sad")); | |
| 1437 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) | |
| 1438 return g_strdup(_("Angry")); | |
| 1439 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) | |
| 1440 return g_strdup(_("Jealous")); | |
| 1441 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) | |
| 1442 return g_strdup(_("Ashamed")); | |
| 1443 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) | |
| 1444 return g_strdup(_("Invincible")); | |
| 1445 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) | |
| 1446 return g_strdup(_("In Love")); | |
| 1447 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) | |
| 1448 return g_strdup(_("Sleepy")); | |
| 1449 if (mood & SILC_ATTRIBUTE_MOOD_BORED) | |
| 1450 return g_strdup(_("Bored")); | |
| 1451 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) | |
| 1452 return g_strdup(_("Excited")); | |
| 1453 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) | |
| 1454 return g_strdup(_("Anxious")); | |
| 1455 } | |
| 1456 | |
| 1457 return NULL; | |
| 1458 } | |
| 1459 | |
| 1460 char *silcgaim_tooltip_text(GaimBuddy *b) | |
| 1461 { | |
| 1462 SilcGaim sg = b->account->gc->proto_data; | |
| 1463 SilcClient client = sg->client; | |
| 1464 SilcClientConnection conn = sg->conn; | |
| 1465 SilcClientID *client_id = b->proto_data; | |
| 1466 SilcClientEntry client_entry; | |
| 9488 | 1467 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; |
| 8849 | 1468 GString *s; |
| 1469 char *buf; | |
| 1470 char tmp[256]; | |
| 1471 | |
| 1472 s = g_string_new(""); | |
| 1473 | |
| 1474 /* Get the client entry. */ | |
| 1475 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1476 if (!client_entry) | |
| 1477 return NULL; | |
| 1478 | |
| 1479 if (client_entry->nickname) | |
| 9272 | 1480 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Nickname"), |
| 8849 | 1481 client_entry->nickname); |
| 1482 if (client_entry->username && client_entry->hostname) | |
| 9272 | 1483 g_string_append_printf(s, "\n<b>%s:</b> %s@%s", _("Username"), |
| 8849 | 1484 client_entry->username, client_entry->hostname); |
| 1485 if (client_entry->mode) { | |
| 9488 | 1486 g_string_append_printf(s, "\n<b>%s:</b> ", _("User Modes")); |
| 8849 | 1487 memset(tmp, 0, sizeof(tmp)); |
| 1488 silcgaim_get_umode_string(client_entry->mode, | |
| 1489 tmp, sizeof(tmp) - strlen(tmp)); | |
| 9272 | 1490 g_string_append_printf(s, "%s", tmp); |
| 8849 | 1491 } |
| 1492 | |
| 9488 | 1493 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); |
| 1494 if (moodstr) { | |
| 1495 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Mood"), moodstr); | |
| 1496 g_free(moodstr); | |
| 1497 } | |
| 1498 if (statusstr) { | |
| 1499 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Status Text"), statusstr); | |
| 1500 g_free(statusstr); | |
| 8849 | 1501 } |
| 1502 | |
| 9488 | 1503 if (contactstr) { |
| 1504 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr); | |
| 1505 g_free(contactstr); | |
| 1506 } | |
| 8849 | 1507 |
| 9488 | 1508 if (langstr) { |
| 1509 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Language"), langstr); | |
| 1510 g_free(langstr); | |
| 8849 | 1511 } |
| 1512 | |
| 9488 | 1513 if (devicestr) { |
| 1514 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Device"), devicestr); | |
| 1515 g_free(devicestr); | |
| 8849 | 1516 } |
| 1517 | |
| 9488 | 1518 if (tzstr) { |
| 1519 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Timezone"), tzstr); | |
| 1520 g_free(tzstr); | |
| 1521 } | |
| 8849 | 1522 |
| 9488 | 1523 if (geostr) { |
| 1524 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Geolocation"), geostr); | |
| 1525 g_free(geostr); | |
| 1526 } | |
| 8849 | 1527 |
| 1528 buf = g_string_free(s, FALSE); | |
| 1529 return buf; | |
| 1530 } | |
| 1531 | |
| 1532 static void | |
| 9038 | 1533 silcgaim_buddy_kill(GaimBlistNode *node, gpointer data) |
| 8849 | 1534 { |
| 9030 | 1535 GaimBuddy *b; |
| 1536 GaimConnection *gc; | |
| 1537 SilcGaim sg; | |
| 1538 | |
| 1539 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 1540 | |
| 1541 b = (GaimBuddy *) node; | |
| 1542 gc = gaim_account_get_connection(b->account); | |
| 1543 sg = gc->proto_data; | |
| 8849 | 1544 |
| 1545 /* Call KILL */ | |
| 9030 | 1546 silc_client_command_call(sg->client, sg->conn, NULL, "KILL", |
| 1547 b->name, "Killed by operator", NULL); | |
| 8849 | 1548 } |
| 1549 | |
| 9030 | 1550 GList *silcgaim_buddy_menu(GaimBuddy *buddy) |
| 8849 | 1551 { |
| 9030 | 1552 |
| 1553 GaimConnection *gc = gaim_account_get_connection(buddy->account); | |
| 8849 | 1554 SilcGaim sg = gc->proto_data; |
| 1555 SilcClientConnection conn = sg->conn; | |
| 1556 const char *pkfile = NULL; | |
| 1557 SilcClientEntry client_entry = NULL; | |
| 9030 | 1558 GaimBlistNodeAction *act; |
| 1559 GList *m = NULL; | |
| 8849 | 1560 |
| 9038 | 1561 pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); |
| 9030 | 1562 client_entry = silc_client_get_client_by_id(sg->client, |
| 1563 sg->conn, | |
| 9038 | 1564 buddy->proto_data); |
| 8849 | 1565 |
| 1566 if (client_entry && client_entry->send_key) { | |
| 9030 | 1567 act = gaim_blist_node_action_new(_("Reset IM Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1568 silcgaim_buddy_resetkey, NULL, NULL); |
| 9030 | 1569 m = g_list_append(m, act); |
| 1570 | |
| 8849 | 1571 } else { |
| 9030 | 1572 act = gaim_blist_node_action_new(_("IM with Key Exchange"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1573 silcgaim_buddy_keyagr, NULL, NULL); |
| 9030 | 1574 m = g_list_append(m, act); |
| 8849 | 1575 |
| 9030 | 1576 act = gaim_blist_node_action_new(_("IM with Password"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1577 silcgaim_buddy_privkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1578 NULL, NULL); |
| 9030 | 1579 m = g_list_append(m, act); |
| 8849 | 1580 } |
| 1581 | |
| 1582 if (pkfile) { | |
| 9030 | 1583 act = gaim_blist_node_action_new(_("Show Public Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1584 silcgaim_buddy_showkey, NULL, NULL); |
| 9030 | 1585 m = g_list_append(m, act); |
| 1586 | |
| 8849 | 1587 } else { |
| 9030 | 1588 act = gaim_blist_node_action_new(_("Get Public Key..."), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1589 silcgaim_buddy_getkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1590 NULL, NULL); |
| 9030 | 1591 m = g_list_append(m, act); |
| 8849 | 1592 } |
| 1593 | |
| 1594 if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { | |
| 9030 | 1595 act = gaim_blist_node_action_new(_("Kill User"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1596 silcgaim_buddy_kill, NULL, NULL); |
| 9030 | 1597 m = g_list_append(m, act); |
| 8849 | 1598 } |
| 1599 | |
| 1600 return m; | |
| 1601 } |
