Updated Changelog
[centerim/davrieb.git] / libjabber / jconn.c
blob3bbb4f35de009d9b92a727de18d33e2c07356ce0
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.
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.
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.
16 * Jabber
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
20 #include "jabber.h"
21 #include "connwrap.h"
23 /* local macros for launching event handlers */
24 #define STATE_EVT(arg) if(j->on_state) { (j->on_state)(j, (arg) ); }
26 /* prototypes of the local functions */
27 static void startElement(void *userdata, const char *name, const char **attribs);
28 static void endElement(void *userdata, const char *name);
29 static void charData(void *userdata, const char *s, int slen);
32 * jab_new -- initialize a new jabber connection
34 * parameters
35 * user -- jabber id of the user
36 * pass -- password of the user
38 * results
39 * a pointer to the connection structure
40 * or NULL if allocations failed
42 jconn jab_new(char *user, char *pass, char *server, int port, int ssl)
44 pool p;
45 jconn j;
47 if(!user) return(NULL);
49 p = pool_new();
50 if(!p) return(NULL);
51 j = pmalloc_x(p, sizeof(jconn_struct), 0);
52 if(!j) return(NULL);
53 j->p = p;
55 j->user = jid_new(p, user);
56 j->pass = pstrdup(p, pass);
57 j->port = port;
58 j->server = server;
60 j->state = JCONN_STATE_OFF;
61 j->cw_state = 0;
62 j->id = 1;
63 j->fd = -1;
64 j->ssl = ssl;
66 return j;
70 * jab_delete -- free a jabber connection
72 * parameters
73 * j -- connection
76 void jab_delete(jconn j)
78 if(!j) return;
80 jab_stop(j);
81 pool_free(j->p);
85 * jab_state_handler -- set callback handler for state change
87 * parameters
88 * j -- connection
89 * h -- name of the handler function
91 void jab_state_handler(jconn j, jconn_state_h h)
93 if(!j) return;
95 j->on_state = h;
99 * jab_packet_handler -- set callback handler for incoming packets
101 * parameters
102 * j -- connection
103 * h -- name of the handler function
105 void jab_packet_handler(jconn j, jconn_packet_h h)
107 if(!j) return;
109 j->on_packet = h;
112 void jab_logger(jconn j, jconn_logger h)
114 if(!j) return;
116 j->logger = h;
121 * jab_start -- start connection
123 * parameters
124 * j -- connection
127 void jab_start(jconn j)
129 xmlnode x;
130 char *t,*t2;
132 if(!j || (j->state != JCONN_STATE_OFF && j->state != JCONN_STATE_CONNECTING) ) return;
134 if (!(j->cw_state & CW_CONNECT_WANT_SOMETHING)) { /* same as state != JCONN_STATE_CONNECTING */
135 j->parser = XML_ParserCreate(NULL);
136 XML_SetUserData(j->parser, (void *)j);
137 XML_SetElementHandler(j->parser, startElement, endElement);
138 XML_SetCharacterDataHandler(j->parser, charData);
140 if (j->cw_state & CW_CONNECT_BLOCKING)
141 j->fd = make_netsocket(j->port, j->server, NETSOCKET_CLIENT, j->ssl);
142 else
143 j->fd = make_nb_netsocket(j->port, j->server, NETSOCKET_CLIENT, j->ssl, &j->cw_state);
145 if(j->fd < 0) {
146 STATE_EVT(JCONN_STATE_OFF);
147 return;
150 else { /* subsequent calls to cw_nb_connect until it finishes negociation */
151 if (cw_nb_connect(j->fd, 0, 0, j->ssl, &j->cw_state)) {
152 STATE_EVT(JCONN_STATE_OFF);
153 return;
156 if (j->cw_state & CW_CONNECT_WANT_SOMETHING){ /* check if it finished negociation */
157 j->state = JCONN_STATE_CONNECTING;
158 STATE_EVT(JCONN_STATE_CONNECTING);
159 return;
161 change_socket_to_blocking(j->fd);
163 j->state = JCONN_STATE_CONNECTED;
164 STATE_EVT(JCONN_STATE_CONNECTED)
166 /* start stream */
167 x = jutil_header(NS_CLIENT, j->user->server);
168 t = xmlnode2str(x);
169 /* this is ugly, we can create the string here instead of jutil_header */
170 /* what do you think about it? -madcat */
171 t2 = strstr(t,"/>");
172 if (t2 != NULL)
174 *t2++ = '>';
175 *t2 = '\0';
177 jab_send_raw(j,"<?xml version='1.0'?>");
178 jab_send_raw(j,t);
179 xmlnode_free(x);
181 j->state = JCONN_STATE_ON;
182 STATE_EVT(JCONN_STATE_ON)
187 * jab_stop -- stop connection
189 * parameters
190 * j -- connection
192 void jab_stop(jconn j)
194 if(!j || j->state == JCONN_STATE_OFF) return;
196 j->state = JCONN_STATE_OFF;
197 cw_close(j->fd);
198 j->fd = -1;
199 XML_ParserFree(j->parser);
203 * jab_getfd -- get file descriptor of connection socket
205 * parameters
206 * j -- connection
208 * returns
209 * fd of the socket or -1 if socket was not connected
211 int jab_getfd(jconn j)
213 if(j)
214 return j->fd;
215 else
216 return -1;
220 * jab_getjid -- get jid structure of user
222 * parameters
223 * j -- connection
225 jid jab_getjid(jconn j)
227 if(j)
228 return(j->user);
229 else
230 return NULL;
233 /* jab_getsid -- get stream id
234 * This is the id of server's <stream:stream> tag and used for
235 * digest authorization.
237 * parameters
238 * j -- connection
240 char *jab_getsid(jconn j)
242 if(j)
243 return(j->sid);
244 else
245 return NULL;
249 * jab_getid -- get a unique id
251 * parameters
252 * j -- connection
254 char *jab_getid(jconn j)
256 snprintf(j->idbuf, 8, "%d", j->id++);
257 return &j->idbuf[0];
261 * jab_send -- send xml data
263 * parameters
264 * j -- connection
265 * x -- xmlnode structure
267 void jab_send(jconn j, xmlnode x)
269 if (j && j->state != JCONN_STATE_OFF)
271 char *buf = xmlnode2str(x);
272 if (buf) {
273 cw_write(j->fd, buf, strlen(buf), j->ssl);
274 if (j->logger)
275 (j->logger)(j, 0, buf);
278 #ifdef JDEBUG
279 printf ("out: %s\n", buf);
280 #endif
285 * jab_send_raw -- send a string
287 * parameters
288 * j -- connection
289 * str -- xml string
291 void jab_send_raw(jconn j, const char *str)
293 if (j && j->state != JCONN_STATE_OFF) {
294 cw_write(j->fd, str, strlen(str), j->ssl);
296 if (j->logger)
297 (j->logger)(j, 0, str);
300 #ifdef JDEBUG
301 printf ("out: %s\n", str);
302 #endif
306 * jab_recv -- read and parse incoming data
308 * parameters
309 * j -- connection
311 void jab_recv(jconn j)
313 static char buf[32768];
314 int len;
316 if(!j || j->state == JCONN_STATE_OFF)
317 return;
319 len = cw_read(j->fd, buf, sizeof(buf)-1, j->ssl);
320 if(len>0)
322 buf[len] = '\0';
324 if (j->logger)
325 (j->logger)(j, 1, buf);
327 #ifdef JDEBUG
328 printf (" in: %s\n", buf);
329 #endif
330 XML_Parse(j->parser, buf, len, 0);
332 else if(len<=0)
334 STATE_EVT(JCONN_STATE_OFF);
335 jab_stop(j);
340 * jab_poll -- check socket for incoming data
342 * parameters
343 * j -- connection
344 * timeout -- poll timeout
346 void jab_poll(jconn j, int timeout)
348 fd_set fds;
349 struct timeval tv;
350 int r;
352 if (!j || j->state == JCONN_STATE_OFF || j->fd == -1)
353 return;
355 FD_ZERO(&fds);
356 FD_SET(j->fd, &fds);
358 if(timeout <= 0) {
359 r = select(j->fd + 1, &fds, NULL, NULL, NULL);
361 } else {
362 tv.tv_sec = 0;
363 tv.tv_usec = timeout;
364 r = select(j->fd + 1, &fds, NULL, NULL, &tv);
368 if(r > 0) {
369 jab_recv(j);
371 } else if(r) {
372 STATE_EVT(JCONN_STATE_OFF);
373 jab_stop(j);
379 * jab_auth -- authorize user
381 * parameters
382 * j -- connection
384 * returns
385 * id of the iq packet
387 char *jab_auth(jconn j)
389 xmlnode x,y,z;
390 char *hash, *user, *id;
392 if(!j) return(NULL);
394 x = jutil_iqnew(JPACKET__SET, NS_AUTH);
395 id = jab_getid(j);
396 xmlnode_put_attrib(x, "id", id);
397 y = xmlnode_get_tag(x,"query");
399 user = j->user->user;
401 if (user)
403 z = xmlnode_insert_tag(y, "username");
404 xmlnode_insert_cdata(z, user, -1);
407 z = xmlnode_insert_tag(y, "resource");
408 xmlnode_insert_cdata(z, j->user->resource, -1);
410 if (j->sid)
412 z = xmlnode_insert_tag(y, "digest");
413 hash = pmalloc(x->p, strlen(j->sid)+strlen(j->pass)+1);
414 strcpy(hash, j->sid);
415 strcat(hash, j->pass);
416 hash = shahash(hash);
417 xmlnode_insert_cdata(z, hash, 40);
419 else
421 z = xmlnode_insert_tag(y, "password");
422 xmlnode_insert_cdata(z, j->pass, -1);
425 jab_send(j, x);
426 xmlnode_free(x);
427 return id;
431 * jab_reg -- register user
433 * parameters
434 * j -- connection
436 * returns
437 * id of the iq packet
439 char *jab_reg(jconn j)
441 xmlnode x,y,z;
442 char *hash, *user, *id;
444 if (!j) return(NULL);
446 x = jutil_iqnew(JPACKET__SET, NS_REGISTER);
447 id = jab_getid(j);
448 xmlnode_put_attrib(x, "id", id);
449 y = xmlnode_get_tag(x,"query");
451 user = j->user->user;
453 if (user)
455 z = xmlnode_insert_tag(y, "username");
456 xmlnode_insert_cdata(z, user, -1);
459 z = xmlnode_insert_tag(y, "resource");
460 xmlnode_insert_cdata(z, j->user->resource, -1);
462 if (j->pass)
464 z = xmlnode_insert_tag(y, "password");
465 xmlnode_insert_cdata(z, j->pass, -1);
468 jab_send(j, x);
469 xmlnode_free(x);
470 j->state = JCONN_STATE_ON;
471 STATE_EVT(JCONN_STATE_ON)
472 return id;
476 /* local functions */
478 static void startElement(void *userdata, const char *name, const char **attribs)
480 xmlnode x;
481 jconn j = (jconn)userdata;
483 if(j->current)
485 /* Append the node to the current one */
486 x = xmlnode_insert_tag(j->current, name);
487 xmlnode_put_expat_attribs(x, attribs);
489 j->current = x;
491 else
493 x = xmlnode_new_tag(name);
494 xmlnode_put_expat_attribs(x, attribs);
495 if(strcmp(name, "stream:stream") == 0) {
496 /* special case: name == stream:stream */
497 /* id attrib of stream is stored for digest auth */
498 j->sid = xmlnode_get_attrib(x, "id");
499 /* STATE_EVT(JCONN_STATE_AUTH) */
500 } else {
501 j->current = x;
506 static void endElement(void *userdata, const char *name)
508 jconn j = (jconn)userdata;
509 xmlnode x;
510 jpacket p;
512 if(j->current == NULL) {
513 /* we got </stream:stream> */
514 STATE_EVT(JCONN_STATE_OFF)
515 return;
518 x = xmlnode_get_parent(j->current);
520 if(x == NULL)
522 /* it is time to fire the event */
523 p = jpacket_new(j->current);
525 if(j->on_packet)
526 (j->on_packet)(j, p);
527 else
528 xmlnode_free(j->current);
531 j->current = x;
534 static void charData(void *userdata, const char *s, int slen)
536 jconn j = (jconn)userdata;
538 if (j->current)
539 xmlnode_insert_cdata(j->current, s, slen);