Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

emimsg.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * emimsg.c
00059  *
00060  * Functions for working with EMI messages
00061  * Uoti Urpala 2001 */
00062 
00063 
00064 #include "emimsg.h"
00065 
00066 /* Return an error string corresponding to the number. */
00067 static char *emi_strerror(int errnum)
00068 {
00069     switch (errnum) {
00070     case  1: return "Checksum error";
00071     case  2: return "Syntax error";
00072     case  3: return "Operation not supported by system";
00073     case  4: return "Operation not allowed";
00074     case  5: return "Call barring active";
00075     case  6: return "AdC invalid";
00076     case  7: return "Authentication failure";
00077     case  8: return "Legitimisation code for all calls, failure";
00078     case  9: return "GA not valid";
00079     case 10: return "Repetition not allowed";
00080     case 11: return "Legitimisation code for repetition, failure";
00081     case 12: return "Priority call not allowed";
00082     case 13: return "Legitimisation code for priority call, failure";
00083     case 14: return "Urgent message not allowed";
00084     case 15: return "Legitimisation code for urgent message, failure";
00085     case 16: return "Reverse charging not allowed";
00086     case 17: return "Legitimisation code for reverse charging, failure";
00087     case 18: return "Deferred delivery not allowed";
00088     case 19: return "New AC not valid";
00089     case 20: return "New legitimisation code not valid";
00090     case 21: return "Standard text not valid";
00091     case 22: return "Time period not valid";
00092     case 23: return "Message type not supported by system";
00093     case 24: return "Message too long";
00094     case 25: return "Requested standard text not valid";
00095     case 26: return "Message type not valid for the pager type";
00096     case 27: return "Message not found in smsc";
00097     case 30: return "Subscriber hang-up";
00098     case 31: return "Fax group not supported";
00099     case 32: return "Fax message type not supported";
00100     case 33: return "Address already in list (60 series)";
00101     case 34: return "Address not in list (60 series)";
00102     case 35: return "List full, cannot add address to list (60 series)";
00103     case 36: return "RPID already in use";
00104     case 37: return "Delivery in progress";
00105     case 38: return "Message forwarded";
00106     default: return "!UNRECOGNIZED ERROR CODE!";
00107     }
00108 }
00109 
00110 
00111 static int field_count_op(int ot, Octstr *whoami)
00112 {
00113     switch (ot) {
00114     case 01:
00115     return SZ01;
00116     case 31:
00117     return 2;
00118     case 51:
00119     case 52:
00120     case 53:
00121     return SZ50;
00122     case 60:
00123     return SZ60;
00124     default:
00125     error(0, "EMI2[%s]: Unsupported EMI operation request type %d", 
00126           octstr_get_cstr(whoami), ot);
00127     return -1;
00128     }
00129 }
00130 
00131 
00132 static int field_count_reply(int ot, int posit, Octstr *whoami)
00133 {
00134     switch(ot) {
00135     case 01:
00136     return posit ? 2 : 3;
00137     case 31:
00138     return posit ? 2 : 3;
00139     case 51:
00140     case 52:
00141     case 53:
00142     return 3;
00143     case 60:
00144     return posit ? 2 : 3;
00145     default:
00146     error(0, "EMI2[%s]: Unsupported EMI operation reply type %d", 
00147           octstr_get_cstr(whoami), ot);
00148     return -1;
00149     }
00150 }
00151 
00152 
00153 static struct emimsg *emimsg_create_withlen(int len)
00154 {
00155     struct emimsg *ret;
00156 
00157     ret = gw_malloc(sizeof(struct emimsg));
00158     ret->fields = gw_malloc(len * sizeof(Octstr *));
00159     ret->num_fields = len;
00160     while (--len >= 0)
00161     ret->fields[len] = NULL;
00162     return ret;
00163 }
00164 
00165 
00166 struct emimsg *emimsg_create_op(int ot, int trn, Octstr *whoami)
00167 {
00168     int len;
00169     struct emimsg *ret;
00170 
00171     len = field_count_op(ot, whoami);
00172     if (len < 0)
00173     return NULL;
00174     ret = emimsg_create_withlen(len);
00175     ret->ot = ot;
00176     ret->or = 'O';
00177     ret->trn = trn;
00178     return ret;
00179 }
00180 
00181 
00182 static struct emimsg *emimsg_create_reply_s(int ot, int trn, int positive,
00183         Octstr *whoami)
00184 {
00185     int len;
00186     struct emimsg *ret;
00187 
00188     len = field_count_reply(ot, positive, whoami);
00189     if (len < 0)
00190     return NULL;
00191     ret = emimsg_create_withlen(len);
00192     ret->ot = ot;
00193     ret->or = 'R';
00194     ret->trn = trn;
00195     return ret;
00196 }
00197 
00198 
00199 struct emimsg *emimsg_create_reply(int ot, int trn, int positive, 
00200         Octstr *whoami)
00201 {
00202     struct emimsg *ret;
00203 
00204     ret = emimsg_create_reply_s(ot, trn, positive, whoami);
00205     if (ret) {
00206     if (positive)
00207         ret->fields[0] = octstr_create("A");
00208     else
00209         ret->fields[0] = octstr_create("N");
00210     }
00211     return ret;
00212 }
00213 
00214 
00215 void emimsg_destroy(struct emimsg *emimsg)
00216 {
00217     int len;
00218 
00219     len = emimsg->num_fields;
00220     while (--len >= 0) {
00221         octstr_destroy(emimsg->fields[len]);  /* octstr_destroy(NULL) is ok */
00222         emimsg->fields[len] = NULL;
00223     }
00224     gw_free(emimsg->fields);
00225     gw_free(emimsg);
00226 }
00227 
00228 
00229 struct emimsg *emimsg_duplicate(struct emimsg *emimsg)
00230 {
00231     int len;
00232     struct emimsg *ret;
00233 
00234     len = emimsg->num_fields;
00235     if (len < 0)
00236         return NULL;
00237     ret = gw_malloc(sizeof(struct emimsg));
00238     ret->fields = gw_malloc(len * sizeof(Octstr *));
00239     ret->num_fields = len;
00240     while (--len >= 0)
00241         ret->fields[len] = octstr_duplicate(emimsg->fields[len]);
00242     ret->ot = emimsg->ot;
00243     ret->or = emimsg->or;
00244     ret->trn = emimsg->trn;
00245 
00246     return ret;
00247 }
00248 
00249 
00250 /* The argument can be either the whole message (with the stx/etx start/end
00251    characters), or miss the last 3 characters (checksum digits and etx) */
00252 static int calculate_checksum(Octstr *message)
00253 {
00254     int end, i, checksum;
00255 
00256     end = octstr_len(message);
00257     if (octstr_get_char(message, end - 1) == 3)  /* etx, whole message */
00258     end -= 3;
00259     checksum = 0;
00260     for (i = 1; i < end; i++)
00261     checksum += octstr_get_char(message, i);
00262     return checksum & 0xff;
00263 }
00264 
00265 
00266 static Octstr *emimsg_tostring(struct emimsg *emimsg)
00267 {
00268     int i, checksum;
00269     Octstr *result, *data;
00270     char *hexits = "0123456789ABCDEF";
00271 
00272     data = octstr_create("");
00273     for (i = 0; i < emimsg->num_fields; i++) {
00274     if (emimsg->fields[i])
00275         octstr_append(data, emimsg->fields[i]);
00276     octstr_append_char(data, '/');
00277     }
00278     result = octstr_format("\02%02d/%05d/%c/%02d/%S", emimsg->trn,
00279         octstr_len(data) + 16, emimsg->or, emimsg->ot, data);
00280     checksum = calculate_checksum(result);
00281     octstr_append_char(result, hexits[checksum >> 4 & 15]);
00282     octstr_append_char(result, hexits[checksum & 15]);
00283     octstr_append_char(result, 3);
00284     octstr_destroy(data);
00285     return result;
00286 }
00287 
00288 
00289 /* Doesn't check that the string is strictly according to format */
00290 struct emimsg *get_fields(Octstr *message, Octstr *whoami)
00291 {
00292     long trn, len, ot, checksum; /* because of Octstr_parse_long... */
00293     char or, posit;
00294     long fieldno, pos, pos2;
00295     struct emimsg *result = NULL;
00296 
00297     debug("smsc.emi2", 0, "EMI2[%s]: emi2 parsing packet: <%s>",
00298       octstr_get_cstr(whoami), octstr_get_cstr(message));
00299     if (octstr_get_char(message, 0) != 2 ||
00300     octstr_get_char(message, octstr_len(message) - 1) != 3)
00301     goto error;
00302     if (octstr_parse_long(&trn, message, 1, 10) != 3)
00303     goto error;
00304     if (octstr_parse_long(&len, message, 4, 10) != 9)
00305     goto error;
00306     if (octstr_len(message) != len + 2)     /* +2 for start/end markers */
00307     goto error;
00308     if ( (or = octstr_get_char(message, 10)) != 'O' && or != 'R')
00309     goto error;
00310     if (octstr_parse_long(&ot, message, 12, 10) != 14)
00311     goto error;
00312     if (or == 'O')
00313     result = emimsg_create_op(ot, trn, whoami);
00314     else {
00315     posit = octstr_get_char(message, 15);
00316     if (posit == 'A')
00317         result = emimsg_create_reply_s(ot, trn, 1, whoami);
00318     else if (posit == 'N')
00319         result = emimsg_create_reply_s(ot, trn, 0, whoami);
00320     else
00321         goto error;
00322     }
00323     if (result == NULL)
00324     goto error;
00325     pos2 = 14;
00326     for (fieldno = 0; fieldno < result->num_fields; fieldno++) {
00327     pos = pos2 + 1;
00328     if ( (pos2 = octstr_search_char(message, '/', pos)) == -1)
00329         goto error;
00330     if (pos2 > pos)
00331         result->fields[fieldno] = octstr_copy(message, pos, pos2 - pos);
00332     }
00333     if (octstr_search_char(message, '/', pos2 + 1) != -1) {
00334     int extrafields = 0;
00335 
00336     pos = pos2;
00337     while ((pos = octstr_search_char(message, '/', pos + 1)) != -1) {
00338         extrafields++;
00339         pos2 = pos;
00340     }
00341     /* The extra fields are ignored */
00342     warning(0, "get_fields: EMI message of type %d/%c has %d more fields "
00343         "than expected.", result->ot, result->or, extrafields);
00344     }
00345     if (octstr_parse_long(&checksum, message, pos2 + 1, 16) !=
00346     octstr_len(message) - 1 || checksum != calculate_checksum(message))
00347     goto error;
00348     if (result->or == 'R' && octstr_get_char(result->fields[0], 0) == 'N') {
00349     long errcode;
00350     if (!result->fields[1] ||
00351         octstr_parse_long(&errcode, result->fields[1], 0, 10) != 2)
00352         goto error;
00353     error(0, "EMI2[%s]: Got negative ack. op:%d, trn:%d, error:%ld (%s), message:%s",
00354           octstr_get_cstr(whoami),
00355           result->ot, result->trn, errcode, emi_strerror(errcode),
00356           result->fields[2] ? octstr_get_cstr(result->fields[2]) : "");
00357     }
00358     return result;
00359 error:
00360     error(0, "EMI2[%s]: Invalid EMI packet: %s", octstr_get_cstr(whoami),
00361       octstr_get_cstr(message));
00362     if (result)
00363     emimsg_destroy(result);
00364     return NULL;
00365 }
00366 
00367 
00368 int emimsg_send(Connection *conn, struct emimsg *emimsg, Octstr *whoami)
00369 {
00370     Octstr *string;
00371 
00372     string = emimsg_tostring(emimsg);
00373     if (!string) {
00374     error(0, "EMI2[%s]: emimsg_send: conversion to string failed",
00375           octstr_get_cstr(whoami));
00376     return -1;
00377     }
00378     if (emimsg->ot == 60)
00379     debug("smsc.emi2", 0, "EMI2[%s]: Sending operation type 60, message with "
00380           "password not shown in log file.", octstr_get_cstr(whoami));
00381     else
00382     debug("smsc.emi2", 0, "EMI2[%s]: emi2 sending packet: <%s>",
00383           octstr_get_cstr(whoami), octstr_get_cstr(string));
00384     if (conn_write(conn, string) == -1) {
00385     octstr_destroy(string);
00386     error(0, "EMI2[%s]: emimsg_send: write failed",
00387           octstr_get_cstr(whoami));
00388     return -1;
00389     }
00390     octstr_destroy(string);
00391     return 1;
00392 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.