6 * Copyright (C) 2008 Novell, Inc.
7 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
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; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <sys/types.h>
28 #include <netinet/in.h>
34 #define _LIBC_INTERNAL_
42 #include "accountopt.h"
44 #include "conversation.h"
55 struct sipmsg
*sipmsg_parse_msg(const gchar
*msg
) {
56 const char *tmp
= strstr(msg
, "\r\n\r\n");
62 line
= g_strndup(msg
, tmp
- msg
);
64 smsg
= sipmsg_parse_header(line
);
65 smsg
->body
= g_strdup(tmp
+ 4);
71 struct sipmsg
*sipmsg_parse_header(const gchar
*header
) {
72 struct sipmsg
*msg
= g_new0(struct sipmsg
,1);
73 gchar
**lines
= g_strsplit(header
,"\r\n",0);
80 if(!lines
[0]) return NULL
;
81 parts
= g_strsplit(lines
[0], " ", 3);
82 if(!parts
[0] || !parts
[1] || !parts
[2]) {
88 if(strstr(parts
[0],"SIP")) { /* numeric response */
89 msg
->method
= g_strdup(parts
[2]);
90 msg
->response
= strtol(parts
[1],NULL
,10);
91 } else { /* request */
92 msg
->method
= g_strdup(parts
[0]);
93 msg
->target
= g_strdup(parts
[1]);
97 for(i
=1; lines
[i
] && strlen(lines
[i
])>2; i
++) {
98 parts
= g_strsplit(lines
[i
], ":", 2);
99 if(!parts
[0] || !parts
[1]) {
107 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
108 dummy2
= g_strdup(dummy
);
109 while(lines
[i
+1] && (lines
[i
+1][0]==' ' || lines
[i
+1][0]=='\t')) {
112 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
113 tmp
= g_strdup_printf("%s %s",dummy2
, dummy
);
117 sipmsg_add_header(msg
, parts
[0], dummy2
);
122 contentlength
= sipmsg_find_header(msg
, "Content-Length");
124 msg
->bodylen
= strtol(contentlength
,NULL
,10);
126 purple_debug_fatal("sipe", "sipmsg_parse_header(): Content-Length header not found\n");
130 tmp
= sipmsg_find_header(msg
, "CSeq");
132 /* SHOULD NOT HAPPEN */
135 parts
= g_strsplit(tmp
, " ", 2);
136 msg
->method
= g_strdup(parts
[1]);
143 void sipmsg_print(const struct sipmsg
*msg
) {
145 struct siphdrelement
*elem
;
146 purple_debug(PURPLE_DEBUG_MISC
, "sipe", "SIP MSG\n");
147 purple_debug(PURPLE_DEBUG_MISC
, "sipe", "response: %d\nmethod: %s\nbodylen: %d\n",msg
->response
,msg
->method
,msg
->bodylen
);
148 if(msg
->target
) purple_debug(PURPLE_DEBUG_MISC
, "sipe", "target: %s\n",msg
->target
);
152 purple_debug(PURPLE_DEBUG_MISC
, "sipe", "name: %s value: %s\n",elem
->name
, elem
->value
);
153 cur
= g_slist_next(cur
);
157 char *sipmsg_to_string(const struct sipmsg
*msg
) {
159 GString
*outstr
= g_string_new("");
160 struct siphdrelement
*elem
;
163 g_string_append_printf(outstr
, "SIP/2.0 %d Unknown\r\n",
166 g_string_append_printf(outstr
, "%s %s SIP/2.0\r\n",
167 msg
->method
, msg
->target
);
172 /*Todo: remove the LFCR in a good way*/
173 /*if(!strcmp(elem->name,"Proxy-Authorization"))
174 g_string_append_printf(outstr, "%s: %s", elem->name,
177 g_string_append_printf(outstr
, "%s: %s\r\n", elem
->name
,
179 cur
= g_slist_next(cur
);
182 g_string_append_printf(outstr
, "\r\n%s", msg
->bodylen
? msg
->body
: "");
184 return g_string_free(outstr
, FALSE
);
187 void sipmsg_add_header(struct sipmsg
*msg
, const gchar
*name
, const gchar
*value
) {
188 struct siphdrelement
*element
= g_new0(struct siphdrelement
,1);
189 element
->name
= g_strdup(name
);
190 element
->value
= g_strdup(value
);
191 msg
->headers
= g_slist_append(msg
->headers
, element
);
194 void sipmsg_add_header_pos(struct sipmsg
*msg
, const gchar
*name
, const gchar
*value
, int pos
) {
195 struct siphdrelement
*element
= g_new0(struct siphdrelement
,1);
196 element
->name
= g_strdup(name
);
197 element
->value
= g_strdup(value
);
198 msg
->headers
= g_slist_insert(msg
->headers
, element
,pos
);
201 void sipmsg_free(struct sipmsg
*msg
) {
202 struct siphdrelement
*elem
;
203 while(msg
->headers
) {
204 elem
= msg
->headers
->data
;
205 msg
->headers
= g_slist_remove(msg
->headers
,elem
);
210 g_free(msg
->signature
);
219 void sipmsg_remove_header(struct sipmsg
*msg
, const gchar
*name
) {
220 struct siphdrelement
*elem
;
221 GSList
*tmp
= msg
->headers
;
224 // OCS2005 can send the same header in either all caps or mixed case
225 if (g_ascii_strcasecmp(elem
->name
, name
)==0) {
226 msg
->headers
= g_slist_remove(msg
->headers
, elem
);
232 tmp
= g_slist_next(tmp
);
237 gchar
*sipmsg_find_header(struct sipmsg
*msg
, const gchar
*name
) {
238 return sipmsg_find_header_instance (msg
, name
, 0);
241 gchar
*sipmsg_find_header_instance(struct sipmsg
*msg
, const gchar
*name
, int which
) {
243 struct siphdrelement
*elem
;
248 // OCS2005 can send the same header in either all caps or mixed case
249 if (g_ascii_strcasecmp(elem
->name
,name
)==0) {
255 tmp
= g_slist_next(tmp
);
260 gchar
*sipmsg_find_part_of_header(const char *hdr
, const char * before
, const char * after
, const char * def
) {
268 //printf("partof %s w/ %s before and %s after\n", hdr, before, after);
270 tmp
= before
== NULL
? hdr
: strstr(hdr
, before
);
272 //printf ("not found, returning null\n");
276 if (before
!= NULL
) {
277 tmp
+= strlen(before
);
278 //printf ("tmp now %s\n", tmp);
281 if (after
!= NULL
&& (tmp2
= strstr(tmp
, after
))) {
282 gchar
* res
= g_strndup(tmp
, tmp2
- tmp
);
283 //printf("returning %s\n", res);
286 res2
= g_strdup(tmp
);
287 //printf("returning %s\n", res2);
292 * sipmsg_find_auth_header will return the particular WWW-Authenticate
293 * header specified by *name.
295 * Use this function when you want to look for a specific authentication
296 * method such as NTLM or Kerberos
299 gchar
*sipmsg_find_auth_header(struct sipmsg
*msg
, const gchar
*name
) {
301 struct siphdrelement
*elem
;
302 int name_len
= strlen(name
);
306 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "Current header: %s\r\n", elem->value);
307 if (elem
&& elem
->name
&& !g_ascii_strcasecmp(elem
->name
,"WWW-Authenticate")) {
308 if (!g_strncasecmp((gchar
*)elem
->value
, name
, name_len
)) {
309 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "elem->value: %s\r\n", elem->value);
313 //purple_debug(PURPLE_DEBUG_MISC, "sipmsg", "moving to next header\r\n");
314 tmp
= g_slist_next(tmp
);
316 purple_debug(PURPLE_DEBUG_MISC
, "sipmsg", "Did not found auth header %s\r\n", name
);
320 gchar
*sipmsg_get_x_mms_im_format(gchar
*msgr
) {
322 gsize msgr_dec64_len
;
327 gchar
*x_mms_im_format
;
330 if (!msgr
) return NULL
;
331 msgr2
= g_strdup(msgr
);
332 while (strlen(msgr2
) % 4 != 0) {
333 gchar
*tmp_msgr2
= msgr2
;
334 msgr2
= g_strdup_printf("%s=", msgr2
);
337 msgr_dec64
= purple_base64_decode(msgr2
, &msgr_dec64_len
);
338 msgr_utf8
= g_convert(msgr_dec64
, msgr_dec64_len
, "UTF-8", "UTF-16LE", NULL
, NULL
, NULL
);
341 lines
= g_strsplit(msgr_utf8
,"\r\n\r\n",0);
343 //@TODO: make extraction like parsing of message headers.
344 parts
= g_strsplit(lines
[0],"X-MMS-IM-Format:",0);
345 x_mms_im_format
= g_strdup(parts
[1]);
348 tmp
= x_mms_im_format
;
349 if (x_mms_im_format
) {
350 while(*x_mms_im_format
==' ' || *x_mms_im_format
=='\t') x_mms_im_format
++;
352 x_mms_im_format
= g_strdup(x_mms_im_format
);
354 return x_mms_im_format
;
357 gchar
*sipmsg_get_msgr_string(gchar
*x_mms_im_format
) {
359 gsize msgr_utf16_len
;
365 if (!x_mms_im_format
) return NULL
;
366 msgr_orig
= g_strdup_printf("X-MMS-IM-Format: %s\r\n\r\n", x_mms_im_format
);
367 msgr_utf16
= g_convert(msgr_orig
, -1, "UTF-16LE", "UTF-8", NULL
, &msgr_utf16_len
, NULL
);
369 msgr_enc
= purple_base64_encode(msgr_utf16
, msgr_utf16_len
);
371 len
= strlen(msgr_enc
);
372 while (msgr_enc
[len
- 1] == '=') len
--;
373 res
= g_strndup(msgr_enc
, len
);
378 gchar
*sipmsg_apply_x_mms_im_format(const char *x_mms_im_format
, gchar
*body
) {
382 if (!x_mms_im_format
) {
383 return body
? g_strdup(body
) : NULL
;
385 msn_parse_format(x_mms_im_format
, &pre
, &post
);
386 res
= g_strdup_printf("%s%s%s", pre
? pre
: "", body
? body
: "", post
? post
: "");
396 //------------------------------------------------------------------------------------------
397 //TEMP solution to include it here (copy from purple's msn protocol
398 //How to reuse msn's util methods from sipe?
400 // from internal.h for linux compilation
403 #define BUF_LEN MSG_LEN
406 msn_parse_format(const char *mime
, char **pre_ret
, char **post_ret
)
409 GString
*pre
= g_string_new(NULL
);
410 GString
*post
= g_string_new(NULL
);
411 unsigned int colors
[3];
413 if (pre_ret
!= NULL
) *pre_ret
= NULL
;
414 if (post_ret
!= NULL
) *post_ret
= NULL
;
416 cur
= strstr(mime
, "FN=");
418 if (cur
&& (*(cur
= cur
+ 3) != ';'))
420 pre
= g_string_append(pre
, "<FONT FACE=\"");
422 while (*cur
&& *cur
!= ';')
424 pre
= g_string_append_c(pre
, *cur
);
428 pre
= g_string_append(pre
, "\">");
429 post
= g_string_prepend(post
, "</FONT>");
432 cur
= strstr(mime
, "EF=");
434 if (cur
&& (*(cur
= cur
+ 3) != ';'))
436 while (*cur
&& *cur
!= ';')
438 pre
= g_string_append_c(pre
, '<');
439 pre
= g_string_append_c(pre
, *cur
);
440 pre
= g_string_append_c(pre
, '>');
441 post
= g_string_prepend_c(post
, '>');
442 post
= g_string_prepend_c(post
, *cur
);
443 post
= g_string_prepend_c(post
, '/');
444 post
= g_string_prepend_c(post
, '<');
449 cur
= strstr(mime
, "CO=");
451 if (cur
&& (*(cur
= cur
+ 3) != ';'))
455 i
= sscanf(cur
, "%02x%02x%02x;", &colors
[0], &colors
[1], &colors
[2]);
468 unsigned int temp
= colors
[0];
470 colors
[0] = colors
[1];
476 unsigned int temp
= colors
[2];
478 colors
[2] = colors
[0];
482 g_snprintf(tag
, sizeof(tag
),
483 "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">",
484 colors
[0], colors
[1], colors
[2]);
486 pre
= g_string_append(pre
, tag
);
487 post
= g_string_prepend(post
, "</FONT>");
491 cur
= strstr(mime
, "RL=");
493 if (cur
&& (*(cur
= cur
+ 3) != ';'))
497 /* RTL text was received */
498 pre
= g_string_append(pre
, "<SPAN style=\"direction:rtl;text-align:right;\">");
499 post
= g_string_prepend(post
, "</SPAN>");
503 cur
= g_strdup(purple_url_decode(pre
->str
));
504 g_string_free(pre
, TRUE
);
511 cur
= g_strdup(purple_url_decode(post
->str
));
512 g_string_free(post
, TRUE
);
514 if (post_ret
!= NULL
)
521 encode_spaces(const char *str
)
523 static char buf
[BUF_LEN
];
527 g_return_val_if_fail(str
!= NULL
, NULL
);
529 for (c
= str
, d
= buf
; *c
!= '\0'; c
++)
546 msn_import_html(const char *html
, char **attributes
, char **message
)
548 int len
, retcount
= 0;
551 char *fontface
= NULL
;
554 char direction
= '0';
556 gboolean has_bold
= FALSE
;
557 gboolean has_italic
= FALSE
;
558 gboolean has_underline
= FALSE
;
559 gboolean has_strikethrough
= FALSE
;
561 g_return_if_fail(html
!= NULL
);
562 g_return_if_fail(attributes
!= NULL
);
563 g_return_if_fail(message
!= NULL
);
566 msg
= g_malloc0(len
+ 1);
568 memset(fontcolor
, 0, sizeof(fontcolor
));
569 strcat(fontcolor
, "0");
570 memset(fonteffect
, 0, sizeof(fonteffect
));
572 for (c
= html
; *c
!= '\0';)
576 if (!g_ascii_strncasecmp(c
+ 1, "br>", 3))
578 msg
[retcount
++] = '\r';
579 msg
[retcount
++] = '\n';
582 else if (!g_ascii_strncasecmp(c
+ 1, "i>", 2))
586 strcat(fonteffect
, "I");
591 else if (!g_ascii_strncasecmp(c
+ 1, "b>", 2))
595 strcat(fonteffect
, "B");
600 else if (!g_ascii_strncasecmp(c
+ 1, "u>", 2))
604 strcat(fonteffect
, "U");
605 has_underline
= TRUE
;
609 else if (!g_ascii_strncasecmp(c
+ 1, "s>", 2))
611 if (!has_strikethrough
)
613 strcat(fonteffect
, "S");
614 has_strikethrough
= TRUE
;
618 else if (!g_ascii_strncasecmp(c
+ 1, "a href=\"", 8))
622 if (!g_ascii_strncasecmp(c
, "mailto:", 7))
625 while ((*c
!= '\0') && g_ascii_strncasecmp(c
, "\">", 2))
626 msg
[retcount
++] = *c
++;
631 /* ignore descriptive string */
632 while ((*c
!= '\0') && g_ascii_strncasecmp(c
, "</a>", 4))
638 else if (!g_ascii_strncasecmp(c
+ 1, "span", 4))
640 /* Bi-directional text support using CSS properties in span tags */
643 while (*c
!= '\0' && *c
!= '>')
647 if (!g_ascii_strncasecmp(c
, "dir=\"rtl\"", 9))
652 else if (!g_ascii_strncasecmp(c
, "style=\"", 7))
654 /* Parse inline CSS attributes */
658 while (*(c
+ attr_len
) != '\0' && *(c
+ attr_len
) != '"')
660 if (*(c
+ attr_len
) == '"')
663 attributes
= g_strndup(c
, attr_len
);
664 attr_dir
= purple_markup_get_css_property(attributes
, "direction");
665 if (attr_dir
&& (!g_ascii_strncasecmp(attr_dir
, "RTL", 3)))
680 else if (!g_ascii_strncasecmp(c
+ 1, "font", 4))
684 while ((*c
!= '\0') && !g_ascii_strncasecmp(c
, " ", 1))
687 if (!g_ascii_strncasecmp(c
, "color=\"#", 7))
691 fontcolor
[0] = *(c
+ 4);
692 fontcolor
[1] = *(c
+ 5);
693 fontcolor
[2] = *(c
+ 2);
694 fontcolor
[3] = *(c
+ 3);
696 fontcolor
[5] = *(c
+ 1);
700 else if (!g_ascii_strncasecmp(c
, "face=\"", 6))
702 const char *end
= NULL
;
703 const char *comma
= NULL
;
704 unsigned int namelen
= 0;
707 end
= strchr(c
, '\"');
708 comma
= strchr(c
, ',');
710 if (comma
== NULL
|| comma
> end
)
711 namelen
= (unsigned int)(end
- c
);
713 namelen
= (unsigned int)(comma
- c
);
715 fontface
= g_strndup(c
, namelen
);
720 /* Drop all unrecognized/misparsed font tags */
721 while ((*c
!= '\0') && g_ascii_strncasecmp(c
, "\">", 2))
730 while ((*c
!= '\0') && (*c
!= '>'))
738 if (!g_ascii_strncasecmp(c
, "<", 4))
740 msg
[retcount
++] = '<';
743 else if (!g_ascii_strncasecmp(c
, ">", 4))
745 msg
[retcount
++] = '>';
748 else if (!g_ascii_strncasecmp(c
, " ", 6))
750 msg
[retcount
++] = ' ';
753 else if (!g_ascii_strncasecmp(c
, """, 6))
755 msg
[retcount
++] = '"';
758 else if (!g_ascii_strncasecmp(c
, "&", 5))
760 msg
[retcount
++] = '&';
763 else if (!g_ascii_strncasecmp(c
, "'", 6))
765 msg
[retcount
++] = '\'';
769 msg
[retcount
++] = *c
++;
772 msg
[retcount
++] = *c
++;
775 if (fontface
== NULL
)
776 fontface
= g_strdup("MS Sans Serif");
778 *attributes
= g_strdup_printf("FN=%s; EF=%s; CO=%s; PF=0; RL=%c",
779 encode_spaces(fontface
),
780 fonteffect
, fontcolor
, direction
);