]> git.evergreen-ils.org Git - Evergreen.git/blob - OpenSRF/src/jserver/jserver-c_session.c
Chop Chop, Jabber
[Evergreen.git] / OpenSRF / src / jserver / jserver-c_session.c
1 #include "jserver-c_session.h"
2
3 static int xml_error_occured = 0;
4 static int client_sent_disconnect = 0;
5
6 jserver_session* jserver_session_init() {
7
8         jserver_session* session = safe_malloc(sizeof(jserver_session));
9         session->parser_ctxt = xmlCreatePushParserCtxt(sax_handler, session, "", 0, NULL);
10         session->current_msg = xmlNewDoc(BAD_CAST "1.0");
11         session->current_to = strdup("");
12         session->current_from = strdup("");
13         session->state = 0;
14         xmlKeepBlanksDefault(0);
15         return session;
16 }
17
18 void jserver_session_free(jserver_session* session) {
19         if(session == NULL) return;
20
21         if( session->parser_ctxt) {
22                 xmlFreeDoc(session->parser_ctxt->myDoc);
23                 xmlFreeParserCtxt(session->parser_ctxt);
24         }
25
26         free(session->current_username);
27         free(session->current_resource);
28         free(session->current_domain);
29
30         xmlCleanupCharEncodingHandlers();
31         xmlFreeDoc(session->current_msg);
32         xmlCleanupParser();
33
34         free(session);
35 }
36
37
38 int jserver_session_push_data(jserver_session* session, char* data) {
39         if(session == NULL || data == NULL) return -1;  
40         debug_handler("pushing data into xml parser: %s", data);
41         xmlParseChunk(session->parser_ctxt, data, strlen(data), 0);
42         if(xml_error_occured) {
43                 xml_error_occured = 0;
44                 return -1;
45         }
46
47         if(client_sent_disconnect) {
48                 client_sent_disconnect = 0;
49                 if(session->on_client_finish)
50                         session->on_client_finish(session->blob);
51         }
52
53         return 0;
54 }
55
56 void sax_start_doc(void* blob) {
57         debug_handler("Starting new session doc");
58 }
59
60 // ---------------------------------------------------------------------------------
61 // Our SAX handlers 
62 // ---------------------------------------------------------------------------------
63 void sax_start_element( 
64                 void* blob, const xmlChar *name, const xmlChar **atts) {
65
66         jserver_session* session = (jserver_session*) blob;
67         if(!session) return;
68
69         debug_handler("jserver-c_session received opening XML node %s", name);
70
71         if(!strcmp(name, "stream:stream")) {
72
73                 /* opening a new session */     
74                 free(session->current_domain);
75                 session->current_domain = strdup(sax_xml_attr(atts, "to"));
76                 char* from_domain = sax_xml_attr(atts, "from");
77                 if(!from_domain) from_domain = "";
78
79                 if(session->current_domain == NULL) {
80                         sax_warning(session->blob, "No 'to' specified in stream opener");
81
82                 }       else {
83                         debug_handler("jserver-c_session received opening stream from client on domain %s", 
84                                 session->current_domain);
85
86                         char buf[512];
87                         memset(buf,0,512);
88
89                         /* reply with the stock jabber login response */
90                         sprintf(buf, "<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' " 
91                                 "xmlns='jabber:client' from='%s' to='%s' version='1.0' id='d253et09iw1fv8a2noqc38f28sb0y5fc7kfmegvx'>",
92                                 session->current_domain, from_domain);
93
94                         debug_handler("Session Sending: %s", buf);
95
96                         session->state = JABBER_STATE_CONNECTING;
97                         if(session->on_login_init)
98                                 session->on_login_init(session->blob, buf);
99                 }
100                 return;
101         }
102
103         if(session->state & JABBER_STATE_CONNECTING) {
104                 /* during the connect shuffle, we have to store off the
105                         username and resource to determine the routing address */
106                 if(!strcmp(name,"iq"))
107                         session->in_iq = 1;
108                 if(!strcmp(name,"username"))
109                         session->in_uname = 1;
110                 if(!strcmp(name,"resource"))
111                         session->in_resource = 1;
112         }
113
114         if(session->state & JABBER_STATE_CONNECTED) {
115
116                 if(!strcmp(name, "message")) {
117                         /* opening of a new message, build a new doc */
118                         xmlNodePtr root = xmlNewNode(NULL, name);
119                         dom_add_attrs(root, atts);
120                         xmlNodePtr old_root = xmlDocSetRootElement(session->current_msg, root);
121
122
123                         free(session->current_to);
124
125                         char* from = sax_xml_attr(atts, "from");
126                         if(from == NULL) from = "";
127                         char* to = sax_xml_attr(atts, "to");
128                         if(to == NULL) to = "";
129
130                         session->current_to = strdup(to);
131
132                         /* free the old message tree */
133                         if(old_root) xmlFreeNode(old_root);
134
135                 } else {
136                         xmlNodePtr node = xmlNewNode(NULL, name);
137                         dom_add_attrs(node, atts);
138                         xmlAddChild(xmlDocGetRootElement(session->current_msg), node);
139                 }
140         }
141 }
142
143 void sax_end_element( void* blob, const xmlChar *name) {
144         jserver_session* session = (jserver_session*) blob;
145         if(!session) return;
146
147         if(session->state & JABBER_STATE_CONNECTED) {
148                 if(!strcmp(name, "message")) {
149                         if(session->on_msg_complete) {
150                                 /* we have to make sure the 'from' address is set.. */
151                                 xmlNodePtr msg = xmlDocGetRootElement(session->current_msg);
152                                 if(msg) xmlSetProp(msg, BAD_CAST "from", BAD_CAST session->current_from );
153
154                                 char* string = _xml_to_string(session->current_msg);
155                                 session->on_msg_complete(session->blob, string, 
156                                         session->current_from, session->current_to );
157                                 free(string);
158                         }
159                 }
160         }
161
162         if(session->state & JABBER_STATE_CONNECTING) {
163                 if(session->in_iq) {
164                         if(!strcmp(name, "iq")) {
165                                 session->in_iq = 0;
166
167                                 char buf[1024];
168                                 memset(buf, 0, 1024);
169                                 snprintf(buf, 1023, "%s@%s/%s", session->current_username,
170                                                 session->current_domain, session->current_resource );
171                                 if(session->on_from_discovered) 
172                                         session->on_from_discovered(session->blob, buf);
173
174                                 free(session->current_from);
175                                 session->current_from = strdup(buf);
176                                 debug_handler("Set from address to %s", session->current_from);
177                                 session->state = JABBER_STATE_CONNECTED;
178                                 if(session->on_login_ok) 
179                                         session->on_login_ok(session->blob);
180
181                         }
182                 }
183         }
184
185         if(!strcmp(name,"stream:stream")) {
186                 debug_handler("receive end of client session doc");
187                 client_sent_disconnect = 1;
188         }
189 }
190
191 void sax_character( void* blob, const xmlChar *ch, int len) {
192         jserver_session* session = (jserver_session*) blob;
193         if(!session) return;
194
195         if(session->state & JABBER_STATE_CONNECTED) {
196                 xmlNodePtr last = xmlGetLastChild(
197                         xmlDocGetRootElement(session->current_msg));
198         
199                 xmlNodePtr txt = xmlNewTextLen(ch, len);
200                 xmlAddChild(last, txt);
201                 return;
202         } 
203
204         if(session->state & JABBER_STATE_CONNECTING) {
205                 if(session->in_iq) {
206                         if(session->in_uname) {
207                                 free(session->current_username);
208                                 session->current_username = strndup((char*) ch, len);
209                                 session->in_uname = 0;
210                         }
211         
212                         if(session->in_resource) {
213                                 free(session->current_resource);
214                                 session->current_resource = strndup((char*) ch, len);
215                                 session->in_resource = 0;
216                         }
217                 }
218                 
219         }
220 }
221
222 void  sax_warning( void* blob, const char* msg, ... ) {
223
224         jserver_session* session = (jserver_session*) blob;
225         if(!session) return;
226
227         char buf[1024];
228         memset(buf, 0,  1024);
229
230         va_list args;
231         va_start(args, msg);
232         vsnprintf(buf, 1023, msg, args);
233         va_end(args);
234         warning_handler("XML Warning : %s", buf);
235         xml_error_occured = 1;
236 }
237
238
239 void dom_add_attrs(xmlNodePtr node, const xmlChar** atts) {
240         int i;
241         if (node != NULL && atts != NULL) {
242                 for(i = 0; (atts[i] != NULL); i++) {
243                         if(atts[i+1]) {
244                                 xmlNewProp(node, atts[i], atts[i+1]);
245                                 i++;
246                         }
247                 }
248         }
249 }
250
251 char* sax_xml_attr( const xmlChar** atts, char* attr_name ) {
252         int i;
253         if(attr_name == NULL) return NULL;
254
255         if (atts != NULL) {
256                 for(i = 0;(atts[i] != NULL);i++) {
257                         if(!strcmp(atts[i], attr_name)) 
258                                 if(atts[++i])
259                                         return (char*) atts[i];
260                 }
261         }
262         return NULL;
263 }
264
265
266
267 char* _xml_to_string( xmlDocPtr doc ) {
268         
269         int                     bufsize;
270         xmlChar*                xmlbuf;
271         xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
272
273         char* xml = strdup(xmlbuf);
274         xmlFree(xmlbuf);
275
276         /*** remove the XML declaration */
277         int len = strlen(xml);
278         char tmp[len];
279         memset( tmp, 0, len );
280         int i;
281         int found_at = 0;
282                                                 
283         /* when we reach the first >, take everything after it */
284         for( i = 0; i!= len; i++ ) {
285                 if( xml[i] == 62) { /* ascii > */
286         
287                         /* found_at holds the starting index of the rest of the doc*/
288                         found_at = i + 1; 
289                         break;
290                 }
291         }
292
293         if( found_at ) {
294
295                 /* move the shortened doc into the tmp buffer */
296                 strncpy( tmp, xml + found_at, len - found_at );
297                 /* move the tmp buffer back into the allocated space */
298                 memset( xml, 0, len );
299                 strcpy( xml, tmp );
300         }
301
302         int l = strlen(xml)-1;
303         if( xml[l] == 10 || xml[l] == 13 )
304                 xml[l] = '\0';
305
306         return xml;
307
308 }
309