00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include "emimsg.h"
00065
00066
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]);
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
00251
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)
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
00290 struct emimsg *get_fields(Octstr *message, Octstr *whoami)
00291 {
00292 long trn, len, ot, checksum;
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)
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
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.