4 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 #define MAX_CONTENT_LENGTH 30000000
29 struct sipmsg
*sipmsg_parse_msg(const gchar
*msg
) {
30 const char *tmp
= strstr(msg
, "\r\n\r\n");
36 line
= g_strndup(msg
, tmp
- msg
);
38 smsg
= sipmsg_parse_header(line
);
40 smsg
->body
= g_strdup(tmp
+ 4);
42 purple_debug_error("SIMPLE", "No header parsed from line: %s\n", line
);
48 struct sipmsg
*sipmsg_parse_header(const gchar
*header
) {
50 gchar
**parts
, **lines
;
51 gchar
*dummy
, *dummy2
, *tmp
;
55 lines
= g_strsplit(header
,"\r\n",0);
61 parts
= g_strsplit(lines
[0], " ", 3);
62 if(!parts
[0] || !parts
[1] || !parts
[2]) {
68 msg
= g_new0(struct sipmsg
,1);
69 if(strstr(parts
[0],"SIP")) { /* numeric response */
70 msg
->method
= g_strdup(parts
[2]);
71 msg
->response
= strtol(parts
[1],NULL
,10);
72 } else { /* request */
73 msg
->method
= g_strdup(parts
[0]);
74 msg
->target
= g_strdup(parts
[1]);
79 for(i
=1; lines
[i
] && strlen(lines
[i
])>2; i
++) {
80 parts
= g_strsplit(lines
[i
], ":", 2);
81 if(!parts
[0] || !parts
[1]) {
89 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
90 dummy2
= g_strdup(dummy
);
91 while(lines
[i
+1] && (lines
[i
+1][0]==' ' || lines
[i
+1][0]=='\t')) {
94 while(*dummy
==' ' || *dummy
=='\t') dummy
++;
95 tmp
= g_strdup_printf("%s %s",dummy2
, dummy
);
99 sipmsg_add_header(msg
, parts
[0], dummy2
);
105 tmp2
= sipmsg_find_header(msg
, "Content-Length");
107 msg
->bodylen
= strtol(tmp2
, NULL
, 10);
108 if (msg
->bodylen
< 0) {
109 purple_debug_warning("simple", "Invalid body length: %d",
112 } else if (msg
->bodylen
> MAX_CONTENT_LENGTH
) {
113 purple_debug_warning("simple", "Got Content-Length of %d bytes on "
114 "incoming message (max is %u bytes). Ignoring message body.\n",
115 msg
->bodylen
, MAX_CONTENT_LENGTH
);
120 tmp2
= sipmsg_find_header(msg
, "CSeq");
123 /* SHOULD NOT HAPPEN */
126 parts
= g_strsplit(tmp2
, " ", 2);
127 msg
->method
= g_strdup(parts
[1]);
135 void sipmsg_print(const struct sipmsg
*msg
) {
137 struct siphdrelement
*elem
;
138 purple_debug(PURPLE_DEBUG_MISC
, "simple", "SIP MSG\n");
139 purple_debug(PURPLE_DEBUG_MISC
, "simple", "response: %d\nmethod: %s\nbodylen: %d\n",msg
->response
,msg
->method
,msg
->bodylen
);
140 if(msg
->target
) purple_debug(PURPLE_DEBUG_MISC
, "simple", "target: %s\n",msg
->target
);
144 purple_debug(PURPLE_DEBUG_MISC
, "simple", "name: %s value: %s\n",elem
->name
, elem
->value
);
145 cur
= g_slist_next(cur
);
149 char *sipmsg_to_string(const struct sipmsg
*msg
) {
151 GString
*outstr
= g_string_new("");
152 struct siphdrelement
*elem
;
155 g_string_append_printf(outstr
, "SIP/2.0 %d Unknown\r\n",
158 g_string_append_printf(outstr
, "%s %s SIP/2.0\r\n",
159 msg
->method
, msg
->target
);
164 g_string_append_printf(outstr
, "%s: %s\r\n", elem
->name
,
166 cur
= g_slist_next(cur
);
169 g_string_append_printf(outstr
, "\r\n%s", msg
->bodylen
? msg
->body
: "");
171 return g_string_free(outstr
, FALSE
);
173 void sipmsg_add_header(struct sipmsg
*msg
, const gchar
*name
, const gchar
*value
) {
174 struct siphdrelement
*element
= g_new(struct siphdrelement
,1);
175 element
->name
= g_strdup(name
);
176 element
->value
= g_strdup(value
);
177 msg
->headers
= g_slist_append(msg
->headers
, element
);
180 void sipmsg_free(struct sipmsg
*msg
) {
181 struct siphdrelement
*elem
;
182 while(msg
->headers
) {
183 elem
= msg
->headers
->data
;
184 msg
->headers
= g_slist_remove(msg
->headers
,elem
);
195 void sipmsg_remove_header(struct sipmsg
*msg
, const gchar
*name
) {
196 GSList
*tmp
= g_slist_find_custom(msg
->headers
, name
, (GCompareFunc
)g_ascii_strcasecmp
);
198 struct siphdrelement
*elem
= tmp
->data
;
199 msg
->headers
= g_slist_delete_link(msg
->headers
, tmp
);
206 const gchar
*sipmsg_find_header(struct sipmsg
*msg
, const gchar
*name
) {
207 GSList
*tmp
= g_slist_find_custom(msg
->headers
, name
, (GCompareFunc
)g_ascii_strcasecmp
);
209 struct siphdrelement
*elem
= tmp
->data
;