Mercurial > pidgin.yaz
comparison libpurple/protocols/msn/msnutils.c @ 20482:1754155051a4
propagate from branch 'im.pidgin.pidgin' (head 4313008137cace2c9699584ec7308c1e888ae137)
to branch 'im.pidgin.cpw.khc.msnp14' (head d42c2c6500b8f7eb1ad6340caf7f1b95d9b02c1b)
author | Carlos Silva <typ0@pidgin.im> |
---|---|
date | Tue, 28 Aug 2007 04:38:24 +0000 |
parents | 530a92d50c5e |
children | 723b5a2f91ce |
comparison
equal
deleted
inserted
replaced
19508:f0c3497e2ea6 | 20482:1754155051a4 |
---|---|
1 /** | |
2 * @file msnutils.c Utility functions | |
3 * | |
4 * purple | |
5 * | |
6 * Purple is the legal property of its developers, whose names are too numerous | |
7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
8 * source distribution. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 */ | |
24 #include "msn.h" | |
25 #include "msnutils.h" | |
26 #include "time.h" | |
27 //#include <openssl/md5.h> | |
28 | |
29 char *rand_guid(void); | |
30 | |
31 /************************************************************************** | |
32 * Util | |
33 **************************************************************************/ | |
34 char * | |
35 rand_guid() | |
36 { | |
37 return g_strdup_printf("%4X%4X-%4X-%4X-%4X-%4X%4X%4X", | |
38 rand() % 0xAAFF + 0x1111, | |
39 rand() % 0xAAFF + 0x1111, | |
40 rand() % 0xAAFF + 0x1111, | |
41 rand() % 0xAAFF + 0x1111, | |
42 rand() % 0xAAFF + 0x1111, | |
43 rand() % 0xAAFF + 0x1111, | |
44 rand() % 0xAAFF + 0x1111, | |
45 rand() % 0xAAFF + 0x1111); | |
46 } | |
47 | |
48 void | |
49 msn_parse_format(const char *mime, char **pre_ret, char **post_ret) | |
50 { | |
51 char *cur; | |
52 GString *pre = g_string_new(NULL); | |
53 GString *post = g_string_new(NULL); | |
54 unsigned int colors[3]; | |
55 | |
56 if (pre_ret != NULL) *pre_ret = NULL; | |
57 if (post_ret != NULL) *post_ret = NULL; | |
58 | |
59 cur = strstr(mime, "FN="); | |
60 | |
61 if (cur && (*(cur = cur + 3) != ';')) | |
62 { | |
63 pre = g_string_append(pre, "<FONT FACE=\""); | |
64 | |
65 while (*cur && *cur != ';') | |
66 { | |
67 pre = g_string_append_c(pre, *cur); | |
68 cur++; | |
69 } | |
70 | |
71 pre = g_string_append(pre, "\">"); | |
72 post = g_string_prepend(post, "</FONT>"); | |
73 } | |
74 | |
75 cur = strstr(mime, "EF="); | |
76 | |
77 if (cur && (*(cur = cur + 3) != ';')) | |
78 { | |
79 while (*cur && *cur != ';') | |
80 { | |
81 pre = g_string_append_c(pre, '<'); | |
82 pre = g_string_append_c(pre, *cur); | |
83 pre = g_string_append_c(pre, '>'); | |
84 post = g_string_prepend_c(post, '>'); | |
85 post = g_string_prepend_c(post, *cur); | |
86 post = g_string_prepend_c(post, '/'); | |
87 post = g_string_prepend_c(post, '<'); | |
88 cur++; | |
89 } | |
90 } | |
91 | |
92 cur = strstr(mime, "CO="); | |
93 | |
94 if (cur && (*(cur = cur + 3) != ';')) | |
95 { | |
96 int i; | |
97 | |
98 i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]); | |
99 | |
100 if (i > 0) | |
101 { | |
102 char tag[64]; | |
103 | |
104 if (i == 1) | |
105 { | |
106 colors[1] = 0; | |
107 colors[2] = 0; | |
108 } | |
109 else if (i == 2) | |
110 { | |
111 unsigned int temp = colors[0]; | |
112 | |
113 colors[0] = colors[1]; | |
114 colors[1] = temp; | |
115 colors[2] = 0; | |
116 } | |
117 else if (i == 3) | |
118 { | |
119 unsigned int temp = colors[2]; | |
120 | |
121 colors[2] = colors[0]; | |
122 colors[0] = temp; | |
123 } | |
124 | |
125 g_snprintf(tag, sizeof(tag), | |
126 "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", | |
127 colors[0], colors[1], colors[2]); | |
128 | |
129 pre = g_string_append(pre, tag); | |
130 post = g_string_prepend(post, "</FONT>"); | |
131 } | |
132 } | |
133 | |
134 cur = strstr(mime, "RL="); | |
135 | |
136 if (cur && (*(cur = cur + 3) != ';')) | |
137 { | |
138 if (*cur == '1') | |
139 { | |
140 /* RTL text was received */ | |
141 pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">"); | |
142 post = g_string_prepend(post, "</SPAN>"); | |
143 } | |
144 } | |
145 | |
146 cur = g_strdup(purple_url_decode(pre->str)); | |
147 g_string_free(pre, TRUE); | |
148 | |
149 if (pre_ret != NULL) | |
150 *pre_ret = cur; | |
151 else | |
152 g_free(cur); | |
153 | |
154 cur = g_strdup(purple_url_decode(post->str)); | |
155 g_string_free(post, TRUE); | |
156 | |
157 if (post_ret != NULL) | |
158 *post_ret = cur; | |
159 else | |
160 g_free(cur); | |
161 } | |
162 | |
163 /*encode the str to RFC2047 style | |
164 * Currently only support the UTF-8 and base64 encode | |
165 */ | |
166 char * | |
167 msn_encode_mime(const char *str) | |
168 { | |
169 char *base64; | |
170 | |
171 base64 = purple_base64_encode((guchar *)str, strlen(str)); | |
172 return g_strdup_printf("=?utf-8?B?%s?=", base64); | |
173 } | |
174 | |
175 /* | |
176 * We need this because we're only supposed to encode spaces in the font | |
177 * names. purple_url_encode() isn't acceptable. | |
178 */ | |
179 static const char * | |
180 encode_spaces(const char *str) | |
181 { | |
182 static char buf[BUF_LEN]; | |
183 const char *c; | |
184 char *d; | |
185 | |
186 g_return_val_if_fail(str != NULL, NULL); | |
187 | |
188 for (c = str, d = buf; *c != '\0'; c++) | |
189 { | |
190 if (*c == ' ') | |
191 { | |
192 *d++ = '%'; | |
193 *d++ = '2'; | |
194 *d++ = '0'; | |
195 } | |
196 else | |
197 *d++ = *c; | |
198 } | |
199 | |
200 return buf; | |
201 } | |
202 | |
203 /* | |
204 * Taken from the zephyr plugin. | |
205 * This parses HTML formatting (put out by one of the gtkimhtml widgets | |
206 * and converts it to msn formatting. It doesn't deal with the tag closing, | |
207 * but gtkimhtml widgets give valid html. | |
208 * It currently deals properly with <b>, <u>, <i>, <font face=...>, | |
209 * <font color=...>, <span dir=...>, <span style="direction: ...">. | |
210 * It ignores <font back=...> and <font size=...> | |
211 */ | |
212 void | |
213 msn_import_html(const char *html, char **attributes, char **message) | |
214 { | |
215 int len, retcount = 0; | |
216 const char *c; | |
217 char *msg; | |
218 char *fontface = NULL; | |
219 char fonteffect[4]; | |
220 char fontcolor[7]; | |
221 char direction = '0'; | |
222 | |
223 gboolean has_bold = FALSE; | |
224 gboolean has_italic = FALSE; | |
225 gboolean has_underline = FALSE; | |
226 gboolean has_strikethrough = FALSE; | |
227 | |
228 g_return_if_fail(html != NULL); | |
229 g_return_if_fail(attributes != NULL); | |
230 g_return_if_fail(message != NULL); | |
231 | |
232 len = strlen(html); | |
233 msg = g_malloc0(len + 1); | |
234 | |
235 memset(fontcolor, 0, sizeof(fontcolor)); | |
236 strcat(fontcolor, "0"); | |
237 memset(fonteffect, 0, sizeof(fonteffect)); | |
238 | |
239 for (c = html; *c != '\0';) | |
240 { | |
241 if (*c == '<') | |
242 { | |
243 if (!g_ascii_strncasecmp(c + 1, "br>", 3)) | |
244 { | |
245 msg[retcount++] = '\r'; | |
246 msg[retcount++] = '\n'; | |
247 c += 4; | |
248 } | |
249 else if (!g_ascii_strncasecmp(c + 1, "i>", 2)) | |
250 { | |
251 if (!has_italic) | |
252 { | |
253 strcat(fonteffect, "I"); | |
254 has_italic = TRUE; | |
255 } | |
256 c += 3; | |
257 } | |
258 else if (!g_ascii_strncasecmp(c + 1, "b>", 2)) | |
259 { | |
260 if (!has_bold) | |
261 { | |
262 strcat(fonteffect, "B"); | |
263 has_bold = TRUE; | |
264 } | |
265 c += 3; | |
266 } | |
267 else if (!g_ascii_strncasecmp(c + 1, "u>", 2)) | |
268 { | |
269 if (!has_underline) | |
270 { | |
271 strcat(fonteffect, "U"); | |
272 has_underline = TRUE; | |
273 } | |
274 c += 3; | |
275 } | |
276 else if (!g_ascii_strncasecmp(c + 1, "s>", 2)) | |
277 { | |
278 if (!has_strikethrough) | |
279 { | |
280 strcat(fonteffect, "S"); | |
281 has_strikethrough = TRUE; | |
282 } | |
283 c += 3; | |
284 } | |
285 else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8)) | |
286 { | |
287 c += 9; | |
288 | |
289 if (!g_ascii_strncasecmp(c, "mailto:", 7)) | |
290 c += 7; | |
291 | |
292 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) | |
293 msg[retcount++] = *c++; | |
294 | |
295 if (*c != '\0') | |
296 c += 2; | |
297 | |
298 /* ignore descriptive string */ | |
299 while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4)) | |
300 c++; | |
301 | |
302 if (*c != '\0') | |
303 c += 4; | |
304 } | |
305 else if (!g_ascii_strncasecmp(c + 1, "span", 4)) | |
306 { | |
307 /* Bi-directional text support using CSS properties in span tags */ | |
308 c += 5; | |
309 | |
310 while (*c != '\0' && *c != '>') | |
311 { | |
312 while (*c == ' ') | |
313 c++; | |
314 if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9)) | |
315 { | |
316 c += 9; | |
317 direction = '1'; | |
318 } | |
319 else if (!g_ascii_strncasecmp(c, "style=\"", 7)) | |
320 { | |
321 /* Parse inline CSS attributes */ | |
322 char *attributes; | |
323 int attr_len = 0; | |
324 c += 7; | |
325 while (*(c + attr_len) != '\0' && *(c + attr_len) != '"') | |
326 attr_len++; | |
327 if (*(c + attr_len) == '"') | |
328 { | |
329 char *attr_dir; | |
330 attributes = g_strndup(c, attr_len); | |
331 attr_dir = purple_markup_get_css_property(attributes, "direction"); | |
332 if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3))) | |
333 direction = '1'; | |
334 g_free(attr_dir); | |
335 g_free(attributes); | |
336 } | |
337 | |
338 } | |
339 else | |
340 { | |
341 c++; | |
342 } | |
343 } | |
344 if (*c == '>') | |
345 c++; | |
346 } | |
347 else if (!g_ascii_strncasecmp(c + 1, "font", 4)) | |
348 { | |
349 c += 5; | |
350 | |
351 while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1)) | |
352 c++; | |
353 | |
354 if (!g_ascii_strncasecmp(c, "color=\"#", 7)) | |
355 { | |
356 c += 8; | |
357 | |
358 fontcolor[0] = *(c + 4); | |
359 fontcolor[1] = *(c + 5); | |
360 fontcolor[2] = *(c + 2); | |
361 fontcolor[3] = *(c + 3); | |
362 fontcolor[4] = *c; | |
363 fontcolor[5] = *(c + 1); | |
364 | |
365 c += 8; | |
366 } | |
367 else if (!g_ascii_strncasecmp(c, "face=\"", 6)) | |
368 { | |
369 const char *end = NULL; | |
370 const char *comma = NULL; | |
371 unsigned int namelen = 0; | |
372 | |
373 c += 6; | |
374 end = strchr(c, '\"'); | |
375 comma = strchr(c, ','); | |
376 | |
377 if (comma == NULL || comma > end) | |
378 namelen = (unsigned int)(end - c); | |
379 else | |
380 namelen = (unsigned int)(comma - c); | |
381 | |
382 fontface = g_strndup(c, namelen); | |
383 c = end + 2; | |
384 } | |
385 else | |
386 { | |
387 /* Drop all unrecognized/misparsed font tags */ | |
388 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2)) | |
389 c++; | |
390 | |
391 if (*c != '\0') | |
392 c += 2; | |
393 } | |
394 } | |
395 else | |
396 { | |
397 while ((*c != '\0') && (*c != '>')) | |
398 c++; | |
399 if (*c != '\0') | |
400 c++; | |
401 } | |
402 } | |
403 else if (*c == '&') | |
404 { | |
405 if (!g_ascii_strncasecmp(c, "<", 4)) | |
406 { | |
407 msg[retcount++] = '<'; | |
408 c += 4; | |
409 } | |
410 else if (!g_ascii_strncasecmp(c, ">", 4)) | |
411 { | |
412 msg[retcount++] = '>'; | |
413 c += 4; | |
414 } | |
415 else if (!g_ascii_strncasecmp(c, " ", 6)) | |
416 { | |
417 msg[retcount++] = ' '; | |
418 c += 6; | |
419 } | |
420 else if (!g_ascii_strncasecmp(c, """, 6)) | |
421 { | |
422 msg[retcount++] = '"'; | |
423 c += 6; | |
424 } | |
425 else if (!g_ascii_strncasecmp(c, "&", 5)) | |
426 { | |
427 msg[retcount++] = '&'; | |
428 c += 5; | |
429 } | |
430 else if (!g_ascii_strncasecmp(c, "'", 6)) | |
431 { | |
432 msg[retcount++] = '\''; | |
433 c += 6; | |
434 } | |
435 else | |
436 msg[retcount++] = *c++; | |
437 } | |
438 else | |
439 msg[retcount++] = *c++; | |
440 } | |
441 | |
442 if (fontface == NULL) | |
443 fontface = g_strdup("MS Sans Serif"); | |
444 | |
445 *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c", | |
446 encode_spaces(fontface), | |
447 fonteffect, fontcolor, direction); | |
448 *message = g_strdup(msg); | |
449 | |
450 g_free(fontface); | |
451 g_free(msg); | |
452 } | |
453 | |
454 void | |
455 msn_parse_socket(const char *str, char **ret_host, int *ret_port) | |
456 { | |
457 char *host; | |
458 char *c; | |
459 int port; | |
460 | |
461 host = g_strdup(str); | |
462 | |
463 if ((c = strchr(host, ':')) != NULL){ | |
464 *c = '\0'; | |
465 port = atoi(c + 1); | |
466 }else{ | |
467 port = 1863; | |
468 } | |
469 | |
470 *ret_host = host; | |
471 *ret_port = port; | |
472 } | |
473 /*************************************************************************** | |
474 * MSN Time Related Funciton | |
475 ***************************************************************************/ | |
476 #if 0 | |
477 int | |
478 msn_convert_iso8601(const char *timestr,struct tm tm_time) | |
479 { | |
480 char temp[64]; | |
481 struct tm ctime; | |
482 time_t ts; | |
483 | |
484 purple_debug_info("MSNP14","convert string is{%s}\n",timestr); | |
485 tzset(); | |
486 /*copy string first*/ | |
487 memset(temp, 0, sizeof(temp)); | |
488 strncpy(temp, timestr, strlen(timestr)); | |
489 | |
490 /*convert via strptime()*/ | |
491 memset(&ctime, 0, sizeof(struct tm)); | |
492 strptime(temp, "%d %b %Y %T %Z", &ctime); | |
493 ts = mktime(&ctime) - timezone; | |
494 localtime_r(&ts, tm_time); | |
495 } | |
496 #endif | |
497 | |
498 /*************************************************************************** | |
499 * MSN Challenge Computing Function | |
500 ***************************************************************************/ | |
501 | |
502 /* | |
503 * Handle MSN Chanllege computation | |
504 *This algorithm reference with http://msnpiki.msnfanatic.com/index.php/MSNP11:Challenges | |
505 */ | |
506 #define BUFSIZE 256 | |
507 void | |
508 msn_handle_chl(char *input, char *output) | |
509 { | |
510 PurpleCipher *cipher; | |
511 PurpleCipherContext *context; | |
512 char *productKey = MSNP13_WLM_PRODUCT_KEY, | |
513 *productID = MSNP13_WLM_PRODUCT_ID, | |
514 *hexChars = "0123456789abcdef", | |
515 buf[BUFSIZE]; | |
516 unsigned char md5Hash[16], *newHash; | |
517 unsigned int *md5Parts, *chlStringParts, newHashParts[5]; | |
518 | |
519 long long nHigh=0, nLow=0; | |
520 | |
521 int i; | |
522 | |
523 /* Create the MD5 hash by using Purple MD5 algorithm*/ | |
524 cipher = purple_ciphers_find_cipher("md5"); | |
525 context = purple_cipher_context_new(cipher, NULL); | |
526 | |
527 purple_cipher_context_append(context, (const guchar *)input, | |
528 strlen(input)); | |
529 purple_cipher_context_append(context, (const guchar *)productKey, | |
530 strlen(productKey)); | |
531 purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); | |
532 purple_cipher_context_destroy(context); | |
533 | |
534 /* Split it into four integers */ | |
535 md5Parts = (unsigned int *)md5Hash; | |
536 for(i=0; i<4; i++){ | |
537 /* adjust endianess */ | |
538 md5Parts[i] = GUINT_TO_LE(md5Parts[i]); | |
539 | |
540 /* & each integer with 0x7FFFFFFF */ | |
541 /* and save one unmodified array for later */ | |
542 newHashParts[i] = md5Parts[i]; | |
543 md5Parts[i] &= 0x7FFFFFFF; | |
544 } | |
545 | |
546 /* make a new string and pad with '0' */ | |
547 snprintf(buf, BUFSIZE-5, "%s%s", input, productID); | |
548 i = strlen(buf); | |
549 memset(&buf[i], '0', 8 - (i % 8)); | |
550 buf[i + (8 - (i % 8))]='\0'; | |
551 | |
552 /* split into integers */ | |
553 chlStringParts = (unsigned int *)buf; | |
554 | |
555 /* this is magic */ | |
556 for (i=0; i<(strlen(buf)/4)-1; i+=2){ | |
557 long long temp; | |
558 | |
559 chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); | |
560 chlStringParts[i+1] = GUINT_TO_LE(chlStringParts[i+1]); | |
561 | |
562 temp=(md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; | |
563 nHigh=(md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; | |
564 nLow=nLow + nHigh + temp; | |
565 } | |
566 nHigh=(nHigh+md5Parts[1]) % 0x7FFFFFFF; | |
567 nLow=(nLow+md5Parts[3]) % 0x7FFFFFFF; | |
568 | |
569 newHashParts[0]^=nHigh; | |
570 newHashParts[1]^=nLow; | |
571 newHashParts[2]^=nHigh; | |
572 newHashParts[3]^=nLow; | |
573 | |
574 /* adjust endianness */ | |
575 for(i=0; i<4; i++) | |
576 newHashParts[i] = GUINT_TO_LE(newHashParts[i]); | |
577 | |
578 /* make a string of the parts */ | |
579 newHash = (unsigned char *)newHashParts; | |
580 | |
581 /* convert to hexadecimal */ | |
582 for (i=0; i<16; i++) | |
583 { | |
584 output[i*2]=hexChars[(newHash[i]>>4)&0xF]; | |
585 output[(i*2)+1]=hexChars[newHash[i]&0xF]; | |
586 } | |
587 | |
588 output[32]='\0'; | |
589 | |
590 // purple_debug_info("MSNP14","chl output{%s}\n",output); | |
591 } |