jabberd2  2.2.17
client.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sx.h"
22 
23 static void _sx_client_element_start(void *arg, const char *name, const char **atts) {
24  sx_t s = (sx_t) arg;
25  int tflag = 0, fflag = 0, vflag = 0, iflag = 0, i;
26  const char **attr;
27  sx_error_t sxe;
28 
29  if(s->fail) return;
30 
31  /* check element and namespace */
32  i = strlen(uri_STREAMS) + 7;
33  if(strlen(name) < i || strncmp(name, uri_STREAMS "|stream", i) != 0 || (name[i] != '\0' && name[i] != '|')) {
34  /* throw an error */
35  _sx_gen_error(sxe, SX_ERR_STREAM, "Stream error", "Expected stream start");
36  _sx_event(s, event_ERROR, (void *) &sxe);
38  s->fail = 1;
39  return;
40  }
41 
42  /* pull interesting things out of the header */
43  attr = atts;
44  while(attr[0] != NULL) {
45  if(!tflag && strcmp(attr[0], "to") == 0) {
46  s->res_to = strdup(attr[1]);
47  tflag = 1;
48  }
49 
50  if(!fflag && strcmp(attr[0], "from") == 0) {
51  s->res_from = strdup(attr[1]);
52  fflag = 1;
53  }
54 
55  if(!vflag && strcmp(attr[0], "version") == 0) {
56  s->res_version = strdup(attr[1]);
57  vflag = 1;
58  }
59 
60  if(!iflag && strcmp(attr[0], "id") == 0) {
61  s->id = strdup(attr[1]);
62  iflag = 1;
63  }
64 
65  attr += 2;
66  }
67 
68  s->depth++;
69 
70  _sx_debug(ZONE, "stream response: to %s from %s version %s id %s", s->res_to, s->res_from, s->res_version, s->id);
71 
72  /* we're alive */
73  XML_SetElementHandler(s->expat, (void *) _sx_element_start, (void *) _sx_element_end);
74  XML_SetCharacterDataHandler(s->expat, (void *) _sx_cdata);
75  XML_SetStartNamespaceDeclHandler(s->expat, (void *) _sx_namespace_start);
76 
77  /* get the plugins to setup */
78  if(s->env != NULL)
79  for(i = 0; i < s->env->nplugins; i++)
80  if(s->env->plugins[i]->stream != NULL)
81  (s->env->plugins[i]->stream)(s, s->env->plugins[i]);
82 
83  /* bump us to stream if a plugin didn't do it already */
84  if(s->state < state_STREAM) {
86  _sx_event(s, event_STREAM, NULL);
87  }
88 }
89 
90 static void _sx_client_element_end(void *arg, const char *name) {
91  sx_t s = (sx_t) arg;
92 
93  if(s->fail) return;
94 
95  s->depth--;
96 }
97 
98 static void _sx_client_notify_header(sx_t s, void *arg) {
99  /* expat callbacks */
100  XML_SetElementHandler(s->expat, (void *) _sx_client_element_start, (void *) _sx_client_element_end);
101 
102  /* state change */
104 
105  _sx_debug(ZONE, "stream header sent, waiting for reply");
106 
107  /* waiting for a response */
108  s->want_read = 1;
109 }
110 
111 void sx_client_init(sx_t s, unsigned int flags, char *ns, char *to, char *from, char *version) {
112  sx_buf_t buf;
113  char *c;
114  int i, len;
115 
116  assert((int) (s != NULL));
117 
118  /* can't do anything if we're alive already */
119  if(s->state != state_NONE)
120  return;
121 
122  _sx_debug(ZONE, "doing client init for sx %d", s->tag);
123 
124  s->type = type_CLIENT;
125  s->flags = flags;
126 
127  if(ns != NULL) s->ns = strdup(ns);
128  if(to != NULL) s->req_to = strdup(to);
129  if(from != NULL) s->req_from = strdup(from);
130  if(version != NULL) s->req_version = strdup(version);
131 
132  /* plugin */
133  if(s->env != NULL)
134  for(i = 0; i < s->env->nplugins; i++)
135  if(s->env->plugins[i]->client != NULL)
136  (s->env->plugins[i]->client)(s, s->env->plugins[i]);
137 
138  _sx_debug(ZONE, "stream request: ns %s to %s from %s version %s", ns, to, from, version);
139 
140  /* build the stream start */
141  len = strlen(uri_STREAMS) + 52;
142 
143  if(ns != NULL) len += 9 + strlen(ns);
144  if(to != NULL) len += 6 + strlen(to);
145  if(from != NULL) len += 8 + strlen(from);
146  if(version != NULL) len += 11 + strlen(version);
147 
148  buf = _sx_buffer_new(NULL, len+1, _sx_client_notify_header, NULL);
149  c = buf->data;
150  strcpy(c, "<?xml version='1.0'?><stream:stream xmlns:stream='" uri_STREAMS "'");
151 
152  if(ns != NULL) { c = strchr(c, '\0'); sprintf(c, " xmlns='%s'", ns); }
153  if(to != NULL) { c = strchr(c, '\0'); sprintf(c, " to='%s'", to); }
154  if(from != NULL) { c = strchr(c, '\0'); sprintf(c, " from='%s'", from); }
155  if(version != NULL) { c = strchr(c, '\0'); sprintf(c, " version='%s'", version); }
156 
157  c = strchr(c, '\0'); sprintf(c, ">");
158 
159  assert(buf->len == strlen(buf->data)+1);
160  buf->len --;
161 
162  /* plugins can mess with the header too */
163  if(s->env != NULL)
164  for(i = 0; i < s->env->nplugins; i++)
165  if(s->env->plugins[i]->header != NULL)
166  (s->env->plugins[i]->header)(s, s->env->plugins[i], buf);
167 
168  _sx_debug(ZONE, "prepared stream header: %.*s", buf->len, buf->data);
169 
170  /* off it goes */
171  jqueue_push(s->wbufq, buf, 0);
172 
173  /* we have stuff to write */
174  s->want_write = 1;
175  _sx_event(s, event_WANT_WRITE, NULL);
176 }
177