jabberd2  2.2.16
sx/client.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "sx.h"
00022 
00023 static void _sx_client_element_start(void *arg, const char *name, const char **atts) {
00024     sx_t s = (sx_t) arg;
00025     int tflag = 0, fflag = 0, vflag = 0, iflag = 0, i;
00026     const char **attr;
00027     sx_error_t sxe;
00028 
00029     if(s->fail) return;
00030 
00031     /* check element and namespace */
00032     i = strlen(uri_STREAMS) + 7;
00033     if(strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|')) {
00034         /* throw an error */
00035         _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream start");
00036         _sx_event(s, event_ERROR, (void *) &sxe);
00037         _sx_error(s, stream_err_BAD_FORMAT, NULL);
00038         s->fail = 1;
00039         return;
00040     }
00041 
00042     /* pull interesting things out of the header */
00043     attr = atts;
00044     while(attr[0] != NULL) {
00045         if(!tflag && strcmp(attr[0], "to") == 0) {
00046             s->res_to = strdup(attr[1]);
00047             tflag = 1;
00048         }
00049 
00050         if(!fflag && strcmp(attr[0], "from") == 0) {
00051             s->res_from = strdup(attr[1]);
00052             fflag = 1;
00053         }
00054 
00055         if(!vflag && strcmp(attr[0], "version") == 0) {
00056             s->res_version = strdup(attr[1]);
00057             vflag = 1;
00058         }
00059 
00060         if(!iflag && strcmp(attr[0], "id") == 0) {
00061             s->id = strdup(attr[1]);
00062             iflag = 1;
00063         }
00064 
00065         attr += 2;
00066     }
00067 
00068     s->depth++;
00069 
00070     _sx_debug(ZONE, "stream response: to %s from %s version %s id %s", s->res_to, s->res_from, s->res_version, s->id);
00071 
00072     /* we're alive */
00073     XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end);
00074     XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata);
00075     XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start);
00076 
00077     /* get the plugins to setup */
00078     if(s->env != NULL)
00079         for(i = 0; i < s->env->nplugins; i++)
00080             if(s->env->plugins[i]->stream != NULL)
00081                 (s->env->plugins[i]->stream)(s, s->env->plugins[i]);
00082 
00083     /* bump us to stream if a plugin didn't do it already */
00084     if(s->state < state_STREAM) {
00085         _sx_state(s, state_STREAM);
00086         _sx_event(s, event_STREAM, NULL);
00087     }
00088 }
00089 
00090 static void _sx_client_element_end(void *arg, const char *name) {
00091     sx_t s = (sx_t) arg;
00092 
00093     if(s->fail) return;
00094 
00095     s->depth--;
00096 }
00097 
00098 static void _sx_client_notify_header(sx_t s, void *arg) {
00099     /* expat callbacks */
00100     XML_SetElementHandler(s->expat, (void *) _sx_client_element_start, (void *) _sx_client_element_end);
00101     
00102     /* state change */
00103     _sx_state(s, state_STREAM_SENT);
00104 
00105     _sx_debug(ZONE, "stream header sent, waiting for reply");
00106 
00107     /* waiting for a response */
00108     s->want_read = 1;
00109 }
00110 
00111 void sx_client_init(sx_t s, unsigned int flags, char *ns, char *to, char *from, char *version) {
00112     sx_buf_t buf;
00113     char *c;
00114     int i, len;
00115 
00116     assert((int) (s != NULL));
00117 
00118     /* can't do anything if we're alive already */
00119     if(s->state != state_NONE)
00120         return;
00121 
00122     _sx_debug(ZONE, "doing client init for sx %d", s->tag);
00123 
00124     s->type = type_CLIENT;
00125     s->flags = flags;
00126 
00127     if(ns != NULL) s->ns = strdup(ns);
00128     if(to != NULL) s->req_to = strdup(to);
00129     if(from != NULL) s->req_from = strdup(from);
00130     if(version != NULL) s->req_version = strdup(version);
00131 
00132     /* plugin */
00133     if(s->env != NULL)
00134         for(i = 0; i < s->env->nplugins; i++)
00135             if(s->env->plugins[i]->client != NULL)
00136                 (s->env->plugins[i]->client)(s, s->env->plugins[i]);
00137 
00138     _sx_debug(ZONE, "stream request: ns %s to %s from %s version %s", ns, to, from, version);
00139 
00140     /* build the stream start */
00141     len = strlen(uri_STREAMS) + 52;
00142 
00143     if(ns != NULL) len += 9 + strlen(ns);
00144     if(to != NULL) len += 6 + strlen(to);
00145     if(from != NULL) len += 8 + strlen(from);
00146     if(version != NULL) len += 11 + strlen(version);
00147 
00148     buf = _sx_buffer_new(NULL, len+1, _sx_client_notify_header, NULL);
00149     c = buf->data;
00150     strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'");
00151 
00152     if(ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", ns); }
00153     if(to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", to); }
00154     if(from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", from); }
00155     if(version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", version); }
00156 
00157     c = strchr(c, '\0'); sprintf(c, ">");
00158 
00159     assert(buf->len == strlen(buf->data)+1);
00160     buf->len --;
00161 
00162     /* plugins can mess with the header too */
00163     if(s->env != NULL)
00164         for(i = 0; i < s->env->nplugins; i++)
00165             if(s->env->plugins[i]->header != NULL)
00166                 (s->env->plugins[i]->header)(s, s->env->plugins[i], buf);
00167 
00168     _sx_debug(ZONE, "prepared stream header: %.*s", buf->len, buf->data);
00169 
00170     /* off it goes */
00171     jqueue_push(s->wbufq, buf, 0);
00172 
00173     /* we have stuff to write */
00174     s->want_write = 1;
00175     _sx_event(s, event_WANT_WRITE, NULL);
00176 }
00177