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