1 #include "jserver-c_session.h"
3 static int xml_error_occured = 0;
4 static int client_sent_disconnect = 0;
6 jserver_session* jserver_session_init() {
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("");
14 xmlKeepBlanksDefault(0);
18 void jserver_session_free(jserver_session* session) {
19 if(session == NULL) return;
21 if( session->parser_ctxt) {
22 xmlFreeDoc(session->parser_ctxt->myDoc);
23 xmlFreeParserCtxt(session->parser_ctxt);
26 free(session->current_username);
27 free(session->current_resource);
28 free(session->current_domain);
30 xmlCleanupCharEncodingHandlers();
31 xmlFreeDoc(session->current_msg);
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;
47 if(client_sent_disconnect) {
48 client_sent_disconnect = 0;
49 if(session->on_client_finish)
50 session->on_client_finish(session->blob);
56 void sax_start_doc(void* blob) {
57 debug_handler("Starting new session doc");
60 // ---------------------------------------------------------------------------------
62 // ---------------------------------------------------------------------------------
63 void sax_start_element(
64 void* blob, const xmlChar *name, const xmlChar **atts) {
66 jserver_session* session = (jserver_session*) blob;
69 debug_handler("jserver-c_session received opening XML node %s", name);
71 if(!strcmp(name, "stream:stream")) {
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 = "";
79 if(session->current_domain == NULL) {
80 sax_warning(session->blob, "No 'to' specified in stream opener");
83 debug_handler("jserver-c_session received opening stream from client on domain %s",
84 session->current_domain);
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);
94 debug_handler("Session Sending: %s", buf);
96 session->state = JABBER_STATE_CONNECTING;
97 if(session->on_login_init)
98 session->on_login_init(session->blob, buf);
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"))
108 if(!strcmp(name,"username"))
109 session->in_uname = 1;
110 if(!strcmp(name,"resource"))
111 session->in_resource = 1;
114 if(session->state & JABBER_STATE_CONNECTED) {
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);
123 free(session->current_to);
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 = "";
130 session->current_to = strdup(to);
132 /* free the old message tree */
133 if(old_root) xmlFreeNode(old_root);
136 xmlNodePtr node = xmlNewNode(NULL, name);
137 dom_add_attrs(node, atts);
138 xmlAddChild(xmlDocGetRootElement(session->current_msg), node);
143 void sax_end_element( void* blob, const xmlChar *name) {
144 jserver_session* session = (jserver_session*) blob;
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 );
154 char* string = _xml_to_string(session->current_msg);
155 session->on_msg_complete(session->blob, string,
156 session->current_from, session->current_to );
162 if(session->state & JABBER_STATE_CONNECTING) {
164 if(!strcmp(name, "iq")) {
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);
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);
185 if(!strcmp(name,"stream:stream")) {
186 debug_handler("receive end of client session doc");
187 client_sent_disconnect = 1;
191 void sax_character( void* blob, const xmlChar *ch, int len) {
192 jserver_session* session = (jserver_session*) blob;
195 if(session->state & JABBER_STATE_CONNECTED) {
196 xmlNodePtr last = xmlGetLastChild(
197 xmlDocGetRootElement(session->current_msg));
199 xmlNodePtr txt = xmlNewTextLen(ch, len);
200 xmlAddChild(last, txt);
204 if(session->state & JABBER_STATE_CONNECTING) {
206 if(session->in_uname) {
207 free(session->current_username);
208 session->current_username = strndup((char*) ch, len);
209 session->in_uname = 0;
212 if(session->in_resource) {
213 free(session->current_resource);
214 session->current_resource = strndup((char*) ch, len);
215 session->in_resource = 0;
222 void sax_warning( void* blob, const char* msg, ... ) {
224 jserver_session* session = (jserver_session*) blob;
228 memset(buf, 0, 1024);
232 vsnprintf(buf, 1023, msg, args);
234 warning_handler("XML Warning : %s", buf);
235 xml_error_occured = 1;
239 void dom_add_attrs(xmlNodePtr node, const xmlChar** atts) {
241 if (node != NULL && atts != NULL) {
242 for(i = 0; (atts[i] != NULL); i++) {
244 xmlNewProp(node, atts[i], atts[i+1]);
251 char* sax_xml_attr( const xmlChar** atts, char* attr_name ) {
253 if(attr_name == NULL) return NULL;
256 for(i = 0;(atts[i] != NULL);i++) {
257 if(!strcmp(atts[i], attr_name))
259 return (char*) atts[i];
267 char* _xml_to_string( xmlDocPtr doc ) {
271 xmlDocDumpFormatMemory( doc, &xmlbuf, &bufsize, 0 );
273 char* xml = strdup(xmlbuf);
276 /*** remove the XML declaration */
277 int len = strlen(xml);
279 memset( tmp, 0, len );
283 /* when we reach the first >, take everything after it */
284 for( i = 0; i!= len; i++ ) {
285 if( xml[i] == 62) { /* ascii > */
287 /* found_at holds the starting index of the rest of the doc*/
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 );
302 int l = strlen(xml)-1;
303 if( xml[l] == 10 || xml[l] == 13 )