Mercurial > hg
annotate mcabber/libjabber/xstream.c @ 798:bbaab5692b0e
hgignore: Ignore hgcset.h
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Sun, 09 Apr 2006 10:15:44 +0200 |
parents | c3ae9251c197 |
children | 0aa9015f06df |
rev | line source |
---|---|
25 | 1 /* |
2 * This program is free software; you can redistribute it and/or modify | |
3 * it under the terms of the GNU General Public License as published by | |
4 * the Free Software Foundation; either version 2 of the License, or | |
5 * (at your option) any later version. | |
6 * | |
7 * This program is distributed in the hope that it will be useful, | |
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 * GNU General Public License for more details. | |
11 * | |
12 * You should have received a copy of the GNU General Public License | |
13 * along with this program; if not, write to the Free Software | |
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
15 * | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
16 * Copyrights |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
17 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
18 * Portions created by or assigned to Jabber.com, Inc. are |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
19 * Copyright (c) 1999-2002 Jabber.com, Inc. All Rights Reserved. Contact |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
20 * information for Jabber.com, Inc. is available at http://www.jabber.com/. |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
21 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
22 * Portions Copyright (c) 1998-1999 Jeremie Miller. |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
23 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
24 * Acknowledgements |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
25 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
26 * Special thanks to the Jabber Open Source Contributors for their |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
27 * suggestions and support of Jabber. |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
28 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
29 */ |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
30 |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
31 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
32 * @file xstream.c |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
33 * @brief handling of incoming XML stream based events |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
34 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
35 * xstream is a way to have a consistent method of handling incoming XML stream based events ... |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
36 * it doesn't handle the generation of an XML stream, but provides some facilities to help doing that |
25 | 37 */ |
38 | |
235 | 39 #include <time.h> |
25 | 40 #include <libxode.h> |
41 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
42 /* ========== internal expat callbacks =========== */ |
25 | 43 |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
44 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
45 * internal expat callback for read start tags of an element |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
46 */ |
25 | 47 void _xstream_startElement(xstream xs, const char* name, const char** atts) |
48 { | |
49 pool p; | |
50 | |
51 /* if xstream is bad, get outa here */ | |
52 if(xs->status > XSTREAM_NODE) return; | |
53 | |
54 if(xs->node == NULL) | |
55 { | |
56 p = pool_heap(5*1024); /* 5k, typically 1-2k each plus copy of self and workspace */ | |
57 xs->node = xmlnode_new_tag_pool(p,name); | |
58 xmlnode_put_expat_attribs(xs->node, atts); | |
59 | |
60 if(xs->status == XSTREAM_ROOT) | |
61 { | |
62 xs->status = XSTREAM_NODE; /* flag status that we're processing nodes now */ | |
63 (xs->f)(XSTREAM_ROOT, xs->node, xs->arg); /* send the root, f must free all nodes */ | |
64 xs->node = NULL; | |
65 } | |
66 }else{ | |
67 xs->node = xmlnode_insert_tag(xs->node, name); | |
68 xmlnode_put_expat_attribs(xs->node, atts); | |
69 } | |
70 | |
71 /* depth check */ | |
72 xs->depth++; | |
73 if(xs->depth > XSTREAM_MAXDEPTH) | |
74 xs->status = XSTREAM_ERR; | |
75 } | |
76 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
77 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
78 * internal expat callback for read end tags of an element |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
79 */ |
25 | 80 void _xstream_endElement(xstream xs, const char* name) |
81 { | |
82 xmlnode parent; | |
83 | |
84 /* if xstream is bad, get outa here */ | |
85 if(xs->status > XSTREAM_NODE) return; | |
86 | |
87 /* if it's already NULL we've received </stream>, tell the app and we're outta here */ | |
88 if(xs->node == NULL) | |
89 { | |
90 xs->status = XSTREAM_CLOSE; | |
91 (xs->f)(XSTREAM_CLOSE, NULL, xs->arg); | |
92 }else{ | |
93 parent = xmlnode_get_parent(xs->node); | |
94 | |
95 /* we are the top-most node, feed to the app who is responsible to delete it */ | |
96 if(parent == NULL) | |
97 (xs->f)(XSTREAM_NODE, xs->node, xs->arg); | |
98 | |
99 xs->node = parent; | |
100 } | |
101 xs->depth--; | |
102 } | |
103 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
104 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
105 * internal expat callback for read CDATA |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
106 */ |
25 | 107 void _xstream_charData(xstream xs, const char *str, int len) |
108 { | |
109 /* if xstream is bad, get outa here */ | |
110 if(xs->status > XSTREAM_NODE) return; | |
111 | |
112 if(xs->node == NULL) | |
113 { | |
114 /* we must be in the root of the stream where CDATA is irrelevant */ | |
115 return; | |
116 } | |
117 | |
118 xmlnode_insert_cdata(xs->node, str, len); | |
119 } | |
120 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
121 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
122 * internal function to be registered as pool cleaner, frees a stream if the associated memory pool is freed |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
123 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
124 * @param pointer to the xstream to free |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
125 */ |
25 | 126 void _xstream_cleanup(void *arg) |
127 { | |
128 xstream xs = (xstream)arg; | |
129 | |
130 xmlnode_free(xs->node); /* cleanup anything left over */ | |
131 XML_ParserFree(xs->parser); | |
132 } | |
133 | |
134 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
135 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
136 * creates a new xstream with given pool, xstream will be cleaned up w/ pool |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
137 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
138 * @param p the memory pool to use for the stream |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
139 * @param f function pointer to the event handler function |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
140 * @param arg parameter to pass to the event handler function |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
141 * @return the created xstream |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
142 */ |
25 | 143 xstream xstream_new(pool p, xstream_onNode f, void *arg) |
144 { | |
145 xstream newx; | |
146 | |
147 if(p == NULL || f == NULL) | |
148 { | |
149 fprintf(stderr,"Fatal Programming Error: xstream_new() was improperly called with NULL.\n"); | |
150 return NULL; | |
151 } | |
152 | |
153 newx = pmalloco(p, sizeof(_xstream)); | |
154 newx->p = p; | |
155 newx->f = f; | |
156 newx->arg = arg; | |
157 | |
158 /* create expat parser and ensure cleanup */ | |
159 newx->parser = XML_ParserCreate(NULL); | |
160 XML_SetUserData(newx->parser, (void *)newx); | |
161 XML_SetElementHandler(newx->parser, (void *)_xstream_startElement, (void *)_xstream_endElement); | |
162 XML_SetCharacterDataHandler(newx->parser, (void *)_xstream_charData); | |
163 pool_cleanup(p, _xstream_cleanup, (void *)newx); | |
164 | |
165 return newx; | |
166 } | |
167 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
168 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
169 * attempts to parse the buff onto this stream firing events to the handler |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
170 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
171 * @param xs the xstream to parse the data on |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
172 * @param buff the new data |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
173 * @param len length of the data |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
174 * @return last known xstream status |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
175 */ |
25 | 176 int xstream_eat(xstream xs, char *buff, int len) |
177 { | |
178 char *err; | |
179 xmlnode xerr; | |
180 static char maxerr[] = "maximum node size reached"; | |
181 static char deeperr[] = "maximum node depth reached"; | |
182 | |
183 if(xs == NULL) | |
184 { | |
185 fprintf(stderr,"Fatal Programming Error: xstream_eat() was improperly called with NULL.\n"); | |
186 return XSTREAM_ERR; | |
187 } | |
188 | |
189 if(len == 0 || buff == NULL) | |
190 return xs->status; | |
191 | |
192 if(len == -1) /* easy for hand-fed eat calls */ | |
193 len = strlen(buff); | |
194 | |
195 if(!XML_Parse(xs->parser, buff, len, 0)) | |
196 { | |
197 err = (char *)XML_ErrorString(XML_GetErrorCode(xs->parser)); | |
198 xs->status = XSTREAM_ERR; | |
199 }else if(pool_size(xmlnode_pool(xs->node)) > XSTREAM_MAXNODE || xs->cdata_len > XSTREAM_MAXNODE){ | |
200 err = maxerr; | |
201 xs->status = XSTREAM_ERR; | |
202 }else if(xs->status == XSTREAM_ERR){ /* set within expat handlers */ | |
203 err = deeperr; | |
204 } | |
205 | |
206 /* fire parsing error event, make a node containing the error string */ | |
207 if(xs->status == XSTREAM_ERR) | |
208 { | |
209 xerr = xmlnode_new_tag("error"); | |
210 xmlnode_insert_cdata(xerr,err,-1); | |
211 (xs->f)(XSTREAM_ERR, xerr, xs->arg); | |
212 } | |
213 | |
214 return xs->status; | |
215 } | |
216 | |
217 | |
218 /* STREAM CREATION UTILITIES */ | |
219 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
220 /** give a standard template xmlnode to work from |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
221 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
222 * @param namespace ("jabber:client", "jabber:server", ...) |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
223 * @param to where the stream is sent to |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
224 * @param from where we are (source of the stream) |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
225 * @return the xmlnode that has been generated as the template |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
226 */ |
25 | 227 xmlnode xstream_header(char *namespace, char *to, char *from) |
228 { | |
229 xmlnode x; | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
230 char id[11]; |
25 | 231 |
232 sprintf(id,"%X",(int)time(NULL)); | |
233 | |
234 x = xmlnode_new_tag("stream:stream"); | |
235 xmlnode_put_attrib(x, "xmlns:stream", "http://etherx.jabber.org/streams"); | |
236 xmlnode_put_attrib(x, "id", id); | |
237 if(namespace != NULL) | |
238 xmlnode_put_attrib(x, "xmlns", namespace); | |
239 if(to != NULL) | |
240 xmlnode_put_attrib(x, "to", to); | |
241 if(from != NULL) | |
242 xmlnode_put_attrib(x, "from", from); | |
243 | |
244 return x; | |
245 } | |
246 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
247 /** |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
248 * trim the xmlnode to only the opening header :) |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
249 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
250 * @note NO CHILDREN ALLOWED |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
251 * |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
252 * @param x the xmlnode |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
253 * @return string representation of the start tag |
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
254 */ |
25 | 255 char *xstream_header_char(xmlnode x) |
256 { | |
257 spool s; | |
258 char *fixr, *head; | |
259 | |
417
c3ae9251c197
Sync libjabber with upstream
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
260 if(xmlnode_has_children(x)) { |
25 | 261 fprintf(stderr,"Fatal Programming Error: xstream_header_char() was sent a header with children!\n"); |
262 return NULL; | |
263 } | |
264 | |
265 s = spool_new(xmlnode_pool(x)); | |
266 spooler(s,"<?xml version='1.0'?>",xmlnode2str(x),s); | |
267 head = spool_print(s); | |
268 fixr = strstr(head,"/>"); | |
269 *fixr = '>'; | |
270 ++fixr; | |
271 *fixr = '\0'; | |
272 | |
273 return head; | |
274 } | |
275 |