comparison libpurple/protocols/silc/buddy.c @ 18080:bb2e5f6ff2b4

propagate from branch 'im.pidgin.pidgin' (head 5fdf4fa0a7dcefa78c9ec2e7c25b151f1e3acf18) to branch 'im.pidgin.pidgin.2.1.0' (head 1d53de833ec35c1899f24b60e7d79db753917c15)
author Stu Tomlinson <stu@nosnilmot.com>
date Sun, 10 Jun 2007 01:46:31 +0000
parents 980a104267da
children 9a96d8711303
comparison
equal deleted inserted replaced
18079:c885a9ccd301 18080:bb2e5f6ff2b4
2 2
3 silcpurple_buddy.c 3 silcpurple_buddy.c
4 4
5 Author: Pekka Riikonen <priikone@silcnet.org> 5 Author: Pekka Riikonen <priikone@silcnet.org>
6 6
7 Copyright (C) 2004 Pekka Riikonen 7 Copyright (C) 2004 - 2007 Pekka Riikonen
8 8
9 This program is free software; you can redistribute it and/or modify 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 10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License. 11 the Free Software Foundation; version 2 of the License.
12 12
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details. 16 GNU General Public License for more details.
17 17
18 */ 18 */
19 19
20 #include "silcincludes.h" 20 #include "silc.h"
21 #include "silcclient.h" 21 #include "silcclient.h"
22 #include "silcpurple.h" 22 #include "silcpurple.h"
23 #include "wb.h" 23 #include "wb.h"
24 24
25 /***************************** Key Agreement *********************************/ 25 /***************************** Key Agreement *********************************/
27 static void 27 static void
28 silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data); 28 silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data);
29 29
30 static void 30 static void
31 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, 31 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name,
32 gboolean force_local); 32 gboolean force_local);
33 33
34 typedef struct { 34 typedef struct {
35 char *nick; 35 char *nick;
36 PurpleConnection *gc; 36 PurpleConnection *gc;
37 } *SilcPurpleResolve; 37 } *SilcPurpleResolve;
38 38
39 static void 39 static void
40 silcpurple_buddy_keyagr_resolved(SilcClient client, 40 silcpurple_buddy_keyagr_resolved(SilcClient client,
41 SilcClientConnection conn, 41 SilcClientConnection conn,
42 SilcClientEntry *clients, 42 SilcStatus status,
43 SilcUInt32 clients_count, 43 SilcDList clients,
44 void *context) 44 void *context)
45 { 45 {
46 PurpleConnection *gc = client->application; 46 PurpleConnection *gc = client->application;
47 SilcPurpleResolve r = context; 47 SilcPurpleResolve r = context;
48 char tmp[256]; 48 char tmp[256];
49 49
60 silcpurple_buddy_keyagr_do(gc, r->nick, FALSE); 60 silcpurple_buddy_keyagr_do(gc, r->nick, FALSE);
61 silc_free(r->nick); 61 silc_free(r->nick);
62 silc_free(r); 62 silc_free(r);
63 } 63 }
64 64
65 typedef struct {
66 gboolean responder;
67 } *SilcPurpleKeyAgr;
68
69 static void 65 static void
70 silcpurple_buddy_keyagr_cb(SilcClient client, 66 silcpurple_buddy_keyagr_cb(SilcClient client,
71 SilcClientConnection conn, 67 SilcClientConnection conn,
72 SilcClientEntry client_entry, 68 SilcClientEntry client_entry,
73 SilcKeyAgreementStatus status, 69 SilcKeyAgreementStatus status,
74 SilcSKEKeyMaterial *key, 70 SilcSKEKeyMaterial key,
75 void *context) 71 void *context)
76 { 72 {
77 PurpleConnection *gc = client->application; 73 PurpleConnection *gc = client->application;
78 SilcPurple sg = gc->proto_data; 74 SilcPurple sg = gc->proto_data;
79 SilcPurpleKeyAgr a = context;
80 75
81 if (!sg->conn) 76 if (!sg->conn)
82 return; 77 return;
83 78
84 switch (status) { 79 switch (status) {
88 char tmp[128]; 83 char tmp[128];
89 84
90 /* Set the private key for this client */ 85 /* Set the private key for this client */
91 silc_client_del_private_message_key(client, conn, client_entry); 86 silc_client_del_private_message_key(client, conn, client_entry);
92 silc_client_add_private_message_key_ske(client, conn, client_entry, 87 silc_client_add_private_message_key_ske(client, conn, client_entry,
93 NULL, NULL, key, a->responder); 88 NULL, NULL, key);
94 silc_ske_free_key_material(key); 89 silc_ske_free_key_material(key);
95 90
96 91
97 /* Open IM window */ 92 /* Open IM window */
98 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, 93 convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
99 client_entry->nickname, sg->account); 94 client_entry->nickname, sg->account);
100 if (convo) { 95 if (convo) {
101 /* we don't have windows in the core anymore...but we may want to 96 /* 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 97 * provide some method for asking the UI to show the window
103 purple_conv_window_show(purple_conversation_get_window(convo)); 98 purple_conv_window_show(purple_conversation_get_window(convo));
104 */ 99 */
105 } else { 100 } else {
106 convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account, 101 convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, sg->account,
107 client_entry->nickname); 102 client_entry->nickname);
108 } 103 }
109 g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname); 104 g_snprintf(tmp, sizeof(tmp), "%s [private key]", client_entry->nickname);
110 purple_conversation_set_title(convo, tmp); 105 purple_conversation_set_title(convo, tmp);
111 } 106 }
112 break; 107 break;
113 108
114 case SILC_KEY_AGREEMENT_ERROR: 109 case SILC_KEY_AGREEMENT_ERROR:
115 purple_notify_error(gc, _("Key Agreement"), 110 purple_notify_error(gc, _("Key Agreement"),
116 _("Error occurred during key agreement"), NULL); 111 _("Error occurred during key agreement"), NULL);
117 break; 112 break;
118 113
119 case SILC_KEY_AGREEMENT_FAILURE: 114 case SILC_KEY_AGREEMENT_FAILURE:
120 purple_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL); 115 purple_notify_error(gc, _("Key Agreement"), _("Key Agreement failed"), NULL);
121 break; 116 break;
122 117
123 case SILC_KEY_AGREEMENT_TIMEOUT: 118 case SILC_KEY_AGREEMENT_TIMEOUT:
124 purple_notify_error(gc, _("Key Agreement"), 119 purple_notify_error(gc, _("Key Agreement"),
125 _("Timeout during key agreement"), NULL); 120 _("Timeout during key agreement"), NULL);
126 break; 121 break;
127 122
128 case SILC_KEY_AGREEMENT_ABORTED: 123 case SILC_KEY_AGREEMENT_ABORTED:
129 purple_notify_error(gc, _("Key Agreement"), 124 purple_notify_error(gc, _("Key Agreement"),
130 _("Key agreement was aborted"), NULL); 125 _("Key agreement was aborted"), NULL);
131 break; 126 break;
132 127
133 case SILC_KEY_AGREEMENT_ALREADY_STARTED: 128 case SILC_KEY_AGREEMENT_ALREADY_STARTED:
134 purple_notify_error(gc, _("Key Agreement"), 129 purple_notify_error(gc, _("Key Agreement"),
135 _("Key agreement is already started"), NULL); 130 _("Key agreement is already started"), NULL);
136 break; 131 break;
137 132
138 case SILC_KEY_AGREEMENT_SELF_DENIED: 133 case SILC_KEY_AGREEMENT_SELF_DENIED:
139 purple_notify_error(gc, _("Key Agreement"), 134 purple_notify_error(gc, _("Key Agreement"),
140 _("Key agreement cannot be started with yourself"), 135 _("Key agreement cannot be started with yourself"),
141 NULL); 136 NULL);
142 break; 137 break;
143 138
144 default: 139 default:
145 break; 140 break;
146 } 141 }
147
148 silc_free(a);
149 } 142 }
150 143
151 static void 144 static void
152 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name, 145 silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name,
153 gboolean force_local) 146 gboolean force_local)
154 { 147 {
155 SilcPurple sg = gc->proto_data; 148 SilcPurple sg = gc->proto_data;
156 SilcClientEntry *clients; 149 SilcDList clients;
157 SilcUInt32 clients_count; 150 SilcClientEntry client_entry;
151 SilcClientConnectionParams params;
158 char *local_ip = NULL, *remote_ip = NULL; 152 char *local_ip = NULL, *remote_ip = NULL;
159 gboolean local = TRUE; 153 gboolean local = TRUE;
160 char *nickname; 154 SilcSocket sock;
161 SilcPurpleKeyAgr a;
162 155
163 if (!sg->conn || !name) 156 if (!sg->conn || !name)
164 return; 157 return;
165 158
166 if (!silc_parse_userfqdn(name, &nickname, NULL))
167 return;
168
169 /* Find client entry */ 159 /* Find client entry */
170 clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name, 160 clients = silc_client_get_clients_local(sg->client, sg->conn, name,
171 &clients_count); 161 FALSE);
172 if (!clients) { 162 if (!clients) {
173 /* Resolve unknown user */ 163 /* Resolve unknown user */
174 SilcPurpleResolve r = silc_calloc(1, sizeof(*r)); 164 SilcPurpleResolve r = silc_calloc(1, sizeof(*r));
175 if (!r) 165 if (!r)
176 return; 166 return;
177 r->nick = g_strdup(name); 167 r->nick = g_strdup(name);
178 r->gc = gc; 168 r->gc = gc;
179 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, 169 silc_client_get_clients(sg->client, sg->conn, name, NULL,
180 silcpurple_buddy_keyagr_resolved, r); 170 silcpurple_buddy_keyagr_resolved, r);
181 silc_free(nickname); 171 return;
182 return; 172 }
183 } 173
174 silc_socket_stream_get_info(silc_packet_stream_get_stream(sg->conn->stream),
175 &sock, NULL, NULL, NULL);
184 176
185 /* Resolve the local IP from the outgoing socket connection. We resolve 177 /* 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 178 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 179 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 180 NAT and will provide automatically the point of connection to the
194 assume that we are chatting in LAN and will provide the point of 186 assume that we are chatting in LAN and will provide the point of
195 connection. 187 connection.
196 188
197 Naturally this algorithm does not always get things right. */ 189 Naturally this algorithm does not always get things right. */
198 190
199 if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) { 191 if (silc_net_check_local_by_sock(sock, NULL, &local_ip)) {
200 /* Check if the IP is private */ 192 /* Check if the IP is private */
201 if (!force_local && silcpurple_ip_is_private(local_ip)) { 193 if (!force_local && silcpurple_ip_is_private(local_ip)) {
202 local = FALSE; 194 local = FALSE;
203 195
204 /* Local IP is private, resolve the remote server IP to see whether 196 /* Local IP is private, resolve the remote server IP to see whether
205 we are talking to Internet or just on LAN. */ 197 we are talking to Internet or just on LAN. */
206 if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL, 198 if (silc_net_check_host_by_sock(sock, NULL,
207 &remote_ip)) 199 &remote_ip))
208 if (silcpurple_ip_is_private(remote_ip)) 200 if (silcpurple_ip_is_private(remote_ip))
209 /* We assume we are in LAN. Let's provide 201 /* We assume we are in LAN. Let's provide
210 the connection point. */ 202 the connection point. */
211 local = TRUE; 203 local = TRUE;
216 local = TRUE; 208 local = TRUE;
217 209
218 if (local && !local_ip) 210 if (local && !local_ip)
219 local_ip = silc_net_localip(); 211 local_ip = silc_net_localip();
220 212
221 a = silc_calloc(1, sizeof(*a)); 213 silc_dlist_start(clients);
222 if (!a) 214 client_entry = silc_dlist_get(clients);
223 return; 215
224 a->responder = local; 216 memset(&params, 0, sizeof(params));
217 params.timeout_secs = 60;
218 if (local)
219 /* Provide connection point */
220 params.local_ip = local_ip;
225 221
226 /* Send the key agreement request */ 222 /* Send the key agreement request */
227 silc_client_send_key_agreement(sg->client, sg->conn, clients[0], 223 silc_client_send_key_agreement(sg->client, sg->conn, client_entry,
228 local ? local_ip : NULL, NULL, 0, 60, 224 &params, sg->public_key,
229 silcpurple_buddy_keyagr_cb, a); 225 sg->private_key,
226 silcpurple_buddy_keyagr_cb, NULL);
230 227
231 silc_free(local_ip); 228 silc_free(local_ip);
232 silc_free(remote_ip); 229 silc_free(remote_ip);
233 silc_free(clients); 230 silc_client_list_free(sg->client, sg->conn, clients);
234 } 231 }
235 232
236 typedef struct { 233 typedef struct {
237 SilcClient client; 234 SilcClient client;
238 SilcClientConnection conn; 235 SilcClientConnection conn;
242 } *SilcPurpleKeyAgrAsk; 239 } *SilcPurpleKeyAgrAsk;
243 240
244 static void 241 static void
245 silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id) 242 silcpurple_buddy_keyagr_request_cb(SilcPurpleKeyAgrAsk a, gint id)
246 { 243 {
247 SilcPurpleKeyAgr ai;
248 SilcClientEntry client_entry; 244 SilcClientEntry client_entry;
245 SilcClientConnectionParams params;
249 246
250 if (id != 1) 247 if (id != 1)
251 goto out; 248 goto out;
252 249
253 /* Get the client entry. */ 250 /* Get the client entry. */
254 client_entry = silc_client_get_client_by_id(a->client, a->conn, 251 client_entry = silc_client_get_client_by_id(a->client, a->conn,
255 &a->client_id); 252 &a->client_id);
256 if (!client_entry) { 253 if (!client_entry) {
257 purple_notify_error(a->client->application, _("Key Agreement"), 254 purple_notify_error(a->client->application, _("Key Agreement"),
258 _("The remote user is not present in the network any more"), 255 _("The remote user is not present in the network any more"),
259 NULL); 256 NULL);
260 goto out; 257 goto out;
261 } 258 }
262 259
263 /* If the hostname was provided by the requestor perform the key agreement 260 /* 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. */ 261 now. Otherwise, we will send him a request to connect to us. */
265 if (a->hostname) { 262 if (a->hostname) {
266 ai = silc_calloc(1, sizeof(*ai)); 263 memset(&params, 0, sizeof(params));
267 if (!ai) 264 params.timeout_secs = 60;
268 goto out; 265 silc_client_perform_key_agreement(a->client, a->conn,
269 ai->responder = FALSE; 266 client_entry, &params,
270 silc_client_perform_key_agreement(a->client, a->conn, client_entry, 267 a->conn->public_key,
268 a->conn->private_key,
271 a->hostname, a->port, 269 a->hostname, a->port,
272 silcpurple_buddy_keyagr_cb, ai); 270 silcpurple_buddy_keyagr_cb, NULL);
273 } else { 271 } else {
274 /* Send request. Force us as the point of connection since requestor 272 /* Send request. Force us as the point of connection since requestor
275 did not provide the point of connection. */ 273 did not provide the point of connection. */
276 silcpurple_buddy_keyagr_do(a->client->application, 274 silcpurple_buddy_keyagr_do(a->client->application,
277 client_entry->nickname, TRUE); 275 client_entry->nickname, TRUE);
278 } 276 }
279 277
280 out: 278 out:
281 silc_free(a->hostname); 279 silc_free(a->hostname);
282 silc_free(a); 280 silc_free(a);
283 } 281 }
284 282
285 void silcpurple_buddy_keyagr_request(SilcClient client, 283 void silcpurple_buddy_keyagr_request(SilcClient client,
286 SilcClientConnection conn, 284 SilcClientConnection conn,
287 SilcClientEntry client_entry, 285 SilcClientEntry client_entry,
288 const char *hostname, SilcUInt16 port) 286 const char *hostname, SilcUInt16 port,
287 SilcUInt16 protocol)
289 { 288 {
290 char tmp[128], tmp2[128]; 289 char tmp[128], tmp2[128];
291 SilcPurpleKeyAgrAsk a; 290 SilcPurpleKeyAgrAsk a;
292 PurpleConnection *gc = client->application; 291 PurpleConnection *gc = client->application;
292
293 /* For now Pidgin don't support UDP key agreement */
294 if (protocol == 1)
295 return;
293 296
294 g_snprintf(tmp, sizeof(tmp), 297 g_snprintf(tmp, sizeof(tmp),
295 _("Key agreement request received from %s. Would you like to " 298 _("Key agreement request received from %s. Would you like to "
296 "perform the key agreement?"), client_entry->nickname); 299 "perform the key agreement?"), client_entry->nickname);
297 if (hostname) 300 if (hostname)
302 a = silc_calloc(1, sizeof(*a)); 305 a = silc_calloc(1, sizeof(*a));
303 if (!a) 306 if (!a)
304 return; 307 return;
305 a->client = client; 308 a->client = client;
306 a->conn = conn; 309 a->conn = conn;
307 a->client_id = *client_entry->id; 310 a->client_id = client_entry->id;
308 if (hostname) 311 if (hostname)
309 a->hostname = strdup(hostname); 312 a->hostname = strdup(hostname);
310 a->port = port; 313 a->port = port;
311 314
312 purple_request_action(client->application, _("Key Agreement Request"), tmp, 315 purple_request_action(client->application, _("Key Agreement Request"), tmp,
313 hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname, 316 hostname ? tmp2 : NULL, 1, gc->account, client_entry->nickname,
314 NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb), 317 NULL, a, 2, _("Yes"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb),
315 _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb)); 318 _("No"), G_CALLBACK(silcpurple_buddy_keyagr_request_cb));
316 } 319 }
317 320
318 static void 321 static void
319 silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data) 322 silcpurple_buddy_keyagr(PurpleBlistNode *node, gpointer data)
320 { 323 {
331 silcpurple_buddy_resetkey(PurpleBlistNode *node, gpointer data) 334 silcpurple_buddy_resetkey(PurpleBlistNode *node, gpointer data)
332 { 335 {
333 PurpleBuddy *b; 336 PurpleBuddy *b;
334 PurpleConnection *gc; 337 PurpleConnection *gc;
335 SilcPurple sg; 338 SilcPurple sg;
336 char *nickname; 339 SilcDList clients;
337 SilcClientEntry *clients;
338 SilcUInt32 clients_count;
339 340
340 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); 341 g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));
341 342
342 b = (PurpleBuddy *) node; 343 b = (PurpleBuddy *) node;
343 gc = purple_account_get_connection(b->account); 344 gc = purple_account_get_connection(b->account);
344 sg = gc->proto_data; 345 sg = gc->proto_data;
345 346
346 if (!silc_parse_userfqdn(b->name, &nickname, NULL))
347 return;
348
349 /* Find client entry */ 347 /* Find client entry */
350 clients = silc_client_get_clients_local(sg->client, sg->conn, 348 clients = silc_client_get_clients_local(sg->client, sg->conn,
351 nickname, b->name, 349 b->name, FALSE);
352 &clients_count); 350 if (!clients)
353 if (!clients) { 351 return;
354 silc_free(nickname); 352
355 return; 353 silc_dlist_start(clients);
356 }
357
358 clients[0]->prv_resp = FALSE;
359 silc_client_del_private_message_key(sg->client, sg->conn, 354 silc_client_del_private_message_key(sg->client, sg->conn,
360 clients[0]); 355 silc_dlist_get(clients));
361 silc_free(clients); 356 silc_client_list_free(sg->client, sg->conn, clients);
362 silc_free(nickname);
363 } 357 }
364 358
365 typedef struct { 359 typedef struct {
366 SilcClient client; 360 SilcClient client;
367 SilcClientConnection conn; 361 SilcClientConnection conn;
384 /* Get the client entry. */ 378 /* Get the client entry. */
385 client_entry = silc_client_get_client_by_id(p->client, p->conn, 379 client_entry = silc_client_get_client_by_id(p->client, p->conn,
386 &p->client_id); 380 &p->client_id);
387 if (!client_entry) { 381 if (!client_entry) {
388 purple_notify_error(p->client->application, _("IM With Password"), 382 purple_notify_error(p->client->application, _("IM With Password"),
389 _("The remote user is not present in the network any more"), 383 _("The remote user is not present in the network any more"),
390 NULL); 384 NULL);
391 silc_free(p); 385 silc_free(p);
392 return; 386 return;
393 } 387 }
394 388
395 /* Set the private message key */ 389 /* Set the private message key */
396 silc_client_del_private_message_key(p->client, p->conn, 390 silc_client_del_private_message_key(p->client, p->conn,
397 client_entry); 391 client_entry);
398 silc_client_add_private_message_key(p->client, p->conn, 392 silc_client_add_private_message_key(p->client, p->conn,
399 client_entry, NULL, NULL, 393 client_entry, NULL, NULL,
400 (unsigned char *)passphrase, 394 (unsigned char *)passphrase,
401 strlen(passphrase), FALSE, 395 strlen(passphrase));
402 client_entry->prv_resp);
403 if (!client_entry->prv_resp)
404 silc_client_send_private_message_key_request(p->client,
405 p->conn,
406 client_entry);
407 silc_free(p); 396 silc_free(p);
408 } 397 }
409 398
410 static void 399 static void
411 silcpurple_buddy_privkey_resolved(SilcClient client, 400 silcpurple_buddy_privkey_resolved(SilcClient client,
412 SilcClientConnection conn, 401 SilcClientConnection conn,
413 SilcClientEntry *clients, 402 SilcStatus status,
414 SilcUInt32 clients_count, 403 SilcDList clients,
415 void *context) 404 void *context)
416 { 405 {
417 char tmp[256]; 406 char tmp[256];
418 407
419 if (!clients) { 408 if (!clients) {
420 g_snprintf(tmp, sizeof(tmp), 409 g_snprintf(tmp, sizeof(tmp),
432 421
433 static void 422 static void
434 silcpurple_buddy_privkey(PurpleConnection *gc, const char *name) 423 silcpurple_buddy_privkey(PurpleConnection *gc, const char *name)
435 { 424 {
436 SilcPurple sg = gc->proto_data; 425 SilcPurple sg = gc->proto_data;
437 char *nickname;
438 SilcPurplePrivkey p; 426 SilcPurplePrivkey p;
439 SilcClientEntry *clients; 427 SilcDList clients;
440 SilcUInt32 clients_count; 428 SilcClientEntry client_entry;
441 429
442 if (!name) 430 if (!name)
443 return;
444 if (!silc_parse_userfqdn(name, &nickname, NULL))
445 return; 431 return;
446 432
447 /* Find client entry */ 433 /* Find client entry */
448 clients = silc_client_get_clients_local(sg->client, sg->conn, 434 clients = silc_client_get_clients_local(sg->client, sg->conn,
449 nickname, name, 435 name, FALSE);
450 &clients_count);
451 if (!clients) { 436 if (!clients) {
452 silc_client_get_clients(sg->client, sg->conn, nickname, NULL, 437 silc_client_get_clients(sg->client, sg->conn, name, NULL,
453 silcpurple_buddy_privkey_resolved, 438 silcpurple_buddy_privkey_resolved,
454 g_strdup(name)); 439 g_strdup(name));
455 silc_free(nickname); 440 return;
456 return; 441 }
457 } 442
443 silc_dlist_start(clients);
444 client_entry = silc_dlist_get(clients);
458 445
459 p = silc_calloc(1, sizeof(*p)); 446 p = silc_calloc(1, sizeof(*p));
460 if (!p) 447 if (!p)
461 return; 448 return;
462 p->client = sg->client; 449 p->client = sg->client;
463 p->conn = sg->conn; 450 p->conn = sg->conn;
464 p->client_id = *clients[0]->id; 451 p->client_id = client_entry->id;
465 purple_request_input(gc, _("IM With Password"), NULL, 452 purple_request_input(gc, _("IM With Password"), NULL,
466 _("Set IM Password"), NULL, FALSE, TRUE, NULL, 453 _("Set IM Password"), NULL, FALSE, TRUE, NULL,
467 _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb), 454 _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb),
468 _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb), 455 _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb),
469 gc->account, NULL, NULL, p); 456 gc->account, NULL, NULL, p);
470 457
471 silc_free(clients); 458 silc_client_list_free(sg->client, sg->conn, clients);
472 silc_free(nickname);
473 } 459 }
474 460
475 static void 461 static void
476 silcpurple_buddy_privkey_menu(PurpleBlistNode *node, gpointer data) 462 silcpurple_buddy_privkey_menu(PurpleBlistNode *node, gpointer data)
477 { 463 {
496 } *SilcPurpleBuddyGetkey; 482 } *SilcPurpleBuddyGetkey;
497 483
498 static void 484 static void
499 silcpurple_buddy_getkey(PurpleConnection *gc, const char *name); 485 silcpurple_buddy_getkey(PurpleConnection *gc, const char *name);
500 486
501 static void 487 static SilcBool
502 silcpurple_buddy_getkey_cb(SilcPurpleBuddyGetkey g, 488 silcpurple_buddy_getkey_cb(SilcClient client, SilcClientConnection conn,
503 SilcClientCommandReplyContext cmd) 489 SilcCommand command, SilcStatus status,
490 SilcStatus error, void *context, va_list ap)
504 { 491 {
505 SilcClientEntry client_entry; 492 SilcClientEntry client_entry;
506 unsigned char *pk; 493 SilcPurpleBuddyGetkey g = context;
507 SilcUInt32 pk_len; 494
495 if (status != SILC_STATUS_OK) {
496 purple_notify_error(g->client->application, _("Get Public Key"),
497 _("The remote user is not present in the network any more"),
498 NULL);
499 silc_free(g);
500 return FALSE;
501 }
508 502
509 /* Get the client entry. */ 503 /* Get the client entry. */
510 client_entry = silc_client_get_client_by_id(g->client, g->conn, 504 client_entry = silc_client_get_client_by_id(g->client, g->conn,
511 &g->client_id); 505 &g->client_id);
512 if (!client_entry) { 506 if (!client_entry) {
513 purple_notify_error(g->client->application, _("Get Public Key"), 507 purple_notify_error(g->client->application, _("Get Public Key"),
514 _("The remote user is not present in the network any more"), 508 _("The remote user is not present in the network any more"),
515 NULL); 509 NULL);
516 silc_free(g); 510 silc_free(g);
517 return; 511 return FALSE;
518 } 512 }
519 513
520 if (!client_entry->public_key) { 514 if (!client_entry->public_key) {
521 silc_free(g); 515 silc_free(g);
522 return; 516 return FALSE;
523 } 517 }
524 518
525 /* Now verify the public key */ 519 /* Now verify the public key */
526 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
527 silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname, 520 silcpurple_verify_public_key(g->client, g->conn, client_entry->nickname,
528 SILC_SOCKET_TYPE_CLIENT, 521 SILC_CONN_CLIENT, client_entry->public_key,
529 pk, pk_len, SILC_SKE_PK_TYPE_SILC, 522 NULL, NULL);
530 NULL, NULL);
531 silc_free(pk);
532 silc_free(g); 523 silc_free(g);
524 return TRUE;
533 } 525 }
534 526
535 static void 527 static void
536 silcpurple_buddy_getkey_resolved(SilcClient client, 528 silcpurple_buddy_getkey_resolved(SilcClient client,
537 SilcClientConnection conn, 529 SilcClientConnection conn,
538 SilcClientEntry *clients, 530 SilcStatus status,
539 SilcUInt32 clients_count, 531 SilcDList clients,
540 void *context) 532 void *context)
541 { 533 {
542 char tmp[256]; 534 char tmp[256];
543 535
544 if (!clients) { 536 if (!clients) {
545 g_snprintf(tmp, sizeof(tmp), 537 g_snprintf(tmp, sizeof(tmp),
546 _("User %s is not present in the network"), 538 _("User %s is not present in the network"),
547 (const char *)context); 539 (const char *)context);
548 purple_notify_error(client->application, _("Get Public Key"), 540 purple_notify_error(client->application, _("Get Public Key"),
549 _("Cannot fetch the public key"), tmp); 541 _("Cannot fetch the public key"), tmp);
550 g_free(context); 542 g_free(context);
551 return; 543 return;
552 } 544 }
553 545
554 silcpurple_buddy_getkey(client->application, context); 546 silcpurple_buddy_getkey(client->application, context);
559 silcpurple_buddy_getkey(PurpleConnection *gc, const char *name) 551 silcpurple_buddy_getkey(PurpleConnection *gc, const char *name)
560 { 552 {
561 SilcPurple sg = gc->proto_data; 553 SilcPurple sg = gc->proto_data;
562 SilcClient client = sg->client; 554 SilcClient client = sg->client;
563 SilcClientConnection conn = sg->conn; 555 SilcClientConnection conn = sg->conn;
564 SilcClientEntry *clients; 556 SilcClientEntry client_entry;
565 SilcUInt32 clients_count; 557 SilcDList clients;
566 SilcPurpleBuddyGetkey g; 558 SilcPurpleBuddyGetkey g;
567 char *nickname; 559 SilcUInt16 cmd_ident;
568 560
569 if (!name) 561 if (!name)
570 return; 562 return;
571 563
572 if (!silc_parse_userfqdn(name, &nickname, NULL))
573 return;
574
575 /* Find client entry */ 564 /* Find client entry */
576 clients = silc_client_get_clients_local(client, conn, nickname, name, 565 clients = silc_client_get_clients_local(client, conn, name, FALSE);
577 &clients_count);
578 if (!clients) { 566 if (!clients) {
579 silc_client_get_clients(client, conn, nickname, NULL, 567 silc_client_get_clients(client, conn, name, NULL,
580 silcpurple_buddy_getkey_resolved, 568 silcpurple_buddy_getkey_resolved,
581 g_strdup(name)); 569 g_strdup(name));
582 silc_free(nickname); 570 return;
583 return; 571 }
584 } 572
573 silc_dlist_start(clients);
574 client_entry = silc_dlist_get(clients);
585 575
586 /* Call GETKEY */ 576 /* Call GETKEY */
587 g = silc_calloc(1, sizeof(*g)); 577 g = silc_calloc(1, sizeof(*g));
588 if (!g) 578 if (!g)
589 return; 579 return;
590 g->client = client; 580 g->client = client;
591 g->conn = conn; 581 g->conn = conn;
592 g->client_id = *clients[0]->id; 582 g->client_id = client_entry->id;
593 silc_client_command_call(client, conn, NULL, "GETKEY", 583 cmd_ident = silc_client_command_call(client, conn, NULL, "GETKEY",
594 clients[0]->nickname, NULL); 584 client_entry->nickname, NULL);
595 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, 585 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, cmd_ident,
596 conn->cmd_ident, 586 silcpurple_buddy_getkey_cb, g);
597 (SilcCommandCb)silcpurple_buddy_getkey_cb, g); 587 silc_client_list_free(client, conn, clients);
598 silc_free(clients);
599 silc_free(nickname);
600 } 588 }
601 589
602 static void 590 static void
603 silcpurple_buddy_getkey_menu(PurpleBlistNode *node, gpointer data) 591 silcpurple_buddy_getkey_menu(PurpleBlistNode *node, gpointer data)
604 { 592 {
627 b = (PurpleBuddy *) node; 615 b = (PurpleBuddy *) node;
628 gc = purple_account_get_connection(b->account); 616 gc = purple_account_get_connection(b->account);
629 sg = gc->proto_data; 617 sg = gc->proto_data;
630 618
631 pkfile = purple_blist_node_get_string(node, "public-key"); 619 pkfile = purple_blist_node_get_string(node, "public-key");
632 if (!silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_PEM) && 620 if (!silc_pkcs_load_public_key(pkfile, &public_key)) {
633 !silc_pkcs_load_public_key(pkfile, &public_key, SILC_PKCS_FILE_BIN)) {
634 purple_notify_error(gc, 621 purple_notify_error(gc,
635 _("Show Public Key"), 622 _("Show Public Key"),
636 _("Could not load public key"), NULL); 623 _("Could not load public key"), NULL);
637 return; 624 return;
638 } 625 }
659 SilcClientConnection conn; 646 SilcClientConnection conn;
660 SilcClientID client_id; 647 SilcClientID client_id;
661 PurpleBuddy *b; 648 PurpleBuddy *b;
662 unsigned char *offline_pk; 649 unsigned char *offline_pk;
663 SilcUInt32 offline_pk_len; 650 SilcUInt32 offline_pk_len;
651 SilcPublicKey public_key;
664 unsigned int offline : 1; 652 unsigned int offline : 1;
665 unsigned int pubkey_search : 1; 653 unsigned int pubkey_search : 1;
666 unsigned int init : 1; 654 unsigned int init : 1;
667 } *SilcPurpleBuddyRes; 655 } *SilcPurpleBuddyRes;
668 656
669 static void 657 static void
670 silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id); 658 silcpurple_add_buddy_ask_pk_cb(SilcPurpleBuddyRes r, gint id);
671 static void 659 static void
672 silcpurple_add_buddy_resolved(SilcClient client, 660 silcpurple_add_buddy_resolved(SilcClient client,
673 SilcClientConnection conn, 661 SilcClientConnection conn,
674 SilcClientEntry *clients, 662 SilcStatus status,
675 SilcUInt32 clients_count, 663 SilcDList clients,
676 void *context); 664 void *context);
677 665
678 void silcpurple_get_info(PurpleConnection *gc, const char *who) 666 void silcpurple_get_info(PurpleConnection *gc, const char *who)
679 { 667 {
680 SilcPurple sg = gc->proto_data; 668 SilcPurple sg = gc->proto_data;
681 SilcClient client = sg->client; 669 SilcClient client = sg->client;
733 { 721 {
734 char tmp[512]; 722 char tmp[512];
735 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"), 723 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not trusted"),
736 r->b->name); 724 r->b->name);
737 purple_notify_error(r->client->application, _("Add Buddy"), tmp, 725 purple_notify_error(r->client->application, _("Add Buddy"), tmp,
738 _("You cannot receive buddy notifications until you " 726 _("You cannot receive buddy notifications until you "
739 "import his/her public key. You can use the Get Public Key " 727 "import his/her public key. You can use the Get Public Key "
740 "command to get the public key.")); 728 "command to get the public key."));
741 purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); 729 purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL);
742 } 730 }
743 731
744 static void 732 static void
745 silcpurple_add_buddy_save(bool success, void *context) 733 silcpurple_add_buddy_save(SilcBool success, void *context)
746 { 734 {
747 SilcPurpleBuddyRes r = context; 735 SilcPurpleBuddyRes r = context;
748 PurpleBuddy *b = r->b; 736 PurpleBuddy *b = r->b;
749 SilcClient client = r->client;
750 SilcClientEntry client_entry; 737 SilcClientEntry client_entry;
751 SilcAttributePayload attr; 738 SilcAttributePayload attr;
752 SilcAttribute attribute; 739 SilcAttribute attribute;
753 SilcVCardStruct vcard; 740 SilcVCardStruct vcard;
754 SilcAttributeObjMime message, extension; 741 SilcMime message = NULL, extension = NULL;
755 #ifdef SILC_ATTRIBUTE_USER_ICON 742 #ifdef SILC_ATTRIBUTE_USER_ICON
756 SilcAttributeObjMime usericon; 743 SilcMime usericon = NULL;
757 #endif 744 #endif
758 SilcAttributeObjPk serverpk, usersign, serversign; 745 SilcAttributeObjPk serverpk, usersign, serversign;
759 gboolean usign_success = TRUE, ssign_success = TRUE; 746 gboolean usign_success = TRUE, ssign_success = TRUE;
760 char filename[512], filename2[512], *fingerprint = NULL, *tmp; 747 char filename[512], filename2[512], *fingerprint = NULL, *tmp;
761 SilcUInt32 len; 748 SilcUInt32 len;
749 SilcHash hash;
762 int i; 750 int i;
763 751
764 if (!success) { 752 if (!success) {
765 /* The user did not trust the public key. */ 753 /* The user did not trust the public key. */
766 silcpurple_add_buddy_pk_no(r); 754 silcpurple_add_buddy_pk_no(r);
755 silc_free(r->offline_pk);
756 if (r->public_key)
757 silc_pkcs_public_key_free(r->public_key);
767 silc_free(r); 758 silc_free(r);
768 return; 759 return;
769 } 760 }
770 761
771 if (r->offline) { 762 if (r->offline) {
781 silcpurple_silcdir(), fingerprint); 772 silcpurple_silcdir(), fingerprint);
782 purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename); 773 purple_blist_node_set_string((PurpleBlistNode *)b, "public-key", filename);
783 purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL); 774 purple_prpl_got_user_status(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), SILCPURPLE_STATUS_ID_OFFLINE, NULL);
784 silc_free(fingerprint); 775 silc_free(fingerprint);
785 silc_free(r->offline_pk); 776 silc_free(r->offline_pk);
777 if (r->public_key)
778 silc_pkcs_public_key_free(r->public_key);
786 silc_free(r); 779 silc_free(r);
787 return; 780 return;
788 } 781 }
789 782
790 /* Get the client entry. */ 783 /* Get the client entry. */
791 client_entry = silc_client_get_client_by_id(r->client, r->conn, 784 client_entry = silc_client_get_client_by_id(r->client, r->conn,
792 &r->client_id); 785 &r->client_id);
793 if (!client_entry) { 786 if (!client_entry) {
787 silc_free(r->offline_pk);
788 silc_pkcs_public_key_free(r->public_key);
789 if (r->public_key)
790 silc_pkcs_public_key_free(r->public_key);
794 silc_free(r); 791 silc_free(r);
795 return; 792 return;
796 } 793 }
797 794
798 memset(&vcard, 0, sizeof(vcard)); 795 memset(&vcard, 0, sizeof(vcard));
799 memset(&message, 0, sizeof(message));
800 memset(&extension, 0, sizeof(extension));
801 #ifdef SILC_ATTRIBUTE_USER_ICON
802 memset(&usericon, 0, sizeof(usericon));
803 #endif
804 memset(&serverpk, 0, sizeof(serverpk)); 796 memset(&serverpk, 0, sizeof(serverpk));
805 memset(&usersign, 0, sizeof(usersign)); 797 memset(&usersign, 0, sizeof(usersign));
806 memset(&serversign, 0, sizeof(serversign)); 798 memset(&serversign, 0, sizeof(serversign));
807 799
808 /* Now that we have the public key and we trust it now we 800 /* Now that we have the public key and we trust it now we
820 sizeof(vcard))) 812 sizeof(vcard)))
821 continue; 813 continue;
822 break; 814 break;
823 815
824 case SILC_ATTRIBUTE_STATUS_MESSAGE: 816 case SILC_ATTRIBUTE_STATUS_MESSAGE:
825 if (!silc_attribute_get_object(attr, (void *)&message, 817 message = silc_mime_alloc();
826 sizeof(message))) 818 if (!silc_attribute_get_object(attr, (void *)message,
819 sizeof(*message)))
827 continue; 820 continue;
828 break; 821 break;
829 822
830 case SILC_ATTRIBUTE_EXTENSION: 823 case SILC_ATTRIBUTE_EXTENSION:
831 if (!silc_attribute_get_object(attr, (void *)&extension, 824 extension = silc_mime_alloc();
832 sizeof(extension))) 825 if (!silc_attribute_get_object(attr, (void *)extension,
826 sizeof(*extension)))
833 continue; 827 continue;
834 break; 828 break;
835 829
836 #ifdef SILC_ATTRIBUTE_USER_ICON 830 #ifdef SILC_ATTRIBUTE_USER_ICON
837 case SILC_ATTRIBUTE_USER_ICON: 831 case SILC_ATTRIBUTE_USER_ICON:
838 if (!silc_attribute_get_object(attr, (void *)&usericon, 832 usericon = silc_mime_alloc();
839 sizeof(usericon))) 833 if (!silc_attribute_get_object(attr, (void *)usericon,
834 sizeof(*usericon)))
840 continue; 835 continue;
841 break; 836 break;
842 #endif 837 #endif
843 838
844 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: 839 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
870 } 865 }
871 } 866 }
872 } 867 }
873 868
874 /* Verify the attribute signatures */ 869 /* Verify the attribute signatures */
870 silc_hash_alloc((const unsigned char *)"sha1", &hash);
875 871
876 if (usersign.data) { 872 if (usersign.data) {
877 SilcPKCS pkcs;
878 unsigned char *verifyd; 873 unsigned char *verifyd;
879 SilcUInt32 verify_len; 874 SilcUInt32 verify_len;
880 875
881 silc_pkcs_alloc((unsigned char*)"rsa", &pkcs);
882 verifyd = silc_attribute_get_verify_data(client_entry->attrs, 876 verifyd = silc_attribute_get_verify_data(client_entry->attrs,
883 FALSE, &verify_len); 877 FALSE, &verify_len);
884 if (verifyd && silc_pkcs_public_key_set(pkcs, client_entry->public_key)){ 878 if (verifyd && !silc_pkcs_verify(client_entry->public_key,
885 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, 879 usersign.data,
886 usersign.data, 880 usersign.data_len,
887 usersign.data_len, 881 verifyd, verify_len, hash))
888 verifyd, verify_len)) 882 usign_success = FALSE;
889 usign_success = FALSE;
890 }
891 silc_free(verifyd); 883 silc_free(verifyd);
892 } 884 }
893 885
894 if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) { 886 if (serversign.data) {
895 SilcPublicKey public_key; 887 SilcPublicKey public_key;
896 SilcPKCS pkcs; 888 SilcPKCSType type = 0;
897 unsigned char *verifyd; 889 unsigned char *verifyd;
898 SilcUInt32 verify_len; 890 SilcUInt32 verify_len;
899 891
900 if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len, 892 if (!strcmp(serverpk.type, "silc-rsa"))
901 &public_key)) { 893 type = SILC_PKCS_SILC;
902 silc_pkcs_alloc((unsigned char *)"rsa", &pkcs); 894 else if (!strcmp(serverpk.type, "ssh-rsa"))
895 type = SILC_PKCS_SSH2;
896 else if (!strcmp(serverpk.type, "x509v3-sign-rsa"))
897 type = SILC_PKCS_X509V3;
898 else if (!strcmp(serverpk.type, "pgp-sign-rsa"))
899 type = SILC_PKCS_OPENPGP;
900
901 if (silc_pkcs_public_key_alloc(type, serverpk.data,
902 serverpk.data_len,
903 &public_key)) {
903 verifyd = silc_attribute_get_verify_data(client_entry->attrs, 904 verifyd = silc_attribute_get_verify_data(client_entry->attrs,
904 TRUE, &verify_len); 905 TRUE, &verify_len);
905 if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) { 906 if (verifyd && !silc_pkcs_verify(public_key,
906 if (!silc_pkcs_verify_with_hash(pkcs, client->sha1hash, 907 serversign.data,
907 serversign.data, 908 serversign.data_len,
908 serversign.data_len, 909 verifyd, verify_len,
909 verifyd, verify_len)) 910 hash))
910 ssign_success = FALSE; 911 ssign_success = FALSE;
911 }
912 silc_pkcs_public_key_free(public_key); 912 silc_pkcs_public_key_free(public_key);
913 silc_free(verifyd); 913 silc_free(verifyd);
914 } 914 }
915 } 915 }
916 916
917 fingerprint = silc_fingerprint(client_entry->fingerprint, 917 fingerprint = silc_fingerprint(client_entry->fingerprint, 20);
918 client_entry->fingerprint_len);
919 for (i = 0; i < strlen(fingerprint); i++) 918 for (i = 0; i < strlen(fingerprint); i++)
920 if (fingerprint[i] == ' ') 919 if (fingerprint[i] == ' ')
921 fingerprint[i] = '_'; 920 fingerprint[i] = '_';
922 921
923 if (usign_success || ssign_success) { 922 if (usign_success || ssign_success) {
952 silc_file_writefile(filename2, tmp, len); 951 silc_file_writefile(filename2, tmp, len);
953 silc_free(tmp); 952 silc_free(tmp);
954 } 953 }
955 954
956 /* Save status message */ 955 /* Save status message */
957 if (message.mime) { 956 if (message) {
958 memset(filename2, 0, sizeof(filename2)); 957 memset(filename2, 0, sizeof(filename2));
959 g_snprintf(filename2, sizeof(filename2) - 1, 958 g_snprintf(filename2, sizeof(filename2) - 1,
960 "%s" G_DIR_SEPARATOR_S "status_message.mime", 959 "%s" G_DIR_SEPARATOR_S "status_message.mime",
961 filename); 960 filename);
962 silc_file_writefile(filename2, (char *)message.mime, 961 tmp = (char *)silc_mime_get_data(message, &len);
963 message.mime_len); 962 silc_file_writefile(filename2, tmp, len);
963 silc_mime_free(message);
964 } 964 }
965 965
966 /* Save extension data */ 966 /* Save extension data */
967 if (extension.mime) { 967 if (extension) {
968 memset(filename2, 0, sizeof(filename2)); 968 memset(filename2, 0, sizeof(filename2));
969 g_snprintf(filename2, sizeof(filename2) - 1, 969 g_snprintf(filename2, sizeof(filename2) - 1,
970 "%s" G_DIR_SEPARATOR_S "extension.mime", 970 "%s" G_DIR_SEPARATOR_S "extension.mime",
971 filename); 971 filename);
972 silc_file_writefile(filename2, (char *)extension.mime, 972 tmp = (char *)silc_mime_get_data(extension, &len);
973 extension.mime_len); 973 silc_file_writefile(filename2, tmp, len);
974 silc_mime_free(extension);
974 } 975 }
975 976
976 #ifdef SILC_ATTRIBUTE_USER_ICON 977 #ifdef SILC_ATTRIBUTE_USER_ICON
977 /* Save user icon */ 978 /* Save user icon */
978 if (usericon.mime) { 979 if (usericon) {
979 SilcMime m = silc_mime_decode(usericon.mime, 980 const char *type = silc_mime_get_field(usericon, "Content-Type");
980 usericon.mime_len); 981 if (type &&
981 if (m) { 982 (!strcmp(type, "image/jpeg") ||
982 const char *type = silc_mime_get_field(m, "Content-Type"); 983 !strcmp(type, "image/gif") ||
983 if (!strcmp(type, "image/jpeg") || 984 !strcmp(type, "image/bmp") ||
984 !strcmp(type, "image/gif") || 985 !strcmp(type, "image/png"))) {
985 !strcmp(type, "image/bmp") || 986 const unsigned char *data;
986 !strcmp(type, "image/png")) { 987 SilcUInt32 data_len;
987 const unsigned char *data; 988 data = silc_mime_get_data(usericon, &data_len);
988 SilcUInt32 data_len; 989 if (data) {
989 data = silc_mime_get_data(m, &data_len); 990 /* TODO: Check if SILC gives us something to use as the checksum instead */
990 if (data) { 991 purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL);
991 /* TODO: Check if SILC gives us something to use as the checksum instead */
992 purple_buddy_icons_set_for_user(purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), g_memdup(data, data_len), data_len, NULL);
993 }
994 } 992 }
995 silc_mime_free(m);
996 } 993 }
994 silc_mime_free(usericon);
997 } 995 }
998 #endif 996 #endif
999 } 997 }
1000 998
1001 /* Save the public key path to buddy properties, as it is used 999 /* Save the public key path to buddy properties, as it is used
1013 changes from the server */ 1011 changes from the server */
1014 g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename); 1012 g_snprintf(filename2, sizeof(filename2) - 1, "+%s", filename);
1015 silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey", 1013 silc_client_command_call(r->client, r->conn, NULL, "WATCH", "-pubkey",
1016 filename2, NULL); 1014 filename2, NULL);
1017 1015
1016 silc_hash_free(hash);
1018 silc_free(fingerprint); 1017 silc_free(fingerprint);
1018 silc_free(r->offline_pk);
1019 if (r->public_key)
1020 silc_pkcs_public_key_free(r->public_key);
1019 silc_free(r); 1021 silc_free(r);
1020 } 1022 }
1021 1023
1022 static void 1024 static void
1023 silcpurple_add_buddy_ask_import(void *user_data, const char *name) 1025 silcpurple_add_buddy_ask_import(void *user_data, const char *name)
1024 { 1026 {
1025 SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data; 1027 SilcPurpleBuddyRes r = (SilcPurpleBuddyRes)user_data;
1026 SilcPublicKey public_key;
1027 1028
1028 /* Load the public key */ 1029 /* Load the public key */
1029 if (!silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_PEM) && 1030 if (!silc_pkcs_load_public_key(name, &r->public_key)) {
1030 !silc_pkcs_load_public_key(name, &public_key, SILC_PKCS_FILE_BIN)) {
1031 silcpurple_add_buddy_ask_pk_cb(r, 0); 1031 silcpurple_add_buddy_ask_pk_cb(r, 0);
1032 purple_notify_error(r->client->application, 1032 purple_notify_error(r->client->application,
1033 _("Add Buddy"), _("Could not load public key"), NULL); 1033 _("Add Buddy"), _("Could not load public key"), NULL);
1034 return; 1034 return;
1035 } 1035 }
1036 1036
1037 /* Now verify the public key */ 1037 /* Now verify the public key */
1038 r->offline_pk = silc_pkcs_public_key_encode(public_key, &r->offline_pk_len); 1038 r->offline_pk = silc_pkcs_public_key_encode(r->public_key, &r->offline_pk_len);
1039 silcpurple_verify_public_key(r->client, r->conn, r->b->name, 1039 silcpurple_verify_public_key(r->client, r->conn, r->b->name,
1040 SILC_SOCKET_TYPE_CLIENT, 1040 SILC_CONN_CLIENT, r->public_key,
1041 r->offline_pk, r->offline_pk_len, 1041 silcpurple_add_buddy_save, r);
1042 SILC_SKE_PK_TYPE_SILC,
1043 silcpurple_add_buddy_save, r);
1044 } 1042 }
1045 1043
1046 static void 1044 static void
1047 silcpurple_add_buddy_ask_pk_cancel(void *user_data, const char *name) 1045 silcpurple_add_buddy_ask_pk_cancel(void *user_data, const char *name)
1048 { 1046 {
1063 return; 1061 return;
1064 } 1062 }
1065 1063
1066 /* Open file selector to select the public key. */ 1064 /* Open file selector to select the public key. */
1067 purple_request_file(r->client->application, _("Open..."), NULL, FALSE, 1065 purple_request_file(r->client->application, _("Open..."), NULL, FALSE,
1068 G_CALLBACK(silcpurple_add_buddy_ask_import), 1066 G_CALLBACK(silcpurple_add_buddy_ask_import),
1069 G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel), 1067 G_CALLBACK(silcpurple_add_buddy_ask_pk_cancel),
1070 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); 1068 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
1071 1069
1072 } 1070 }
1073 1071
1074 static void 1072 static void
1075 silcpurple_add_buddy_ask_pk(SilcPurpleBuddyRes r) 1073 silcpurple_add_buddy_ask_pk(SilcPurpleBuddyRes r)
1076 { 1074 {
1077 char tmp[512]; 1075 char tmp[512];
1078 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"), 1076 g_snprintf(tmp, sizeof(tmp), _("The %s buddy is not present in the network"),
1079 r->b->name); 1077 r->b->name);
1080 purple_request_action(r->client->application, _("Add Buddy"), tmp, 1078 purple_request_action(r->client->application, _("Add Buddy"), tmp,
1081 _("To add the buddy you must import his/her public key. " 1079 _("To add the buddy you must import his/her public key. "
1082 "Press Import to import a public key."), 0, 1080 "Press Import to import a public key."), 0,
1083 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2, 1081 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r, 2,
1084 _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb), 1082 _("Cancel"), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb),
1085 _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb)); 1083 _("_Import..."), G_CALLBACK(silcpurple_add_buddy_ask_pk_cb));
1086 } 1084 }
1087 1085
1088 static void 1086 static SilcBool
1089 silcpurple_add_buddy_getkey_cb(SilcPurpleBuddyRes r, 1087 silcpurple_add_buddy_getkey_cb(SilcClient client, SilcClientConnection conn,
1090 SilcClientCommandReplyContext cmd) 1088 SilcCommand command, SilcStatus status,
1091 { 1089 SilcStatus error, void *context, va_list ap)
1090 {
1091 SilcPurpleBuddyRes r = context;
1092 SilcClientEntry client_entry; 1092 SilcClientEntry client_entry;
1093 unsigned char *pk; 1093
1094 SilcUInt32 pk_len; 1094 if (status != SILC_STATUS_OK) {
1095 /* The buddy is offline/nonexistent. We will require user
1096 to associate a public key with the buddy or the buddy
1097 cannot be added. */
1098 r->offline = TRUE;
1099 silcpurple_add_buddy_ask_pk(r);
1100 return FALSE;
1101 }
1095 1102
1096 /* Get the client entry. */ 1103 /* Get the client entry. */
1097 client_entry = silc_client_get_client_by_id(r->client, r->conn, 1104 client_entry = silc_client_get_client_by_id(r->client, r->conn,
1098 &r->client_id); 1105 &r->client_id);
1099 if (!client_entry || !client_entry->public_key) { 1106 if (!client_entry || !client_entry->public_key) {
1100 /* The buddy is offline/nonexistent. We will require user 1107 /* The buddy is offline/nonexistent. We will require user
1101 to associate a public key with the buddy or the buddy 1108 to associate a public key with the buddy or the buddy
1102 cannot be added. */ 1109 cannot be added. */
1103 r->offline = TRUE; 1110 r->offline = TRUE;
1104 silcpurple_add_buddy_ask_pk(r); 1111 silcpurple_add_buddy_ask_pk(r);
1105 return; 1112 return FALSE;
1106 } 1113 }
1107 1114
1108 /* Now verify the public key */ 1115 /* Now verify the public key */
1109 pk = silc_pkcs_public_key_encode(client_entry->public_key, &pk_len);
1110 silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname, 1116 silcpurple_verify_public_key(r->client, r->conn, client_entry->nickname,
1111 SILC_SOCKET_TYPE_CLIENT, 1117 SILC_CONN_CLIENT, client_entry->public_key,
1112 pk, pk_len, SILC_SKE_PK_TYPE_SILC, 1118 silcpurple_add_buddy_save, r);
1113 silcpurple_add_buddy_save, r); 1119 return TRUE;
1114 silc_free(pk);
1115 } 1120 }
1116 1121
1117 static void 1122 static void
1118 silcpurple_add_buddy_select_cb(SilcPurpleBuddyRes r, PurpleRequestFields *fields) 1123 silcpurple_add_buddy_select_cb(SilcPurpleBuddyRes r, PurpleRequestFields *fields)
1119 { 1124 {
1120 PurpleRequestField *f; 1125 PurpleRequestField *f;
1121 const GList *list; 1126 const GList *list;
1122 SilcClientEntry client_entry; 1127 SilcClientEntry client_entry;
1128 SilcDList clients;
1123 1129
1124 f = purple_request_fields_get_field(fields, "list"); 1130 f = purple_request_fields_get_field(fields, "list");
1125 list = purple_request_field_list_get_selected(f); 1131 list = purple_request_field_list_get_selected(f);
1126 if (!list) { 1132 if (!list) {
1127 /* The user did not select any user. */ 1133 /* The user did not select any user. */
1129 silc_free(r); 1135 silc_free(r);
1130 return; 1136 return;
1131 } 1137 }
1132 1138
1133 client_entry = purple_request_field_list_get_data(f, list->data); 1139 client_entry = purple_request_field_list_get_data(f, list->data);
1134 silcpurple_add_buddy_resolved(r->client, r->conn, &client_entry, 1, r); 1140 clients = silc_dlist_init();
1141 silc_dlist_add(clients, client_entry);
1142 silcpurple_add_buddy_resolved(r->client, r->conn, SILC_STATUS_OK,
1143 clients, r);
1144 silc_dlist_uninit(clients);
1135 } 1145 }
1136 1146
1137 static void 1147 static void
1138 silcpurple_add_buddy_select_cancel(SilcPurpleBuddyRes r, PurpleRequestFields *fields) 1148 silcpurple_add_buddy_select_cancel(SilcPurpleBuddyRes r, PurpleRequestFields *fields)
1139 { 1149 {
1141 silcpurple_add_buddy_pk_no(r); 1151 silcpurple_add_buddy_pk_no(r);
1142 silc_free(r); 1152 silc_free(r);
1143 } 1153 }
1144 1154
1145 static void 1155 static void
1146 silcpurple_add_buddy_select(SilcPurpleBuddyRes r, 1156 silcpurple_add_buddy_select(SilcPurpleBuddyRes r, SilcDList clients)
1147 SilcClientEntry *clients,
1148 SilcUInt32 clients_count)
1149 { 1157 {
1150 PurpleRequestFields *fields; 1158 PurpleRequestFields *fields;
1151 PurpleRequestFieldGroup *g; 1159 PurpleRequestFieldGroup *g;
1152 PurpleRequestField *f; 1160 PurpleRequestField *f;
1153 char tmp[512], tmp2[128]; 1161 char tmp[512], tmp2[128];
1154 int i;
1155 char *fingerprint; 1162 char *fingerprint;
1163 SilcClientEntry client_entry;
1156 1164
1157 fields = purple_request_fields_new(); 1165 fields = purple_request_fields_new();
1158 g = purple_request_field_group_new(NULL); 1166 g = purple_request_field_group_new(NULL);
1159 f = purple_request_field_list_new("list", NULL); 1167 f = purple_request_field_list_new("list", NULL);
1160 purple_request_field_group_add_field(g, f); 1168 purple_request_field_group_add_field(g, f);
1161 purple_request_field_list_set_multi_select(f, FALSE); 1169 purple_request_field_list_set_multi_select(f, FALSE);
1162 purple_request_fields_add_group(fields, g); 1170 purple_request_fields_add_group(fields, g);
1163 1171
1164 for (i = 0; i < clients_count; i++) { 1172 silc_dlist_start(clients);
1173 while ((client_entry = silc_dlist_get(clients))) {
1165 fingerprint = NULL; 1174 fingerprint = NULL;
1166 if (clients[i]->fingerprint) { 1175 if (*client_entry->fingerprint) {
1167 fingerprint = silc_fingerprint(clients[i]->fingerprint, 1176 fingerprint = silc_fingerprint(client_entry->fingerprint, 20);
1168 clients[i]->fingerprint_len);
1169 g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint); 1177 g_snprintf(tmp2, sizeof(tmp2), "\n%s", fingerprint);
1170 } 1178 }
1171 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s", 1179 g_snprintf(tmp, sizeof(tmp), "%s - %s (%s@%s)%s",
1172 clients[i]->realname, clients[i]->nickname, 1180 client_entry->realname, client_entry->nickname,
1173 clients[i]->username, clients[i]->hostname ? 1181 client_entry->username, *client_entry->hostname ?
1174 clients[i]->hostname : "", 1182 client_entry->hostname : "",
1175 fingerprint ? tmp2 : ""); 1183 fingerprint ? tmp2 : "");
1176 purple_request_field_list_add(f, tmp, clients[i]); 1184 purple_request_field_list_add(f, tmp, client_entry);
1177 silc_free(fingerprint); 1185 silc_free(fingerprint);
1178 } 1186 }
1179 1187
1180 purple_request_fields(r->client->application, _("Add Buddy"), 1188 purple_request_fields(r->client->application, _("Add Buddy"),
1181 _("Select correct user"), 1189 _("Select correct user"),
1182 r->pubkey_search 1190 r->pubkey_search
1183 ? _("More than one user was found with the same public key. Select " 1191 ? _("More than one user was found with the same public key. Select "
1184 "the correct user from the list to add to the buddy list.") 1192 "the correct user from the list to add to the buddy list.")
1185 : _("More than one user was found with the same name. Select " 1193 : _("More than one user was found with the same name. Select "
1186 "the correct user from the list to add to the buddy list."), 1194 "the correct user from the list to add to the buddy list."),
1187 fields, 1195 fields,
1188 _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb), 1196 _("OK"), G_CALLBACK(silcpurple_add_buddy_select_cb),
1189 _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel), 1197 _("Cancel"), G_CALLBACK(silcpurple_add_buddy_select_cancel),
1190 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r); 1198 purple_buddy_get_account(r->b), purple_buddy_get_name(r->b), NULL, r);
1191 } 1199 }
1192 1200
1193 static void 1201 static void
1194 silcpurple_add_buddy_resolved(SilcClient client, 1202 silcpurple_add_buddy_resolved(SilcClient client,
1195 SilcClientConnection conn, 1203 SilcClientConnection conn,
1196 SilcClientEntry *clients, 1204 SilcStatus status,
1197 SilcUInt32 clients_count, 1205 SilcDList clients,
1198 void *context) 1206 void *context)
1199 { 1207 {
1200 SilcPurpleBuddyRes r = context; 1208 SilcPurpleBuddyRes r = context;
1201 PurpleBuddy *b = r->b; 1209 PurpleBuddy *b = r->b;
1202 SilcAttributePayload pub; 1210 SilcAttributePayload pub;
1203 SilcAttributeObjPk userpk; 1211 SilcAttributeObjPk userpk;
1204 unsigned char *pk;
1205 SilcUInt32 pk_len;
1206 const char *filename; 1212 const char *filename;
1213 SilcClientEntry client_entry = NULL;
1214 SilcUInt16 cmd_ident;
1207 1215
1208 filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); 1216 filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
1209 1217
1210 /* If the buddy is offline/nonexistent, we will require user 1218 /* If the buddy is offline/nonexistent, we will require user
1211 to associate a public key with the buddy or the buddy 1219 to associate a public key with the buddy or the buddy
1212 cannot be added. */ 1220 cannot be added. */
1213 if (!clients_count) { 1221 if (!clients) {
1214 if (r->init) { 1222 if (r->init) {
1215 silc_free(r); 1223 silc_free(r);
1216 return; 1224 return;
1217 } 1225 }
1218 1226
1226 return; 1234 return;
1227 } 1235 }
1228 1236
1229 /* If more than one client was found with nickname, we need to verify 1237 /* If more than one client was found with nickname, we need to verify
1230 from user which one is the correct. */ 1238 from user which one is the correct. */
1231 if (clients_count > 1 && !r->pubkey_search) { 1239 if (silc_dlist_count(clients) > 1 && !r->pubkey_search) {
1232 if (r->init) { 1240 if (r->init) {
1233 silc_free(r); 1241 silc_free(r);
1234 return; 1242 return;
1235 } 1243 }
1236 1244
1237 silcpurple_add_buddy_select(r, clients, clients_count); 1245 silcpurple_add_buddy_select(r, clients);
1238 return; 1246 return;
1239 } 1247 }
1248
1249 silc_dlist_start(clients);
1250 client_entry = silc_dlist_get(clients);
1240 1251
1241 /* If we searched using public keys and more than one entry was found 1252 /* If we searched using public keys and more than one entry was found
1242 the same person is logged on multiple times. */ 1253 the same person is logged on multiple times. */
1243 if (clients_count > 1 && r->pubkey_search && b->name) { 1254 if (silc_dlist_count(clients) > 1 && r->pubkey_search && b->name) {
1244 if (r->init) { 1255 if (r->init) {
1245 /* Find the entry that closest matches to the 1256 /* Find the entry that closest matches to the
1246 buddy nickname. */ 1257 buddy nickname. */
1247 int i; 1258 SilcClientEntry entry;
1248 for (i = 0; i < clients_count; i++) { 1259 silc_dlist_start(clients);
1249 if (!strncasecmp(b->name, clients[i]->nickname, 1260 while ((entry = silc_dlist_get(clients))) {
1261 if (!strncasecmp(b->name, entry->nickname,
1250 strlen(b->name))) { 1262 strlen(b->name))) {
1251 clients[0] = clients[i]; 1263 client_entry = entry;
1252 break; 1264 break;
1253 } 1265 }
1254 } 1266 }
1255 } else { 1267 } else {
1256 /* Verify from user which one is correct */ 1268 /* Verify from user which one is correct */
1257 silcpurple_add_buddy_select(r, clients, clients_count); 1269 silcpurple_add_buddy_select(r, clients);
1258 return; 1270 return;
1259 } 1271 }
1260 } 1272 }
1261 1273
1262 /* The client was found. Now get its public key and verify 1274 /* The client was found. Now get its public key and verify
1263 that before adding the buddy. */ 1275 that before adding the buddy. */
1264 memset(&userpk, 0, sizeof(userpk)); 1276 memset(&userpk, 0, sizeof(userpk));
1265 b->proto_data = silc_memdup(clients[0]->id, sizeof(*clients[0]->id)); 1277 b->proto_data = silc_memdup(&client_entry->id, sizeof(client_entry->id));
1266 r->client_id = *clients[0]->id; 1278 r->client_id = client_entry->id;
1267 1279
1268 /* Get the public key from attributes, if not present then 1280 /* Get the public key from attributes, if not present then
1269 resolve it with GETKEY unless we have it cached already. */ 1281 resolve it with GETKEY unless we have it cached already. */
1270 if (clients[0]->attrs && !clients[0]->public_key) { 1282 if (client_entry->attrs && !client_entry->public_key) {
1271 pub = silcpurple_get_attr(clients[0]->attrs, 1283 pub = silcpurple_get_attr(client_entry->attrs,
1272 SILC_ATTRIBUTE_USER_PUBLIC_KEY); 1284 SILC_ATTRIBUTE_USER_PUBLIC_KEY);
1273 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk, 1285 if (!pub || !silc_attribute_get_object(pub, (void *)&userpk,
1274 sizeof(userpk))) { 1286 sizeof(userpk))) {
1275 /* Get public key with GETKEY */ 1287 /* Get public key with GETKEY */
1276 silc_client_command_call(client, conn, NULL, 1288 cmd_ident =
1277 "GETKEY", clients[0]->nickname, NULL); 1289 silc_client_command_call(client, conn, NULL,
1290 "GETKEY", client_entry->nickname, NULL);
1278 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, 1291 silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
1279 conn->cmd_ident, 1292 cmd_ident,
1280 (SilcCommandCb)silcpurple_add_buddy_getkey_cb, 1293 silcpurple_add_buddy_getkey_cb,
1281 r); 1294 r);
1282 return; 1295 return;
1283 } 1296 }
1284 if (!silc_pkcs_public_key_decode(userpk.data, userpk.data_len, 1297 if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
1285 &clients[0]->public_key)) 1298 userpk.data, userpk.data_len,
1299 &client_entry->public_key))
1286 return; 1300 return;
1287 silc_free(userpk.data); 1301 silc_free(userpk.data);
1288 } else if (filename && !clients[0]->public_key) { 1302 } else if (filename && !client_entry->public_key) {
1289 if (!silc_pkcs_load_public_key(filename, &clients[0]->public_key, 1303 if (!silc_pkcs_load_public_key(filename, &client_entry->public_key)) {
1290 SILC_PKCS_FILE_PEM) &&
1291 !silc_pkcs_load_public_key(filename, &clients[0]->public_key,
1292 SILC_PKCS_FILE_BIN)) {
1293 /* Get public key with GETKEY */ 1304 /* Get public key with GETKEY */
1294 silc_client_command_call(client, conn, NULL, 1305 cmd_ident =
1295 "GETKEY", clients[0]->nickname, NULL); 1306 silc_client_command_call(client, conn, NULL,
1307 "GETKEY", client_entry->nickname, NULL);
1296 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, 1308 silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
1297 conn->cmd_ident, 1309 cmd_ident,
1298 (SilcCommandCb)silcpurple_add_buddy_getkey_cb, 1310 silcpurple_add_buddy_getkey_cb,
1299 r); 1311 r);
1300 return; 1312 return;
1301 } 1313 }
1302 } else if (!clients[0]->public_key) { 1314 } else if (!client_entry->public_key) {
1303 /* Get public key with GETKEY */ 1315 /* Get public key with GETKEY */
1304 silc_client_command_call(client, conn, NULL, 1316 cmd_ident =
1305 "GETKEY", clients[0]->nickname, NULL); 1317 silc_client_command_call(client, conn, NULL,
1318 "GETKEY", client_entry->nickname, NULL);
1306 silc_client_command_pending(conn, SILC_COMMAND_GETKEY, 1319 silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
1307 conn->cmd_ident, 1320 cmd_ident,
1308 (SilcCommandCb)silcpurple_add_buddy_getkey_cb, 1321 silcpurple_add_buddy_getkey_cb,
1309 r); 1322 r);
1310 return; 1323 return;
1311 } 1324 }
1312 1325
1313 /* We have the public key, verify it. */ 1326 /* We have the public key, verify it. */
1314 pk = silc_pkcs_public_key_encode(clients[0]->public_key, &pk_len); 1327 silcpurple_verify_public_key(client, conn, client_entry->nickname,
1315 silcpurple_verify_public_key(client, conn, clients[0]->nickname, 1328 SILC_CONN_CLIENT,
1316 SILC_SOCKET_TYPE_CLIENT, 1329 client_entry->public_key,
1317 pk, pk_len, SILC_SKE_PK_TYPE_SILC, 1330 silcpurple_add_buddy_save, r);
1318 silcpurple_add_buddy_save, r);
1319 silc_free(pk);
1320 } 1331 }
1321 1332
1322 static void 1333 static void
1323 silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init) 1334 silcpurple_add_buddy_i(PurpleConnection *gc, PurpleBuddy *b, gboolean init)
1324 { 1335 {
1342 filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key"); 1353 filename = purple_blist_node_get_string((PurpleBlistNode *)b, "public-key");
1343 if (filename) { 1354 if (filename) {
1344 SilcPublicKey public_key; 1355 SilcPublicKey public_key;
1345 SilcAttributeObjPk userpk; 1356 SilcAttributeObjPk userpk;
1346 1357
1347 if (!silc_pkcs_load_public_key(filename, &public_key, 1358 if (!silc_pkcs_load_public_key(filename, &public_key))
1348 SILC_PKCS_FILE_PEM) &&
1349 !silc_pkcs_load_public_key(filename, &public_key,
1350 SILC_PKCS_FILE_BIN))
1351 return; 1359 return;
1352 1360
1353 /* Get all attributes, and use the public key to search user */ 1361 /* Get all attributes, and use the public key to search user */
1354 name = NULL; 1362 name = NULL;
1355 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO, 1363 attrs = silc_client_attributes_request(SILC_ATTRIBUTE_USER_INFO,
1630 pkfile = purple_blist_node_get_string((PurpleBlistNode *) buddy, "public-key"); 1638 pkfile = purple_blist_node_get_string((PurpleBlistNode *) buddy, "public-key");
1631 client_entry = silc_client_get_client_by_id(sg->client, 1639 client_entry = silc_client_get_client_by_id(sg->client,
1632 sg->conn, 1640 sg->conn,
1633 buddy->proto_data); 1641 buddy->proto_data);
1634 1642
1635 if (client_entry && client_entry->send_key) { 1643 if (client_entry &&
1644 silc_client_private_message_key_is_set(sg->client,
1645 sg->conn, client_entry)) {
1636 act = purple_menu_action_new(_("Reset IM Key"), 1646 act = purple_menu_action_new(_("Reset IM Key"),
1637 PURPLE_CALLBACK(silcpurple_buddy_resetkey), 1647 PURPLE_CALLBACK(silcpurple_buddy_resetkey),
1638 NULL, NULL); 1648 NULL, NULL);
1639 m = g_list_append(m, act); 1649 m = g_list_append(m, act);
1640
1641 } else { 1650 } else {
1642 act = purple_menu_action_new(_("IM with Key Exchange"), 1651 act = purple_menu_action_new(_("IM with Key Exchange"),
1643 PURPLE_CALLBACK(silcpurple_buddy_keyagr), 1652 PURPLE_CALLBACK(silcpurple_buddy_keyagr),
1644 NULL, NULL); 1653 NULL, NULL);
1645 m = g_list_append(m, act); 1654 m = g_list_append(m, act);
1688 SilcPurple sg = gc->proto_data; 1697 SilcPurple sg = gc->proto_data;
1689 SilcClient client = sg->client; 1698 SilcClient client = sg->client;
1690 SilcClientConnection conn = sg->conn; 1699 SilcClientConnection conn = sg->conn;
1691 SilcMime mime; 1700 SilcMime mime;
1692 char type[32]; 1701 char type[32];
1693 unsigned char *icon;
1694 const char *t; 1702 const char *t;
1695 SilcAttributeObjMime obj;
1696 1703
1697 /* Remove */ 1704 /* Remove */
1698 if (!img) { 1705 if (!img) {
1699 silc_client_attribute_del(client, conn, 1706 silc_client_attribute_del(client, conn,
1700 SILC_ATTRIBUTE_USER_ICON, NULL); 1707 SILC_ATTRIBUTE_USER_ICON, NULL);
1715 t = "jpeg"; 1722 t = "jpeg";
1716 g_snprintf(type, sizeof(type), "image/%s", t); 1723 g_snprintf(type, sizeof(type), "image/%s", t);
1717 silc_mime_add_field(mime, "Content-Type", type); 1724 silc_mime_add_field(mime, "Content-Type", type);
1718 silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img)); 1725 silc_mime_add_data(mime, purple_imgstore_get_data(img), purple_imgstore_get_size(img));
1719 1726
1720 obj.mime = icon = silc_mime_encode(mime, &obj.mime_len); 1727 silc_client_attribute_add(client, conn,
1721 if (obj.mime) 1728 SILC_ATTRIBUTE_USER_ICON, mime, sizeof(*mime));
1722 silc_client_attribute_add(client, conn, 1729
1723 SILC_ATTRIBUTE_USER_ICON, &obj, sizeof(obj));
1724
1725 silc_free(icon);
1726 silc_mime_free(mime); 1730 silc_mime_free(mime);
1727 } 1731 }
1728 #endif 1732 #endif