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.
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
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
35 * user -- jabber id of the user
36 * pass -- password of the user
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
)
47 if(!user
) return(NULL
);
51 j
= pmalloc_x(p
, sizeof(jconn_struct
), 0);
55 j
->user
= jid_new(p
, user
);
56 j
->pass
= pstrdup(p
, pass
);
60 j
->state
= JCONN_STATE_OFF
;
70 * jab_delete -- free a jabber connection
76 void jab_delete(jconn j
)
85 * jab_state_handler -- set callback handler for state change
89 * h -- name of the handler function
91 void jab_state_handler(jconn j
, jconn_state_h h
)
99 * jab_packet_handler -- set callback handler for incoming packets
103 * h -- name of the handler function
105 void jab_packet_handler(jconn j
, jconn_packet_h h
)
112 void jab_logger(jconn j
, jconn_logger h
)
121 * jab_start -- start connection
127 void jab_start(jconn j
)
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
);
143 j
->fd
= make_nb_netsocket(j
->port
, j
->server
, NETSOCKET_CLIENT
, j
->ssl
, &j
->cw_state
);
146 STATE_EVT(JCONN_STATE_OFF
);
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
);
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
);
161 change_socket_to_blocking(j
->fd
);
163 j
->state
= JCONN_STATE_CONNECTED
;
164 STATE_EVT(JCONN_STATE_CONNECTED
)
167 x
= jutil_header(NS_CLIENT
, j
->user
->server
);
169 /* this is ugly, we can create the string here instead of jutil_header */
170 /* what do you think about it? -madcat */
177 jab_send_raw(j
,"<?xml version='1.0'?>");
181 j
->state
= JCONN_STATE_ON
;
182 STATE_EVT(JCONN_STATE_ON
)
187 * jab_stop -- stop connection
192 void jab_stop(jconn j
)
194 if(!j
|| j
->state
== JCONN_STATE_OFF
) return;
196 j
->state
= JCONN_STATE_OFF
;
199 XML_ParserFree(j
->parser
);
203 * jab_getfd -- get file descriptor of connection socket
209 * fd of the socket or -1 if socket was not connected
211 int jab_getfd(jconn j
)
220 * jab_getjid -- get jid structure of user
225 jid
jab_getjid(jconn j
)
233 /* jab_getsid -- get stream id
234 * This is the id of server's <stream:stream> tag and used for
235 * digest authorization.
240 char *jab_getsid(jconn j
)
249 * jab_getid -- get a unique id
254 char *jab_getid(jconn j
)
256 snprintf(j
->idbuf
, 8, "%d", j
->id
++);
261 * jab_send -- send xml data
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
);
273 cw_write(j
->fd
, buf
, strlen(buf
), j
->ssl
);
275 (j
->logger
)(j
, 0, buf
);
279 printf ("out: %s\n", buf
);
285 * jab_send_raw -- send a 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
);
297 (j
->logger
)(j
, 0, str
);
301 printf ("out: %s\n", str
);
306 * jab_recv -- read and parse incoming data
311 void jab_recv(jconn j
)
313 static char buf
[32768];
316 if(!j
|| j
->state
== JCONN_STATE_OFF
)
319 len
= cw_read(j
->fd
, buf
, sizeof(buf
)-1, j
->ssl
);
325 (j
->logger
)(j
, 1, buf
);
328 printf (" in: %s\n", buf
);
330 XML_Parse(j
->parser
, buf
, len
, 0);
334 STATE_EVT(JCONN_STATE_OFF
);
340 * jab_poll -- check socket for incoming data
344 * timeout -- poll timeout
346 void jab_poll(jconn j
, int timeout
)
352 if (!j
|| j
->state
== JCONN_STATE_OFF
|| j
->fd
== -1)
359 r
= select(j
->fd
+ 1, &fds
, NULL
, NULL
, NULL
);
363 tv
.tv_usec
= timeout
;
364 r
= select(j
->fd
+ 1, &fds
, NULL
, NULL
, &tv
);
372 STATE_EVT(JCONN_STATE_OFF
);
379 * jab_auth -- authorize user
385 * id of the iq packet
387 char *jab_auth(jconn j
)
390 char *hash
, *user
, *id
;
394 x
= jutil_iqnew(JPACKET__SET
, NS_AUTH
);
396 xmlnode_put_attrib(x
, "id", id
);
397 y
= xmlnode_get_tag(x
,"query");
399 user
= j
->user
->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);
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);
421 z
= xmlnode_insert_tag(y
, "password");
422 xmlnode_insert_cdata(z
, j
->pass
, -1);
431 * jab_reg -- register user
437 * id of the iq packet
439 char *jab_reg(jconn j
)
442 char *hash
, *user
, *id
;
444 if (!j
) return(NULL
);
446 x
= jutil_iqnew(JPACKET__SET
, NS_REGISTER
);
448 xmlnode_put_attrib(x
, "id", id
);
449 y
= xmlnode_get_tag(x
,"query");
451 user
= j
->user
->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);
464 z
= xmlnode_insert_tag(y
, "password");
465 xmlnode_insert_cdata(z
, j
->pass
, -1);
470 j
->state
= JCONN_STATE_ON
;
471 STATE_EVT(JCONN_STATE_ON
)
476 /* local functions */
478 static void startElement(void *userdata
, const char *name
, const char **attribs
)
481 jconn j
= (jconn
)userdata
;
485 /* Append the node to the current one */
486 x
= xmlnode_insert_tag(j
->current
, name
);
487 xmlnode_put_expat_attribs(x
, attribs
);
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) */
506 static void endElement(void *userdata
, const char *name
)
508 jconn j
= (jconn
)userdata
;
512 if(j
->current
== NULL
) {
513 /* we got </stream:stream> */
514 STATE_EVT(JCONN_STATE_OFF
)
518 x
= xmlnode_get_parent(j
->current
);
522 /* it is time to fire the event */
523 p
= jpacket_new(j
->current
);
526 (j
->on_packet
)(j
, p
);
528 xmlnode_free(j
->current
);
534 static void charData(void *userdata
, const char *s
, int slen
)
536 jconn j
= (jconn
)userdata
;
539 xmlnode_insert_cdata(j
->current
, s
, slen
);