jabberd2  2.6.1
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(const 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, const 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, const char *cmd)
119 {
120  jid_t jid;
121  int action = 0, len;
122  sess_t sess;
123  char hashbuf[44] = "PBX";
124  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 }
struct bres_st * bres_t
Definition: c2s.h:54
bres_t resources
Definition: c2s.h:103
Definition: nad.h:93
struct sess_st * sess_t
Definition: c2s.h:55
C2S_API void sm_end(sess_t sess, bres_t res)
Definition: sm.c:72
nad_t nad_new(void)
create a new nad
Definition: nad.c:125
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
attach new attr to the last elem
Definition: nad.c:745
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:338
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
jid_t jid_new(const char *id, int len)
make a new jid
Definition: jid.c:81
static nad_t _pbx_presence_nad(int available, const char *cmd)
Definition: pbx_commands.c:46
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:753
void log_write(log_t log, int level, const char *msgfmt,...)
Definition: log.c:104
C2S_API void sm_packet(sess_t sess, bres_t res, nad_t nad)
Definition: sm.c:86
void shahash_r(const char *str, char hashbuf[41])
convenience (originally by Thomas Muldowney)
Definition: str.c:358
list of resources bound to session
Definition: c2s.h:59
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:778
char * resource
Definition: jid.h:46
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:711
time_t last_activity
Definition: c2s.h:97
void jqueue_push(jqueue_t q, void *data, int priority)
Definition: jqueue.c:44
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
int _pbx_process_command(c2s_t c2s, const char *cmd)
process commandline
Definition: pbx_commands.c:118
Definition: jid.h:42
void xhash_zap(xht h, const char *key)
Definition: xhash.c:235
#define log_debug(...)
Definition: log.h:65
#define uri_CLIENT
Definition: uri.h:35
Definition: c2s.h:157
C2S_API void sm_start(sess_t sess, bres_t res)
Definition: sm.c:66
jqueue_t dead_sess
list of sess on the way out
Definition: c2s.h:302
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
xht sessions
sessions
Definition: c2s.h:175
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define ZONE
Definition: mio_impl.h:76
c2s_t c2s
Definition: c2s.h:75
log_t log
logging
Definition: c2s.h:196
char skey[44]
Definition: c2s.h:79
static int _pbx_command_part_len(const char *cmd)
Available commands: START jid/resource [[priority ]status] [description] - opens PBX resource session...
Definition: pbx_commands.c:39