jabberd2  2.2.16
c2s/pbx_commands.c
Go to the documentation of this file.
00001 /* vim: set noet ts=4 sw=4: */
00002 /*
00003  * jabberd - Jabber Open Source Server
00004  * Copyright (c) 2009 Tomasz Sterna
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 
00037 #include "c2s.h"
00038 
00039 static int _pbx_command_part_len(char *cmd)
00040 {
00041     int i;
00042     for(i=0; *cmd != ' ' && *cmd != '\t' && *cmd != '\n' && *cmd != '\0'; cmd++, i++);
00043     return i;
00044 }
00045 
00046 static nad_t _pbx_presence_nad(int available, char *cmd)
00047 {
00048     nad_t nad;
00049     int ns;
00050     char *show = NULL;
00051 
00052     nad = nad_new();
00053     ns = nad_add_namespace(nad, uri_CLIENT, NULL);
00054     nad_append_elem(nad, ns, "presence", 0);
00055 
00056     if(!available) {
00057         nad_append_attr(nad, -1, "type", "unavailable");
00058     }
00059     else {
00060         char *cont;
00061         long int priority;
00062         char prioritystr[5]; // -128 to +127 + \0
00063 
00064         priority = strtol(cmd, &cont, 10);
00065         log_debug(ZONE, "Read %ld priority", priority);
00066         if(cmd == cont) priority = -1; // use -1 priority if not given
00067         if(priority < -128) priority = -128;
00068         if(priority > 127) priority = 127;
00069         nad_append_elem(nad, -1, "priority", 1);
00070         snprintf(prioritystr, 5, "%ld", priority);
00071         nad_append_cdata(nad, prioritystr, strlen(prioritystr), 2);
00072         if(cmd != cont) {
00073             cmd = cont;
00074             while(*cmd == ' ') { cmd++; }
00075         }
00076 
00077 
00078         if(!strncmp("CHAT", cmd, 4)) {
00079             cmd += 4;
00080             show = "chat";
00081         }
00082         if(!strncmp("ONLINE", cmd, 6)) {
00083             cmd += 6;
00084         }
00085         if(!strncmp("DND", cmd, 3)) {
00086             cmd += 3;
00087             show = "dnd";
00088         }
00089         if(!strncmp("AWAY", cmd, 4)) {
00090             cmd += 4;
00091             show = "away";
00092         }
00093         if(!strncmp("XA", cmd, 2)) {
00094             cmd += 2;
00095             show = "xa";
00096         }
00097         if(show) {
00098             nad_append_elem(nad, -1, "show", 1);
00099             nad_append_cdata(nad, show, strlen(show), 2);
00100         }
00101     }
00102 
00103     while(*cmd == ' ') { cmd++; }
00104 
00105     if(*cmd != '\0' && *cmd != '\n') {
00106         int len = strlen(cmd);
00107         nad_append_elem(nad, -1, "status", 1);
00108         nad_append_cdata(nad, cmd, len - (cmd[len-1] == '\n' ? 1 : 0), 2);
00109     }
00110 
00111     return nad;
00112 }
00113 
00118 int _pbx_process_command(c2s_t c2s, char *cmd)
00119 {
00120     jid_t jid;
00121     int action = 0, len;
00122     sess_t sess;
00123     unsigned char hashbuf[44] = "PBX";
00124     unsigned char *sesshash;
00125 
00126     sesshash = hashbuf+3;
00127 
00128     /* get command */
00129     if(!strncasecmp("START ", cmd, 6)) {
00130         cmd += 6;
00131         action = 1;
00132     }
00133     if(!strncasecmp("STOP ", cmd, 5)) {
00134         cmd += 5;
00135         action = 2;
00136     }
00137     if(action != 0) {
00138         len = _pbx_command_part_len(cmd);
00139         if(len > 0) {
00140             jid = jid_new(cmd, len);
00141             if(jid) {
00142                 cmd += len;
00143                 if(*cmd != '\0') cmd++;
00144 
00145                 shahash_r(jid_full(jid), sesshash);
00146                 sess = xhash_get(c2s->sessions, hashbuf);
00147 
00148                 switch(action) {
00149                     case 1:
00150                         log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd);
00151 
00152                         if(sess == NULL) {
00153                         /* create new session */
00154                             sess = (sess_t) calloc(1, sizeof(struct sess_st));
00155                             sess->c2s = c2s;
00156                             sess->last_activity = time(NULL);
00157                             /* put into sessions hash */
00158                             snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf);
00159                             xhash_put(c2s->sessions, sess->skey, (void *) sess);
00160                             /* generate bound resource */
00161                             sess->resources = (bres_t) calloc(1, sizeof(struct bres_st));
00162                             snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf);
00163                             sess->resources->jid = jid;
00164                             /* open SM session */
00165                             log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid));
00166                             sm_start(sess, sess->resources);
00167 
00168                             /* generate presence packet to get session online */
00169                             /* a bit hacky, but we need to emulate _some_ of the client behavior */
00170                             sess->result = _pbx_presence_nad(1, cmd);
00171                         }
00172                         else {
00173                             /* just send the presence */
00174                             sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd));
00175                         }
00176 
00177                         break;
00178 
00179                     case 2:
00180                         log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd);
00181 
00182                         if(sess != NULL) {
00183                             /* send unavailable presence */
00184                             sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd));
00185                             /* end the session */
00186                             sm_end(sess, sess->resources);
00187                             xhash_zap(c2s->sessions, sess->skey);
00188                             jqueue_push(c2s->dead_sess, (void *) sess, 0);
00189                         }
00190 
00191                         break;
00192                 }
00193 
00194                 /* TODO: respond with "OK", return 0 */
00195                 return -1;
00196             }
00197         }
00198         /* TODO: generate "ERR" response, return 0 */
00199         return -1;
00200     }
00201     if(!strncasecmp("STATUS", cmd, 6)) {
00202         log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet");
00203         return -1;
00204     }
00205     return -1;
00206 }