comparison libpurple/protocols/silc10/util.c @ 32819:2c6510167895 default tip

propagate from branch 'im.pidgin.pidgin.2.x.y' (head 3315c5dfbd0ad16511bdcf865e5b07c02d07df24) to branch 'im.pidgin.pidgin' (head cbd1eda6bcbf0565ae7766396bb8f6f419cb6a9a)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Sat, 02 Jun 2012 02:30:49 +0000
parents 01ff09d4a463 071a0e568ac5
children
comparison
equal deleted inserted replaced
32818:01ff09d4a463 32819:2c6510167895
1 /*
2
3 silcpurple_util.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2004 - 2005 Pekka Riikonen
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 */
19
20 #include "silcincludes.h"
21 #include "silcclient.h"
22 #include "silcpurple.h"
23 #include "imgstore.h"
24
25 /**************************** Utility Routines *******************************/
26
27 static char str[256], str2[256];
28
29 const char *silcpurple_silcdir(void)
30 {
31 const char *hd = purple_home_dir();
32 memset(str, 0, sizeof(str));
33 g_snprintf(str, sizeof(str) - 1, "%s" G_DIR_SEPARATOR_S ".silc", hd ? hd : "/tmp");
34 return (const char *)str;
35 }
36
37 const char *silcpurple_session_file(const char *account)
38 {
39 memset(str2, 0, sizeof(str2));
40 g_snprintf(str2, sizeof(str2) - 1, "%s" G_DIR_SEPARATOR_S "%s_session",
41 silcpurple_silcdir(), account);
42 return (const char *)str2;
43 }
44
45 gboolean silcpurple_ip_is_private(const char *ip)
46 {
47 if (silc_net_is_ip4(ip)) {
48 if (!strncmp(ip, "10.", 3)) {
49 return TRUE;
50 } else if (!strncmp(ip, "172.", 4) && strlen(ip) > 6) {
51 char tmp[3];
52 int s;
53 memset(tmp, 0, sizeof(tmp));
54 strncpy(tmp, ip + 4, 2);
55 s = atoi(tmp);
56 if (s >= 16 && s <= 31)
57 return TRUE;
58 } else if (!strncmp(ip, "192.168.", 8)) {
59 return TRUE;
60 }
61 }
62
63 return FALSE;
64 }
65
66 /* This checks stats for various SILC files and directories. First it
67 checks if ~/.silc directory exist and is owned by the correct user. If
68 it doesn't exist, it will create the directory. After that it checks if
69 user's Public and Private key files exists and creates them if needed. */
70
71 gboolean silcpurple_check_silc_dir(PurpleConnection *gc)
72 {
73 char filename[256], file_public_key[256], file_private_key[256];
74 char servfilename[256], clientfilename[256], friendsfilename[256];
75 char pkd[256], prd[256];
76 struct stat st;
77 struct passwd *pw;
78 int fd;
79
80 pw = getpwuid(getuid());
81 if (!pw) {
82 purple_debug_error("silc", "silc: %s\n", g_strerror(errno));
83 return FALSE;
84 }
85
86 g_snprintf(filename, sizeof(filename) - 1, "%s", silcpurple_silcdir());
87 g_snprintf(servfilename, sizeof(servfilename) - 1, "%s" G_DIR_SEPARATOR_S "serverkeys",
88 silcpurple_silcdir());
89 g_snprintf(clientfilename, sizeof(clientfilename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys",
90 silcpurple_silcdir());
91 g_snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s" G_DIR_SEPARATOR_S "friends",
92 silcpurple_silcdir());
93
94 /*
95 * Check ~/.silc directory
96 */
97 if ((g_stat(filename, &st)) == -1) {
98 /* If dir doesn't exist */
99 if (errno == ENOENT) {
100 if (pw->pw_uid == geteuid()) {
101 if ((g_mkdir(filename, 0755)) == -1) {
102 purple_debug_error("silc", "Couldn't create '%s' directory\n", filename);
103 return FALSE;
104 }
105 } else {
106 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
107 filename);
108 return FALSE;
109 }
110 } else {
111 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", filename, g_strerror(errno));
112 return FALSE;
113 }
114 } else {
115 #ifndef _WIN32
116 /* Check the owner of the dir */
117 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
118 purple_debug_error("silc", "You don't seem to own '%s' directory\n",
119 filename);
120 return FALSE;
121 }
122 #endif
123 }
124
125 /*
126 * Check ~./silc/serverkeys directory
127 */
128 if ((g_stat(servfilename, &st)) == -1) {
129 /* If dir doesn't exist */
130 if (errno == ENOENT) {
131 if (pw->pw_uid == geteuid()) {
132 if ((g_mkdir(servfilename, 0755)) == -1) {
133 purple_debug_error("silc", "Couldn't create '%s' directory\n", servfilename);
134 return FALSE;
135 }
136 } else {
137 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
138 servfilename);
139 return FALSE;
140 }
141 } else {
142 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
143 servfilename, g_strerror(errno));
144 return FALSE;
145 }
146 }
147
148 /*
149 * Check ~./silc/clientkeys directory
150 */
151 if ((g_stat(clientfilename, &st)) == -1) {
152 /* If dir doesn't exist */
153 if (errno == ENOENT) {
154 if (pw->pw_uid == geteuid()) {
155 if ((g_mkdir(clientfilename, 0755)) == -1) {
156 purple_debug_error("silc", "Couldn't create '%s' directory\n", clientfilename);
157 return FALSE;
158 }
159 } else {
160 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
161 clientfilename);
162 return FALSE;
163 }
164 } else {
165 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
166 clientfilename, g_strerror(errno));
167 return FALSE;
168 }
169 }
170
171 /*
172 * Check ~./silc/friends directory
173 */
174 if ((g_stat(friendsfilename, &st)) == -1) {
175 /* If dir doesn't exist */
176 if (errno == ENOENT) {
177 if (pw->pw_uid == geteuid()) {
178 if ((g_mkdir(friendsfilename, 0755)) == -1) {
179 purple_debug_error("silc", "Couldn't create '%s' directory\n", friendsfilename);
180 return FALSE;
181 }
182 } else {
183 purple_debug_error("silc", "Couldn't create '%s' directory due to a wrong uid!\n",
184 friendsfilename);
185 return FALSE;
186 }
187 } else {
188 purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n",
189 friendsfilename, g_strerror(errno));
190 return FALSE;
191 }
192 }
193
194 /*
195 * Check Public and Private keys
196 */
197 g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
198 g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
199 g_snprintf(file_public_key, sizeof(file_public_key) - 1, "%s",
200 purple_account_get_string(gc->account, "public-key", pkd));
201 g_snprintf(file_private_key, sizeof(file_public_key) - 1, "%s",
202 purple_account_get_string(gc->account, "private-key", prd));
203
204 if ((g_stat(file_public_key, &st)) == -1) {
205 /* If file doesn't exist */
206 if (errno == ENOENT) {
207 purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
208 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
209 SILCPURPLE_DEF_PKCS_LEN,
210 file_public_key, file_private_key, NULL,
211 (gc->password == NULL) ? "" : gc->password,
212 NULL, NULL, NULL, FALSE)) {
213 purple_debug_error("silc", "Couldn't create key pair\n");
214 return FALSE;
215 }
216
217 if ((g_stat(file_public_key, &st)) == -1) {
218 purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
219 file_public_key, g_strerror(errno));
220 return FALSE;
221 }
222 } else {
223 purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
224 file_public_key, g_strerror(errno));
225 return FALSE;
226 }
227 }
228
229 #ifndef _WIN32
230 /* Check the owner of the public key */
231 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
232 purple_debug_error("silc", "You don't seem to own your public key!?\n");
233 return FALSE;
234 }
235 #endif
236
237 if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
238 if ((fstat(fd, &st)) == -1) {
239 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
240 file_private_key, g_strerror(errno));
241 close(fd);
242 return FALSE;
243 }
244 } else if ((g_stat(file_private_key, &st)) == -1) {
245 /* If file doesn't exist */
246 if (errno == ENOENT) {
247 purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
248 if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
249 SILCPURPLE_DEF_PKCS_LEN,
250 file_public_key, file_private_key, NULL,
251 (gc->password == NULL) ? "" : gc->password,
252 NULL, NULL, NULL, FALSE)) {
253 purple_debug_error("silc", "Couldn't create key pair\n");
254 return FALSE;
255 }
256
257 if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
258 if ((fstat(fd, &st)) == -1) {
259 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
260 file_private_key, g_strerror(errno));
261 close(fd);
262 return FALSE;
263 }
264 }
265 /* This shouldn't really happen because silc_create_key_pair()
266 * will set the permissions */
267 else if ((g_stat(file_private_key, &st)) == -1) {
268 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
269 file_private_key, g_strerror(errno));
270 return FALSE;
271 }
272 } else {
273 purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
274 file_private_key, g_strerror(errno));
275 return FALSE;
276 }
277 }
278
279 #ifndef _WIN32
280 /* Check the owner of the private key */
281 if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
282 purple_debug_error("silc", "You don't seem to own your private key!?\n");
283 if (fd != -1)
284 close(fd);
285 return FALSE;
286 }
287
288 /* Check the permissions for the private key */
289 if ((st.st_mode & 0777) != 0600) {
290 purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n"
291 "Trying to change them ...\n", file_private_key);
292 if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR)) == -1) {
293 purple_debug_error("silc",
294 "Failed to change permissions for private key file!\n"
295 "Permissions for your private key file must be 0600.\n");
296 if (fd != -1)
297 close(fd);
298 return FALSE;
299 }
300 purple_debug_warning("silc", "Done.\n\n");
301 }
302 #endif
303
304 if (fd != -1)
305 close(fd);
306
307 return TRUE;
308 }
309
310 #ifdef _WIN32
311 struct passwd *getpwuid(uid_t uid) {
312 struct passwd *pwd = calloc(1, sizeof(struct passwd));
313 return pwd;
314 }
315
316 uid_t getuid() {
317 return 0;
318 }
319
320 uid_t geteuid() {
321 return 0;
322 }
323 #endif
324
325 void silcpurple_show_public_key(SilcPurple sg,
326 const char *name, SilcPublicKey public_key,
327 GCallback callback, void *context)
328 {
329 SilcPublicKeyIdentifier ident;
330 SilcPKCS pkcs;
331 char *fingerprint, *babbleprint;
332 unsigned char *pk;
333 SilcUInt32 pk_len, key_len = 0;
334 GString *s;
335 char *buf;
336
337 ident = silc_pkcs_decode_identifier(public_key->identifier);
338 if (!ident)
339 return;
340
341 pk = silc_pkcs_public_key_encode(public_key, &pk_len);
342 fingerprint = silc_hash_fingerprint(NULL, pk, pk_len);
343 babbleprint = silc_hash_babbleprint(NULL, pk, pk_len);
344
345 if (silc_pkcs_alloc((unsigned char *)public_key->name, &pkcs)) {
346 key_len = silc_pkcs_public_key_set(pkcs, public_key);
347 silc_pkcs_free(pkcs);
348 }
349
350 s = g_string_new("");
351 if (ident->realname)
352 /* Hint for translators: Please check the tabulator width here and in
353 the next strings (short strings: 2 tabs, longer strings 1 tab,
354 sum: 3 tabs or 24 characters) */
355 g_string_append_printf(s, _("Real Name: \t%s\n"), ident->realname);
356 if (ident->username)
357 g_string_append_printf(s, _("User Name: \t%s\n"), ident->username);
358 if (ident->email)
359 g_string_append_printf(s, _("Email: \t\t%s\n"), ident->email);
360 if (ident->host)
361 g_string_append_printf(s, _("Host Name: \t%s\n"), ident->host);
362 if (ident->org)
363 g_string_append_printf(s, _("Organization: \t%s\n"), ident->org);
364 if (ident->country)
365 g_string_append_printf(s, _("Country: \t%s\n"), ident->country);
366 g_string_append_printf(s, _("Algorithm: \t%s\n"), public_key->name);
367 g_string_append_printf(s, _("Key Length: \t%d bits\n"), (int)key_len);
368 g_string_append_printf(s, "\n");
369 g_string_append_printf(s, _("Public Key Fingerprint:\n%s\n\n"), fingerprint);
370 g_string_append_printf(s, _("Public Key Babbleprint:\n%s"), babbleprint);
371
372 buf = g_string_free(s, FALSE);
373
374 purple_request_action(sg->gc, _("Public Key Information"),
375 _("Public Key Information"),
376 buf, 0, purple_connection_get_account(sg->gc),
377 NULL, NULL, context, 1, _("Close"), callback);
378
379 g_free(buf);
380 silc_free(fingerprint);
381 silc_free(babbleprint);
382 silc_free(pk);
383 silc_pkcs_free_identifier(ident);
384 }
385
386 SilcAttributePayload
387 silcpurple_get_attr(SilcDList attrs, SilcAttribute attribute)
388 {
389 SilcAttributePayload attr = NULL;
390
391 if (!attrs)
392 return NULL;
393
394 silc_dlist_start(attrs);
395 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END)
396 if (attribute == silc_attribute_get_attribute(attr))
397 break;
398
399 return attr;
400 }
401
402 void silcpurple_get_umode_string(SilcUInt32 mode, char *buf,
403 SilcUInt32 buf_size)
404 {
405 memset(buf, 0, buf_size);
406 if ((mode & SILC_UMODE_SERVER_OPERATOR) ||
407 (mode & SILC_UMODE_ROUTER_OPERATOR)) {
408 strcat(buf, (mode & SILC_UMODE_SERVER_OPERATOR) ?
409 "[server operator] " :
410 (mode & SILC_UMODE_ROUTER_OPERATOR) ?
411 "[SILC operator] " : "[unknown mode] ");
412 }
413 if (mode & SILC_UMODE_GONE)
414 strcat(buf, "[away] ");
415 if (mode & SILC_UMODE_INDISPOSED)
416 strcat(buf, "[indisposed] ");
417 if (mode & SILC_UMODE_BUSY)
418 strcat(buf, "[busy] ");
419 if (mode & SILC_UMODE_PAGE)
420 strcat(buf, "[wake me up] ");
421 if (mode & SILC_UMODE_HYPER)
422 strcat(buf, "[hyperactive] ");
423 if (mode & SILC_UMODE_ROBOT)
424 strcat(buf, "[robot] ");
425 if (mode & SILC_UMODE_ANONYMOUS)
426 strcat(buf, "[anonymous] ");
427 if (mode & SILC_UMODE_BLOCK_PRIVMSG)
428 strcat(buf, "[blocks private messages] ");
429 if (mode & SILC_UMODE_DETACHED)
430 strcat(buf, "[detached] ");
431 if (mode & SILC_UMODE_REJECT_WATCHING)
432 strcat(buf, "[rejects watching] ");
433 if (mode & SILC_UMODE_BLOCK_INVITE)
434 strcat(buf, "[blocks invites] ");
435 g_strchomp(buf);
436 }
437
438 void silcpurple_get_chmode_string(SilcUInt32 mode, char *buf,
439 SilcUInt32 buf_size)
440 {
441 memset(buf, 0, buf_size);
442 if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
443 strcat(buf, "[permanent] ");
444 if (mode & SILC_CHANNEL_MODE_PRIVATE)
445 strcat(buf, "[private] ");
446 if (mode & SILC_CHANNEL_MODE_SECRET)
447 strcat(buf, "[secret] ");
448 if (mode & SILC_CHANNEL_MODE_PRIVKEY)
449 strcat(buf, "[private key] ");
450 if (mode & SILC_CHANNEL_MODE_INVITE)
451 strcat(buf, "[invite only] ");
452 if (mode & SILC_CHANNEL_MODE_TOPIC)
453 strcat(buf, "[topic restricted] ");
454 if (mode & SILC_CHANNEL_MODE_ULIMIT)
455 strcat(buf, "[user count limit] ");
456 if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
457 strcat(buf, "[passphrase auth] ");
458 if (mode & SILC_CHANNEL_MODE_CHANNEL_AUTH)
459 strcat(buf, "[public key auth] ");
460 if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
461 strcat(buf, "[users silenced] ");
462 if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
463 strcat(buf, "[operators silenced] ");
464 g_strchomp(buf);
465 }
466
467 void silcpurple_get_chumode_string(SilcUInt32 mode, char *buf,
468 SilcUInt32 buf_size)
469 {
470 memset(buf, 0, buf_size);
471 if (mode & SILC_CHANNEL_UMODE_CHANFO)
472 strcat(buf, "[founder] ");
473 if (mode & SILC_CHANNEL_UMODE_CHANOP)
474 strcat(buf, "[operator] ");
475 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES)
476 strcat(buf, "[blocks messages] ");
477 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_USERS)
478 strcat(buf, "[blocks user messages] ");
479 if (mode & SILC_CHANNEL_UMODE_BLOCK_MESSAGES_ROBOTS)
480 strcat(buf, "[blocks robot messages] ");
481 if (mode & SILC_CHANNEL_UMODE_QUIET)
482 strcat(buf, "[quieted] ");
483 g_strchomp(buf);
484 }
485
486 void
487 silcpurple_parse_attrs(SilcDList attrs, char **moodstr, char **statusstr,
488 char **contactstr, char **langstr, char **devicestr,
489 char **tzstr, char **geostr)
490 {
491 SilcAttributePayload attr;
492 SilcAttributeMood mood = 0;
493 SilcAttributeContact contact;
494 SilcAttributeObjDevice device;
495 SilcAttributeObjGeo geo;
496
497 char tmp[1024];
498 GString *s;
499
500 *moodstr = NULL;
501 *statusstr = NULL;
502 *contactstr = NULL;
503 *langstr = NULL;
504 *devicestr = NULL;
505 *tzstr = NULL;
506 *geostr = NULL;
507
508 if (!attrs)
509 return;
510
511 s = g_string_new("");
512 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_MOOD);
513 if (attr && silc_attribute_get_object(attr, &mood, sizeof(mood))) {
514 if (mood & SILC_ATTRIBUTE_MOOD_HAPPY)
515 g_string_append_printf(s, "[%s] ", _("Happy"));
516 if (mood & SILC_ATTRIBUTE_MOOD_SAD)
517 g_string_append_printf(s, "[%s] ", _("Sad"));
518 if (mood & SILC_ATTRIBUTE_MOOD_ANGRY)
519 g_string_append_printf(s, "[%s] ", _("Angry"));
520 if (mood & SILC_ATTRIBUTE_MOOD_JEALOUS)
521 g_string_append_printf(s, "[%s] ", _("Jealous"));
522 if (mood & SILC_ATTRIBUTE_MOOD_ASHAMED)
523 g_string_append_printf(s, "[%s] ", _("Ashamed"));
524 if (mood & SILC_ATTRIBUTE_MOOD_INVINCIBLE)
525 g_string_append_printf(s, "[%s] ", _("Invincible"));
526 if (mood & SILC_ATTRIBUTE_MOOD_INLOVE)
527 g_string_append_printf(s, "[%s] ", _("In Love"));
528 if (mood & SILC_ATTRIBUTE_MOOD_SLEEPY)
529 g_string_append_printf(s, "[%s] ", _("Sleepy"));
530 if (mood & SILC_ATTRIBUTE_MOOD_BORED)
531 g_string_append_printf(s, "[%s] ", _("Bored"));
532 if (mood & SILC_ATTRIBUTE_MOOD_EXCITED)
533 g_string_append_printf(s, "[%s] ", _("Excited"));
534 if (mood & SILC_ATTRIBUTE_MOOD_ANXIOUS)
535 g_string_append_printf(s, "[%s] ", _("Anxious"));
536 }
537 if (strlen(s->str)) {
538 *moodstr = s->str;
539 g_string_free(s, FALSE);
540 g_strchomp(*moodstr);
541 } else
542 g_string_free(s, TRUE);
543
544 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_STATUS_FREETEXT);
545 memset(tmp, 0, sizeof(tmp));
546 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
547 *statusstr = g_strdup(tmp);
548
549 s = g_string_new("");
550 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_CONTACT);
551 if (attr && silc_attribute_get_object(attr, &contact, sizeof(contact))) {
552 if (contact & SILC_ATTRIBUTE_CONTACT_CHAT)
553 g_string_append_printf(s, "[%s] ", _("Chat"));
554 if (contact & SILC_ATTRIBUTE_CONTACT_EMAIL)
555 g_string_append_printf(s, "[%s] ", _("Email"));
556 if (contact & SILC_ATTRIBUTE_CONTACT_CALL)
557 g_string_append_printf(s, "[%s] ", _("Phone"));
558 if (contact & SILC_ATTRIBUTE_CONTACT_PAGE)
559 g_string_append_printf(s, "[%s] ", _("Paging"));
560 if (contact & SILC_ATTRIBUTE_CONTACT_SMS)
561 g_string_append_printf(s, "[%s] ", _("SMS"));
562 if (contact & SILC_ATTRIBUTE_CONTACT_MMS)
563 g_string_append_printf(s, "[%s] ", _("MMS"));
564 if (contact & SILC_ATTRIBUTE_CONTACT_VIDEO)
565 g_string_append_printf(s, "[%s] ", _("Video Conferencing"));
566 }
567 if (strlen(s->str)) {
568 *contactstr = s->str;
569 g_string_free(s, FALSE);
570 g_strchomp(*contactstr);
571 } else
572 g_string_free(s, TRUE);
573
574 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_PREFERRED_LANGUAGE);
575 memset(tmp, 0, sizeof(tmp));
576 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
577 *langstr = g_strdup(tmp);
578
579 s = g_string_new("");
580 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_DEVICE_INFO);
581 memset(&device, 0, sizeof(device));
582 if (attr && silc_attribute_get_object(attr, &device, sizeof(device))) {
583 if (device.type == SILC_ATTRIBUTE_DEVICE_COMPUTER)
584 g_string_append_printf(s, "%s: ", _("Computer"));
585 if (device.type == SILC_ATTRIBUTE_DEVICE_MOBILE_PHONE)
586 g_string_append_printf(s, "%s: ", _("Mobile Phone"));
587 if (device.type == SILC_ATTRIBUTE_DEVICE_PDA)
588 g_string_append_printf(s, "%s: ", _("PDA"));
589 if (device.type == SILC_ATTRIBUTE_DEVICE_TERMINAL)
590 g_string_append_printf(s, "%s: ", _("Terminal"));
591 g_string_append_printf(s, "%s %s %s %s",
592 device.manufacturer ? device.manufacturer : "",
593 device.version ? device.version : "",
594 device.model ? device.model : "",
595 device.language ? device.language : "");
596 }
597 if (strlen(s->str)) {
598 *devicestr = s->str;
599 g_string_free(s, FALSE);
600 } else
601 g_string_free(s, TRUE);
602
603 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_TIMEZONE);
604 memset(tmp, 0, sizeof(tmp));
605 if (attr && silc_attribute_get_object(attr, tmp, sizeof(tmp)))
606 *tzstr = g_strdup(tmp);
607
608 attr = silcpurple_get_attr(attrs, SILC_ATTRIBUTE_GEOLOCATION);
609 memset(&geo, 0, sizeof(geo));
610 if (attr && silc_attribute_get_object(attr, &geo, sizeof(geo)))
611 *geostr = g_strdup_printf("%s %s %s (%s)",
612 geo.longitude ? geo.longitude : "",
613 geo.latitude ? geo.latitude : "",
614 geo.altitude ? geo.altitude : "",
615 geo.accuracy ? geo.accuracy : "");
616 }
617
618 #ifdef HAVE_SILCMIME_H
619 /* Returns MIME type of filetype */
620
621 char *silcpurple_file2mime(const char *filename)
622 {
623 const char *ct;
624
625 ct = strrchr(filename, '.');
626 if (!ct)
627 return NULL;
628 else if (!g_ascii_strcasecmp(".png", ct))
629 return strdup("image/png");
630 else if (!g_ascii_strcasecmp(".jpg", ct))
631 return strdup("image/jpeg");
632 else if (!g_ascii_strcasecmp(".jpeg", ct))
633 return strdup("image/jpeg");
634 else if (!g_ascii_strcasecmp(".gif", ct))
635 return strdup("image/gif");
636 else if (!g_ascii_strcasecmp(".tiff", ct))
637 return strdup("image/tiff");
638
639 return NULL;
640 }
641
642 /* Checks if message has images, and assembles MIME message if it has.
643 If only one image is present, creates simple MIME image message. If
644 there are multiple images and/or text with images multipart MIME
645 message is created. */
646
647 SilcDList silcpurple_image_message(const char *msg, SilcUInt32 *mflags)
648 {
649 SilcMime mime = NULL, p;
650 SilcDList list, parts = NULL;
651 const char *start, *end, *last;
652 GData *attribs;
653 char *type;
654 gboolean images = FALSE;
655
656 last = msg;
657 while (last && *last && purple_markup_find_tag("img", last, &start,
658 &end, &attribs)) {
659 PurpleStoredImage *image = NULL;
660 const char *id;
661
662 /* Check if there is text before image */
663 if (start - last) {
664 char *text, *tmp;
665 p = silc_mime_alloc();
666
667 /* Add content type */
668 silc_mime_add_field(p, "Content-Type",
669 "text/plain; charset=utf-8");
670
671 tmp = g_strndup(last, start - last);
672 text = purple_unescape_html(tmp);
673 g_free(tmp);
674 /* Add text */
675 silc_mime_add_data(p, (unsigned char *)text, strlen(text));
676 g_free(text);
677
678 if (!parts)
679 parts = silc_dlist_init();
680 silc_dlist_add(parts, p);
681 }
682
683 id = g_datalist_get_data(&attribs, "id");
684 if (id && (image = purple_imgstore_find_by_id(atoi(id)))) {
685 unsigned long imglen = purple_imgstore_get_size(image);
686 gconstpointer img = purple_imgstore_get_data(image);
687
688 p = silc_mime_alloc();
689
690 /* Add content type */
691 type = silcpurple_file2mime(purple_imgstore_get_filename(image));
692 if (!type) {
693 g_datalist_clear(&attribs);
694 last = end + 1;
695 continue;
696 }
697 silc_mime_add_field(p, "Content-Type", type);
698 silc_free(type);
699
700 /* Add content transfer encoding */
701 silc_mime_add_field(p, "Content-Transfer-Encoding", "binary");
702
703 /* Add image data */
704 silc_mime_add_data(p, img, imglen);
705
706 if (!parts)
707 parts = silc_dlist_init();
708 silc_dlist_add(parts, p);
709 images = TRUE;
710 }
711
712 g_datalist_clear(&attribs);
713
714 /* Continue after tag */
715 last = end + 1;
716 }
717
718 /* Check for text after the image(s) */
719 if (images && last && *last) {
720 char *tmp = purple_unescape_html(last);
721 p = silc_mime_alloc();
722
723 /* Add content type */
724 silc_mime_add_field(p, "Content-Type",
725 "text/plain; charset=utf-8");
726
727 /* Add text */
728 silc_mime_add_data(p, (unsigned char *)tmp, strlen(tmp));
729 g_free(tmp);
730
731 if (!parts)
732 parts = silc_dlist_init();
733 silc_dlist_add(parts, p);
734 }
735
736 /* If there weren't any images, don't return anything. */
737 if (!images) {
738 if (parts)
739 silc_dlist_uninit(parts);
740 return NULL;
741 }
742
743 if (silc_dlist_count(parts) > 1) {
744 /* Multipart MIME message */
745 char b[32];
746 mime = silc_mime_alloc();
747 silc_mime_add_field(mime, "MIME-Version", "1.0");
748 g_snprintf(b, sizeof(b), "b%4X%4X",
749 (unsigned int)time(NULL),
750 silc_dlist_count(parts));
751 silc_mime_set_multipart(mime, "mixed", b);
752 silc_dlist_start(parts);
753 while ((p = silc_dlist_get(parts)) != SILC_LIST_END)
754 silc_mime_add_multipart(mime, p);
755 } else {
756 /* Simple MIME message */
757 silc_dlist_start(parts);
758 mime = silc_dlist_get(parts);
759 silc_mime_add_field(mime, "MIME-Version", "1.0");
760 }
761
762 *mflags &= ~SILC_MESSAGE_FLAG_UTF8;
763 *mflags |= SILC_MESSAGE_FLAG_DATA;
764
765 /* Encode message. Fragment if it is too large */
766 list = silc_mime_encode_partial(mime, 0xfc00);
767
768 silc_dlist_uninit(parts);
769
770 /* Added multiparts gets freed here */
771 silc_mime_free(mime);
772
773 return list;
774 }
775
776 #endif /* HAVE_SILCMIME_H */