audio: send 486 Busy Here when call is in progress and another call invitation arrives.
[siplcs.git] / src / core / sipmsg.c
blobc17821467b68c001ed8782cce9a5c64306d5a2ed
1 /**
2 * @file sipmsg.c
4 * pidgin-sipe
6 * Copyright (C) 2010 SIPE Project <http://sipe.sourceforge.net/>
7 * Copyright (C) 2008 Novell, Inc.
8 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
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.
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.
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
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <time.h>
30 #include <glib.h>
32 #include "sipmsg.h"
33 #include "sipe-backend.h"
34 #include "sipe-mime.h"
35 #include "sipe-utils.h"
37 struct sipmsg *sipmsg_parse_msg(const gchar *msg) {
38 const char *tmp = strstr(msg, "\r\n\r\n");
39 char *line;
40 struct sipmsg *smsg;
42 if(!tmp) return NULL;
44 line = g_strndup(msg, tmp - msg);
46 smsg = sipmsg_parse_header(line);
47 smsg->body = g_strdup(tmp + 4);
49 g_free(line);
50 return smsg;
53 struct sipmsg *sipmsg_parse_header(const gchar *header) {
54 struct sipmsg *msg = g_new0(struct sipmsg,1);
55 gchar **lines = g_strsplit(header,"\r\n",0);
56 gchar **parts;
57 const gchar *contentlength;
58 if(!lines[0]) {
59 g_strfreev(lines);
60 g_free(msg);
61 return NULL;
63 parts = g_strsplit(lines[0], " ", 3);
64 if(!parts[0] || !parts[1] || !parts[2]) {
65 g_strfreev(parts);
66 g_strfreev(lines);
67 g_free(msg);
68 return NULL;
70 if(strstr(parts[0],"SIP") || strstr(parts[0],"HTTP")) { /* numeric response */
71 msg->method = g_strdup(parts[2]);
72 msg->response = strtol(parts[1],NULL,10);
73 } else { /* request */
74 msg->method = g_strdup(parts[0]);
75 msg->target = g_strdup(parts[1]);
76 msg->response = 0;
78 g_strfreev(parts);
79 if (sipe_utils_parse_lines(&msg->headers, lines + 1, ":") == FALSE) {
80 g_strfreev(lines);
81 sipmsg_free(msg);
82 return NULL;
84 g_strfreev(lines);
85 contentlength = sipmsg_find_header(msg, "Content-Length");
86 if (contentlength) {
87 msg->bodylen = strtol(contentlength,NULL,10);
88 } else {
89 SIPE_DEBUG_FATAL_NOFORMAT("sipmsg_parse_header(): Content-Length header not found");
91 if(msg->response) {
92 const gchar *tmp;
93 g_free(msg->method);
94 tmp = sipmsg_find_header(msg, "CSeq");
95 if(!tmp) {
96 /* SHOULD NOT HAPPEN */
97 msg->method = 0;
98 } else {
99 parts = g_strsplit(tmp, " ", 2);
100 msg->method = g_strdup(parts[1]);
101 g_strfreev(parts);
104 return msg;
107 char *sipmsg_to_string(const struct sipmsg *msg) {
108 GSList *cur;
109 GString *outstr = g_string_new("");
110 struct sipnameval *elem;
112 if(msg->response)
113 g_string_append_printf(outstr, "SIP/2.0 %d Unknown\r\n",
114 msg->response);
115 else
116 g_string_append_printf(outstr, "%s %s SIP/2.0\r\n",
117 msg->method, msg->target);
119 cur = msg->headers;
120 while(cur) {
121 elem = cur->data;
122 /*Todo: remove the LFCR in a good way*/
123 /*if(sipe_strequal(elem->name,"Proxy-Authorization"))
124 g_string_append_printf(outstr, "%s: %s", elem->name,
125 elem->value);
126 else */
127 g_string_append_printf(outstr, "%s: %s\r\n", elem->name,
128 elem->value);
129 cur = g_slist_next(cur);
132 g_string_append_printf(outstr, "\r\n%s", msg->bodylen ? msg->body : "");
134 return g_string_free(outstr, FALSE);
138 * Adds header to current message headers at specified position
140 void sipmsg_add_header_now_pos(struct sipmsg *msg, const gchar *name, const gchar *value, int pos) {
141 struct sipnameval *element = g_new0(struct sipnameval,1);
143 /* SANITY CHECK: the calling code must be fixed if this happens! */
144 if (!value) {
145 SIPE_DEBUG_ERROR("sipmsg_add_header_now_pos: NULL value for %s (%d)",
146 name, pos);
147 value = "";
150 element->name = g_strdup(name);
151 element->value = g_strdup(value);
152 msg->headers = g_slist_insert(msg->headers, element,pos);
156 * Adds header to current message headers
158 void sipmsg_add_header_now(struct sipmsg *msg, const gchar *name, const gchar *value) {
159 struct sipnameval *element = g_new0(struct sipnameval,1);
161 /* SANITY CHECK: the calling code must be fixed if this happens! */
162 if (!value) {
163 SIPE_DEBUG_ERROR("sipmsg_add_header_now: NULL value for %s",
164 name);
165 value = "";
168 element->name = g_strdup(name);
169 element->value = g_strdup(value);
170 msg->headers = g_slist_append(msg->headers, element);
174 * Adds header to separate storage for future merge
176 void sipmsg_add_header(struct sipmsg *msg, const gchar *name, const gchar *value) {
177 struct sipnameval *element = g_new0(struct sipnameval,1);
179 /* SANITY CHECK: the calling code must be fixed if this happens! */
180 if (!value) {
181 SIPE_DEBUG_ERROR("sipmsg_add_header: NULL value for %s", name);
182 value = "";
185 element->name = g_strdup(name);
186 element->value = g_strdup(value);
187 msg->new_headers = g_slist_append(msg->new_headers, element);
191 * Removes header if it's not in keepers array
193 void sipmsg_strip_headers(struct sipmsg *msg, const gchar *keepers[]) {
194 GSList *entry;
195 struct sipnameval *elem;
197 entry = msg->headers;
198 while(entry) {
199 int i = 0;
200 gboolean keeper = FALSE;
202 elem = entry->data;
203 while (keepers[i]) {
204 if (!g_strcasecmp(elem->name, keepers[i])) {
205 keeper = TRUE;
206 break;
208 i++;
211 if (!keeper) {
212 GSList *to_delete = entry;
213 SIPE_DEBUG_INFO("sipmsg_strip_headers: removing %s", elem->name);
214 entry = g_slist_next(entry);
215 msg->headers = g_slist_delete_link(msg->headers, to_delete);
216 g_free(elem->name);
217 g_free(elem->value);
218 g_free(elem);
219 } else {
220 entry = g_slist_next(entry);
226 * Merges newly added headers to message
228 void sipmsg_merge_new_headers(struct sipmsg *msg) {
229 while(msg->new_headers) {
230 msg->headers = g_slist_append(msg->headers, msg->new_headers->data);
231 msg->new_headers = g_slist_remove(msg->new_headers, msg->new_headers->data);
235 void sipmsg_free(struct sipmsg *msg) {
236 sipe_utils_nameval_free(msg->headers);
237 sipe_utils_nameval_free(msg->new_headers);
238 g_free(msg->signature);
239 g_free(msg->rand);
240 g_free(msg->num);
241 g_free(msg->method);
242 g_free(msg->target);
243 g_free(msg->body);
244 g_free(msg);
247 void sipmsg_remove_header_now(struct sipmsg *msg, const gchar *name) {
248 struct sipnameval *elem;
249 GSList *tmp = msg->headers;
250 while(tmp) {
251 elem = tmp->data;
252 // OCS2005 can send the same header in either all caps or mixed case
253 if (sipe_strcase_equal(elem->name, name)) {
254 msg->headers = g_slist_remove(msg->headers, elem);
255 g_free(elem->name);
256 g_free(elem->value);
257 g_free(elem);
258 return;
260 tmp = g_slist_next(tmp);
262 return;
265 const gchar *sipmsg_find_header(const struct sipmsg *msg, const gchar *name) {
266 return sipe_utils_nameval_find_instance (msg->headers, name, 0);
269 const gchar *sipmsg_find_header_instance(const struct sipmsg *msg, const gchar *name, int which) {
270 return sipe_utils_nameval_find_instance(msg->headers, name, which);
273 gchar *sipmsg_find_part_of_header(const char *hdr, const char * before, const char * after, const char * def) {
274 const char *tmp;
275 const char *tmp2;
276 gchar *res2;
277 if (!hdr) {
278 return NULL;
281 //printf("partof %s w/ %s before and %s after\n", hdr, before, after);
283 tmp = before == NULL ? hdr : strstr(hdr, before);
284 if (!tmp) {
285 //printf ("not found, returning null\n");
286 return (gchar *)def;
289 if (before != NULL) {
290 tmp += strlen(before);
291 //printf ("tmp now %s\n", tmp);
294 if (after != NULL && (tmp2 = strstr(tmp, after))) {
295 gchar * res = g_strndup(tmp, tmp2 - tmp);
296 //printf("returning %s\n", res);
297 return res;
299 res2 = g_strdup(tmp);
300 //printf("returning %s\n", res2);
301 return res2;
305 * Parse EndPoints header from INVITE request
306 * Returns a list of end points: contact URI plus optional epid.
307 * You must free the values and the list.
309 * Example headers:
310 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>;epid=ebca82d94d, <sip:carol@atlanta.local>
311 * EndPoints: "alice, alisson" <sip:alice@atlanta.local>, <sip:bob@atlanta.local>
312 * EndPoints: "alice alisson" <sip:alice@atlanta.local>, "Super, Man" <sip:super@atlanta.local>
314 * @param header (in) EndPoints header contents
316 * @return GSList with struct sipendpoint as elements
318 GSList *sipmsg_parse_endpoints_header(const gchar *header)
320 GSList *list = NULL;
321 gchar **parts = g_strsplit(header, ",", 0);
322 gchar *part;
323 int i;
325 for (i = 0; (part = parts[i]) != NULL; i++) {
326 /* Does the part contain a URI? */
327 gchar *contact = sipmsg_find_part_of_header(part, "<", ">", NULL);
328 if (contact) {
329 struct sipendpoint *end_point = g_new(struct sipendpoint, 1);
330 end_point->contact = contact;
331 end_point->epid = sipmsg_find_part_of_header(part, "epid=", NULL, NULL);
332 list = g_slist_append(list, end_point);
335 g_strfreev(parts);
337 return(list);
341 * sipmsg_find_auth_header will return the particular WWW-Authenticate
342 * header specified by *name.
344 * Use this function when you want to look for a specific authentication
345 * method such as NTLM or Kerberos
348 gchar *sipmsg_find_auth_header(struct sipmsg *msg, const gchar *name) {
349 GSList *tmp;
350 struct sipnameval *elem;
351 int name_len = strlen(name);
352 tmp = msg->headers;
353 while(tmp) {
354 elem = tmp->data;
355 /* SIPE_DEBUG_INFO("Current header: %s", elem->value); */
356 if (elem && elem->name &&
357 (sipe_strcase_equal(elem->name,"WWW-Authenticate") ||
358 sipe_strcase_equal(elem->name,"Authentication-Info")) ) {
359 if (!g_strncasecmp((gchar *)elem->value, name, name_len)) {
360 /* SIPE_DEBUG_INFO("elem->value: %s", elem->value); */
361 return elem->value;
364 /* SIPE_DEBUG_INFO_NOFORMAT("moving to next header"); */
365 tmp = g_slist_next(tmp);
367 SIPE_DEBUG_INFO("auth header '%s' not found.", name);
368 return NULL;
371 gchar *sipmsg_get_x_mms_im_format(gchar *msgr) {
372 gchar *msgr2;
373 gsize msgr_dec64_len;
374 guchar *msgr_dec64;
375 gchar *msgr_utf8;
376 gchar **lines;
377 gchar **parts;
378 gchar *x_mms_im_format;
379 gchar *tmp;
381 if (!msgr) return NULL;
382 msgr2 = g_strdup(msgr);
383 while (strlen(msgr2) % 4 != 0) {
384 gchar *tmp_msgr2 = msgr2;
385 msgr2 = g_strdup_printf("%s=", msgr2);
386 g_free(tmp_msgr2);
388 msgr_dec64 = g_base64_decode(msgr2, &msgr_dec64_len);
389 msgr_utf8 = g_convert((gchar *) msgr_dec64, msgr_dec64_len, "UTF-8", "UTF-16LE", NULL, NULL, NULL);
390 g_free(msgr_dec64);
391 g_free(msgr2);
392 lines = g_strsplit(msgr_utf8,"\r\n\r\n",0);
393 g_free(msgr_utf8);
394 //@TODO: make extraction like parsing of message headers.
395 parts = g_strsplit(lines[0],"X-MMS-IM-Format:",0);
396 x_mms_im_format = g_strdup(parts[1]);
397 g_strfreev(parts);
398 g_strfreev(lines);
399 tmp = x_mms_im_format;
400 if (x_mms_im_format) {
401 while(*x_mms_im_format==' ' || *x_mms_im_format=='\t') x_mms_im_format++;
403 x_mms_im_format = g_strdup(x_mms_im_format);
404 g_free(tmp);
405 return x_mms_im_format;
408 gchar *sipmsg_get_msgr_string(gchar *x_mms_im_format) {
409 gchar *msgr_orig;
410 gsize msgr_utf16_len;
411 gchar *msgr_utf16;
412 gchar *msgr_enc;
413 gchar *res;
414 int len;
416 if (!x_mms_im_format) return NULL;
417 msgr_orig = g_strdup_printf("X-MMS-IM-Format: %s\r\n\r\n", x_mms_im_format);
418 msgr_utf16 = g_convert(msgr_orig, -1, "UTF-16LE", "UTF-8", NULL, &msgr_utf16_len, NULL);
419 g_free(msgr_orig);
420 msgr_enc = g_base64_encode((guchar *) msgr_utf16, msgr_utf16_len);
421 g_free(msgr_utf16);
422 len = strlen(msgr_enc);
423 while (msgr_enc[len - 1] == '=') len--;
424 res = g_strndup(msgr_enc, len);
425 g_free(msgr_enc);
426 return res;
429 gchar *sipmsg_apply_x_mms_im_format(const char *x_mms_im_format, gchar *body) {
430 char *pre, *post;
431 gchar *res;
433 if (!x_mms_im_format) {
434 return body ? g_strdup(body) : NULL;
436 msn_parse_format(x_mms_im_format, &pre, &post);
437 res = g_strdup_printf("%s%s%s", pre ? pre : "", body ? body : "", post ? post : "");
438 g_free(pre);
439 g_free(post);
440 return res;
443 struct html_message_data {
444 gchar *ms_text_format;
445 gchar *body;
446 gboolean preferred;
449 static void get_html_message_mime_cb(gpointer user_data,
450 const GSList *fields,
451 const gchar *body,
452 gsize length)
454 const gchar *type = sipe_utils_nameval_find(fields, "Content-Type");
455 struct html_message_data *data = user_data;
457 if (!data->preferred) {
458 gboolean copy = FALSE;
460 /* preferred format */
461 if (g_str_has_prefix(type, "text/html")) {
462 copy = TRUE;
463 data->preferred = TRUE;
465 /* fallback format */
466 } else if (g_str_has_prefix(type, "text/plain")) {
467 copy = TRUE;
470 if (copy) {
471 g_free(data->ms_text_format);
472 g_free(data->body);
473 data->ms_text_format = g_strdup(type);
474 data->body = g_strndup(body, length);
479 /* ms-text-format: text/plain; charset=UTF-8;msgr=WAAtAE0...DIADQAKAA0ACgA;ms-body=SGk= */
480 gchar *get_html_message(const gchar *ms_text_format_in, const gchar *body_in)
482 gchar *msgr;
483 gchar *res;
484 gchar *ms_text_format = NULL;
485 gchar *body = NULL;
487 if (g_str_has_prefix(ms_text_format_in, "multipart/related") ||
488 g_str_has_prefix(ms_text_format_in, "multipart/alternative")) {
489 struct html_message_data data = { NULL, NULL, FALSE };
491 sipe_mime_parts_foreach(ms_text_format_in, body_in,
492 get_html_message_mime_cb, &data);
494 ms_text_format = data.ms_text_format;
495 body = data.body;
497 } else {
498 ms_text_format = g_strdup(ms_text_format_in);
499 body = g_strdup(body_in);
502 if (body) {
503 res = body;
504 } else {
505 gchar *tmp = sipmsg_find_part_of_header(ms_text_format, "ms-body=", NULL, NULL);
506 gsize len;
507 if (!tmp) {
508 g_free(ms_text_format);
509 return NULL;
511 res = (gchar *) g_base64_decode(tmp, &len);
512 g_free(tmp);
513 if (!res) {
514 g_free(ms_text_format);
515 return NULL;
519 if (!g_str_has_prefix(ms_text_format, "text/html")) { // NOT html
520 char *tmp = res;
521 res = g_markup_escape_text(res, -1); // as this is not html
522 g_free(tmp);
525 msgr = sipmsg_find_part_of_header(ms_text_format, "msgr=", ";", NULL);
526 if (msgr) {
527 gchar *x_mms_im_format = sipmsg_get_x_mms_im_format(msgr);
528 gchar *tmp = res;
529 g_free(msgr);
530 res = sipmsg_apply_x_mms_im_format(x_mms_im_format, res);
531 g_free(tmp);
532 g_free(x_mms_im_format);
535 g_free(ms_text_format);
537 return res;
544 //------------------------------------------------------------------------------------------
545 //TEMP solution to include it here (copy from purple's msn protocol
546 //How to reuse msn's util methods from sipe?
548 /* from internal.h */
549 #define MSG_LEN 2048
550 #define BUF_LEN MSG_LEN
552 static
553 gchar *sipmsg_uri_unescape(const gchar *string)
555 gchar *unescaped, *tmp;
557 if (!string) return(NULL);
559 #if GLIB_CHECK_VERSION(2,16,0)
560 unescaped = g_uri_unescape_string(string, NULL);
561 #else
562 /* loosely based on libpurple/util.c:purple_url_decode() */
564 gsize i = 0;
565 gsize len = strlen(string);
567 unescaped = g_malloc(len + 1);
568 while (len-- > 0) {
569 gchar c = *string++;
570 if ((len >= 2) && (c == '%')) {
571 char hex[3];
572 strncpy(hex, string, 2);
573 hex[2] = '\0';
574 c = strtol(hex, NULL, 16);
575 string += 2;
576 len -= 2;
578 unescaped[i++] = c;
580 unescaped[i] = '\0';
582 #endif
584 if (!g_utf8_validate(unescaped, -1, (const gchar **)&tmp))
585 *tmp = '\0';
587 return(unescaped);
590 void
591 msn_parse_format(const char *mime, char **pre_ret, char **post_ret)
593 char *cur;
594 GString *pre = g_string_new(NULL);
595 GString *post = g_string_new(NULL);
596 unsigned int colors[3];
598 if (pre_ret != NULL) *pre_ret = NULL;
599 if (post_ret != NULL) *post_ret = NULL;
601 cur = strstr(mime, "FN=");
603 if (cur && (*(cur = cur + 3) != ';'))
605 pre = g_string_append(pre, "<FONT FACE=\"");
607 while (*cur && *cur != ';')
609 pre = g_string_append_c(pre, *cur);
610 cur++;
613 pre = g_string_append(pre, "\">");
614 post = g_string_prepend(post, "</FONT>");
617 cur = strstr(mime, "EF=");
619 if (cur && (*(cur = cur + 3) != ';'))
621 while (*cur && *cur != ';')
623 pre = g_string_append_c(pre, '<');
624 pre = g_string_append_c(pre, *cur);
625 pre = g_string_append_c(pre, '>');
626 post = g_string_prepend_c(post, '>');
627 post = g_string_prepend_c(post, *cur);
628 post = g_string_prepend_c(post, '/');
629 post = g_string_prepend_c(post, '<');
630 cur++;
634 cur = strstr(mime, "CO=");
636 if (cur && (*(cur = cur + 3) != ';'))
638 int i;
640 i = sscanf(cur, "%02x%02x%02x;", &colors[0], &colors[1], &colors[2]);
642 if (i > 0)
644 char tag[64];
646 if (i == 1)
648 colors[1] = 0;
649 colors[2] = 0;
651 else if (i == 2)
653 unsigned int temp = colors[0];
655 colors[0] = colors[1];
656 colors[1] = temp;
657 colors[2] = 0;
659 else if (i == 3)
661 unsigned int temp = colors[2];
663 colors[2] = colors[0];
664 colors[0] = temp;
667 /* hh is undefined in mingw's gcc 4.4
668 * https://sourceforge.net/tracker/index.php?func=detail&aid=2818436&group_id=2435&atid=102435
670 g_snprintf(tag, sizeof(tag),
671 "<FONT COLOR=\"#%02x%02x%02x\">",
672 (unsigned char)colors[0], (unsigned char)colors[1], (unsigned char)colors[2]);
674 pre = g_string_append(pre, tag);
675 post = g_string_prepend(post, "</FONT>");
679 cur = strstr(mime, "RL=");
681 if (cur && (*(cur = cur + 3) != ';'))
683 if (*cur == '1')
685 /* RTL text was received */
686 pre = g_string_append(pre, "<SPAN style=\"direction:rtl;text-align:right;\">");
687 post = g_string_prepend(post, "</SPAN>");
691 cur = sipmsg_uri_unescape(pre->str);
692 g_string_free(pre, TRUE);
694 if (pre_ret != NULL)
695 *pre_ret = cur;
696 else
697 g_free(cur);
699 cur = sipmsg_uri_unescape(post->str);
700 g_string_free(post, TRUE);
702 if (post_ret != NULL)
703 *post_ret = cur;
704 else
705 g_free(cur);
708 static const char *
709 encode_spaces(const char *str)
711 static char buf[BUF_LEN];
712 const char *c;
713 char *d;
715 g_return_val_if_fail(str != NULL, NULL);
717 for (c = str, d = buf; *c != '\0'; c++)
719 if (*c == ' ')
721 *d++ = '%';
722 *d++ = '2';
723 *d++ = '0';
725 else
726 *d++ = *c;
728 *d = '\0';
730 return buf;
733 void
734 msn_import_html(const char *html, char **attributes, char **message)
736 int len, retcount = 0;
737 const char *c;
738 char *msg;
739 char *fontface = NULL;
740 char fonteffect[4];
741 char fontcolor[7];
742 char direction = '0';
744 gboolean has_bold = FALSE;
745 gboolean has_italic = FALSE;
746 gboolean has_underline = FALSE;
747 gboolean has_strikethrough = FALSE;
749 g_return_if_fail(html != NULL);
750 g_return_if_fail(attributes != NULL);
751 g_return_if_fail(message != NULL);
753 len = strlen(html);
754 msg = g_malloc0(len + 1);
756 memset(fontcolor, 0, sizeof(fontcolor));
757 strcat(fontcolor, "0");
758 memset(fonteffect, 0, sizeof(fonteffect));
760 for (c = html; *c != '\0';)
762 if (*c == '<')
764 if (!g_ascii_strncasecmp(c + 1, "br>", 3))
766 msg[retcount++] = '\r';
767 msg[retcount++] = '\n';
768 c += 4;
770 else if (!g_ascii_strncasecmp(c + 1, "i>", 2))
772 if (!has_italic)
774 strcat(fonteffect, "I");
775 has_italic = TRUE;
777 c += 3;
779 else if (!g_ascii_strncasecmp(c + 1, "b>", 2))
781 if (!has_bold)
783 strcat(fonteffect, "B");
784 has_bold = TRUE;
786 c += 3;
788 else if (!g_ascii_strncasecmp(c + 1, "u>", 2))
790 if (!has_underline)
792 strcat(fonteffect, "U");
793 has_underline = TRUE;
795 c += 3;
797 else if (!g_ascii_strncasecmp(c + 1, "s>", 2))
799 if (!has_strikethrough)
801 strcat(fonteffect, "S");
802 has_strikethrough = TRUE;
804 c += 3;
806 else if (!g_ascii_strncasecmp(c + 1, "a href=\"", 8))
808 c += 9;
810 if (!g_ascii_strncasecmp(c, "mailto:", 7))
811 c += 7;
813 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
814 msg[retcount++] = *c++;
816 if (*c != '\0')
817 c += 2;
819 /* ignore descriptive string */
820 while ((*c != '\0') && g_ascii_strncasecmp(c, "</a>", 4))
821 c++;
823 if (*c != '\0')
824 c += 4;
826 else if (!g_ascii_strncasecmp(c + 1, "span", 4))
828 /* Bi-directional text support using CSS properties in span tags */
829 c += 5;
831 while (*c != '\0' && *c != '>')
833 while (*c == ' ')
834 c++;
835 if (!g_ascii_strncasecmp(c, "dir=\"rtl\"", 9))
837 c += 9;
838 direction = '1';
840 else if (!g_ascii_strncasecmp(c, "style=\"", 7))
842 /* Parse inline CSS attributes */
843 int attr_len = 0;
844 c += 7;
845 while (*(c + attr_len) != '\0' && *(c + attr_len) != '"')
846 attr_len++;
847 if (*(c + attr_len) == '"')
849 char *css_attributes;
850 char *attr_dir;
851 css_attributes = g_strndup(c, attr_len);
852 attr_dir = sipe_backend_markup_css_property(css_attributes, "direction");
853 g_free(css_attributes);
854 if (attr_dir && (!g_ascii_strncasecmp(attr_dir, "RTL", 3)))
855 direction = '1';
856 g_free(attr_dir);
860 else
862 c++;
865 if (*c == '>')
866 c++;
868 else if (!g_ascii_strncasecmp(c + 1, "font", 4))
870 c += 5;
872 while ((*c != '\0') && !g_ascii_strncasecmp(c, " ", 1))
873 c++;
875 if (!g_ascii_strncasecmp(c, "color=\"#", 7))
877 c += 8;
879 fontcolor[0] = *(c + 4);
880 fontcolor[1] = *(c + 5);
881 fontcolor[2] = *(c + 2);
882 fontcolor[3] = *(c + 3);
883 fontcolor[4] = *c;
884 fontcolor[5] = *(c + 1);
886 c += 8;
888 else if (!g_ascii_strncasecmp(c, "face=\"", 6))
890 const char *end = NULL;
891 const char *comma = NULL;
892 unsigned int namelen = 0;
894 c += 6;
895 end = strchr(c, '\"');
896 comma = strchr(c, ',');
898 if (comma == NULL || comma > end)
899 namelen = (unsigned int)(end - c);
900 else
901 namelen = (unsigned int)(comma - c);
903 g_free(fontface);
904 fontface = g_strndup(c, namelen);
905 c = end + 2;
907 else
909 /* Drop all unrecognized/misparsed font tags */
910 while ((*c != '\0') && g_ascii_strncasecmp(c, "\">", 2))
911 c++;
913 if (*c != '\0')
914 c += 2;
917 else
919 while ((*c != '\0') && (*c != '>'))
920 c++;
921 if (*c != '\0')
922 c++;
925 else if (*c == '&')
927 if (!g_ascii_strncasecmp(c, "&lt;", 4))
929 msg[retcount++] = '<';
930 c += 4;
932 else if (!g_ascii_strncasecmp(c, "&gt;", 4))
934 msg[retcount++] = '>';
935 c += 4;
937 else if (!g_ascii_strncasecmp(c, "&nbsp;", 6))
939 msg[retcount++] = ' ';
940 c += 6;
942 else if (!g_ascii_strncasecmp(c, "&quot;", 6))
944 msg[retcount++] = '"';
945 c += 6;
947 else if (!g_ascii_strncasecmp(c, "&amp;", 5))
949 msg[retcount++] = '&';
950 c += 5;
952 else if (!g_ascii_strncasecmp(c, "&apos;", 6))
954 msg[retcount++] = '\'';
955 c += 6;
957 else
958 msg[retcount++] = *c++;
960 else
961 msg[retcount++] = *c++;
964 if (fontface == NULL)
965 fontface = g_strdup("MS Sans Serif");
967 *attributes = g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
968 encode_spaces(fontface),
969 fonteffect, fontcolor, direction);
970 *message = msg;
972 g_free(fontface);
974 // End of TEMP
977 Local Variables:
978 mode: c
979 c-file-style: "bsd"
980 indent-tabs-mode: t
981 tab-width: 8
982 End: