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/
26 /* local macros for launching event handlers */
27 #define STATE_EVT(arg) if(j->on_state) { (j->on_state)(j, (arg) ); }
30 /* prototypes of the local functions */
31 static void startElement(void *userdata
, const char *name
, const char **attribs
);
32 static void endElement(void *userdata
, const char *name
);
33 static void charData(void *userdata
, const char *s
, int slen
);
37 * jab_new -- initialize a new jabber connection
40 * user -- jabber id of the user
41 * pass -- password of the user
44 * a pointer to the connection structure
45 * or NULL if allocations failed
47 jconn
jab_new(char *user
, char *pass
, char *server
, int port
, int ssl
)
52 if(!user
) return(NULL
);
56 j
= pmalloc_x(p
, sizeof(jconn_struct
), 0);
60 j
->user
= jid_new(p
, user
);
61 j
->pass
= pstrdup(p
, pass
);
65 j
->state
= JCONN_STATE_OFF
;
75 * jab_delete -- free a jabber connection
81 void jab_delete(jconn j
)
90 * jab_state_handler -- set callback handler for state change
94 * h -- name of the handler function
96 void jab_state_handler(jconn j
, jconn_state_h h
)
104 * jab_packet_handler -- set callback handler for incoming packets
108 * h -- name of the handler function
110 void jab_packet_handler(jconn j
, jconn_packet_h h
)
117 void jab_logger(jconn j
, jconn_logger h
)
126 * jab_start -- start connection
132 void jab_start(jconn j
)
137 if(!j
|| (j
->state
!= JCONN_STATE_OFF
&& j
->state
!= JCONN_STATE_CONNECTING
) ) return;
139 if (!(j
->cw_state
& CW_CONNECT_WANT_SOMETHING
)) { /* same as state != JCONN_STATE_CONNECTING */
140 j
->parser
= XML_ParserCreate(NULL
);
141 XML_SetUserData(j
->parser
, (void *)j
);
142 XML_SetElementHandler(j
->parser
, startElement
, endElement
);
143 XML_SetCharacterDataHandler(j
->parser
, charData
);
145 if (j
->cw_state
& CW_CONNECT_BLOCKING
)
146 j
->fd
= make_netsocket(j
->port
, j
->server
, NETSOCKET_CLIENT
, j
->ssl
);
148 j
->fd
= make_nb_netsocket(j
->port
, j
->server
, NETSOCKET_CLIENT
, j
->ssl
, &j
->cw_state
);
151 STATE_EVT(JCONN_STATE_OFF
);
155 else { /* subsequent calls to cw_nb_connect until it finishes negociation */
156 if (cw_nb_connect(j
->fd
, 0, 0, j
->ssl
, &j
->cw_state
)) {
157 STATE_EVT(JCONN_STATE_OFF
);
161 if (j
->cw_state
& CW_CONNECT_WANT_SOMETHING
){ /* check if it finished negociation */
162 j
->state
= JCONN_STATE_CONNECTING
;
163 STATE_EVT(JCONN_STATE_CONNECTING
);
166 change_socket_to_blocking(j
->fd
);
168 j
->state
= JCONN_STATE_CONNECTED
;
169 STATE_EVT(JCONN_STATE_CONNECTED
)
172 x
= jutil_header(NS_CLIENT
, j
->user
->server
);
174 /* this is ugly, we can create the string here instead of jutil_header */
175 /* what do you think about it? -madcat */
182 jab_send_raw(j
,"<?xml version='1.0'?>");
186 j
->state
= JCONN_STATE_ON
;
187 STATE_EVT(JCONN_STATE_ON
)
192 * jab_stop -- stop connection
197 void jab_stop(jconn j
)
199 if(!j
|| j
->state
== JCONN_STATE_OFF
) return;
201 j
->state
= JCONN_STATE_OFF
;
204 XML_ParserFree(j
->parser
);
208 * jab_getfd -- get file descriptor of connection socket
214 * fd of the socket or -1 if socket was not connected
216 int jab_getfd(jconn j
)
225 * jab_getjid -- get jid structure of user
230 jid
jab_getjid(jconn j
)
238 /* jab_getsid -- get stream id
239 * This is the id of server's <stream:stream> tag and used for
240 * digest authorization.
245 char *jab_getsid(jconn j
)
254 * jab_getid -- get a unique id
259 char *jab_getid(jconn j
)
261 snprintf(j
->idbuf
, 8, "%d", j
->id
++);
266 * jab_send -- send xml data
270 * x -- xmlnode structure
272 void jab_send(jconn j
, xmlnode x
)
274 if (j
&& j
->state
!= JCONN_STATE_OFF
)
276 char *buf
= xmlnode2str(x
);
278 cw_write(j
->fd
, buf
, strlen(buf
), j
->ssl
);
280 (j
->logger
)(j
, 0, buf
);
284 printf ("out: %s\n", buf
);
290 * jab_send_raw -- send a string
296 void jab_send_raw(jconn j
, const char *str
)
298 if (j
&& j
->state
!= JCONN_STATE_OFF
) {
299 cw_write(j
->fd
, str
, strlen(str
), j
->ssl
);
302 (j
->logger
)(j
, 0, str
);
306 printf ("out: %s\n", str
);
311 * jab_recv -- read and parse incoming data
316 void jab_recv(jconn j
)
318 static char buf
[32768];
321 if(!j
|| j
->state
== JCONN_STATE_OFF
)
324 len
= cw_read(j
->fd
, buf
, sizeof(buf
)-1, j
->ssl
);
330 (j
->logger
)(j
, 1, buf
);
333 printf (" in: %s\n", buf
);
335 XML_Parse(j
->parser
, buf
, len
, 0);
339 STATE_EVT(JCONN_STATE_OFF
);
345 * jab_poll -- check socket for incoming data
349 * timeout -- poll timeout
351 void jab_poll(jconn j
, int timeout
)
357 if (!j
|| j
->state
== JCONN_STATE_OFF
|| j
->fd
== -1)
364 r
= select(j
->fd
+ 1, &fds
, NULL
, NULL
, NULL
);
368 tv
.tv_usec
= timeout
;
369 r
= select(j
->fd
+ 1, &fds
, NULL
, NULL
, &tv
);
377 STATE_EVT(JCONN_STATE_OFF
);
384 * jab_auth -- authorize user
390 * id of the iq packet
392 char *jab_auth(jconn j
)
395 char *hash
, *user
, *id
;
399 x
= jutil_iqnew(JPACKET__SET
, NS_AUTH
);
401 xmlnode_put_attrib(x
, "id", id
);
402 y
= xmlnode_get_tag(x
,"query");
404 user
= j
->user
->user
;
408 z
= xmlnode_insert_tag(y
, "username");
409 xmlnode_insert_cdata(z
, user
, -1);
412 z
= xmlnode_insert_tag(y
, "resource");
413 xmlnode_insert_cdata(z
, j
->user
->resource
, -1);
417 z
= xmlnode_insert_tag(y
, "digest");
418 hash
= pmalloc(x
->p
, strlen(j
->sid
)+strlen(j
->pass
)+1);
419 strcpy(hash
, j
->sid
);
420 strcat(hash
, j
->pass
);
421 hash
= shahash(hash
);
422 xmlnode_insert_cdata(z
, hash
, 40);
426 z
= xmlnode_insert_tag(y
, "password");
427 xmlnode_insert_cdata(z
, j
->pass
, -1);
436 * jab_reg -- register user
442 * id of the iq packet
444 char *jab_reg(jconn j
)
447 char *hash
, *user
, *id
;
449 if (!j
) return(NULL
);
451 x
= jutil_iqnew(JPACKET__SET
, NS_REGISTER
);
453 xmlnode_put_attrib(x
, "id", id
);
454 y
= xmlnode_get_tag(x
,"query");
456 user
= j
->user
->user
;
460 z
= xmlnode_insert_tag(y
, "username");
461 xmlnode_insert_cdata(z
, user
, -1);
464 z
= xmlnode_insert_tag(y
, "resource");
465 xmlnode_insert_cdata(z
, j
->user
->resource
, -1);
469 z
= xmlnode_insert_tag(y
, "password");
470 xmlnode_insert_cdata(z
, j
->pass
, -1);
475 j
->state
= JCONN_STATE_ON
;
476 STATE_EVT(JCONN_STATE_ON
)
481 /* local functions */
483 static void startElement(void *userdata
, const char *name
, const char **attribs
)
486 jconn j
= (jconn
)userdata
;
490 /* Append the node to the current one */
491 x
= xmlnode_insert_tag(j
->current
, name
);
492 xmlnode_put_expat_attribs(x
, attribs
);
498 x
= xmlnode_new_tag(name
);
499 xmlnode_put_expat_attribs(x
, attribs
);
500 if(strcmp(name
, "stream:stream") == 0) {
501 /* special case: name == stream:stream */
502 /* id attrib of stream is stored for digest auth */
503 j
->sid
= xmlnode_get_attrib(x
, "id");
504 /* STATE_EVT(JCONN_STATE_AUTH) */
511 static void endElement(void *userdata
, const char *name
)
513 jconn j
= (jconn
)userdata
;
517 if(j
->current
== NULL
) {
518 /* we got </stream:stream> */
519 STATE_EVT(JCONN_STATE_OFF
)
523 x
= xmlnode_get_parent(j
->current
);
527 /* it is time to fire the event */
528 p
= jpacket_new(j
->current
);
531 (j
->on_packet
)(j
, p
);
533 xmlnode_free(j
->current
);
539 static void charData(void *userdata
, const char *s
, int slen
)
541 jconn j
= (jconn
)userdata
;
544 xmlnode_insert_cdata(j
->current
, s
, slen
);
547 void cleanup_thread(void *arg
)
549 struct pargs_r
*argument
= (struct pargs_r
*)arg
;
552 close(argument
->fd_file
);
553 close(argument
->sock
);
555 free(argument
->hash
);
557 free(argument
->rfile
);
562 void jabber_send_file(jconn j
, const char *filename
, long int size
, struct send_file
*file
, void *rfile
, void (*function
)(void *file
, long int bytes
, long int size
, int status
, int conn_type
), int start_port
, int end_port
) //returning ip address and port after binding
566 struct sockaddr_in addr
;
569 int fd_file
= open(filename
, O_RDONLY
);
573 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
580 addr
.sin_family
= AF_INET
;
582 if( (start_port
== 0) || (end_port
== 0))
583 addr
.sin_port
= htons(0); //
585 addr
.sin_port
= htons(next_random(start_port
,end_port
)); //
587 struct sockaddr_in sa
;
588 int sa_len
= sizeof( sa
);
589 getsockname( j
->fd
, (struct sockaddr
*) &sa
, &sa_len
); //geting address for bind
590 addr
.sin_addr
.s_addr
= sa
.sin_addr
.s_addr
;
592 // addr.sin_addr.s_addr = htonl(INADDR_ANY);
593 if (setsockopt(sock
, SOL_SOCKET
, SO_REUSEADDR
, (const void *)&optval
, sizeof(int)) < 0)
599 if ( (bind(sock
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr
)) ) < 0 )
603 if( errno
== EADDRINUSE
) //select another port
604 addr
.sin_port
= htons(next_random(start_port
, end_port
)); //geting another random port
612 while(bind(sock
, (struct sockaddr
*) &addr
, sizeof(struct sockaddr
)) < 0);
615 file
->host
= strdup(inet_ntoa(sa
.sin_addr
));
617 getsockname( sock
, (struct sockaddr
*) &sa
, &sa_len
);
618 file
->port
= (int) ntohs(sa
.sin_port
);
621 arg
= (struct pargs_r
*)calloc(1, sizeof(struct pargs_r
));
626 arg
->fd_file
= fd_file
;
631 arg
->callback
= function
;
632 if (pthread_create(&file
->thread
, NULL
, jabber_send_file_fd
, (void *)arg
))
648 void *jabber_send_file_fd(void *arg
)
651 struct pargs_r
*argument
;
654 struct sockaddr_in
*addr
;
656 argument
= (struct pargs_r
*)arg
;
658 sock
= argument
->sock
;
659 fd_file
= argument
->fd_file
;
660 size
= argument
->size
;
662 pthread_cleanup_push(cleanup_thread
, argument
);
663 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
666 char buff
[SEND_BUF
+1];
668 char sbuf
[SEND_BUF
+1];
671 int addr_size
= sizeof( addr
);
672 client
= accept(sock
, (struct sockaddr
*) &addr
, &addr_size
);
676 n
= recv(client
, buff
, SEND_BUF
, 0);
677 if( strstr( buff
, "GET /" ) )
679 snprintf( sbuf
, SEND_BUF
, "%d\r\n\r\n", size
);
680 strncpy( buff
, "HTTP/1.0 200 OK\r\nContent-Type: application/data\r\nContent-Length: ", SEND_BUF
);
681 strncat( buff
, sbuf
, SEND_BUF
);
682 int str_len
= strlen( buff
);
683 send( client
, buff
, str_len
, 0);
684 while( ( n
= read( fd_file
, buff
, SEND_BUF
)) > 0 )
687 if( send( client
, buff
, n
, 0) != n
)
690 argument
->callback(argument
->rfile
, counter
, size
, 0, 1);
697 if( counter
== size
)
698 argument
->callback(argument
->rfile
, counter
, size
, 1, 1);
700 argument
->callback(argument
->rfile
, counter
, size
, 2, 1);
702 pthread_cleanup_pop(1);
708 int next_random( int start_port
, int end_port
) //generate random number between two digits
710 srand( time( NULL
) );
711 return (start_port
+ rand() % (end_port
-start_port
+1));
714 void jabber_get_file(jconn j
, const char *filename
, long int size
, struct send_file
*file
, void *rfile
, void (*function
)(void *file
, long int bytes
, long int size
, int status
, int conn_type
) ) //returning ip address and port after binding
718 struct sockaddr_in addr
;
720 char *ip_addr
= file
->host
;
721 char *sid_from_to
= file
->sid_from_to
;
722 int port
= file
->port
;
724 int fd_file
= open(filename
, O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
728 sock
= socket(AF_INET
, SOCK_STREAM
, 0);
735 struct hostent
*host
= gethostbyname(ip_addr
);
736 bcopy(host
->h_addr
, &addr
.sin_addr
, host
->h_length
);
738 addr
.sin_family
= AF_INET
;
739 addr
.sin_port
= htons( port
);
742 if ( connect(sock
, (struct sockaddr
*) &addr
, sizeof(addr
) ) < 0 )
753 hash
= shahash(sid_from_to
);
756 arg
= (struct pargs_r
*)calloc(1, sizeof(struct pargs_r
));
761 arg
->fd_file
= fd_file
;
764 arg
->hash
= strdup( hash
);
766 arg
->url
= file
->url
;
767 arg
->callback
= function
;
768 if(file
->transfer_type
== 0)
770 if (pthread_create(&file
->thread
, NULL
, jabber_recieve_file_fd
, (void *)arg
))
780 if (pthread_create(&file
->thread
, NULL
, jabber_recieve_file_fd_http
, (void *)arg
))
797 void *jabber_recieve_file_fd(void *arg
)
800 struct pargs_r
*argument
;
805 argument
= (struct pargs_r
*)arg
;
807 sock
= argument
->sock
;
808 fd_file
= argument
->fd_file
;
809 size
= argument
->size
;
810 hash
= argument
->hash
;
811 pthread_cleanup_push(cleanup_thread
, argument
);
812 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
822 if( send( sock
, buff
, 3, 0 ) != 3 )
830 recv( sock
, buff
, SEND_BUF
, 0 );
831 if( buff
[0] != 0x05 || buff
[1] != 0x00 )
839 //socks5 bytestream packet
845 strncpy( (char*)(buff
+ 5), hash
, 40 );
849 if( send( sock
, buff
, 47, 0 ) != 47 )
856 recv( sock
, buff
, 47, 0 );
857 if( buff
[0] != 0x05 || buff
[3] != 0x03 )
870 bytes
= recv( sock
, buff
, SEND_BUF
, 0 );
875 write(fd_file
, buff
, bytes
);
877 argument
->callback(argument
->rfile
, counter
, size
, 0, 0);
881 if( counter
== size
)
882 argument
->callback(argument
->rfile
, counter
, size
, 1, 0);
884 argument
->callback(argument
->rfile
, counter
, size
, 2, 0);
886 pthread_cleanup_pop(1);
895 void *jabber_recieve_file_fd_http(void *arg
)
898 struct pargs_r
*argument
;
903 argument
= (struct pargs_r
*)arg
;
905 sock
= argument
->sock
;
906 fd_file
= argument
->fd_file
;
907 size
= argument
->size
;
909 pthread_cleanup_push(cleanup_thread
, argument
);
910 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE
, NULL
);
914 snprintf( buff
, SEND_BUF
, "GET %s HTTP/1.0\r\n\r\n", url
);
915 send( sock
, buff
, strlen(buff
), 0 );
918 int but
= recv( sock
, buff
, SEND_BUF
, 0 );
919 if( strstr(buff
, "200 OK" ) )
921 char *length
= strstr( buff
, "Content-Length:" );
922 sscanf( length
, "Content-Length: %d", &size
);
927 if(buff
[i
] == '\r' && buff
[i
+1] == '\n' && buff
[i
+2] == '\r' && buff
[i
+3] == '\n' )
938 write(fd_file
, (buff
+i
), bytes
);
943 bytes
= recv( sock
, buff
, SEND_BUF
, 0 );
948 write(fd_file
, buff
, bytes
);
950 argument
->callback(argument
->rfile
, counter
, size
, 0, 0);
954 if( counter
== size
)
955 argument
->callback(argument
->rfile
, counter
, size
, 1, 0);
957 argument
->callback(argument
->rfile
, counter
, size
, 2, 0);
960 pthread_cleanup_pop(1);