Mercurial > pidgin
annotate src/protocols/silc/buddy.c @ 12301:39fca2edf7da
[gaim-migrate @ 14605]
I only caught this as I was committing, and besides I forgot to mention what
sadrul's patch did. It puts the emblem for the active status on the accounts
in the Accounts menu (he put them in the Remove menu as well but that felt
wrong to me.)
committer: Tailor Script <tailor@pidgin.im>
| author | Etan Reisner <pidgin@unreliablesource.net> |
|---|---|
| date | Sat, 03 Dec 2005 06:50:41 +0000 |
| parents | 5851a9219bc7 |
| children | e4e47871c373 |
| 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 | |
| 612 silcgaim_buddy_privkey(gc, buddy->name); | |
| 613 | |
| 614 } | |
| 615 | |
| 616 static void | |
| 9030 | 617 silcgaim_buddy_showkey(GaimBlistNode *node, gpointer data) |
| 8849 | 618 { |
| 9030 | 619 GaimBuddy *b; |
| 620 GaimConnection *gc; | |
| 621 SilcGaim sg; | |
| 8849 | 622 SilcPublicKey public_key; |
| 623 const char *pkfile; | |
| 9030 | 624 |
| 625 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 8849 | 626 |
| 9030 | 627 b = (GaimBuddy *) node; |
| 628 gc = gaim_account_get_connection(b->account); | |
| 629 sg = gc->proto_data; | |
| 8849 | 630 |
| 9038 | 631 pkfile = gaim_blist_node_get_string(node, "public-key"); |
| 8849 | 632 if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && |
| 633 !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) { | |
| 634 gaim_notify_error(gc, | |
| 635 _("Show Public Key"), | |
| 636 _("Could not load public key"), NULL); | |
| 637 return; | |
| 638 } | |
| 639 | |
| 9030 | 640 silcgaim_show_public_key(sg, b->name, public_key, NULL, NULL); |
| 8849 | 641 silc_pkcs_public_key_free(public_key); |
| 642 } | |
| 643 | |
| 644 | |
| 645 /**************************** Buddy routines *********************************/ | |
| 646 | |
| 647 /* The buddies are implemented by using the WHOIS and WATCH commands that | |
| 648 can be used to search users by their public key. Since nicknames aren't | |
| 649 unique in SILC we cannot trust the buddy list using their nickname. We | |
| 650 associate public keys to buddies and use those to search and watch | |
| 651 in the network. | |
| 652 | |
| 653 The problem is that Gaim does not return GaimBuddy contexts to the | |
| 654 callbacks but the buddy names. Naturally, this is not going to work | |
| 655 with SILC. But, for now, we have to do what we can... */ | |
| 656 | |
| 657 typedef struct { | |
| 658 SilcClient client; | |
| 659 SilcClientConnection conn; | |
| 660 SilcClientID client_id; | |
| 661 GaimBuddy *b; | |
| 662 unsigned char *offline_pk; | |
| 663 SilcUInt32 offline_pk_len; | |
| 664 unsigned int offline : 1; | |
| 665 unsigned int pubkey_search : 1; | |
| 666 unsigned int init : 1; | |
| 667 } *SilcGaimBuddyRes; | |
| 668 | |
| 669 static void | |
| 670 silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id); | |
| 671 static void | |
| 672 silcgaim_add_buddy_resolved(SilcClient client, | |
| 673 SilcClientConnection conn, | |
| 674 SilcClientEntry *clients, | |
| 675 SilcUInt32 clients_count, | |
| 676 void *context); | |
| 677 | |
| 678 void silcgaim_get_info(GaimConnection *gc, const char *who) | |
| 679 { | |
| 680 SilcGaim sg = gc->proto_data; | |
| 681 SilcClient client = sg->client; | |
| 682 SilcClientConnection conn = sg->conn; | |
| 683 SilcClientEntry client_entry; | |
| 684 GaimBuddy *b; | |
| 685 const char *filename, *nick = who; | |
| 686 char tmp[256]; | |
| 687 | |
| 688 if (!who) | |
| 689 return; | |
| 690 if (strlen(who) > 1 && who[0] == '@') | |
| 691 nick = who + 1; | |
| 692 if (strlen(who) > 1 && who[0] == '*') | |
| 693 nick = who + 1; | |
| 694 if (strlen(who) > 2 && who[0] == '*' && who[1] == '@') | |
| 695 nick = who + 2; | |
| 696 | |
| 697 b = gaim_find_buddy(gc->account, nick); | |
| 698 if (b) { | |
| 699 /* See if we have this buddy's public key. If we do use that | |
| 700 to search the details. */ | |
| 701 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 702 if (filename) { | |
| 703 /* Call WHOIS. The user info is displayed in the WHOIS | |
| 704 command reply. */ | |
| 705 silc_client_command_call(client, conn, NULL, "WHOIS", | |
| 706 "-details", "-pubkey", filename, NULL); | |
| 707 return; | |
| 708 } | |
| 709 | |
| 710 if (!b->proto_data) { | |
| 711 g_snprintf(tmp, sizeof(tmp), | |
| 712 _("User %s is not present in the network"), b->name); | |
| 713 gaim_notify_error(gc, _("User Information"), | |
| 714 _("Cannot get user information"), tmp); | |
| 715 return; | |
| 716 } | |
| 717 | |
| 718 client_entry = silc_client_get_client_by_id(client, conn, b->proto_data); | |
| 719 if (client_entry) { | |
| 720 /* Call WHOIS. The user info is displayed in the WHOIS | |
| 721 command reply. */ | |
| 722 silc_client_command_call(client, conn, NULL, "WHOIS", | |
| 723 client_entry->nickname, "-details", NULL); | |
| 724 } | |
| 725 } else { | |
| 726 /* Call WHOIS just with nickname. */ | |
| 727 silc_client_command_call(client, conn, NULL, "WHOIS", nick, NULL); | |
| 728 } | |
| 729 } | |
| 730 | |
| 731 static void | |
| 732 silcgaim_add_buddy_pk_no(SilcGaimBuddyRes r) | |
| 733 { | |
| 734 char tmp[512]; | |
| 735 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), | |
| 736 r->b->name); | |
| 737 gaim_notify_error(r->client->application, _("Add Buddy"), tmp, | |
| 8910 | 738 _("You cannot receive buddy notifications until you " |
| 739 "import his/her public key. You can use the Get Public Key " | |
| 8849 | 740 "command to get the public key.")); |
| 10050 | 741 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); |
| 8849 | 742 } |
| 743 | |
| 744 static void | |
| 745 silcgaim_add_buddy_save(bool success, void *context) | |
| 746 { | |
| 747 SilcGaimBuddyRes r = context; | |
| 748 GaimBuddy *b = r->b; | |
| 749 SilcClient client = r->client; | |
| 750 SilcClientEntry client_entry; | |
| 751 SilcAttributePayload attr; | |
| 752 SilcAttribute attribute; | |
| 753 SilcVCardStruct vcard; | |
| 754 SilcAttributeObjMime message, extension; | |
| 755 SilcAttributeObjPk serverpk, usersign, serversign; | |
| 756 gboolean usign_success = TRUE, ssign_success = TRUE; | |
| 11165 | 757 char filename[512], filename2[512], *fingerprint = NULL, *tmp; |
| 8849 | 758 SilcUInt32 len; |
| 759 int i; | |
| 760 | |
| 761 if (!success) { | |
| 762 /* The user did not trust the public key. */ | |
| 763 silcgaim_add_buddy_pk_no(r); | |
| 764 silc_free(r); | |
| 765 return; | |
| 766 } | |
| 767 | |
| 768 if (r->offline) { | |
| 769 /* User is offline. Associate the imported public key with | |
| 770 this user. */ | |
| 771 fingerprint = silc_hash_fingerprint(NULL, r->offline_pk, | |
| 772 r->offline_pk_len); | |
| 773 for (i = 0; i < strlen(fingerprint); i++) | |
| 774 if (fingerprint[i] == ' ') | |
| 775 fingerprint[i] = '_'; | |
| 776 g_snprintf(filename, sizeof(filename) - 1, | |
| 777 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 778 silcgaim_silcdir(), fingerprint); | |
| 779 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 10050 | 780 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_OFFLINE, NULL); |
| 8849 | 781 silc_free(fingerprint); |
| 782 silc_free(r->offline_pk); | |
| 783 silc_free(r); | |
| 784 return; | |
| 785 } | |
| 786 | |
| 787 /* Get the client entry. */ | |
| 788 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 789 &r->client_id); | |
| 790 if (!client_entry) { | |
| 791 silc_free(r); | |
| 792 return; | |
| 793 } | |
| 794 | |
| 795 memset(&vcard, 0, sizeof(vcard)); | |
| 796 memset(&message, 0, sizeof(message)); | |
| 797 memset(&extension, 0, sizeof(extension)); | |
| 798 memset(&serverpk, 0, sizeof(serverpk)); | |
| 799 memset(&usersign, 0, sizeof(usersign)); | |
| 800 memset(&serversign, 0, sizeof(serversign)); | |
| 801 | |
| 802 /* Now that we have the public key and we trust it now we | |
| 803 save the attributes of the buddy and update its status. */ | |
| 804 | |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
805 if (client_entry->attrs) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
806 silc_dlist_start(client_entry->attrs); |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
807 while ((attr = silc_dlist_get(client_entry->attrs)) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
808 != SILC_LIST_END) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
809 attribute = silc_attribute_get_attribute(attr); |
| 8849 | 810 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
811 switch (attribute) { |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
812 case SILC_ATTRIBUTE_USER_INFO: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
813 if (!silc_attribute_get_object(attr, (void *)&vcard, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
814 sizeof(vcard))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
815 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
816 break; |
| 8849 | 817 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
818 case SILC_ATTRIBUTE_STATUS_MESSAGE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
819 if (!silc_attribute_get_object(attr, (void *)&message, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
820 sizeof(message))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
821 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
822 break; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
823 |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
824 case SILC_ATTRIBUTE_EXTENSION: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
825 if (!silc_attribute_get_object(attr, (void *)&extension, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
826 sizeof(extension))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
827 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
828 break; |
| 8849 | 829 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
830 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
831 if (serverpk.type) |
|
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 if (!silc_attribute_get_object(attr, (void *)&serverpk, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
834 sizeof(serverpk))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
835 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
836 break; |
| 8849 | 837 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
838 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
839 if (usersign.data) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
840 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
841 if (!silc_attribute_get_object(attr, (void *)&usersign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
842 sizeof(usersign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
843 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
844 break; |
| 8849 | 845 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
846 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
847 if (serversign.data) |
|
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 if (!silc_attribute_get_object(attr, (void *)&serversign, |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
850 sizeof(serversign))) |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
851 continue; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
852 break; |
| 8849 | 853 |
|
9133
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
854 default: |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
855 break; |
|
c42c3ac3466e
[gaim-migrate @ 9915]
Christian Hammond <chipx86@chipx86.com>
parents:
9060
diff
changeset
|
856 } |
| 8849 | 857 } |
| 858 } | |
| 859 | |
| 860 /* Verify the attribute signatures */ | |
| 861 | |
| 862 if (usersign.data) { | |
| 863 SilcPKCS pkcs; | |
| 864 unsigned char *verifyd; | |
| 865 SilcUInt32 verify_len; | |
| 866 | |
| 11488 | 867 silc_pkcs_alloc((unsigned char*)"rsa", &pkcs); |
| 8849 | 868 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 869 FALSE, &verify_len); | |
| 870 if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ | |
| 871 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 872 usersign.data, | |
| 873 usersign.data_len, | |
| 874 verifyd, verify_len)) | |
| 875 usign_success = FALSE; | |
| 876 } | |
| 877 silc_free(verifyd); | |
| 878 } | |
| 879 | |
| 880 if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { | |
| 881 SilcPublicKey public_key; | |
| 882 SilcPKCS pkcs; | |
| 883 unsigned char *verifyd; | |
| 884 SilcUInt32 verify_len; | |
| 885 | |
| 886 if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, | |
| 887 &public_key)) { | |
| 11488 | 888 silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); |
| 8849 | 889 verifyd = silc_attribute_get_verify_data(client_entry->attrs, |
| 890 TRUE, &verify_len); | |
| 891 if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { | |
| 892 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, | |
| 893 serversign.data, | |
| 894 serversign.data_len, | |
| 895 verifyd, verify_len)) | |
| 896 ssign_success = FALSE; | |
| 897 } | |
| 898 silc_pkcs_public_key_free(public_key); | |
| 899 silc_free(verifyd); | |
| 900 } | |
| 901 } | |
| 902 | |
| 903 fingerprint = silc_fingerprint(client_entry->fingerprint, | |
| 904 client_entry->fingerprint_len); | |
| 905 for (i = 0; i < strlen(fingerprint); i++) | |
| 906 if (fingerprint[i] == ' ') | |
| 907 fingerprint[i] = '_'; | |
| 908 | |
| 909 if (usign_success || ssign_success) { | |
| 910 struct passwd *pw; | |
| 911 struct stat st; | |
| 912 | |
| 913 memset(filename2, 0, sizeof(filename2)); | |
| 914 | |
| 915 /* Filename for dir */ | |
| 916 tmp = fingerprint + strlen(fingerprint) - 9; | |
| 917 g_snprintf(filename, sizeof(filename) - 1, | |
| 918 "%s" G_DIR_SEPARATOR_S "friends" G_DIR_SEPARATOR_S "%s", | |
| 919 silcgaim_silcdir(), tmp); | |
| 920 | |
| 921 pw = getpwuid(getuid()); | |
| 922 if (!pw) | |
| 923 return; | |
| 924 | |
| 925 /* Create dir if it doesn't exist */ | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
926 if ((g_stat(filename, &st)) == -1) { |
| 8849 | 927 if (errno == ENOENT) { |
| 928 if (pw->pw_uid == geteuid()) | |
|
10589
0f7452b1f777
[gaim-migrate @ 11994]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
10341
diff
changeset
|
929 g_mkdir(filename, 0755); |
| 8849 | 930 } |
| 931 } | |
| 932 | |
| 933 /* Save VCard */ | |
| 934 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 935 "%s" G_DIR_SEPARATOR_S "vcard", filename); | |
| 936 if (vcard.full_name) { | |
| 11488 | 937 tmp = (char *)silc_vcard_encode(&vcard, &len); |
| 8849 | 938 silc_file_writefile(filename2, tmp, len); |
| 939 silc_free(tmp); | |
| 940 } | |
| 941 | |
| 942 /* Save status message */ | |
| 943 if (message.mime) { | |
| 944 memset(filename2, 0, sizeof(filename2)); | |
| 945 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 946 "%s" G_DIR_SEPARATOR_S "status_message.mime", | |
| 947 filename); | |
| 11488 | 948 silc_file_writefile(filename2, (char *)message.mime, |
| 8849 | 949 message.mime_len); |
| 950 } | |
| 951 | |
| 952 /* Save extension data */ | |
| 953 if (extension.mime) { | |
| 954 memset(filename2, 0, sizeof(filename2)); | |
| 955 g_snprintf(filename2, sizeof(filename2) - 1, | |
| 956 "%s" G_DIR_SEPARATOR_S "extension.mime", | |
| 957 filename); | |
| 11488 | 958 silc_file_writefile(filename2, (char *)extension.mime, |
| 8849 | 959 extension.mime_len); |
| 960 } | |
| 961 } | |
| 962 | |
| 963 /* Save the public key path to buddy properties, as it is used | |
| 964 to identify the buddy in the network (and not the nickname). */ | |
| 965 memset(filename, 0, sizeof(filename)); | |
| 966 g_snprintf(filename, sizeof(filename) - 1, | |
| 967 "%s" G_DIR_SEPARATOR_S "clientkeys" G_DIR_SEPARATOR_S "clientkey_%s.pub", | |
| 968 silcgaim_silcdir(), fingerprint); | |
| 969 gaim_blist_node_set_string((GaimBlistNode *)b, "public-key", filename); | |
| 970 | |
| 10050 | 971 /* Update online status */ |
| 11522 | 972 gaim_prpl_got_user_status(gaim_buddy_get_account(r->b), gaim_buddy_get_name(r->b), SILCGAIM_STATUS_ID_AVAILABLE, NULL); |
| 8849 | 973 |
| 974 /* Finally, start watching this user so we receive its status | |
| 975 changes from the server */ | |
| 976 g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); | |
| 977 silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", | |
| 978 filename2, NULL); | |
| 979 | |
| 980 silc_free(fingerprint); | |
| 981 silc_free(r); | |
| 982 } | |
| 983 | |
| 984 static void | |
| 985 silcgaim_add_buddy_ask_import(void *user_data, const char *name) | |
| 986 { | |
| 987 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 988 SilcPublicKey public_key; | |
| 989 | |
| 990 /* Load the public key */ | |
| 991 if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && | |
| 992 !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) { | |
| 993 silcgaim_add_buddy_ask_pk_cb(r, 0); | |
| 994 gaim_notify_error(r->client->application, | |
| 995 _("Add Buddy"), _("Could not load public key"), NULL); | |
| 996 return; | |
| 997 } | |
| 998 | |
| 999 /* Now verify the public key */ | |
| 1000 r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); | |
| 1001 silcgaim_verify_public_key(r->client, r->conn, r->b->name, | |
| 1002 SILC_SOCKET_TYPE_CLIENT, | |
| 1003 r->offline_pk, r->offline_pk_len, | |
| 1004 SILC_SKE_PK_TYPE_SILC, | |
| 1005 silcgaim_add_buddy_save, r); | |
| 1006 } | |
| 1007 | |
| 1008 static void | |
| 1009 silcgaim_add_buddy_ask_pk_cancel(void *user_data, const char *name) | |
| 1010 { | |
| 1011 SilcGaimBuddyRes r = (SilcGaimBuddyRes)user_data; | |
| 1012 | |
| 1013 /* The user did not import public key. The buddy is unusable. */ | |
| 1014 silcgaim_add_buddy_pk_no(r); | |
| 1015 silc_free(r); | |
| 1016 } | |
| 1017 | |
| 1018 static void | |
| 1019 silcgaim_add_buddy_ask_pk_cb(SilcGaimBuddyRes r, gint id) | |
| 1020 { | |
| 1021 if (id != 0) { | |
| 1022 /* The user did not import public key. The buddy is unusable. */ | |
| 1023 silcgaim_add_buddy_pk_no(r); | |
| 1024 silc_free(r); | |
| 1025 return; | |
| 1026 } | |
| 1027 | |
| 1028 /* Open file selector to select the public key. */ | |
| 11201 | 1029 gaim_request_file(r->client->application, _("Open..."), NULL, FALSE, |
| 8849 | 1030 G_CALLBACK(silcgaim_add_buddy_ask_import), |
| 1031 G_CALLBACK(silcgaim_add_buddy_ask_pk_cancel), r); | |
| 1032 } | |
| 1033 | |
| 1034 static void | |
| 1035 silcgaim_add_buddy_ask_pk(SilcGaimBuddyRes r) | |
| 1036 { | |
| 1037 char tmp[512]; | |
| 1038 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), | |
| 1039 r->b->name); | |
| 11201 | 1040 gaim_request_action(r->client->application, _("Add Buddy"), tmp, |
| 8910 | 1041 _("To add the buddy you must import his/her public key. " |
| 8849 | 1042 "Press Import to import a public key."), 0, r, 2, |
| 1043 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb), | |
| 1044 _("Import..."), G_CALLBACK(silcgaim_add_buddy_ask_pk_cb)); | |
| 1045 } | |
| 1046 | |
| 1047 static void | |
| 1048 silcgaim_add_buddy_getkey_cb(SilcGaimBuddyRes r, | |
| 1049 SilcClientCommandReplyContext cmd) | |
| 1050 { | |
| 1051 SilcClientEntry client_entry; | |
| 1052 unsigned char *pk; | |
| 1053 SilcUInt32 pk_len; | |
| 1054 | |
| 1055 /* Get the client entry. */ | |
| 1056 client_entry = silc_client_get_client_by_id(r->client, r->conn, | |
| 1057 &r->client_id); | |
| 1058 if (!client_entry || !client_entry->public_key) { | |
| 1059 /* The buddy is offline/nonexistent. We will require user | |
| 1060 to associate a public key with the buddy or the buddy | |
| 1061 cannot be added. */ | |
| 1062 r->offline = TRUE; | |
| 1063 silcgaim_add_buddy_ask_pk(r); | |
| 1064 return; | |
| 1065 } | |
| 1066 | |
| 1067 /* Now verify the public key */ | |
| 1068 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len); | |
| 1069 silcgaim_verify_public_key(r->client, r->conn, client_entry->nickname, | |
| 1070 SILC_SOCKET_TYPE_CLIENT, | |
| 1071 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1072 silcgaim_add_buddy_save, r); | |
| 1073 silc_free(pk); | |
| 1074 } | |
| 1075 | |
| 1076 static void | |
| 1077 silcgaim_add_buddy_select_cb(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1078 { | |
| 1079 GaimRequestField *f; | |
| 1080 const GList *list; | |
| 1081 SilcClientEntry client_entry; | |
| 1082 | |
| 1083 f = gaim_request_fields_get_field(fields, "list"); | |
| 1084 list = gaim_request_field_list_get_selected(f); | |
| 1085 if (!list) { | |
| 1086 /* The user did not select any user. */ | |
| 1087 silcgaim_add_buddy_pk_no(r); | |
| 1088 silc_free(r); | |
| 1089 return; | |
| 1090 } | |
| 1091 | |
| 1092 client_entry = gaim_request_field_list_get_data(f, list->data); | |
| 1093 silcgaim_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); | |
| 1094 } | |
| 1095 | |
| 1096 static void | |
| 1097 silcgaim_add_buddy_select_cancel(SilcGaimBuddyRes r, GaimRequestFields *fields) | |
| 1098 { | |
| 1099 /* The user did not select any user. */ | |
| 1100 silcgaim_add_buddy_pk_no(r); | |
| 1101 silc_free(r); | |
| 1102 } | |
| 1103 | |
| 1104 static void | |
| 1105 silcgaim_add_buddy_select(SilcGaimBuddyRes r, | |
| 1106 SilcClientEntry *clients, | |
| 1107 SilcUInt32 clients_count) | |
| 1108 { | |
| 1109 GaimRequestFields *fields; | |
| 1110 GaimRequestFieldGroup *g; | |
| 1111 GaimRequestField *f; | |
| 12167 | 1112 char tmp[512], tmp2[128]; |
| 8849 | 1113 int i; |
| 12167 | 1114 char *fingerprint; |
| 8849 | 1115 |
| 1116 fields = gaim_request_fields_new(); | |
| 1117 g = gaim_request_field_group_new(NULL); | |
| 1118 f = gaim_request_field_list_new("list", NULL); | |
| 1119 gaim_request_field_group_add_field(g, f); | |
| 1120 gaim_request_field_list_set_multi_select(f, FALSE); | |
| 1121 gaim_request_fields_add_group(fields, g); | |
| 1122 | |
| 1123 for (i = 0; i < clients_count; i++) { | |
| 12167 | 1124 fingerprint = NULL; |
| 1125 if (clients[i]->fingerprint) { | |
| 1126 fingerprint = silc_fingerprint(clients[i]->fingerprint, | |
| 1127 clients[i]->fingerprint_len); | |
| 1128 g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); | |
| 1129 } | |
| 1130 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", | |
| 8849 | 1131 clients[i]->realname, clients[i]->nickname, |
| 1132 clients[i]->username, clients[i]->hostname ? | |
| 12167 | 1133 clients[i]->hostname : "", |
| 1134 fingerprint ? tmp2 : ""); | |
| 8849 | 1135 gaim_request_field_list_add(f, tmp, clients[i]); |
| 12167 | 1136 silc_free(fingerprint); |
| 8849 | 1137 } |
| 1138 | |
| 11201 | 1139 gaim_request_fields(r->client->application, _("Add Buddy"), |
| 8891 | 1140 _("Select correct user"), |
| 1141 r->pubkey_search | |
| 1142 ? _("More than one user was found with the same public key. Select " | |
| 1143 "the correct user from the list to add to the buddy list.") | |
| 1144 : _("More than one user was found with the same name. Select " | |
| 1145 "the correct user from the list to add to the buddy list."), | |
| 1146 fields, | |
| 1147 _("OK"), G_CALLBACK(silcgaim_add_buddy_select_cb), | |
| 1148 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_select_cancel), r); | |
| 8849 | 1149 } |
| 1150 | |
| 1151 static void | |
| 1152 silcgaim_add_buddy_resolved(SilcClient client, | |
| 1153 SilcClientConnection conn, | |
| 1154 SilcClientEntry *clients, | |
| 1155 SilcUInt32 clients_count, | |
| 1156 void *context) | |
| 1157 { | |
| 1158 SilcGaimBuddyRes r = context; | |
| 1159 GaimBuddy *b = r->b; | |
| 1160 SilcAttributePayload pub; | |
| 1161 SilcAttributeObjPk userpk; | |
| 1162 unsigned char *pk; | |
| 1163 SilcUInt32 pk_len; | |
| 1164 const char *filename; | |
| 1165 | |
| 10029 | 1166 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); |
| 1167 | |
| 8849 | 1168 /* If the buddy is offline/nonexistent, we will require user |
| 1169 to associate a public key with the buddy or the buddy | |
| 1170 cannot be added. */ | |
| 1171 if (!clients_count) { | |
| 1172 if (r->init) { | |
| 1173 silc_free(r); | |
| 1174 return; | |
| 1175 } | |
| 1176 | |
| 1177 r->offline = TRUE; | |
| 10029 | 1178 /* If the user has already associated a public key, try loading it |
| 1179 * before prompting the user to load it again */ | |
| 1180 if (filename != NULL) | |
| 1181 silcgaim_add_buddy_ask_import(r, filename); | |
| 1182 else | |
| 1183 silcgaim_add_buddy_ask_pk(r); | |
| 8849 | 1184 return; |
| 1185 } | |
| 1186 | |
| 1187 /* If more than one client was found with nickname, we need to verify | |
| 1188 from user which one is the correct. */ | |
| 1189 if (clients_count > 1 && !r->pubkey_search) { | |
| 1190 if (r->init) { | |
| 1191 silc_free(r); | |
| 1192 return; | |
| 1193 } | |
| 1194 | |
| 1195 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1196 return; | |
| 1197 } | |
| 1198 | |
| 1199 /* If we searched using public keys and more than one entry was found | |
| 1200 the same person is logged on multiple times. */ | |
| 1201 if (clients_count > 1 && r->pubkey_search && b->name) { | |
| 1202 if (r->init) { | |
| 1203 /* Find the entry that closest matches to the | |
| 1204 buddy nickname. */ | |
| 1205 int i; | |
| 1206 for (i = 0; i < clients_count; i++) { | |
| 1207 if (!strncasecmp(b->name, clients[i]->nickname, | |
| 1208 strlen(b->name))) { | |
| 1209 clients[0] = clients[i]; | |
| 1210 break; | |
| 1211 } | |
| 1212 } | |
| 1213 } else { | |
| 1214 /* Verify from user which one is correct */ | |
| 1215 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1216 return; | |
| 1217 } | |
| 1218 } | |
| 1219 | |
| 1220 /* The client was found. Now get its public key and verify | |
| 1221 that before adding the buddy. */ | |
| 1222 memset(&userpk, 0, sizeof(userpk)); | |
| 1223 b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); | |
| 1224 r->client_id = *clients[0]->id; | |
| 1225 | |
| 1226 /* Get the public key from attributes, if not present then | |
| 1227 resolve it with GETKEY unless we have it cached already. */ | |
| 1228 if (clients[0]->attrs && !clients[0]->public_key) { | |
| 1229 pub = silcgaim_get_attr(clients[0]->attrs, | |
| 1230 SILC_ATTRIBUTE_USER_PUBLIC_KEY); | |
| 1231 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, | |
| 1232 sizeof(userpk))) { | |
| 1233 /* Get public key with GETKEY */ | |
| 1234 silc_client_command_call(client, conn, NULL, | |
| 1235 "GETKEY", clients[0]->nickname, NULL); | |
| 1236 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1237 conn->cmd_ident, | |
| 1238 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1239 r); | |
| 1240 return; | |
| 1241 } | |
| 1242 if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, | |
| 1243 &clients[0]->public_key)) | |
| 1244 return; | |
| 1245 silc_free(userpk.data); | |
| 1246 } else if (filename && !clients[0]->public_key) { | |
| 1247 if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1248 SILC_PKCS_FILE_PEM) && | |
| 1249 !silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1250 SILC_PKCS_FILE_BIN)) { | |
| 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 } else if (!clients[0]->public_key) { | |
| 1261 /* Get public key with GETKEY */ | |
| 1262 silc_client_command_call(client, conn, NULL, | |
| 1263 "GETKEY", clients[0]->nickname, NULL); | |
| 1264 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1265 conn->cmd_ident, | |
| 1266 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1267 r); | |
| 1268 return; | |
| 1269 } | |
| 1270 | |
| 1271 /* We have the public key, verify it. */ | |
| 1272 pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); | |
| 1273 silcgaim_verify_public_key(client, conn, clients[0]->nickname, | |
| 1274 SILC_SOCKET_TYPE_CLIENT, | |
| 1275 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1276 silcgaim_add_buddy_save, r); | |
| 1277 silc_free(pk); | |
| 1278 } | |
| 1279 | |
| 1280 static void | |
| 1281 silcgaim_add_buddy_i(GaimConnection *gc, GaimBuddy *b, gboolean init) | |
| 1282 { | |
| 1283 SilcGaim sg = gc->proto_data; | |
| 1284 SilcClient client = sg->client; | |
| 1285 SilcClientConnection conn = sg->conn; | |
| 1286 SilcGaimBuddyRes r; | |
| 1287 SilcBuffer attrs; | |
| 1288 const char *filename, *name = b->name; | |
| 1289 | |
| 1290 r = silc_calloc(1, sizeof(*r)); | |
| 1291 if (!r) | |
| 1292 return; | |
| 1293 r->client = client; | |
| 1294 r->conn = conn; | |
| 1295 r->b = b; | |
| 1296 r->init = init; | |
| 1297 | |
| 1298 /* See if we have this buddy's public key. If we do use that | |
| 1299 to search the details. */ | |
| 1300 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 1301 if (filename) { | |
| 1302 SilcPublicKey public_key; | |
| 1303 SilcAttributeObjPk userpk; | |
| 1304 | |
| 1305 if (!silc_pkcs_load_public_key(filename, &public_key, | |
| 1306 SILC_PKCS_FILE_PEM) && | |
| 1307 !silc_pkcs_load_public_key(filename, &public_key, | |
| 1308 SILC_PKCS_FILE_BIN)) | |
| 1309 return; | |
| 1310 | |
| 1311 /* Get all attributes, and use the public key to search user */ | |
| 1312 name = NULL; | |
| 1313 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, | |
| 1314 SILC_ATTRIBUTE_SERVICE, | |
| 1315 SILC_ATTRIBUTE_STATUS_MOOD, | |
| 1316 SILC_ATTRIBUTE_STATUS_FREETEXT, | |
| 1317 SILC_ATTRIBUTE_STATUS_MESSAGE, | |
| 1318 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, | |
| 1319 SILC_ATTRIBUTE_PREFERRED_CONTACT, | |
| 1320 SILC_ATTRIBUTE_TIMEZONE, | |
| 1321 SILC_ATTRIBUTE_GEOLOCATION, | |
| 1322 SILC_ATTRIBUTE_DEVICE_INFO, 0); | |
| 1323 userpk.type = "silc-rsa"; | |
| 1324 userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); | |
| 1325 attrs = silc_attribute_payload_encode(attrs, | |
| 1326 SILC_ATTRIBUTE_USER_PUBLIC_KEY, | |
| 1327 SILC_ATTRIBUTE_FLAG_VALID, | |
| 1328 &userpk, sizeof(userpk)); | |
| 1329 silc_free(userpk.data); | |
| 1330 silc_pkcs_public_key_free(public_key); | |
| 1331 r->pubkey_search = TRUE; | |
| 1332 } else { | |
| 1333 /* Get all attributes */ | |
| 1334 attrs = silc_client_attributes_request(0); | |
| 1335 } | |
| 1336 | |
| 1337 /* Resolve */ | |
| 1338 silc_client_get_clients_whois(client, conn, name, NULL, attrs, | |
| 1339 silcgaim_add_buddy_resolved, r); | |
| 1340 silc_buffer_free(attrs); | |
| 1341 } | |
| 1342 | |
| 9285 | 1343 void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
| 8849 | 1344 { |
| 9285 | 1345 silcgaim_add_buddy_i(gc, buddy, FALSE); |
| 8849 | 1346 } |
| 1347 | |
| 10869 | 1348 void silcgaim_send_buddylist(GaimConnection *gc) |
| 10341 | 1349 { |
| 10869 | 1350 GaimBuddyList *blist; |
| 1351 GaimBlistNode *gnode, *cnode, *bnode; | |
| 1352 GaimBuddy *buddy; | |
| 12111 | 1353 GaimAccount *account; |
| 1354 | |
| 1355 account = gaim_connection_get_account(gc); | |
| 10869 | 1356 |
| 1357 if ((blist = gaim_get_blist()) != NULL) | |
| 1358 { | |
| 1359 for (gnode = blist->root; gnode != NULL; gnode = gnode->next) | |
| 1360 { | |
| 1361 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 1362 continue; | |
| 1363 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) | |
| 1364 { | |
| 1365 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 1366 continue; | |
| 1367 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) | |
| 1368 { | |
| 1369 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 1370 continue; | |
| 1371 buddy = (GaimBuddy *)bnode; | |
| 12111 | 1372 if (gaim_buddy_get_account(buddy) == account) |
| 1373 silcgaim_add_buddy_i(gc, buddy, TRUE); | |
| 10869 | 1374 } |
| 1375 } | |
| 1376 } | |
| 10341 | 1377 } |
| 1378 } | |
| 1379 | |
| 9285 | 1380 void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
| 1381 GaimGroup *group) | |
| 8849 | 1382 { |
| 9285 | 1383 silc_free(buddy->proto_data); |
| 8849 | 1384 } |
| 1385 | |
| 1386 void silcgaim_idle_set(GaimConnection *gc, int idle) | |
| 1387 | |
| 1388 { | |
| 1389 SilcGaim sg = gc->proto_data; | |
| 1390 SilcClient client = sg->client; | |
| 1391 SilcClientConnection conn = sg->conn; | |
| 1392 SilcAttributeObjService service; | |
| 1393 const char *server; | |
| 1394 int port; | |
| 1395 | |
| 1396 server = gaim_account_get_string(sg->account, "server", | |
| 1397 "silc.silcnet.org"); | |
| 1398 port = gaim_account_get_int(sg->account, "port", 706), | |
| 1399 | |
| 1400 memset(&service, 0, sizeof(service)); | |
| 1401 silc_client_attribute_del(client, conn, | |
| 1402 SILC_ATTRIBUTE_SERVICE, NULL); | |
| 1403 service.port = port; | |
| 1404 g_snprintf(service.address, sizeof(service.address), "%s", server); | |
| 1405 service.idle = idle; | |
| 1406 silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, | |
| 1407 &service, sizeof(service)); | |
| 1408 } | |
| 1409 | |
| 1410 char *silcgaim_status_text(GaimBuddy *b) | |
| 1411 { | |
| 1412 SilcGaim sg = b->account->gc->proto_data; | |
| 1413 SilcClient client = sg->client; | |
| 1414 SilcClientConnection conn = sg->conn; | |
| 1415 SilcClientID *client_id = b->proto_data; | |
| 1416 SilcClientEntry client_entry; | |
| 1417 SilcAttributePayload attr; | |
| 1418 SilcAttributeMood mood = 0; | |
| 1419 | |
| 1420 /* Get the client entry. */ | |
| 1421 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1422 if (!client_entry) | |
| 1423 return NULL; | |
| 1424 | |
| 1425 /* If user is online, we show the mood status, if available. | |
| 1426 If user is offline or away that status is indicated. */ | |
| 1427 | |
| 1428 if (client_entry->mode & SILC_UMODE_DETACHED) | |
| 1429 return g_strdup(_("Detached")); | |
| 1430 if (client_entry->mode & SILC_UMODE_GONE) | |
| 1431 return g_strdup(_("Away")); | |
| 1432 if (client_entry->mode & SILC_UMODE_INDISPOSED) | |
| 1433 return g_strdup(_("Indisposed")); | |
| 1434 if (client_entry->mode & SILC_UMODE_BUSY) | |
| 1435 return g_strdup(_("Busy")); | |
| 1436 if (client_entry->mode & SILC_UMODE_PAGE) | |
| 1437 return g_strdup(_("Wake Me Up")); | |
| 1438 if (client_entry->mode & SILC_UMODE_HYPER) | |
| 1439 return g_strdup(_("Hyper Active")); | |
| 1440 if (client_entry->mode & SILC_UMODE_ROBOT) | |
| 1441 return g_strdup(_("Robot")); | |
| 1442 | |
| 1443 attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); | |
| 1444 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { | |
| 1445 /* The mood is a bit mask, so we could show multiple moods, | |
| 1446 but let's show only one for now. */ | |
| 1447 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) | |
| 1448 return g_strdup(_("Happy")); | |
| 1449 if (mood & SILC_ATTRIBUTE_MOOD_SAD) | |
| 1450 return g_strdup(_("Sad")); | |
| 1451 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) | |
| 1452 return g_strdup(_("Angry")); | |
| 1453 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) | |
| 1454 return g_strdup(_("Jealous")); | |
| 1455 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) | |
| 1456 return g_strdup(_("Ashamed")); | |
| 1457 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) | |
| 1458 return g_strdup(_("Invincible")); | |
| 1459 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) | |
| 1460 return g_strdup(_("In Love")); | |
| 1461 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) | |
| 1462 return g_strdup(_("Sleepy")); | |
| 1463 if (mood & SILC_ATTRIBUTE_MOOD_BORED) | |
| 1464 return g_strdup(_("Bored")); | |
| 1465 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) | |
| 1466 return g_strdup(_("Excited")); | |
| 1467 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) | |
| 1468 return g_strdup(_("Anxious")); | |
| 1469 } | |
| 1470 | |
| 1471 return NULL; | |
| 1472 } | |
| 1473 | |
| 1474 char *silcgaim_tooltip_text(GaimBuddy *b) | |
| 1475 { | |
| 1476 SilcGaim sg = b->account->gc->proto_data; | |
| 1477 SilcClient client = sg->client; | |
| 1478 SilcClientConnection conn = sg->conn; | |
| 1479 SilcClientID *client_id = b->proto_data; | |
| 1480 SilcClientEntry client_entry; | |
| 9488 | 1481 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; |
| 8849 | 1482 GString *s; |
| 1483 char *buf; | |
| 1484 char tmp[256]; | |
| 1485 | |
| 1486 s = g_string_new(""); | |
| 1487 | |
| 1488 /* Get the client entry. */ | |
| 1489 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1490 if (!client_entry) | |
| 1491 return NULL; | |
| 1492 | |
| 1493 if (client_entry->nickname) | |
| 9272 | 1494 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Nickname"), |
| 8849 | 1495 client_entry->nickname); |
| 1496 if (client_entry->username && client_entry->hostname) | |
| 9272 | 1497 g_string_append_printf(s, "\n<b>%s:</b> %s@%s", _("Username"), |
| 8849 | 1498 client_entry->username, client_entry->hostname); |
| 1499 if (client_entry->mode) { | |
| 9488 | 1500 g_string_append_printf(s, "\n<b>%s:</b> ", _("User Modes")); |
| 8849 | 1501 memset(tmp, 0, sizeof(tmp)); |
| 1502 silcgaim_get_umode_string(client_entry->mode, | |
| 1503 tmp, sizeof(tmp) - strlen(tmp)); | |
| 9272 | 1504 g_string_append_printf(s, "%s", tmp); |
| 8849 | 1505 } |
| 1506 | |
| 9488 | 1507 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); |
| 1508 if (moodstr) { | |
| 1509 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Mood"), moodstr); | |
| 1510 g_free(moodstr); | |
| 1511 } | |
| 1512 if (statusstr) { | |
| 1513 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Status Text"), statusstr); | |
| 1514 g_free(statusstr); | |
| 8849 | 1515 } |
| 1516 | |
| 9488 | 1517 if (contactstr) { |
| 1518 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr); | |
| 1519 g_free(contactstr); | |
| 1520 } | |
| 8849 | 1521 |
| 9488 | 1522 if (langstr) { |
| 1523 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Language"), langstr); | |
| 1524 g_free(langstr); | |
| 8849 | 1525 } |
| 1526 | |
| 9488 | 1527 if (devicestr) { |
| 1528 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Device"), devicestr); | |
| 1529 g_free(devicestr); | |
| 8849 | 1530 } |
| 1531 | |
| 9488 | 1532 if (tzstr) { |
| 1533 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Timezone"), tzstr); | |
| 1534 g_free(tzstr); | |
| 1535 } | |
| 8849 | 1536 |
| 9488 | 1537 if (geostr) { |
| 1538 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Geolocation"), geostr); | |
| 1539 g_free(geostr); | |
| 1540 } | |
| 8849 | 1541 |
| 1542 buf = g_string_free(s, FALSE); | |
| 1543 return buf; | |
| 1544 } | |
| 1545 | |
| 1546 static void | |
| 9038 | 1547 silcgaim_buddy_kill(GaimBlistNode *node, gpointer data) |
| 8849 | 1548 { |
| 9030 | 1549 GaimBuddy *b; |
| 1550 GaimConnection *gc; | |
| 1551 SilcGaim sg; | |
| 1552 | |
| 1553 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 1554 | |
| 1555 b = (GaimBuddy *) node; | |
| 1556 gc = gaim_account_get_connection(b->account); | |
| 1557 sg = gc->proto_data; | |
| 8849 | 1558 |
| 1559 /* Call KILL */ | |
| 9030 | 1560 silc_client_command_call(sg->client, sg->conn, NULL, "KILL", |
| 1561 b->name, "Killed by operator", NULL); | |
| 8849 | 1562 } |
| 1563 | |
| 12058 | 1564 typedef struct { |
| 1565 SilcGaim sg; | |
| 1566 SilcClientEntry client_entry; | |
| 1567 } *SilcGaimBuddyWb; | |
| 1568 | |
| 1569 static void | |
| 1570 silcgaim_buddy_wb(GaimBlistNode *node, gpointer data) | |
| 1571 { | |
| 1572 SilcGaimBuddyWb wb = data; | |
| 1573 silcgaim_wb_init(wb->sg, wb->client_entry); | |
| 1574 silc_free(wb); | |
| 1575 } | |
| 1576 | |
| 9030 | 1577 GList *silcgaim_buddy_menu(GaimBuddy *buddy) |
| 8849 | 1578 { |
| 9030 | 1579 GaimConnection *gc = gaim_account_get_connection(buddy->account); |
| 8849 | 1580 SilcGaim sg = gc->proto_data; |
| 1581 SilcClientConnection conn = sg->conn; | |
| 1582 const char *pkfile = NULL; | |
| 1583 SilcClientEntry client_entry = NULL; | |
| 9030 | 1584 GaimBlistNodeAction *act; |
| 1585 GList *m = NULL; | |
| 12058 | 1586 SilcGaimBuddyWb wb; |
| 8849 | 1587 |
| 9038 | 1588 pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); |
| 9030 | 1589 client_entry = silc_client_get_client_by_id(sg->client, |
| 1590 sg->conn, | |
| 9038 | 1591 buddy->proto_data); |
| 8849 | 1592 |
| 1593 if (client_entry && client_entry->send_key) { | |
| 9030 | 1594 act = gaim_blist_node_action_new(_("Reset IM Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1595 silcgaim_buddy_resetkey, NULL, NULL); |
| 9030 | 1596 m = g_list_append(m, act); |
| 1597 | |
| 8849 | 1598 } else { |
| 9030 | 1599 act = gaim_blist_node_action_new(_("IM with Key Exchange"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1600 silcgaim_buddy_keyagr, NULL, NULL); |
| 9030 | 1601 m = g_list_append(m, act); |
| 8849 | 1602 |
| 9030 | 1603 act = gaim_blist_node_action_new(_("IM with Password"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1604 silcgaim_buddy_privkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1605 NULL, NULL); |
| 9030 | 1606 m = g_list_append(m, act); |
| 8849 | 1607 } |
| 1608 | |
| 1609 if (pkfile) { | |
| 9030 | 1610 act = gaim_blist_node_action_new(_("Show Public Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1611 silcgaim_buddy_showkey, NULL, NULL); |
| 9030 | 1612 m = g_list_append(m, act); |
| 1613 | |
| 8849 | 1614 } else { |
| 9030 | 1615 act = gaim_blist_node_action_new(_("Get Public Key..."), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1616 silcgaim_buddy_getkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1617 NULL, NULL); |
| 9030 | 1618 m = g_list_append(m, act); |
| 8849 | 1619 } |
| 1620 | |
| 1621 if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { | |
| 9030 | 1622 act = gaim_blist_node_action_new(_("Kill User"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1623 silcgaim_buddy_kill, NULL, NULL); |
| 9030 | 1624 m = g_list_append(m, act); |
| 8849 | 1625 } |
| 1626 | |
| 12167 | 1627 if (client_entry) { |
| 1628 wb = silc_calloc(1, sizeof(*wb)); | |
| 1629 wb->sg = sg; | |
| 1630 wb->client_entry = client_entry; | |
| 1631 act = gaim_blist_node_action_new(_("Draw On Whiteboard"), | |
| 1632 silcgaim_buddy_wb, (void *)wb, NULL); | |
| 1633 m = g_list_append(m, act); | |
| 1634 } | |
| 8849 | 1635 return m; |
| 1636 } |
