e4a03ae881c3b8c167c6ab77e8338cedb2ee0b72
[silc.git] / apps / irssi / src / silc / core / silc-queries.c
1 /*
2
3   silc-queries.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 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 "module.h"
21 #include "signals.h"
22 #include "misc.h"
23 #include "silc-queries.h"
24 #include "settings.h"
25 #include "levels.h"
26 #include "modules.h"
27 #include "commands.h"
28 #include "misc.h"
29
30 #include "fe-common/core/printtext.h"
31 #include "fe-common/core/fe-channels.h"
32 #include "fe-common/core/keyboard.h"
33 #include "fe-common/silc/module-formats.h"
34
35 static void silc_query_attributes_print_final(bool success, void *context);
36 static void silc_query_attributes_accept(const char *line, void *context);
37
38 QUERY_REC *silc_query_create(const char *server_tag,
39                              const char *nick, int automatic)
40 {
41   QUERY_REC *rec;
42
43   g_return_val_if_fail(nick != NULL, NULL);
44
45   rec = g_new0(QUERY_REC, 1);
46   rec->chat_type = SILC_PROTOCOL;
47   rec->name = g_strdup(nick);
48   rec->server_tag = g_strdup(server_tag);
49   query_init(rec, automatic);
50   return rec;
51 }
52
53 void silc_queries_init(void)
54 {
55 }
56
57 void silc_queries_deinit(void)
58 {
59 }
60
61 /* ATTR command */
62
63 void command_attr(const char *data, SILC_SERVER_REC *server,
64                   WI_ITEM_REC *item)
65 {
66   char *tmp;
67   unsigned char **argv;
68   SilcUInt32 argc;
69   SilcUInt32 *argv_lens, *argv_types;
70   const char *sv;
71   bool allowed;
72
73   /* Now parse all arguments */
74   tmp = g_strconcat("ATTR", " ", data, NULL);
75   silc_parse_command_line(tmp, &argv, &argv_lens, &argv_types, &argc, 3);
76   g_free(tmp);
77
78   if (argc == 1) {
79     /* Show all attributes */
80     printformat_module("fe-common/silc", server, NULL,
81                        MSGLEVEL_CRAP, SILCTXT_ATTR_HEADER);
82
83     allowed = settings_get_bool("attr_allow");
84     printformat_module("fe-common/silc", server, NULL,
85                        MSGLEVEL_CRAP, SILCTXT_ATTR_ALLOW,
86                        allowed ? "Yes" : "No");
87
88     sv = settings_get_str("attr_vcard");
89     if (sv && *sv)
90       printformat_module("fe-common/silc", server, NULL,
91                          MSGLEVEL_CRAP, SILCTXT_ATTR_VCARD_FILE, sv);
92
93     sv = settings_get_str("attr_services");
94     if (sv && *sv)
95       printformat_module("fe-common/silc", server, NULL,
96                          MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, sv);
97
98     sv = settings_get_str("attr_status_mood");
99     if (sv && *sv)
100       printformat_module("fe-common/silc", server, NULL,
101                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MOOD, sv);
102
103     sv = settings_get_str("attr_status_text");
104     if (sv && *sv)
105       printformat_module("fe-common/silc", server, NULL,
106                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_TEXT, sv);
107
108     sv = settings_get_str("attr_status_message");
109     if (sv && *sv)
110       printformat_module("fe-common/silc", server, NULL,
111                          MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE_FILE,
112                          sv);
113
114     sv = settings_get_str("attr_preferred_language");
115     if (sv && *sv)
116       printformat_module("fe-common/silc", server, NULL,
117                          MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_LANGUAGE,
118                          sv);
119
120     sv = settings_get_str("attr_preferred_contact");
121     if (sv && *sv)
122       printformat_module("fe-common/silc", server, NULL,
123                          MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_CONTACT,
124                          sv);
125
126     sv = settings_get_str("attr_geolocation");
127     if (sv && *sv)
128       printformat_module("fe-common/silc", server, NULL,
129                          MSGLEVEL_CRAP, SILCTXT_ATTR_GEOLOCATION,
130                          sv);
131
132     sv = settings_get_str("attr_device_info");
133     if (sv && *sv)
134       printformat_module("fe-common/silc", server, NULL,
135                          MSGLEVEL_CRAP, SILCTXT_ATTR_DEVICE_INFO,
136                          sv);
137
138     sv = settings_get_str("attr_public_keys");
139     if (sv && *sv)
140       printformat_module("fe-common/silc", server, NULL,
141                          MSGLEVEL_CRAP, SILCTXT_ATTR_PUBLIC_KEYS,
142                          sv);
143
144     allowed = settings_get_bool("attr_timezone");
145     printformat_module("fe-common/silc", server, NULL,
146                        MSGLEVEL_CRAP, SILCTXT_ATTR_TIMEZONE_ALLOW,
147                        allowed ? "Yes" : "No");
148
149     printformat_module("fe-common/silc", server, NULL,
150                        MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
151     return;
152   }
153
154   if (argc < 3)
155     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
156
157   if (!strcasecmp(argv[1], "-del")) {
158     /* Delete attribute */
159     if (!strcasecmp(argv[2], "vcard")) {
160       silc_client_attribute_del(silc_client, server->conn,
161                                 SILC_ATTRIBUTE_USER_INFO, NULL);
162       settings_set_str("attr_vcard", "");
163     } else if (!strcasecmp(argv[2], "services")) {
164       silc_client_attribute_del(silc_client, server->conn,
165                                 SILC_ATTRIBUTE_SERVICE, NULL);
166       settings_set_str("attr_services", argv[2]);
167     } else if (!strcasecmp(argv[2], "status_mood")) {
168       silc_client_attribute_del(silc_client, server->conn,
169                                 SILC_ATTRIBUTE_STATUS_MOOD, NULL);
170       settings_set_str("attr_status_mood", "");
171     } else if (!strcasecmp(argv[2], "status_text")) {
172       silc_client_attribute_del(silc_client, server->conn,
173                                 SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
174       settings_set_str("attr_status_text", "");
175     } else if (!strcasecmp(argv[2], "status_message")) {
176       silc_client_attribute_del(silc_client, server->conn,
177                                 SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
178       settings_set_str("attr_status_message", "");
179     } else if (!strcasecmp(argv[2], "preferred_language")) {
180       silc_client_attribute_del(silc_client, server->conn,
181                                 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
182       settings_set_str("attr_preferred_language", "");
183     } else if (!strcasecmp(argv[2], "preferred_contact")) {
184       silc_client_attribute_del(silc_client, server->conn,
185                                 SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
186       settings_set_str("attr_preferred_contact", "");
187     } else if (!strcasecmp(argv[2], "timezone")) {
188       return;
189     } else if (!strcasecmp(argv[2], "geolocation")) {
190       silc_client_attribute_del(silc_client, server->conn,
191                                 SILC_ATTRIBUTE_GEOLOCATION, NULL);
192       settings_set_str("attr_geolocation", "");
193     } else if (!strcasecmp(argv[2], "device_info")) {
194       silc_client_attribute_del(silc_client, server->conn,
195                                 SILC_ATTRIBUTE_DEVICE_INFO, NULL);
196       settings_set_str("attr_device_info", "");
197     } else if (!strcasecmp(argv[2], "public_keys")) {
198       silc_client_attribute_del(silc_client, server->conn,
199                                 SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
200       settings_set_str("attr_public_keys", "");
201     } else {
202       cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
203     }
204     return;
205   }
206
207   /* Add new attribute */
208   if (!strcasecmp(argv[1], "allow")) {
209     allowed = !strcasecmp(argv[2], "ON") || !strcasecmp(argv[2], "YES");
210     settings_set_bool("attr_allow", allowed);
211   } else if (!strcasecmp(argv[1], "vcard")) {
212     settings_set_str("attr_vcard", argv[2]);
213   } else if (!strcasecmp(argv[1], "services")) {
214     settings_set_str("attr_services", argv[2]);
215   } else if (!strcasecmp(argv[1], "status_mood")) {
216     settings_set_str("attr_status_mood", argv[2]);
217   } else if (!strcasecmp(argv[1], "status_text")) {
218     settings_set_str("attr_status_text", argv[2]);
219   } else if (!strcasecmp(argv[1], "status_message")) {
220     settings_set_str("attr_status_message", argv[2]);
221   } else if (!strcasecmp(argv[1], "preferred_language")) {
222     settings_set_str("attr_preferred_language", argv[2]);
223   } else if (!strcasecmp(argv[1], "preferred_contact")) {
224     settings_set_str("attr_preferred_contact", argv[2]);
225   } else if (!strcasecmp(argv[1], "timezone")) {
226     allowed = !strcasecmp(argv[2], "ON") || !strcasecmp(argv[2], "YES");
227     settings_set_bool("attr_timezone", allowed);
228   } else if (!strcasecmp(argv[1], "geolocation")) {
229     settings_set_str("attr_geolocation", argv[2]);
230   } else if (!strcasecmp(argv[1], "device_info")) {
231     settings_set_str("attr_device_info", argv[2]);
232   } else if (!strcasecmp(argv[1], "public_keys")) {
233     settings_set_str("attr_public_keys", argv[2]);
234   } else {
235     cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
236   }
237
238   silc_query_attributes_default(silc_client, server->conn);
239 }
240
241 /* Put default attributes to client library */
242
243 void silc_query_attributes_default(SilcClient client,
244                                    SilcClientConnection conn)
245 {
246   char *tmp, **list, **entry;
247   const char *sv;
248   SilcUInt32 tmp_len, mask;
249   SilcAttributeObjService service;
250   SilcAttributeObjMime mime;
251   SilcAttributeObjGeo geo;
252   SilcAttributeObjDevice dev;
253   SilcAttributeObjPk pk;
254   SilcVCardStruct vcard;
255   bool allowed;
256
257   memset(&service, 0, sizeof(service));
258   memset(&mime, 0, sizeof(mime));
259   memset(&geo, 0, sizeof(geo));
260   memset(&dev, 0, sizeof(dev));
261   memset(&pk, 0, sizeof(pk));
262   memset(&vcard, 0, sizeof(vcard));
263
264   allowed = settings_get_bool("attr_allow");
265   if (!allowed) {
266     silc_client_attribute_del(silc_client, conn,
267                               SILC_ATTRIBUTE_USER_INFO, NULL);
268     silc_client_attribute_del(silc_client, conn,
269                               SILC_ATTRIBUTE_SERVICE, NULL);
270     silc_client_attribute_del(silc_client, conn,
271                               SILC_ATTRIBUTE_STATUS_MOOD, NULL);
272     silc_client_attribute_del(silc_client, conn,
273                               SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
274     silc_client_attribute_del(silc_client, conn,
275                               SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
276     silc_client_attribute_del(silc_client, conn,
277                               SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
278     silc_client_attribute_del(silc_client, conn,
279                               SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
280     silc_client_attribute_del(silc_client, conn,
281                               SILC_ATTRIBUTE_TIMEZONE, NULL);
282     silc_client_attribute_del(silc_client, conn,
283                               SILC_ATTRIBUTE_GEOLOCATION, NULL);
284     silc_client_attribute_del(silc_client, conn,
285                               SILC_ATTRIBUTE_DEVICE_INFO, NULL);
286     silc_client_attribute_del(silc_client, conn,
287                               SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
288     return;
289   }
290
291   sv = settings_get_str("attr_vcard");
292   if (sv && *sv) {
293     /* Put USER_INFO */
294     silc_client_attribute_del(silc_client, conn,
295                               SILC_ATTRIBUTE_USER_INFO, NULL);
296     tmp = silc_file_readfile(sv, &tmp_len);
297     if (tmp) {
298       tmp[tmp_len] = 0;
299       if (silc_vcard_decode(tmp, tmp_len, &vcard))
300         silc_client_attribute_add(silc_client, conn,
301                                   SILC_ATTRIBUTE_USER_INFO, (void *)&vcard,
302                                   sizeof(vcard));
303     }
304     silc_vcard_free(&vcard);
305     silc_free(tmp);
306   }
307
308   sv = settings_get_str("attr_services");
309   if (sv && *sv) {
310     /* Put SERVICE */
311     silc_client_attribute_del(silc_client, conn,
312                               SILC_ATTRIBUTE_SERVICE, NULL);
313     list = g_strsplit(sv, " ", -1);
314     for (entry = list; *entry != NULL; entry++) {
315       if (!strchr(*entry, ':'))
316         continue;
317       tmp = strchr(*entry, ':') + 1;
318       if (!tmp || !(*tmp))
319         continue;
320       memset(&service, 0, sizeof(service));
321       service.port = atoi(tmp);
322       *strchr(*entry, ':') = '\0';
323       silc_strncat(service.address, sizeof(service.address), *entry,
324                    strlen(*entry));
325       service.status = TRUE;
326       silc_client_attribute_add(silc_client, conn,
327                                 SILC_ATTRIBUTE_SERVICE, &service,
328                                 sizeof(service));
329     }
330     g_strfreev(list);
331   }
332
333   sv = settings_get_str("attr_status_mood");
334   if (sv && *sv) {
335     /* Put STATUS_MOOD */
336     silc_client_attribute_del(silc_client, conn,
337                               SILC_ATTRIBUTE_STATUS_MOOD, NULL);
338     mask = 0;
339     list = g_strsplit(sv, " ", -1);
340     for (entry = list; *entry != NULL; entry++) {
341       if (!strcasecmp(*entry, "NORMAL"))
342         mask |= SILC_ATTRIBUTE_MOOD_NORMAL;
343       if (!strcasecmp(*entry, "HAPPY"))
344         mask |= SILC_ATTRIBUTE_MOOD_HAPPY;
345       if (!strcasecmp(*entry, "SAD"))
346         mask |= SILC_ATTRIBUTE_MOOD_SAD;
347       if (!strcasecmp(*entry, "ANGRY"))
348         mask |= SILC_ATTRIBUTE_MOOD_ANGRY;
349       if (!strcasecmp(*entry, "JEALOUS"))
350         mask |= SILC_ATTRIBUTE_MOOD_JEALOUS;
351       if (!strcasecmp(*entry, "ASHAMED"))
352         mask |= SILC_ATTRIBUTE_MOOD_ASHAMED;
353       if (!strcasecmp(*entry, "INVINCIBLE"))
354         mask |= SILC_ATTRIBUTE_MOOD_INVINCIBLE;
355       if (!strcasecmp(*entry, "INLOVE"))
356         mask |= SILC_ATTRIBUTE_MOOD_INLOVE;
357       if (!strcasecmp(*entry, "SLEEPY"))
358         mask |= SILC_ATTRIBUTE_MOOD_SLEEPY;
359       if (!strcasecmp(*entry, "BORED"))
360         mask |= SILC_ATTRIBUTE_MOOD_BORED;
361       if (!strcasecmp(*entry, "EXCITED"))
362         mask |= SILC_ATTRIBUTE_MOOD_EXCITED;
363       if (!strcasecmp(*entry, "ANXIOUS"))
364         mask |= SILC_ATTRIBUTE_MOOD_ANXIOUS;
365     }
366     silc_client_attribute_add(silc_client, conn,
367                               SILC_ATTRIBUTE_STATUS_MOOD, (void *)mask,
368                               sizeof(SilcUInt32));
369     g_strfreev(list);
370   }
371
372   sv = settings_get_str("attr_status_text");
373   if (sv && *sv) {
374     /* Put STATUS_TEXT */
375     silc_client_attribute_del(silc_client, conn,
376                               SILC_ATTRIBUTE_STATUS_FREETEXT, NULL);
377     silc_client_attribute_add(silc_client, conn,
378                               SILC_ATTRIBUTE_STATUS_FREETEXT, (void *)sv,
379                               strlen(sv));
380   }
381
382   sv = settings_get_str("attr_status_message");
383   if (sv && *sv) {
384     /* Put STATUS_MESSAGE */
385     silc_client_attribute_del(silc_client, conn,
386                               SILC_ATTRIBUTE_STATUS_MESSAGE, NULL);
387     tmp = silc_file_readfile(sv, &tmp_len);
388     if (tmp) {
389       tmp[tmp_len] = 0;
390       mime.mime = (const unsigned char *)tmp;
391       mime.mime_len = tmp_len;
392       silc_client_attribute_add(silc_client, conn,
393                                 SILC_ATTRIBUTE_STATUS_MESSAGE, &mime,
394                                 sizeof(mime));
395     }
396     silc_free(tmp);
397   }
398
399   sv = settings_get_str("attr_preferred_language");
400   if (sv && *sv) {
401     /* Put PREFERRED_LANGUAGE */
402     silc_client_attribute_del(silc_client, conn,
403                               SILC_ATTRIBUTE_PREFERRED_LANGUAGE, NULL);
404     list = g_strsplit(sv, " ", -1);
405     for (entry = list; *entry != NULL; entry++) {
406       silc_client_attribute_add(silc_client, conn,
407                                 SILC_ATTRIBUTE_PREFERRED_LANGUAGE, *entry,
408                                 strlen(*entry));
409     }
410     g_strfreev(list);
411   }
412
413   sv = settings_get_str("attr_preferred_contact");
414   if (sv && *sv) {
415     /* Put PREFERRED_CONTACT */
416     silc_client_attribute_del(silc_client, conn,
417                               SILC_ATTRIBUTE_PREFERRED_CONTACT, NULL);
418     mask = 0;
419     list = g_strsplit(sv, " ", -1);
420     for (entry = list; *entry != NULL; entry++) {
421       if (!strcasecmp(*entry, "NONE"))
422         mask = 0;
423       if (!strcasecmp(*entry, "EMAIL"))
424         mask |= SILC_ATTRIBUTE_CONTACT_EMAIL;
425       if (!strcasecmp(*entry, "CALL"))
426         mask |= SILC_ATTRIBUTE_CONTACT_CALL;
427       if (!strcasecmp(*entry, "PAGE"))
428         mask |= SILC_ATTRIBUTE_CONTACT_PAGE;
429       if (!strcasecmp(*entry, "SMS"))
430         mask |= SILC_ATTRIBUTE_CONTACT_SMS;
431       if (!strcasecmp(*entry, "MMS"))
432         mask |= SILC_ATTRIBUTE_CONTACT_MMS;
433       if (!strcasecmp(*entry, "CHAT"))
434         mask |= SILC_ATTRIBUTE_CONTACT_CHAT;
435     }
436     silc_client_attribute_add(silc_client, conn,
437                               SILC_ATTRIBUTE_PREFERRED_CONTACT, (void *)mask,
438                               sizeof(SilcUInt32));
439     g_strfreev(list);
440   }
441
442   /* Put TIMEZONE */
443   allowed = settings_get_bool("attr_timezone");
444   silc_client_attribute_del(silc_client, conn,
445                             SILC_ATTRIBUTE_TIMEZONE, NULL);
446   if (allowed)
447     silc_client_attribute_add(silc_client, conn,
448                               SILC_ATTRIBUTE_TIMEZONE, "foo", 3);
449
450   sv = settings_get_str("attr_geolocation");
451   if (sv && *sv) {
452     /* Put GEOLOCATION */
453     silc_client_attribute_del(silc_client, conn,
454                               SILC_ATTRIBUTE_GEOLOCATION, NULL);
455     list = g_strsplit(sv, ":", -1);
456     for (entry = list; *entry != NULL; entry++) {
457       if (!geo.longitude) {
458         geo.longitude = *entry;
459         continue;
460       }
461       if (!geo.latitude) {
462         geo.latitude = *entry;
463         continue;
464       }
465       if (!geo.altitude) {
466         geo.altitude = *entry;
467         continue;
468       }
469       if (!geo.accuracy) {
470         geo.accuracy = *entry;
471         continue;
472       }
473     }
474     silc_client_attribute_add(silc_client, conn,
475                               SILC_ATTRIBUTE_GEOLOCATION, &geo,
476                               sizeof(geo));
477     g_strfreev(list);
478   }
479
480   sv = settings_get_str("attr_device_info");
481   if (sv && *sv) {
482     /* Put DEVICE_INFO */
483     silc_client_attribute_del(silc_client, conn,
484                               SILC_ATTRIBUTE_DEVICE_INFO, NULL);
485     allowed = FALSE;
486     list = g_strsplit(sv, ":", -1);
487     for (entry = list; *entry != NULL; entry++) {
488       if (!allowed) {
489         allowed = TRUE;
490         if (!strcasecmp(*entry, "COMPUTER"))
491           dev.type = SILC_ATTRIBUTE_DEVICE_COMPUTER;
492         if (!strcasecmp(*entry, "MOBILE_PHONE"))
493           dev.type = SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE;
494         if (!strcasecmp(sv, "PDA"))
495           dev.type = SILC_ATTRIBUTE_DEVICE_PDA;
496         if (!strcasecmp(sv, "TERMINAL"))
497           dev.type = SILC_ATTRIBUTE_DEVICE_TERMINAL;
498         continue;
499       }
500       if (!dev.manufacturer) {
501         dev.manufacturer = *entry;
502         continue;
503       }
504       if (!dev.version) {
505         dev.version = *entry;
506         continue;
507       }
508       if (!dev.model) {
509         dev.model = *entry;
510         continue;
511       }
512       if (!dev.language) {
513         dev.language = *entry;
514         continue;
515       }
516     }
517     silc_client_attribute_add(silc_client, conn,
518                               SILC_ATTRIBUTE_DEVICE_INFO, &dev,
519                               sizeof(dev));
520     g_strfreev(list);
521   }
522
523   sv = settings_get_str("attr_public_keys");
524   if (sv && *sv) {
525     /* Put USER_PUBLIC_KEY */
526     silc_client_attribute_del(silc_client, conn,
527                               SILC_ATTRIBUTE_USER_PUBLIC_KEY, NULL);
528     list = g_strsplit(sv, " ", -1);
529     for (entry = list; *entry != NULL; entry++) {
530       if (!strncasecmp(*entry, "silc-rsa:", 8)) {
531         tmp = silc_file_readfile((*entry) + 8, &tmp_len);
532         if (tmp) {
533           tmp[tmp_len] = 0;
534           pk.type = "silc-rsa";
535           pk.data = tmp;
536           pk.data_len = tmp_len;
537           silc_client_attribute_add(silc_client, conn,
538                                     SILC_ATTRIBUTE_USER_PUBLIC_KEY, &pk,
539                                     sizeof(pk));
540         }
541         silc_free(tmp);
542       } else {
543         silc_say_error("Unsupported public key type '%s'", *entry);
544       }
545     }
546     g_strfreev(list);
547   }
548 }
549
550 typedef struct {
551   SilcClient client;
552   SILC_SERVER_REC *server;
553   char *name;
554   SilcAttributeObjPk userpk;
555   SilcVCardStruct vcard;
556   SilcAttributeObjMime message;
557   SilcAttributeObjMime extension;
558   bool nopk;
559 } *AttrVerify;
560
561 void silc_query_attributes_print(SILC_SERVER_REC *server,
562                                  SilcClient client,
563                                  SilcClientConnection conn,
564                                  SilcDList attrs,
565                                  SilcClientEntry client_entry)
566 {
567   SilcAttributePayload attr;
568   SilcAttribute attribute;
569   char tmp[512];
570   SilcAttributeObjPk serverpk, usersign, serversign;
571   AttrVerify verify;
572
573   printformat_module("fe-common/silc", server, NULL,
574                      MSGLEVEL_CRAP, SILCTXT_ATTR_HEADER);
575
576   memset(&serverpk, 0, sizeof(serverpk));
577   memset(&usersign, 0, sizeof(usersign));
578   memset(&serversign, 0, sizeof(serversign));
579
580   verify = silc_calloc(1, sizeof(*verify));
581   if (!verify)
582     return;
583   verify->client = client;
584   verify->server = server;
585   verify->name = strdup(client_entry->nickname);
586
587   silc_dlist_start(attrs);
588   while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
589     attribute = silc_attribute_get_attribute(attr);
590     memset(tmp, 0, sizeof(tmp));
591
592     switch (attribute) {
593
594     case SILC_ATTRIBUTE_USER_INFO:
595       {
596         if (!silc_attribute_get_object(attr, (void *)&verify->vcard,
597                                        sizeof(verify->vcard)))
598           continue;
599         printformat_module("fe-common/silc", server, NULL,
600                            MSGLEVEL_CRAP, SILCTXT_ATTR_VCARD_FILE,
601                            "present");
602       }
603       break;
604
605     case SILC_ATTRIBUTE_SERVICE:
606       {
607         SilcAttributeObjService service;
608         memset(&service, 0, sizeof(service));
609         if (!silc_attribute_get_object(attr, (void *)&service,
610                                        sizeof(service)))
611           continue;
612         snprintf(tmp, sizeof(tmp) - 1, "%s:%d (logged %s)",
613                  service.address, (unsigned int)service.port,
614                  service.status ? "in" : "out");
615         printformat_module("fe-common/silc", server, NULL,
616                            MSGLEVEL_CRAP, SILCTXT_ATTR_SERVICES, tmp);
617       }
618       break;
619
620     case SILC_ATTRIBUTE_STATUS_MOOD:
621       {
622         SilcUInt32 mask;
623         if (!silc_attribute_get_object(attr, (void *)&mask, sizeof(mask)))
624           continue;
625         if (!mask)
626           silc_strncat(tmp, sizeof(tmp), "NORMAL ", strlen(" NORMAL"));
627         if (mask & SILC_ATTRIBUTE_MOOD_HAPPY)
628           silc_strncat(tmp, sizeof(tmp), "HAPPY ", strlen(" HAPPY"));
629         if (mask & SILC_ATTRIBUTE_MOOD_SAD)
630           silc_strncat(tmp, sizeof(tmp), "SAD ", strlen(" SAD"));
631         if (mask & SILC_ATTRIBUTE_MOOD_ANGRY)
632           silc_strncat(tmp, sizeof(tmp), "ANGRY ", strlen(" ANGRY"));
633         if (mask & SILC_ATTRIBUTE_MOOD_JEALOUS)
634           silc_strncat(tmp, sizeof(tmp), "JEALOUS ", strlen(" JEALOUS"));
635         if (mask & SILC_ATTRIBUTE_MOOD_ASHAMED)
636           silc_strncat(tmp, sizeof(tmp), "ASHAMED ", strlen(" ASHAMED"));
637         if (mask & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
638           silc_strncat(tmp, sizeof(tmp), "INVINCIBLE ", strlen(" INVINCIBLE"));
639         if (mask & SILC_ATTRIBUTE_MOOD_INLOVE)
640           silc_strncat(tmp, sizeof(tmp), "INLOVE ", strlen(" INLOVE"));
641         if (mask & SILC_ATTRIBUTE_MOOD_SLEEPY)
642           silc_strncat(tmp, sizeof(tmp), "SLEEPY ", strlen(" SLEEPY"));
643         if (mask & SILC_ATTRIBUTE_MOOD_BORED)
644           silc_strncat(tmp, sizeof(tmp), "BORED ", strlen(" BORED"));
645         if (mask & SILC_ATTRIBUTE_MOOD_EXCITED)
646           silc_strncat(tmp, sizeof(tmp), "EXCITED ", strlen(" EXCITED"));
647         if (mask & SILC_ATTRIBUTE_MOOD_ANXIOUS)
648           silc_strncat(tmp, sizeof(tmp), "ANXIOUS ", strlen(" ANXIOUS"));
649         printformat_module("fe-common/silc", server, NULL,
650                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MOOD, tmp);
651       }
652       break;
653
654     case SILC_ATTRIBUTE_STATUS_FREETEXT:
655       {
656         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
657           continue;
658         printformat_module("fe-common/silc", server, NULL,
659                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_TEXT, tmp);
660       }
661       break;
662
663     case SILC_ATTRIBUTE_STATUS_MESSAGE:
664       {
665         if (!silc_attribute_get_object(attr, (void *)&verify->message,
666                                        sizeof(verify->message)))
667           continue;
668         printformat_module("fe-common/silc", server, NULL,
669                            MSGLEVEL_CRAP, SILCTXT_ATTR_STATUS_MESSAGE,
670                            "present");
671       }
672       break;
673
674     case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
675       {
676         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
677           continue;
678         printformat_module("fe-common/silc", server, NULL,
679                            MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_LANGUAGE,
680                            tmp);
681       }
682       break;
683
684     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
685       {
686         SilcUInt32 mask;
687         if (!silc_attribute_get_object(attr, (void *)&mask, sizeof(mask)))
688           continue;
689         if (!mask)
690           silc_strncat(tmp, sizeof(tmp), "NONE ", strlen(" NONE"));
691         if (mask & SILC_ATTRIBUTE_CONTACT_CHAT)
692           silc_strncat(tmp, sizeof(tmp), "CHAT ", strlen(" CHAT"));
693         if (mask & SILC_ATTRIBUTE_CONTACT_EMAIL)
694           silc_strncat(tmp, sizeof(tmp), "EMAIL ", strlen(" EMAIL"));
695         if (mask & SILC_ATTRIBUTE_CONTACT_CALL)
696           silc_strncat(tmp, sizeof(tmp), "CALL ", strlen(" CALL"));
697         if (mask & SILC_ATTRIBUTE_CONTACT_PAGE)
698           silc_strncat(tmp, sizeof(tmp), "PAGE ", strlen(" PAGE"));
699         if (mask & SILC_ATTRIBUTE_CONTACT_SMS)
700           silc_strncat(tmp, sizeof(tmp), "SMS ", strlen(" SMS"));
701         if (mask & SILC_ATTRIBUTE_CONTACT_MMS)
702           silc_strncat(tmp, sizeof(tmp), "MMS ", strlen(" MMS"));
703         printformat_module("fe-common/silc", server, NULL,
704                            MSGLEVEL_CRAP, SILCTXT_ATTR_PREFERRED_CONTACT, tmp);
705       }
706       break;
707
708     case SILC_ATTRIBUTE_TIMEZONE:
709       {
710         if (!silc_attribute_get_object(attr, (void *)&tmp, sizeof(tmp) - 1))
711           continue;
712         printformat_module("fe-common/silc", server, NULL,
713                            MSGLEVEL_CRAP, SILCTXT_ATTR_TIMEZONE, tmp);
714       }
715       break;
716
717     case SILC_ATTRIBUTE_EXTENSION:
718       {
719         if (!silc_attribute_get_object(attr, (void *)&verify->extension,
720                                        sizeof(verify->extension)))
721           continue;
722         printformat_module("fe-common/silc", server, NULL,
723                            MSGLEVEL_CRAP, SILCTXT_ATTR_EXTENSION,
724                            "present");
725       }
726       break;
727
728     case SILC_ATTRIBUTE_GEOLOCATION:
729       {
730         SilcAttributeObjGeo geo;
731         memset(&geo, 0, sizeof(geo));
732         if (!silc_attribute_get_object(attr, (void *)&geo, sizeof(geo)))
733           continue;
734         snprintf(tmp, sizeof(tmp) - 1, "%s:%s:%s:%s",
735                  geo.longitude ? geo.longitude : "",
736                  geo.latitude ? geo.latitude : "",
737                  geo.altitude ? geo.altitude : "",
738                  geo.accuracy ? geo.accuracy : "");
739         printformat_module("fe-common/silc", server, NULL,
740                            MSGLEVEL_CRAP, SILCTXT_ATTR_GEOLOCATION, tmp);
741       }
742       break;
743
744     case SILC_ATTRIBUTE_DEVICE_INFO:
745       {
746         SilcAttributeObjDevice dev;
747         memset(&dev, 0, sizeof(dev));
748         if (!silc_attribute_get_object(attr, (void *)&dev, sizeof(dev)))
749           continue;
750         snprintf(tmp, sizeof(tmp) - 1, "%s:%s:%s:%s:%s",
751                  (dev.type == SILC_ATTRIBUTE_DEVICE_COMPUTER ? "COMPUTER" :
752                   dev.type == SILC_ATTRIBUTE_DEVICE_PDA ? "PDA" :
753                   dev.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE ?
754                   "MOBILE PHONE" :
755                   dev.type == SILC_ATTRIBUTE_DEVICE_TERMINAL ? "TERMINAL" :
756                   ""),
757                  dev.manufacturer ? dev.manufacturer : "",
758                  dev.version ? dev.version : "",
759                  dev.model ? dev.model: "",
760                  dev.language ? dev.language : "");
761         printformat_module("fe-common/silc", server, NULL,
762                            MSGLEVEL_CRAP, SILCTXT_ATTR_DEVICE_INFO, tmp);
763       }
764       break;
765
766     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
767       {
768         if (verify->userpk.type)
769           continue;
770         if (!silc_attribute_get_object(attr, (void *)&verify->userpk,
771                                        sizeof(verify->userpk)))
772           continue;
773       }
774       break;
775
776     case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
777       {
778         if (serverpk.type)
779           continue;
780         if (!silc_attribute_get_object(attr, (void *)&serverpk,
781                                        sizeof(serverpk)))
782           continue;
783       }
784       break;
785
786     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
787       {
788         if (usersign.data)
789           continue;
790         if (!silc_attribute_get_object(attr, (void *)&usersign,
791                                        sizeof(usersign)))
792           continue;
793       }
794       break;
795
796     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
797       {
798         if (serversign.data)
799           continue;
800         if (!silc_attribute_get_object(attr, (void *)&serversign,
801                                        sizeof(serversign)))
802           continue;
803       }
804       break;
805
806     default:
807       break;
808     }
809   }
810
811   /* Handle the signature verifications and public key verifying here */
812
813   if (usersign.data && !strcmp(verify->userpk.type, "silc-rsa")) {
814     /* Verify the signature now */
815     SilcPublicKey public_key;
816     SilcPKCS pkcs;
817     unsigned char *verifyd;
818     SilcUInt32 verify_len;
819
820     if (silc_pkcs_public_key_decode(verify->userpk.data,
821                                     verify->userpk.data_len,
822                                     &public_key)) {
823       silc_pkcs_alloc("rsa", &pkcs);
824       verifyd = silc_attribute_get_verify_data(attrs, FALSE, &verify_len);
825       if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)){
826         if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
827                                        usersign.data,
828                                        usersign.data_len,
829                                        verifyd, verify_len)) {
830           printformat_module("fe-common/silc", server, NULL,
831                              MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_VERIFIED);
832         } else {
833           printformat_module("fe-common/silc", server, NULL,
834                              MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_FAILED);
835         }
836       }
837
838       silc_pkcs_public_key_free(public_key);
839       silc_free(verifyd);
840     }
841   } else {
842     printformat_module("fe-common/silc", server, NULL,
843                        MSGLEVEL_CRAP, SILCTXT_ATTR_USER_SIGN_NOT_PRESENT);
844   }
845
846   if (serversign.data && !strcmp(serverpk.type, "silc-rsa")) {
847     /* Verify the signature now */
848     SilcPublicKey public_key;
849     SilcPKCS pkcs;
850     unsigned char *verifyd;
851     SilcUInt32 verify_len;
852
853     if (silc_pkcs_public_key_decode(serverpk.data, serverpk.data_len,
854                                     &public_key)) {
855       silc_pkcs_alloc("rsa", &pkcs);
856       verifyd = silc_attribute_get_verify_data(attrs, TRUE, &verify_len);
857       if (verifyd && silc_pkcs_public_key_set(pkcs, public_key)) {
858         if (silc_pkcs_verify_with_hash(pkcs, client->sha1hash,
859                                        serversign.data,
860                                        serversign.data_len,
861                                        verifyd, verify_len)) {
862           printformat_module("fe-common/silc", server, NULL,
863                              MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_VERIFIED);
864         } else {
865           printformat_module("fe-common/silc", server, NULL,
866                              MSGLEVEL_CRAP, SILCTXT_ATTR_SERVER_SIGN_FAILED);
867         }
868       }
869
870       silc_pkcs_public_key_free(public_key);
871       silc_free(verifyd);
872     }
873   }
874
875   if (verify->userpk.data) {
876     silc_verify_public_key(client, conn, SILC_SOCKET_TYPE_CLIENT,
877                            verify->userpk.data, verify->userpk.data_len, 
878                            SILC_SKE_PK_TYPE_SILC,
879                            silc_query_attributes_print_final, verify);
880   } else {
881     verify->nopk = TRUE;
882     silc_query_attributes_print_final(FALSE, verify);
883   }
884 }
885
886 static void silc_query_attributes_print_final(bool success, void *context)
887 {
888   AttrVerify verify = context;
889   SilcClient client = verify->client;
890   SILC_SERVER_REC *server = verify->server;
891   char *format = NULL;
892   unsigned char filename[256], *fingerprint = NULL, *tmp;
893   struct stat st;
894   int i;
895
896   if (!verify->nopk) {
897     if (success) {
898       printformat_module("fe-common/silc", NULL, NULL,
899                          MSGLEVEL_CRAP, SILCTXT_PUBKEY_VERIFIED, "user",
900                          verify->name);
901     } else {
902       printformat_module("fe-common/silc", NULL, NULL,
903                          MSGLEVEL_CRAP, SILCTXT_PUBKEY_NOTVERIFIED, "user",
904                          verify->name);
905     }
906   }
907
908   printformat_module("fe-common/silc", server, NULL,
909                      MSGLEVEL_CRAP, SILCTXT_ATTR_FOOTER);
910
911   /* Replace all whitespaces with `_'. */
912   fingerprint = silc_hash_fingerprint(client->sha1hash,
913                                       verify->userpk.data,
914                                       verify->userpk.data_len);
915   for (i = 0; i < strlen(fingerprint); i++)
916     if (fingerprint[i] == ' ')
917       fingerprint[i] = '_';
918   
919   /* Filename for dir */
920   tmp = fingerprint + strlen(fingerprint) - 9;
921   snprintf(filename, sizeof(filename) - 1, "%s/friends/%s", 
922            get_irssi_dir(), tmp);
923   silc_free(fingerprint);
924
925   if ((stat(filename, &st)) == -1) {
926     /* Ask to accept save requested attributes */
927     format = format_get_text("fe-common/silc", NULL, NULL, NULL,
928                              SILCTXT_ATTR_SAVE);
929     keyboard_entry_redirect((SIGNAL_FUNC)silc_query_attributes_accept,
930                             format, 0, verify);
931   } else {
932     /* Save new data to existing directory */
933     silc_query_attributes_accept("Y", verify);
934   }
935
936   g_free(format);
937 }
938
939 static void silc_query_attributes_accept(const char *line, void *context)
940 {
941   AttrVerify verify = context;
942   SilcClient client = verify->client;
943   SILC_SERVER_REC *server = verify->server;
944   struct stat st;
945   struct passwd *pw;
946   unsigned char filename[256], filename2[256], *fingerprint = NULL, *tmp;
947   SilcUInt32 len;
948   int i;
949
950   if (line[0] == 'Y' || line[0] == 'y') {
951     /* Save the attributes */
952     memset(filename, 0, sizeof(filename));
953     memset(filename2, 0, sizeof(filename2));
954
955     pw = getpwuid(getuid());
956     if (!pw)
957       goto out;
958
959     /* Replace all whitespaces with `_'. */
960     fingerprint = silc_hash_fingerprint(client->sha1hash,
961                                         verify->userpk.data,
962                                         verify->userpk.data_len);
963     for (i = 0; i < strlen(fingerprint); i++)
964       if (fingerprint[i] == ' ')
965         fingerprint[i] = '_';
966
967     /* Filename for dir */
968     tmp = fingerprint + strlen(fingerprint) - 9;
969     snprintf(filename, sizeof(filename) - 1, "%s/friends/%s", 
970              get_irssi_dir(), tmp);
971
972     /* Create dir if it doesn't exist */
973     if ((stat(filename, &st)) == -1) {
974       /* If dir doesn't exist */
975       if (errno == ENOENT) {
976         if (pw->pw_uid == geteuid()) {
977           if ((mkdir(filename, 0755)) == -1) {
978             silc_say_error("Couldn't create `%s' directory",
979                            filename);
980             goto out;
981           }
982         } else {
983           silc_say_error("Couldn't create `%s' directory due to a "
984                          "wrong uid!", filename);
985           goto out;
986         }
987       } else {
988         silc_say_error("%s", strerror(errno));
989         goto out;
990       }
991     }
992
993     /* Save the stuff to the directory */
994
995     /* Save VCard */
996     snprintf(filename2, sizeof(filename2) - 1, "%s/vcard", filename);
997     if (verify->vcard.full_name) {
998       tmp = silc_vcard_encode(&verify->vcard, &len);
999       silc_file_writefile(filename2, tmp, len);
1000       silc_free(tmp);
1001     }
1002
1003     /* Save public key */
1004     memset(filename2, 0, sizeof(filename2));
1005     snprintf(filename2, sizeof(filename2) - 1, "%s/clientkey_%s.pub",
1006              filename, fingerprint);
1007     silc_pkcs_save_public_key_data(filename2, verify->userpk.data,
1008                                    verify->userpk.data_len,
1009                                    SILC_PKCS_FILE_PEM);
1010
1011     /* Save extension data */
1012     if (verify->extension.mime) {
1013       memset(filename2, 0, sizeof(filename2));
1014       snprintf(filename2, sizeof(filename2) - 1, "%s/extension.mime",
1015                filename);
1016       silc_file_writefile(filename2, verify->extension.mime,
1017                           verify->extension.mime_len);
1018     }
1019
1020     /* Save MIME message data */
1021     if (verify->extension.mime) {
1022       memset(filename2, 0, sizeof(filename2));
1023       snprintf(filename2, sizeof(filename2) - 1, "%s/status_message.mime",
1024                filename);
1025       silc_file_writefile(filename2, verify->message.mime,
1026                           verify->message.mime_len);
1027     }
1028
1029     printformat_module("fe-common/silc", server, NULL,
1030                        MSGLEVEL_CRAP, SILCTXT_ATTR_SAVED, filename);
1031   }
1032
1033  out:
1034   silc_free(fingerprint);
1035   silc_free(verify->name);
1036   silc_vcard_free(&verify->vcard);
1037   silc_free(verify);
1038 }