Mercurial > pidgin
annotate src/protocols/silc/buddy.c @ 12111:b528f37d8e95
[gaim-migrate @ 14411]
sf patch #1357831, from Sadrul Habib Chowdhury
Looks like this was my bug (me being KingAnt). Sorry!
The description from Sadrul:
This is a simple fix for the following "ShowStopperBug"
(from the kwiki):
==========
buddy shows as online when offline
* I(luke) played with this some today. when my
lschiere SILC account signs on, lschiere(aim) appears
on my LSchiere2 buddy list as though signing on. As far
as the gaim UI is concerned, there is no SILC buddy in
that contact. as LSchiere (aim) is my account, I am
quite sure that it is not online, plus attempting to IM
it yeilds the same result.
==========
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Wed, 16 Nov 2005 06:07:42 +0000 |
| parents | d5daff460913 |
| children | 5851a9219bc7 |
| 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; | |
| 1112 char tmp[512]; | |
| 1113 int i; | |
| 1114 | |
| 1115 fields = gaim_request_fields_new(); | |
| 1116 g = gaim_request_field_group_new(NULL); | |
| 1117 f = gaim_request_field_list_new("list", NULL); | |
| 1118 gaim_request_field_group_add_field(g, f); | |
| 1119 gaim_request_field_list_set_multi_select(f, FALSE); | |
| 1120 gaim_request_fields_add_group(fields, g); | |
| 1121 | |
| 1122 for (i = 0; i < clients_count; i++) { | |
| 1123 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)", | |
| 1124 clients[i]->realname, clients[i]->nickname, | |
| 1125 clients[i]->username, clients[i]->hostname ? | |
| 1126 clients[i]->hostname : ""); | |
| 1127 gaim_request_field_list_add(f, tmp, clients[i]); | |
| 1128 } | |
| 1129 | |
| 11201 | 1130 gaim_request_fields(r->client->application, _("Add Buddy"), |
| 8891 | 1131 _("Select correct user"), |
| 1132 r->pubkey_search | |
| 1133 ? _("More than one user was found with the same public key. Select " | |
| 1134 "the correct user from the list to add to the buddy list.") | |
| 1135 : _("More than one user was found with the same name. Select " | |
| 1136 "the correct user from the list to add to the buddy list."), | |
| 1137 fields, | |
| 1138 _("OK"), G_CALLBACK(silcgaim_add_buddy_select_cb), | |
| 1139 _("Cancel"), G_CALLBACK(silcgaim_add_buddy_select_cancel), r); | |
| 8849 | 1140 } |
| 1141 | |
| 1142 static void | |
| 1143 silcgaim_add_buddy_resolved(SilcClient client, | |
| 1144 SilcClientConnection conn, | |
| 1145 SilcClientEntry *clients, | |
| 1146 SilcUInt32 clients_count, | |
| 1147 void *context) | |
| 1148 { | |
| 1149 SilcGaimBuddyRes r = context; | |
| 1150 GaimBuddy *b = r->b; | |
| 1151 SilcAttributePayload pub; | |
| 1152 SilcAttributeObjPk userpk; | |
| 1153 unsigned char *pk; | |
| 1154 SilcUInt32 pk_len; | |
| 1155 const char *filename; | |
| 1156 | |
| 10029 | 1157 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); |
| 1158 | |
| 8849 | 1159 /* If the buddy is offline/nonexistent, we will require user |
| 1160 to associate a public key with the buddy or the buddy | |
| 1161 cannot be added. */ | |
| 1162 if (!clients_count) { | |
| 1163 if (r->init) { | |
| 1164 silc_free(r); | |
| 1165 return; | |
| 1166 } | |
| 1167 | |
| 1168 r->offline = TRUE; | |
| 10029 | 1169 /* If the user has already associated a public key, try loading it |
| 1170 * before prompting the user to load it again */ | |
| 1171 if (filename != NULL) | |
| 1172 silcgaim_add_buddy_ask_import(r, filename); | |
| 1173 else | |
| 1174 silcgaim_add_buddy_ask_pk(r); | |
| 8849 | 1175 return; |
| 1176 } | |
| 1177 | |
| 1178 /* If more than one client was found with nickname, we need to verify | |
| 1179 from user which one is the correct. */ | |
| 1180 if (clients_count > 1 && !r->pubkey_search) { | |
| 1181 if (r->init) { | |
| 1182 silc_free(r); | |
| 1183 return; | |
| 1184 } | |
| 1185 | |
| 1186 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1187 return; | |
| 1188 } | |
| 1189 | |
| 1190 /* If we searched using public keys and more than one entry was found | |
| 1191 the same person is logged on multiple times. */ | |
| 1192 if (clients_count > 1 && r->pubkey_search && b->name) { | |
| 1193 if (r->init) { | |
| 1194 /* Find the entry that closest matches to the | |
| 1195 buddy nickname. */ | |
| 1196 int i; | |
| 1197 for (i = 0; i < clients_count; i++) { | |
| 1198 if (!strncasecmp(b->name, clients[i]->nickname, | |
| 1199 strlen(b->name))) { | |
| 1200 clients[0] = clients[i]; | |
| 1201 break; | |
| 1202 } | |
| 1203 } | |
| 1204 } else { | |
| 1205 /* Verify from user which one is correct */ | |
| 1206 silcgaim_add_buddy_select(r, clients, clients_count); | |
| 1207 return; | |
| 1208 } | |
| 1209 } | |
| 1210 | |
| 1211 /* The client was found. Now get its public key and verify | |
| 1212 that before adding the buddy. */ | |
| 1213 memset(&userpk, 0, sizeof(userpk)); | |
| 1214 b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); | |
| 1215 r->client_id = *clients[0]->id; | |
| 1216 | |
| 1217 /* Get the public key from attributes, if not present then | |
| 1218 resolve it with GETKEY unless we have it cached already. */ | |
| 1219 if (clients[0]->attrs && !clients[0]->public_key) { | |
| 1220 pub = silcgaim_get_attr(clients[0]->attrs, | |
| 1221 SILC_ATTRIBUTE_USER_PUBLIC_KEY); | |
| 1222 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, | |
| 1223 sizeof(userpk))) { | |
| 1224 /* Get public key with GETKEY */ | |
| 1225 silc_client_command_call(client, conn, NULL, | |
| 1226 "GETKEY", clients[0]->nickname, NULL); | |
| 1227 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1228 conn->cmd_ident, | |
| 1229 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1230 r); | |
| 1231 return; | |
| 1232 } | |
| 1233 if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, | |
| 1234 &clients[0]->public_key)) | |
| 1235 return; | |
| 1236 silc_free(userpk.data); | |
| 1237 } else if (filename && !clients[0]->public_key) { | |
| 1238 if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1239 SILC_PKCS_FILE_PEM) && | |
| 1240 !silc_pkcs_load_public_key(filename, &clients[0]->public_key, | |
| 1241 SILC_PKCS_FILE_BIN)) { | |
| 1242 /* Get public key with GETKEY */ | |
| 1243 silc_client_command_call(client, conn, NULL, | |
| 1244 "GETKEY", clients[0]->nickname, NULL); | |
| 1245 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1246 conn->cmd_ident, | |
| 1247 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1248 r); | |
| 1249 return; | |
| 1250 } | |
| 1251 } else if (!clients[0]->public_key) { | |
| 1252 /* Get public key with GETKEY */ | |
| 1253 silc_client_command_call(client, conn, NULL, | |
| 1254 "GETKEY", clients[0]->nickname, NULL); | |
| 1255 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, | |
| 1256 conn->cmd_ident, | |
| 1257 (SilcCommandCb)silcgaim_add_buddy_getkey_cb, | |
| 1258 r); | |
| 1259 return; | |
| 1260 } | |
| 1261 | |
| 1262 /* We have the public key, verify it. */ | |
| 1263 pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); | |
| 1264 silcgaim_verify_public_key(client, conn, clients[0]->nickname, | |
| 1265 SILC_SOCKET_TYPE_CLIENT, | |
| 1266 pk, pk_len, SILC_SKE_PK_TYPE_SILC, | |
| 1267 silcgaim_add_buddy_save, r); | |
| 1268 silc_free(pk); | |
| 1269 } | |
| 1270 | |
| 1271 static void | |
| 1272 silcgaim_add_buddy_i(GaimConnection *gc, GaimBuddy *b, gboolean init) | |
| 1273 { | |
| 1274 SilcGaim sg = gc->proto_data; | |
| 1275 SilcClient client = sg->client; | |
| 1276 SilcClientConnection conn = sg->conn; | |
| 1277 SilcGaimBuddyRes r; | |
| 1278 SilcBuffer attrs; | |
| 1279 const char *filename, *name = b->name; | |
| 1280 | |
| 1281 r = silc_calloc(1, sizeof(*r)); | |
| 1282 if (!r) | |
| 1283 return; | |
| 1284 r->client = client; | |
| 1285 r->conn = conn; | |
| 1286 r->b = b; | |
| 1287 r->init = init; | |
| 1288 | |
| 1289 /* See if we have this buddy's public key. If we do use that | |
| 1290 to search the details. */ | |
| 1291 filename = gaim_blist_node_get_string((GaimBlistNode *)b, "public-key"); | |
| 1292 if (filename) { | |
| 1293 SilcPublicKey public_key; | |
| 1294 SilcAttributeObjPk userpk; | |
| 1295 | |
| 1296 if (!silc_pkcs_load_public_key(filename, &public_key, | |
| 1297 SILC_PKCS_FILE_PEM) && | |
| 1298 !silc_pkcs_load_public_key(filename, &public_key, | |
| 1299 SILC_PKCS_FILE_BIN)) | |
| 1300 return; | |
| 1301 | |
| 1302 /* Get all attributes, and use the public key to search user */ | |
| 1303 name = NULL; | |
| 1304 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, | |
| 1305 SILC_ATTRIBUTE_SERVICE, | |
| 1306 SILC_ATTRIBUTE_STATUS_MOOD, | |
| 1307 SILC_ATTRIBUTE_STATUS_FREETEXT, | |
| 1308 SILC_ATTRIBUTE_STATUS_MESSAGE, | |
| 1309 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, | |
| 1310 SILC_ATTRIBUTE_PREFERRED_CONTACT, | |
| 1311 SILC_ATTRIBUTE_TIMEZONE, | |
| 1312 SILC_ATTRIBUTE_GEOLOCATION, | |
| 1313 SILC_ATTRIBUTE_DEVICE_INFO, 0); | |
| 1314 userpk.type = "silc-rsa"; | |
| 1315 userpk.data = silc_pkcs_public_key_encode(public_key, &userpk.data_len); | |
| 1316 attrs = silc_attribute_payload_encode(attrs, | |
| 1317 SILC_ATTRIBUTE_USER_PUBLIC_KEY, | |
| 1318 SILC_ATTRIBUTE_FLAG_VALID, | |
| 1319 &userpk, sizeof(userpk)); | |
| 1320 silc_free(userpk.data); | |
| 1321 silc_pkcs_public_key_free(public_key); | |
| 1322 r->pubkey_search = TRUE; | |
| 1323 } else { | |
| 1324 /* Get all attributes */ | |
| 1325 attrs = silc_client_attributes_request(0); | |
| 1326 } | |
| 1327 | |
| 1328 /* Resolve */ | |
| 1329 silc_client_get_clients_whois(client, conn, name, NULL, attrs, | |
| 1330 silcgaim_add_buddy_resolved, r); | |
| 1331 silc_buffer_free(attrs); | |
| 1332 } | |
| 1333 | |
| 9285 | 1334 void silcgaim_add_buddy(GaimConnection *gc, GaimBuddy *buddy, GaimGroup *group) |
| 8849 | 1335 { |
| 9285 | 1336 silcgaim_add_buddy_i(gc, buddy, FALSE); |
| 8849 | 1337 } |
| 1338 | |
| 10869 | 1339 void silcgaim_send_buddylist(GaimConnection *gc) |
| 10341 | 1340 { |
| 10869 | 1341 GaimBuddyList *blist; |
| 1342 GaimBlistNode *gnode, *cnode, *bnode; | |
| 1343 GaimBuddy *buddy; | |
| 12111 | 1344 GaimAccount *account; |
| 1345 | |
| 1346 account = gaim_connection_get_account(gc); | |
| 10869 | 1347 |
| 1348 if ((blist = gaim_get_blist()) != NULL) | |
| 1349 { | |
| 1350 for (gnode = blist->root; gnode != NULL; gnode = gnode->next) | |
| 1351 { | |
| 1352 if (!GAIM_BLIST_NODE_IS_GROUP(gnode)) | |
| 1353 continue; | |
| 1354 for (cnode = gnode->child; cnode != NULL; cnode = cnode->next) | |
| 1355 { | |
| 1356 if (!GAIM_BLIST_NODE_IS_CONTACT(cnode)) | |
| 1357 continue; | |
| 1358 for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) | |
| 1359 { | |
| 1360 if (!GAIM_BLIST_NODE_IS_BUDDY(bnode)) | |
| 1361 continue; | |
| 1362 buddy = (GaimBuddy *)bnode; | |
| 12111 | 1363 if (gaim_buddy_get_account(buddy) == account) |
| 1364 silcgaim_add_buddy_i(gc, buddy, TRUE); | |
| 10869 | 1365 } |
| 1366 } | |
| 1367 } | |
| 10341 | 1368 } |
| 1369 } | |
| 1370 | |
| 9285 | 1371 void silcgaim_remove_buddy(GaimConnection *gc, GaimBuddy *buddy, |
| 1372 GaimGroup *group) | |
| 8849 | 1373 { |
| 9285 | 1374 silc_free(buddy->proto_data); |
| 8849 | 1375 } |
| 1376 | |
| 1377 void silcgaim_idle_set(GaimConnection *gc, int idle) | |
| 1378 | |
| 1379 { | |
| 1380 SilcGaim sg = gc->proto_data; | |
| 1381 SilcClient client = sg->client; | |
| 1382 SilcClientConnection conn = sg->conn; | |
| 1383 SilcAttributeObjService service; | |
| 1384 const char *server; | |
| 1385 int port; | |
| 1386 | |
| 1387 server = gaim_account_get_string(sg->account, "server", | |
| 1388 "silc.silcnet.org"); | |
| 1389 port = gaim_account_get_int(sg->account, "port", 706), | |
| 1390 | |
| 1391 memset(&service, 0, sizeof(service)); | |
| 1392 silc_client_attribute_del(client, conn, | |
| 1393 SILC_ATTRIBUTE_SERVICE, NULL); | |
| 1394 service.port = port; | |
| 1395 g_snprintf(service.address, sizeof(service.address), "%s", server); | |
| 1396 service.idle = idle; | |
| 1397 silc_client_attribute_add(client, conn, SILC_ATTRIBUTE_SERVICE, | |
| 1398 &service, sizeof(service)); | |
| 1399 } | |
| 1400 | |
| 1401 char *silcgaim_status_text(GaimBuddy *b) | |
| 1402 { | |
| 1403 SilcGaim sg = b->account->gc->proto_data; | |
| 1404 SilcClient client = sg->client; | |
| 1405 SilcClientConnection conn = sg->conn; | |
| 1406 SilcClientID *client_id = b->proto_data; | |
| 1407 SilcClientEntry client_entry; | |
| 1408 SilcAttributePayload attr; | |
| 1409 SilcAttributeMood mood = 0; | |
| 1410 | |
| 1411 /* Get the client entry. */ | |
| 1412 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1413 if (!client_entry) | |
| 1414 return NULL; | |
| 1415 | |
| 1416 /* If user is online, we show the mood status, if available. | |
| 1417 If user is offline or away that status is indicated. */ | |
| 1418 | |
| 1419 if (client_entry->mode & SILC_UMODE_DETACHED) | |
| 1420 return g_strdup(_("Detached")); | |
| 1421 if (client_entry->mode & SILC_UMODE_GONE) | |
| 1422 return g_strdup(_("Away")); | |
| 1423 if (client_entry->mode & SILC_UMODE_INDISPOSED) | |
| 1424 return g_strdup(_("Indisposed")); | |
| 1425 if (client_entry->mode & SILC_UMODE_BUSY) | |
| 1426 return g_strdup(_("Busy")); | |
| 1427 if (client_entry->mode & SILC_UMODE_PAGE) | |
| 1428 return g_strdup(_("Wake Me Up")); | |
| 1429 if (client_entry->mode & SILC_UMODE_HYPER) | |
| 1430 return g_strdup(_("Hyper Active")); | |
| 1431 if (client_entry->mode & SILC_UMODE_ROBOT) | |
| 1432 return g_strdup(_("Robot")); | |
| 1433 | |
| 1434 attr = silcgaim_get_attr(client_entry->attrs, SILC_ATTRIBUTE_STATUS_MOOD); | |
| 1435 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) { | |
| 1436 /* The mood is a bit mask, so we could show multiple moods, | |
| 1437 but let's show only one for now. */ | |
| 1438 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY) | |
| 1439 return g_strdup(_("Happy")); | |
| 1440 if (mood & SILC_ATTRIBUTE_MOOD_SAD) | |
| 1441 return g_strdup(_("Sad")); | |
| 1442 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY) | |
| 1443 return g_strdup(_("Angry")); | |
| 1444 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS) | |
| 1445 return g_strdup(_("Jealous")); | |
| 1446 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED) | |
| 1447 return g_strdup(_("Ashamed")); | |
| 1448 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE) | |
| 1449 return g_strdup(_("Invincible")); | |
| 1450 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE) | |
| 1451 return g_strdup(_("In Love")); | |
| 1452 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY) | |
| 1453 return g_strdup(_("Sleepy")); | |
| 1454 if (mood & SILC_ATTRIBUTE_MOOD_BORED) | |
| 1455 return g_strdup(_("Bored")); | |
| 1456 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED) | |
| 1457 return g_strdup(_("Excited")); | |
| 1458 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS) | |
| 1459 return g_strdup(_("Anxious")); | |
| 1460 } | |
| 1461 | |
| 1462 return NULL; | |
| 1463 } | |
| 1464 | |
| 1465 char *silcgaim_tooltip_text(GaimBuddy *b) | |
| 1466 { | |
| 1467 SilcGaim sg = b->account->gc->proto_data; | |
| 1468 SilcClient client = sg->client; | |
| 1469 SilcClientConnection conn = sg->conn; | |
| 1470 SilcClientID *client_id = b->proto_data; | |
| 1471 SilcClientEntry client_entry; | |
| 9488 | 1472 char *moodstr, *statusstr, *contactstr, *langstr, *devicestr, *tzstr, *geostr; |
| 8849 | 1473 GString *s; |
| 1474 char *buf; | |
| 1475 char tmp[256]; | |
| 1476 | |
| 1477 s = g_string_new(""); | |
| 1478 | |
| 1479 /* Get the client entry. */ | |
| 1480 client_entry = silc_client_get_client_by_id(client, conn, client_id); | |
| 1481 if (!client_entry) | |
| 1482 return NULL; | |
| 1483 | |
| 1484 if (client_entry->nickname) | |
| 9272 | 1485 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Nickname"), |
| 8849 | 1486 client_entry->nickname); |
| 1487 if (client_entry->username && client_entry->hostname) | |
| 9272 | 1488 g_string_append_printf(s, "\n<b>%s:</b> %s@%s", _("Username"), |
| 8849 | 1489 client_entry->username, client_entry->hostname); |
| 1490 if (client_entry->mode) { | |
| 9488 | 1491 g_string_append_printf(s, "\n<b>%s:</b> ", _("User Modes")); |
| 8849 | 1492 memset(tmp, 0, sizeof(tmp)); |
| 1493 silcgaim_get_umode_string(client_entry->mode, | |
| 1494 tmp, sizeof(tmp) - strlen(tmp)); | |
| 9272 | 1495 g_string_append_printf(s, "%s", tmp); |
| 8849 | 1496 } |
| 1497 | |
| 9488 | 1498 silcgaim_parse_attrs(client_entry->attrs, &moodstr, &statusstr, &contactstr, &langstr, &devicestr, &tzstr, &geostr); |
| 1499 if (moodstr) { | |
| 1500 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Mood"), moodstr); | |
| 1501 g_free(moodstr); | |
| 1502 } | |
| 1503 if (statusstr) { | |
| 1504 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Status Text"), statusstr); | |
| 1505 g_free(statusstr); | |
| 8849 | 1506 } |
| 1507 | |
| 9488 | 1508 if (contactstr) { |
| 1509 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Contact"), contactstr); | |
| 1510 g_free(contactstr); | |
| 1511 } | |
| 8849 | 1512 |
| 9488 | 1513 if (langstr) { |
| 1514 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Preferred Language"), langstr); | |
| 1515 g_free(langstr); | |
| 8849 | 1516 } |
| 1517 | |
| 9488 | 1518 if (devicestr) { |
| 1519 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Device"), devicestr); | |
| 1520 g_free(devicestr); | |
| 8849 | 1521 } |
| 1522 | |
| 9488 | 1523 if (tzstr) { |
| 1524 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Timezone"), tzstr); | |
| 1525 g_free(tzstr); | |
| 1526 } | |
| 8849 | 1527 |
| 9488 | 1528 if (geostr) { |
| 1529 g_string_append_printf(s, "\n<b>%s:</b> %s", _("Geolocation"), geostr); | |
| 1530 g_free(geostr); | |
| 1531 } | |
| 8849 | 1532 |
| 1533 buf = g_string_free(s, FALSE); | |
| 1534 return buf; | |
| 1535 } | |
| 1536 | |
| 1537 static void | |
| 9038 | 1538 silcgaim_buddy_kill(GaimBlistNode *node, gpointer data) |
| 8849 | 1539 { |
| 9030 | 1540 GaimBuddy *b; |
| 1541 GaimConnection *gc; | |
| 1542 SilcGaim sg; | |
| 1543 | |
| 1544 g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node)); | |
| 1545 | |
| 1546 b = (GaimBuddy *) node; | |
| 1547 gc = gaim_account_get_connection(b->account); | |
| 1548 sg = gc->proto_data; | |
| 8849 | 1549 |
| 1550 /* Call KILL */ | |
| 9030 | 1551 silc_client_command_call(sg->client, sg->conn, NULL, "KILL", |
| 1552 b->name, "Killed by operator", NULL); | |
| 8849 | 1553 } |
| 1554 | |
| 12058 | 1555 typedef struct { |
| 1556 SilcGaim sg; | |
| 1557 SilcClientEntry client_entry; | |
| 1558 } *SilcGaimBuddyWb; | |
| 1559 | |
| 1560 static void | |
| 1561 silcgaim_buddy_wb(GaimBlistNode *node, gpointer data) | |
| 1562 { | |
| 1563 SilcGaimBuddyWb wb = data; | |
| 1564 silcgaim_wb_init(wb->sg, wb->client_entry); | |
| 1565 silc_free(wb); | |
| 1566 } | |
| 1567 | |
| 9030 | 1568 GList *silcgaim_buddy_menu(GaimBuddy *buddy) |
| 8849 | 1569 { |
| 9030 | 1570 GaimConnection *gc = gaim_account_get_connection(buddy->account); |
| 8849 | 1571 SilcGaim sg = gc->proto_data; |
| 1572 SilcClientConnection conn = sg->conn; | |
| 1573 const char *pkfile = NULL; | |
| 1574 SilcClientEntry client_entry = NULL; | |
| 9030 | 1575 GaimBlistNodeAction *act; |
| 1576 GList *m = NULL; | |
| 12058 | 1577 SilcGaimBuddyWb wb; |
| 8849 | 1578 |
| 9038 | 1579 pkfile = gaim_blist_node_get_string((GaimBlistNode *) buddy, "public-key"); |
| 9030 | 1580 client_entry = silc_client_get_client_by_id(sg->client, |
| 1581 sg->conn, | |
| 9038 | 1582 buddy->proto_data); |
| 8849 | 1583 |
| 1584 if (client_entry && client_entry->send_key) { | |
| 9030 | 1585 act = gaim_blist_node_action_new(_("Reset IM Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1586 silcgaim_buddy_resetkey, NULL, NULL); |
| 9030 | 1587 m = g_list_append(m, act); |
| 1588 | |
| 8849 | 1589 } else { |
| 9030 | 1590 act = gaim_blist_node_action_new(_("IM with Key Exchange"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1591 silcgaim_buddy_keyagr, NULL, NULL); |
| 9030 | 1592 m = g_list_append(m, act); |
| 8849 | 1593 |
| 9030 | 1594 act = gaim_blist_node_action_new(_("IM with Password"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1595 silcgaim_buddy_privkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1596 NULL, NULL); |
| 9030 | 1597 m = g_list_append(m, act); |
| 8849 | 1598 } |
| 1599 | |
| 1600 if (pkfile) { | |
| 9030 | 1601 act = gaim_blist_node_action_new(_("Show Public Key"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1602 silcgaim_buddy_showkey, NULL, NULL); |
| 9030 | 1603 m = g_list_append(m, act); |
| 1604 | |
| 8849 | 1605 } else { |
| 9030 | 1606 act = gaim_blist_node_action_new(_("Get Public Key..."), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1607 silcgaim_buddy_getkey_menu, |
|
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1608 NULL, NULL); |
| 9030 | 1609 m = g_list_append(m, act); |
| 8849 | 1610 } |
| 1611 | |
| 1612 if (conn && conn->local_entry->mode & SILC_UMODE_ROUTER_OPERATOR) { | |
| 9030 | 1613 act = gaim_blist_node_action_new(_("Kill User"), |
|
10662
54ac161a876e
[gaim-migrate @ 12199]
Etan Reisner <pidgin@unreliablesource.net>
parents:
10589
diff
changeset
|
1614 silcgaim_buddy_kill, NULL, NULL); |
| 9030 | 1615 m = g_list_append(m, act); |
| 8849 | 1616 } |
| 1617 | |
| 12058 | 1618 wb = silc_calloc(1, sizeof(*wb)); |
| 1619 wb->sg = sg; | |
| 1620 wb->client_entry = client_entry; | |
| 1621 act = gaim_blist_node_action_new(_("Draw On Whiteboard"), | |
| 1622 silcgaim_buddy_wb, (void *)wb, NULL); | |
| 1623 m = g_list_append(m, act); | |
| 1624 | |
| 8849 | 1625 return m; |
| 1626 } |
