jabberd2  2.2.17
pbx_commands.c
Go to the documentation of this file.
1 /* vim: set noet ts=4 sw=4: */
2 /*
3  * jabberd - Jabber Open Source Server
4  * Copyright (c) 2009 Tomasz Sterna
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 
37 #include "c2s.h"
38 
39 static int _pbx_command_part_len(char *cmd)
40 {
41  int i;
42  for(i=0; *cmd != ' ' && *cmd != '\t' && *cmd != '\n' && *cmd != '\0'; cmd++, i++);
43  return i;
44 }
45 
46 static nad_t _pbx_presence_nad(int available, char *cmd)
47 {
48  nad_t nad;
49  int ns;
50  char *show = NULL;
51 
52  nad = nad_new();
53  ns = nad_add_namespace(nad, uri_CLIENT, NULL);
54  nad_append_elem(nad, ns, "presence", 0);
55 
56  if(!available) {
57  nad_append_attr(nad, -1, "type", "unavailable");
58  }
59  else {
60  char *cont;
61  long int priority;
62  char prioritystr[5]; // -128 to +127 + \0
63 
64  priority = strtol(cmd, &cont, 10);
65  log_debug(ZONE, "Read %ld priority", priority);
66  if(cmd == cont) priority = -1; // use -1 priority if not given
67  if(priority < -128) priority = -128;
68  if(priority > 127) priority = 127;
69  nad_append_elem(nad, -1, "priority", 1);
70  snprintf(prioritystr, 5, "%ld", priority);
71  nad_append_cdata(nad, prioritystr, strlen(prioritystr), 2);
72  if(cmd != cont) {
73  cmd = cont;
74  while(*cmd == ' ') { cmd++; }
75  }
76 
77 
78  if(!strncmp("CHAT", cmd, 4)) {
79  cmd += 4;
80  show = "chat";
81  }
82  if(!strncmp("ONLINE", cmd, 6)) {
83  cmd += 6;
84  }
85  if(!strncmp("DND", cmd, 3)) {
86  cmd += 3;
87  show = "dnd";
88  }
89  if(!strncmp("AWAY", cmd, 4)) {
90  cmd += 4;
91  show = "away";
92  }
93  if(!strncmp("XA", cmd, 2)) {
94  cmd += 2;
95  show = "xa";
96  }
97  if(show) {
98  nad_append_elem(nad, -1, "show", 1);
99  nad_append_cdata(nad, show, strlen(show), 2);
100  }
101  }
102 
103  while(*cmd == ' ') { cmd++; }
104 
105  if(*cmd != '\0' && *cmd != '\n') {
106  int len = strlen(cmd);
107  nad_append_elem(nad, -1, "status", 1);
108  nad_append_cdata(nad, cmd, len - (cmd[len-1] == '\n' ? 1 : 0), 2);
109  }
110 
111  return nad;
112 }
113 
118 int _pbx_process_command(c2s_t c2s, char *cmd)
119 {
120  jid_t jid;
121  int action = 0, len;
122  sess_t sess;
123  unsigned char hashbuf[44] = "PBX";
124  unsigned char *sesshash;
125 
126  sesshash = hashbuf+3;
127 
128  /* get command */
129  if(!strncasecmp("START ", cmd, 6)) {
130  cmd += 6;
131  action = 1;
132  }
133  if(!strncasecmp("STOP ", cmd, 5)) {
134  cmd += 5;
135  action = 2;
136  }
137  if(action != 0) {
138  len = _pbx_command_part_len(cmd);
139  if(len > 0) {
140  jid = jid_new(cmd, len);
141  if(jid) {
142  cmd += len;
143  if(*cmd != '\0') cmd++;
144 
145  shahash_r(jid_full(jid), sesshash);
146  sess = xhash_get(c2s->sessions, hashbuf);
147 
148  switch(action) {
149  case 1:
150  log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd);
151 
152  if(sess == NULL) {
153  /* create new session */
154  sess = (sess_t) calloc(1, sizeof(struct sess_st));
155  sess->c2s = c2s;
156  sess->last_activity = time(NULL);
157  /* put into sessions hash */
158  snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf);
159  xhash_put(c2s->sessions, sess->skey, (void *) sess);
160  /* generate bound resource */
161  sess->resources = (bres_t) calloc(1, sizeof(struct bres_st));
162  snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf);
163  sess->resources->jid = jid;
164  /* open SM session */
165  log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid));
166  sm_start(sess, sess->resources);
167 
168  /* generate presence packet to get session online */
169  /* a bit hacky, but we need to emulate _some_ of the client behavior */
170  sess->result = _pbx_presence_nad(1, cmd);
171  }
172  else {
173  /* just send the presence */
174  sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd));
175  }
176 
177  break;
178 
179  case 2:
180  log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd);
181 
182  if(sess != NULL) {
183  /* send unavailable presence */
184  sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd));
185  /* end the session */
186  sm_end(sess, sess->resources);
187  xhash_zap(c2s->sessions, sess->skey);
188  jqueue_push(c2s->dead_sess, (void *) sess, 0);
189  }
190 
191  break;
192  }
193 
194  /* TODO: respond with "OK", return 0 */
195  return -1;
196  }
197  }
198  /* TODO: generate "ERR" response, return 0 */
199  return -1;
200  }
201  if(!strncasecmp("STATUS", cmd, 6)) {
202  log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet");
203  return -1;
204  }
205  return -1;
206 }