capi4yaps/ucp.c

1802 lines
37 KiB
C
Raw Normal View History

2005-06-02 18:28:35 +00:00
/* -*- mode: c; mode: fold -*- */
# include "config.h"
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include "pager.h"
/*{{{ typedefs */
typedef struct {
# ifndef NDEBUG
# define MAGIC MKMAGIC ('u', 'c', 'p', '\0')
long magic;
# endif /* NDEBUG */
void *sp; /* the serial connection */
void *ctab; /* the conversion table */
void (*logger) (char, char *, ...);
char *uline; /* received input line */
string_t
*callid; /* caller id */
Bool xtend; /* use extended UCP version */
int send_tout; /* timeout during sending */
int send_retry; /* # of retries to send a message */
int rds_tout; /* timeout for status report */
date_t delay; /* delay message */
date_t expire; /* expire message */
Bool rds; /* request delivery status */
int cnr; /* current transaction number */
} ucp;
typedef struct {
char *AdC;
char *OAdC;
char *PID;
char *na;
char *MT;
char *Msg;
char *adc;
char *oadc;
int pid;
int mt;
string_t *msg;
} bsimple;
typedef struct {
char *AdC;
char *OAdC;
char *AC;
char *NRq;
char *NAdC;
char *NT;
char *NPID;
char *na1;
char *na2;
char *na3;
char *DD;
char *DDT;
char *VP;
char *RPID;
char *SCTS;
char *DSt;
char *Rsn;
char *DSCTS;
char *MT;
char *NB;
char *Msg;
char *MMS;
char *na4;
char *DCS;
char *MCL;
char *RPI;
char *na5;
char *na6;
char *res1;
char *res2;
char *res3;
char *res4;
char *res5;
char *adc;
char *oadc;
char *ac;
Bool nrq;
char *nadc;
int nt;
int npid;
Bool dd;
date_t ddt;
date_t vp;
int rpid;
date_t scts;
int dst;
int rsn;
date_t dscts;
int mt;
int nb;
string_t *msg;
Bool mms;
Bool dcs;
int mcl;
int rpi;
} bextend;
typedef struct {
char *Res;
char *MVP;
char *EC;
char *MSG;
Bool ack;
date_t mvp;
int ec;
char *adc;
date_t scts;
} banswer;
typedef struct {
int trn;
int len;
char ttyp;
int ot;
char *data;
int cnt;
union {
bsimple s;
bextend e;
banswer a;
} b;
int chksum;
} frame;
/*}}}*/
/*{{{ support routines */
static char_t
hex (int val)
{
switch (val) {
default:
case 0: return (char_t) '0';
case 1: return (char_t) '1';
case 2: return (char_t) '2';
case 3: return (char_t) '3';
case 4: return (char_t) '4';
case 5: return (char_t) '5';
case 6: return (char_t) '6';
case 7: return (char_t) '7';
case 8: return (char_t) '8';
case 9: return (char_t) '9';
case 10: return (char_t) 'A';
case 11: return (char_t) 'B';
case 12: return (char_t) 'C';
case 13: return (char_t) 'D';
case 14: return (char_t) 'E';
case 15: return (char_t) 'F';
}
}
static int
unhex (char ch)
{
switch (ch) {
default:
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'A':
case 'a': return 10;
case 'B':
case 'b': return 11;
case 'C':
case 'c': return 12;
case 'D':
case 'd': return 13;
case 'E':
case 'e': return 14;
case 'F':
case 'f': return 15;
}
}
/*}}}*/
/*{{{ frame basics */
static frame *
new_frame (char ttyp, int ot)
{
frame *f;
bsimple *s;
bextend *e;
banswer *a;
if (f = (frame *) malloc (sizeof (frame))) {
f -> trn = 0;
f -> len = 0;
f -> ttyp = ttyp;
f -> ot = ot;
f -> data = NULL;
f -> cnt = 0;
memset (& f -> b, 0, sizeof (f -> b));
f -> chksum = 0;
if (f -> ttyp == 'R')
switch (f -> ot) {
case 1:
case 31:
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
a = & f -> b.a;
a -> Res = NULL;
a -> MVP = NULL;
a -> EC = NULL;
a -> MSG = NULL;
a -> ack = False;
dat_clear (& a -> mvp);
a -> ec = -1;
a -> adc = NULL;
dat_clear (& a -> scts);
break;
}
else if (f -> ttyp == 'O')
switch (f -> ot) {
case 1:
case 31:
s = & f -> b.s;
s -> AdC = NULL;
s -> OAdC = NULL;
s -> PID = NULL;
s -> na = NULL;
s -> MT = NULL;
s -> Msg = NULL;
s -> adc = NULL;
s -> oadc = NULL;
s -> pid = -1;
s -> mt = -1;
s -> msg = NULL;
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
e = & f -> b.e;
e -> AdC = NULL;
e -> OAdC = NULL;
e -> AC = NULL;
e -> NRq = NULL;
e -> NAdC = NULL;
e -> NT = NULL;
e -> NPID = NULL;
e -> na1 = NULL;
e -> na2 = NULL;
e -> na3 = NULL;
e -> DD = NULL;
e -> DDT = NULL;
e -> VP = NULL;
e -> RPID = NULL;
e -> SCTS = NULL;
e -> DSt = NULL;
e -> Rsn = NULL;
e -> DSCTS = NULL;
e -> MT = NULL;
e -> NB = NULL;
e -> Msg = NULL;
e -> MMS = NULL;
e -> na4 = NULL;
e -> DCS = NULL;
e -> MCL = NULL;
e -> RPI = NULL;
e -> na5 = NULL;
e -> na6 = NULL;
e -> res1 = NULL;
e -> res2 = NULL;
e -> res3 = NULL;
e -> res4 = NULL;
e -> res5 = NULL;
e -> adc = NULL;
e -> oadc = NULL;
e -> ac = NULL;
e -> nrq = False;
e -> nadc = NULL;
e -> nt = -1;
e -> npid = -1;
e -> dd = False;
dat_clear (& e -> ddt);
dat_clear (& e -> vp);
e -> rpid = -1;
dat_clear (& e -> scts);
e -> dst = -1;
e -> rsn = -1;
dat_clear (& e -> dscts);
e -> mt = -1;
e -> nb = -1;
e -> msg = NULL;
e -> mms = False;
e -> dcs = False;
e -> mcl = -1;
e -> rpi = -1;
break;
}
}
return f;
}
static void
free_body (frame *f)
{
# define dfr(xxx) if (xxx) free (xxx)
bsimple *s;
bextend *e;
banswer *a;
s = NULL;
e = NULL;
a = NULL;
if (f -> ttyp == 'O')
switch (f -> ot) {
case 1:
case 31:
s = & f -> b.s;
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
e = & f -> b.e;
break;
}
else if (f -> ttyp == 'R')
switch (f -> ot) {
case 1:
case 31:
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
a = & f -> b.a;
break;
}
if (s) {
dfr (s -> AdC);
dfr (s -> OAdC);
dfr (s -> PID);
dfr (s -> na);
dfr (s -> MT);
dfr (s -> Msg);
dfr (s -> adc);
dfr (s -> oadc);
sfree (s -> msg);
} else if (e) {
dfr (e -> AdC);
dfr (e -> OAdC);
dfr (e -> AC);
dfr (e -> NRq);
dfr (e -> NAdC);
dfr (e -> NT);
dfr (e -> NPID);
dfr (e -> na1);
dfr (e -> na2);
dfr (e -> na3);
dfr (e -> DD);
dfr (e -> DDT);
dfr (e -> VP);
dfr (e -> RPID);
dfr (e -> SCTS);
dfr (e -> DSt);
dfr (e -> Rsn);
dfr (e -> DSCTS);
dfr (e -> MT);
dfr (e -> NB);
dfr (e -> Msg);
dfr (e -> MMS);
dfr (e -> na4);
dfr (e -> DCS);
dfr (e -> MCL);
dfr (e -> RPI);
dfr (e -> na5);
dfr (e -> na6);
dfr (e -> res1);
dfr (e -> res2);
dfr (e -> res3);
dfr (e -> res4);
dfr (e -> res5);
dfr (e -> adc);
dfr (e -> oadc);
dfr (e -> ac);
dfr (e -> nadc);
sfree (e -> msg);
} else if (a) {
dfr (a -> Res);
dfr (a -> MVP);
dfr (a -> EC);
dfr (a -> MSG);
dfr (a -> adc);
}
# undef dfr
}
static void
free_frame (frame *f)
{
if (f) {
if (f -> data)
free (f -> data);
free_body (f);
free (f);
}
}
/*}}}*/
/*{{{ assemble */
static char *
encode (ucp *u, string_t *s, Bool docv)
{
char *ret;
char_t ch;
int c;
int len;
int n, m;
len = s ? (s -> len * 2) : 0;
if (ret = malloc (len + 2)) {
for (n = 0, m = 0; n < len; ++m) {
if (docv) {
if ((c = cv_conv (u -> ctab, s -> str[m])) < 0)
continue;
ch = (char_t) c;
} else
ch = s -> str[m];
ret[n++] = hex ((ch >> 4) & 0xf);
ret[n++] = hex (ch & 0xf);
}
ret[n] = '\0';
}
return ret;
}
static inline void
gbool (char **ptr, Bool what, char *t, char *f)
{
if (*ptr)
free (*ptr);
if (what)
*ptr = t ? strdup (t) : NULL;
else
*ptr = f ? strdup (f) : NULL;
}
static inline void
gdate (char **ptr, date_t *d, int len)
{
if (*ptr)
free (*ptr);
if (d -> day > 0) {
if (*ptr = malloc (14)) {
sprintf (*ptr, "%02d%02d%02d%02d%02d%02d",
d -> day, d -> mon, d -> year % 100,
d -> hour, d -> min, d -> sec);
if (len < 12)
(*ptr)[len] = '\0';
}
} else
*ptr = NULL;
}
static inline void
gint (char **ptr, int val, char *fmt, int def)
{
if (*ptr)
free (*ptr);
if (val == -1)
val = def;
if (val != -1) {
if (*ptr = malloc (32))
sprintf (*ptr, (fmt ? fmt : "%d"), val);
} else
*ptr = NULL;
}
static inline void
gstr (char **ptr, char *str)
{
if (*ptr)
free (*ptr);
*ptr = str ? strdup (str) : NULL;
}
static string_t *
assemble_frame (ucp *u, frame *f)
{
bsimple *s;
bextend *e;
banswer *a;
string_t *ret;
Bool fail;
char buf[64], *ptr;
int len, n;
unsigned long chk;
if (! (ret = snew (NULL, 128)))
return NULL;
if (! (scopyc (ret, "\x02") && scatc (ret, "00/00000/")))
return sfree (ret);
sprintf (buf, "%c/%02d/", f -> ttyp, f -> ot);
if (! scatc (ret, buf))
return sfree (ret);
fail = False;
if (f -> ttyp == 'R') {
a = & f -> b.a;
switch (f -> ot) {
default:
fail = True;
break;
case 1:
case 31:
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
gbool (& a -> Res, a -> ack, "A", "N");
if (a -> MSG) {
free (a -> MSG);
a -> MSG = NULL;
}
if (a -> ack) {
gdate (& a -> MVP, & a -> mvp, 10);
ptr = NULL;
gdate (& ptr, & a -> scts, 12);
if (ptr) {
if (a -> adc) {
if (a -> MSG = malloc (strlen (ptr) + strlen (a -> adc) + 4))
sprintf (a -> MSG, "%s:%s", a -> adc, ptr);
free (ptr);
} else
a -> MSG = ptr;
} else if (a -> adc)
a -> MSG = strdup (a -> adc);
} else
gint (& a -> EC, a -> ec, NULL, 3);
if (((f -> ot == 1) || (f -> ot == 31)) && a -> ack) {
if (! (scatc (ret, a -> Res) && scatc (ret, "/") &&
scatc (ret, a -> MSG) && scatc (ret, "/")))
fail = True;
} else if (! (scatc (ret, a -> Res) && scatc (ret, "/") &&
scatc (ret, (a -> ack ? a -> MVP : a -> EC)) && scatc (ret, "/") &&
scatc (ret, a -> MSG) && scatc (ret, "/")))
fail = True;
break;
}
} else if (f -> ttyp == 'O') {
s = & f -> b.s;
e = & f -> b.e;
switch (f -> ot) {
default:
fail = True;
break;
case 1:
gstr (& s -> AdC, s -> adc);
gstr (& s -> OAdC, s -> oadc);
gstr (& s -> na, NULL);
gint (& s -> MT, s -> mt, NULL, 3);
if (s -> Msg)
free (s -> Msg);
s -> Msg = encode (u, s -> msg, True);
if (! (scatc (ret, s -> AdC) && scatc (ret, "/") &&
scatc (ret, s -> OAdC) && scatc (ret, "/") &&
scatc (ret, s -> na) && scatc (ret, "/") &&
scatc (ret, s -> MT) && scatc (ret, "/") &&
scatc (ret, s -> Msg) && scatc (ret, "/")))
fail = True;
break;
case 31:
gstr (& s -> AdC, s -> adc);
gint (& s -> PID, s -> pid, "%04d", -1);
if (! (scatc (ret, s -> AdC) && scatc (ret, "/") &&
scatc (ret, s -> PID) && scatc (ret, "/")))
fail = True;
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
gstr (& e -> AdC, e -> adc);
gstr (& e -> OAdC, e -> oadc);
gstr (& e -> AC, e -> ac);
gbool (& e -> NRq, e -> nrq, "1", NULL);
gstr (& e -> NAdC, (e -> nrq ? e -> nadc : NULL));
gint (& e -> NT, (e -> nrq ? e -> nt : -1), NULL, -1);
gint (& e -> NPID, (e -> nrq ? e -> npid : -1), "%04d", -1);
gstr (& e -> na1, NULL);
gstr (& e -> na2, NULL);
gstr (& e -> na3, NULL);
gbool (& e -> DD, e -> dd, "1", NULL);
if (e -> dd)
gdate (& e -> DDT, & e -> ddt, 10);
else
gstr (& e -> DDT, NULL);
gdate (& e -> VP, & e -> vp, 10);
gint (& e -> RPID, e -> rpid, "%04d", -1);
gdate (& e -> SCTS, & e -> scts, 12);
gint (& e -> DSt, e -> dst, NULL, -1);
gint (& e -> Rsn, e -> rsn, "%03d", -1);
gdate (& e -> DSCTS, & e -> dscts, 12);
gint (& e -> MT, e -> mt, NULL, 3);
if (e -> mt == 4)
if (e -> nb != -1)
len = e -> nb;
else
len = e -> msg ? e -> msg -> len * 8 : 0;
else
len = -1;
gint (& e -> NB, len, NULL, -1);
if (e -> Msg)
free (e -> Msg);
e -> Msg = encode (u, e -> msg, (e -> mt == 4 ? False : True));
gbool (& e -> MMS, e -> mms, "1", NULL);
gstr (& e -> na4, NULL);
gbool (& e -> DCS, e -> dcs, "1", NULL);
gint (& e -> MCL, e -> mcl, NULL, -1);
gint (& e -> RPI, e -> rpi, NULL, -1);
gstr (& e -> na5, NULL);
gstr (& e -> na6, NULL);
gstr (& e -> res1, NULL);
gstr (& e -> res2, NULL);
gstr (& e -> res3, NULL);
gstr (& e -> res4, NULL);
gstr (& e -> res5, NULL);
if (! (scatc (ret, e -> AdC) && scatc (ret, "/") &&
scatc (ret, e -> OAdC) && scatc (ret, "/") &&
scatc (ret, e -> AC) && scatc (ret, "/") &&
scatc (ret, e -> NRq) && scatc (ret, "/") &&
scatc (ret, e -> NAdC) && scatc (ret, "/") &&
scatc (ret, e -> NT) && scatc (ret, "/") &&
scatc (ret, e -> NPID) && scatc (ret, "/") &&
scatc (ret, e -> na1) && scatc (ret, "/") &&
scatc (ret, e -> na2) && scatc (ret, "/") &&
scatc (ret, e -> na3) && scatc (ret, "/") &&
scatc (ret, e -> DD) && scatc (ret, "/") &&
scatc (ret, e -> DDT) && scatc (ret, "/") &&
scatc (ret, e -> VP) && scatc (ret, "/") &&
scatc (ret, e -> RPID) && scatc (ret, "/") &&
scatc (ret, e -> SCTS) && scatc (ret, "/") &&
scatc (ret, e -> DSt) && scatc (ret, "/") &&
scatc (ret, e -> Rsn) && scatc (ret, "/") &&
scatc (ret, e -> DSCTS) && scatc (ret, "/") &&
scatc (ret, e -> MT) && scatc (ret, "/") &&
scatc (ret, e -> NB) && scatc (ret, "/") &&
scatc (ret, e -> Msg) && scatc (ret, "/") &&
scatc (ret, e -> MMS) && scatc (ret, "/") &&
scatc (ret, e -> na4) && scatc (ret, "/") &&
scatc (ret, e -> DCS) && scatc (ret, "/") &&
scatc (ret, e -> MCL) && scatc (ret, "/") &&
scatc (ret, e -> RPI) && scatc (ret, "/") &&
scatc (ret, e -> na5) && scatc (ret, "/") &&
scatc (ret, e -> na6) && scatc (ret, "/") &&
scatc (ret, e -> res1) && scatc (ret, "/") &&
scatc (ret, e -> res2) && scatc (ret, "/") &&
scatc (ret, e -> res3) && scatc (ret, "/") &&
scatc (ret, e -> res4) && scatc (ret, "/") &&
scatc (ret, e -> res5) && scatc (ret, "/")))
fail = True;
break;
}
} else
fail = True;
if (! fail) {
len = ret -> len - 1 + 2;
sprintf (buf, "%02d/%05d", f -> trn, len);
if (sputc (ret, buf, 1, -1)) {
for (n = 1, chk = 0; n < ret -> len; ++n)
chk += ret -> str[n] & 0xff;
if (sexpand (ret, ret -> len + 4)) {
ret -> str[ret -> len++] = hex ((chk >> 4) & 0xf);
ret -> str[ret -> len++] = hex (chk & 0xf);
ret -> str[ret -> len++] = '\x03';
}
} else
fail = True;
}
if (fail)
ret = sfree (ret);
return ret;
}
/*}}}*/
/*{{{ parse */
static date_t
parse_date (char *str)
{
date_t ret;
int n;
int val;
time_t tim;
struct tm *tt;
ret.day = 0;
ret.mon = 0;
ret.year = 0;
ret.hour = 0;
ret.min = 0;
ret.sec = 0;
if (str)
for (n = 0; (n < 6) && *str && *(str + 1); ++n) {
val = unhex (*str) * 10 + unhex (*(str + 1));
str += 2;
switch (n) {
case 0: ret.day = val; break;
case 1: ret.mon = val; break;
case 2: ret.year = val; break;
case 3: ret.hour = val; break;
case 4: ret.min = val; break;
case 5: ret.sec = val; break;
}
}
time (& tim);
if (tt = localtime (& tim))
ret.year += ((tt -> tm_year + 1900) / 100) * 100;
return ret;
}
static string_t *
parse_message (ucp *u, int mt, char *msg)
{
string_t *ret;
int len;
int n;
char_t ch;
void *ct;
if ((mt != 4) && (u -> ctab))
ct = cv_reverse (u -> ctab);
else
ct = NULL;
len = strlen (msg);
if (ret = snew (NULL, len / 2 + 2))
for (n = 0; n + 1 < len; n += 2) {
ch = (unhex (msg[n]) << 4) | unhex (msg[n + 1]);
ret -> str[ret -> len++] = cv_conv (ct, ch);
}
if (ct)
cv_free (ct);
return ret;
}
static Bool
parse_body (ucp *u, frame *f)
{
Bool ret;
char *dat, *ptr, *sav;
char **rev;
Bool done, fail;
int n;
if (! (dat = strdup (f -> data)))
return False;
ret = False;
done = False;
fail = False;
for (ptr = dat, n = 0; (! done) && (! fail) && ptr; ++n) {
sav = ptr;
if (ptr = strchr (ptr, '/'))
*ptr++ = '\0';
rev = NULL;
if (f -> ttyp == 'O') {
switch (f -> ot) {
case 1:
switch (n) {
case 0: rev = & f -> b.s.AdC; break;
case 1:
rev = & f -> b.s.OAdC;
f -> b.s.adc = f -> b.s.AdC ? strdup (f -> b.s.AdC) : NULL;
break;
case 2:
rev = & f -> b.s.na;
f -> b.s.oadc = f -> b.s.OAdC ? strdup (f -> b.s.OAdC) : NULL;
break;
case 3: rev = & f -> b.s.MT; break;
case 4:
rev = & f -> b.s.Msg;
f -> b.s.mt = f -> b.s.MT ? atoi (f -> b.s.MT) : -1;
done = True;
break;
}
break;
case 31:
switch (n) {
case 0: rev = & f -> b.s.AdC; break;
case 1:
rev = & f -> b.s.PID;
f -> b.s.adc = f -> b.s.AdC ? strdup (f -> b.s.AdC) : NULL;
done = True;
break;
}
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
switch (n) {
case 0: rev = & f -> b.e.AdC; break;
case 1:
rev = & f -> b.e.OAdC;
f -> b.e.adc = f -> b.e.AdC ? strdup (f -> b.e.AdC) : NULL;
break;
case 2:
rev = & f -> b.e.AC;
f -> b.e.oadc = f -> b.e.OAdC ? strdup (f -> b.e.OAdC) : NULL;
break;
case 3:
rev = & f -> b.e.NRq;
f -> b.e.ac = f -> b.e.AC ? strdup (f -> b.e.AC) : NULL;
break;
case 4:
rev = & f -> b.e.NAdC;
if (f -> b.e.NRq)
f -> b.e.nrq = (atoi (f -> b.e.NRq) == 1 ? True : False);
else
f -> b.e.nrq = False;
break;
case 5:
rev = & f -> b.e.NT;
f -> b.e.nadc = f -> b.e.NAdC ? strdup (f -> b.e.NAdC) : NULL;
break;
case 6:
rev = & f -> b.e.NPID;
f -> b.e.nt = f -> b.e.NT ? atoi (f -> b.e.NT) : 0;
break;
case 7:
rev = & f -> b.e.na1;
f -> b.e.npid = f -> b.e.NPID ? atoi (f -> b.e.NPID) : -1;
break;
case 8: rev = & f -> b.e.na2; break;
case 9: rev = & f -> b.e.na3; break;
case 10: rev = & f -> b.e.DD; break;
case 11:
rev = & f -> b.e.DDT;
if (f -> b.e.DD)
f -> b.e.dd = (atoi (f -> b.e.DD) == 1 ? True : False);
else
f -> b.e.dd = False;
break;
case 12:
rev = & f -> b.e.VP;
f -> b.e.ddt = parse_date (f -> b.e.DDT);
break;
case 13:
rev = & f -> b.e.RPID;
f -> b.e.vp = parse_date (f -> b.e.VP);
break;
case 14:
rev = & f -> b.e.SCTS;
f -> b.e.rpid = f -> b.e.RPID ? atoi (f -> b.e.RPID) : -1;
break;
case 15:
rev = & f -> b.e.DSt;
f -> b.e.scts = parse_date (f -> b.e.SCTS);
break;
case 16:
rev = & f -> b.e.Rsn;
f -> b.e.dst = f -> b.e.DSt ? atoi (f -> b.e.DSt) : -1;
break;
case 17:
rev = & f -> b.e.DSCTS;
f -> b.e.rsn = f -> b.e.Rsn ? atoi (f -> b.e.Rsn) : 0;
break;
case 18:
rev = & f -> b.e.MT;
f -> b.e.dscts = parse_date (f -> b.e.DSCTS);
break;
case 19:
rev = & f -> b.e.NB;
f -> b.e.mt = f -> b.e.MT ? atoi (f -> b.e.MT) : -1;
break;
case 20:
rev = & f -> b.e.Msg;
f -> b.e.nb = f -> b.e.NB ? atoi (f -> b.e.NB) : 0;
break;
case 21:
rev = & f -> b.e.MMS;
if (f -> b.e.Msg)
if (! (f -> b.e.msg = parse_message (u, f -> b.e.mt, f -> b.e.Msg)))
fail = True;
break;
case 22:
rev = & f -> b.e.na4;
if (f -> b.e.MMS)
f -> b.e.mms = (atoi (f -> b.e.MMS) == 1 ? True : False);
else
f -> b.e.mms = False;
break;
case 23: rev = & f -> b.e.DCS; break;
case 24:
rev = & f -> b.e.MCL;
if (f -> b.e.DCS)
f -> b.e.dcs = (atoi (f -> b.e.DCS) == 1 ? True : False);
else
f -> b.e.dcs = False;
break;
case 25:
rev = & f -> b.e.RPI;
f -> b.e.mcl = f -> b.e.MCL ? atoi (f -> b.e.MCL) : -1;
break;
case 26:
rev = & f -> b.e.na5;
f -> b.e.rpi = f -> b.e.RPI ? atoi (f -> b.e.RPI) : -1;
break;
case 27: rev = & f -> b.e.na6; break;
case 28: rev = & f -> b.e.res1; break;
case 29: rev = & f -> b.e.res2; break;
case 30: rev = & f -> b.e.res3; break;
case 31: rev = & f -> b.e.res4; break;
case 32:
rev = & f -> b.e.res5;
done = True;
break;
}
break;
}
} else if (f -> ttyp == 'R') {
switch (f -> ot) {
case 1:
case 31:
switch (n) {
case 0: rev = & f -> b.a.Res; break;
case 1:
if (f -> b.a.Res) {
if (f -> b.a.Res[0] == 'A') {
f -> b.a.ack = True;
rev = & f -> b.a.MSG;
done = True;
} else if (f -> b.a.Res[0] == 'N') {
f -> b.a.ack = False;
rev = & f -> b.a.EC;
} else
fail = True;
}
break;
case 2:
if (! f -> b.a.ack) {
f -> b.a.ec = f -> b.a.EC ? atoi (f -> b.a.EC) : -1;
rev = & f -> b.a.MSG;
done = True;
}
break;
}
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
switch (n) {
case 0: rev = & f -> b.a.Res; break;
case 1:
if (f -> b.a.Res) {
if (f -> b.a.Res[0] == 'A') {
f -> b.a.ack = True;
rev = & f -> b.a.MVP;
} else if (f -> b.a.Res[0] == 'N') {
f -> b.a.ack = False;
rev = & f -> b.a.EC;
} else
fail = True;
} else
fail = True;
break;
case 2:
if (f -> b.a.ack)
f -> b.a.mvp = parse_date (f -> b.a.MVP);
else
f -> b.a.ec = f -> b.a.EC ? atoi (f -> b.a.EC) : -1;
rev = & f -> b.a.MSG;
done = True;
break;
}
break;
}
} else
fail = True;
if (! fail) {
if (! rev)
fail = True;
else {
if (*sav) {
if (! (*rev = strdup (sav)))
fail = True;
} else
*rev = NULL;
}
if ((! ptr) && (! done))
fail = True;
}
}
if (done && (! fail) && (! ptr)) {
if (f -> ttyp == 'O') {
switch (f -> ot) {
case 1:
case 31:
if (f -> b.s.Msg)
if (! (f -> b.s.msg = parse_message (u, f -> b.s.mt, f -> b.s.Msg)))
fail = True;
break;
}
} else if (f -> ttyp == 'R') {
switch (f -> ot) {
case 1:
case 31:
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
if (f -> b.a.MSG) {
if (! (f -> b.a.adc = strdup (f -> b.a.MSG)))
fail = True;
else {
if (ptr = strchr (f -> b.a.adc, ':'))
*ptr++ = '\0';
f -> b.a.scts = parse_date (ptr);
}
}
break;
}
} else
fail = True;
if (! fail)
ret = True;
}
free (dat);
return ret;
}
static frame *
parse_frame (ucp *u, char *str)
{
frame *f;
char *start, *end;
char *ptr, *sav;
int n, len;
unsigned int chksum;
f = NULL;
if (str = strdup (str)) {
start = strchr (str, '\x02');
end = strchr (str, '\x03');
ptr = strrchr (str, '/');
if (start && end && (end > start) &&
ptr && (start + 1 < ptr) && (ptr + 3 == end) &&
(f = new_frame ('\0', 0))) {
memset (f, 0, sizeof (frame));
len = (int) ((unsigned long) end - (unsigned long) start) - 1;
for (chksum = 0, n = 1; n < len - 1; ++n)
chksum += (unsigned char) start[n];
chksum &= 0xff;
ptr = start + 1;
for (n = 0; n < 4; ++n) {
if (! (sav = ptr))
break;
if (ptr = strchr (ptr, '/'))
*ptr++ = '\0';
switch (n) {
case 0:
f -> trn = atoi (sav);
break;
case 1:
f -> len = atoi (sav);
break;
case 2:
f -> ttyp = *sav;
break;
case 3:
f -> ot = atoi (sav);
break;
}
}
sav = ptr;
if ((n < 4) || (f -> len != len) || (! sav) || (! (ptr = strrchr (sav, '/')))) {
free (f);
f = NULL;
} else {
f -> cnt = (int) ((unsigned long) ptr - (unsigned long) sav);
++ptr;
if (*ptr && *(ptr + 1))
f -> chksum = (unhex (*ptr) << 4) | unhex (*(ptr + 1));
else
f -> chksum = -1;
if ((chksum == f -> chksum) && (f -> data = malloc (f -> cnt + 1))) {
memcpy (f -> data, sav, f -> cnt);
f -> data[f -> cnt] = '\0';
if (! parse_body (u, f)) {
free_frame (f);
f = NULL;
}
} else {
free (f);
f = NULL;
}
}
}
free (str);
}
return f;
}
/*}}}*/
/*{{{ convert */
static string_t *
convert_ucp (ucp *u, Bool last, string_t *pagerid, string_t *msg)
{
string_t *ret;
frame *f;
int ot;
int n;
int ch;
char *adc, *oadc;
ret = NULL;
if (! u -> xtend)
ot = 1;
else
ot = 51;
if (f = new_frame ('O', ot)) {
f -> trn = u -> cnr++;
adc = sextract (pagerid);
oadc = u -> callid ? sextract (u -> callid) : NULL;
if (msg)
msg = snew (msg -> str, msg -> len);
if (u -> xtend) {
f -> b.e.adc = adc;
f -> b.e.oadc = oadc;
if (u -> rds && (u -> delay.day <= 0)) {
f -> b.e.nrq = True;
f -> b.e.nt = 7;
} else
f -> b.e.nrq = False;
if (u -> delay.day > 0) {
f -> b.e.dd = True;
f -> b.e.ddt = u -> delay;
} else
f -> b.e.dd = False;
if (u -> expire.day > 0)
f -> b.e.vp = u -> expire;
for (n = 0; n < msg -> len; ++n)
if ((ch = cv_conv (u -> ctab, msg -> str[n])) != -1)
if (ch & 0x80)
break;
if (n < msg -> len) {
f -> b.e.mt = 4;
f -> b.e.nb = msg -> len * 8;
} else
f -> b.e.mt = 3;
f -> b.e.msg = msg;
} else {
f -> b.s.adc = adc;
f -> b.s.oadc = oadc;
f -> b.s.mt = 3;
f -> b.s.msg = msg;
}
ret = assemble_frame (u, f);
free_frame (f);
}
return ret;
}
/*}}}*/
/*{{{ callback interface */
static void
grabline (void *sp, string_t *s, char_t sep, void *data)
{
ucp *u = (ucp *) data;
char *str;
MCHK (u);
if (u) {
if (u -> uline) {
free (u -> uline);
u -> uline = NULL;
}
if (str = sextract (s)) {
if (u -> uline = malloc (strlen (str) + 4))
sprintf (u -> uline, "%s%c", str, (char) sep);
free (str);
}
}
}
/*}}}*/
/*{{{ interpret originate message */
static void
interpret_originate (ucp *u, frame *f)
{
string_t *msg;
msg = NULL;
switch (f -> ot) {
case 1:
case 31:
msg = f -> b.s.msg;
break;
case 51:
case 52:
case 53:
case 55:
case 56:
case 57:
case 58:
msg = f -> b.e.msg;
break;
}
if (msg)
V (1, ("Got message type %d: `%s'\n", f -> ot, schar (msg)));
}
/*}}}*/
/*{{{ send a message */
static Bool
send_msg (ucp *u, string_t *msg, Bool wds, int *err)
{
Bool ret;
Bool dosend;
int n;
int ep;
frame *f, *ans;
banswer *an;
string_t *astr;
char *ptr;
ret = False;
dosend = True;
for (n = 0; n < 2; ++n) {
if ((! n) && dosend) {
dosend = False;
if (tty_send (u -> sp, msg -> str, msg -> len) != msg -> len) {
V (1, ("Unable to send message\n"));
*err = ERR_FAIL;
break;
}
}
if (n && (! wds))
continue;
ep = tty_expect (u -> sp, (n ? u -> rds_tout : u -> send_tout), "\x03", 1, NULL);
if ((ep != 1) || (! u -> uline)) {
if (ep < 0)
*err = ERR_FAIL;
break;
}
if (f = parse_frame (u, u -> uline)) {
switch (f -> ttyp) {
case 'R':
if (f -> b.a.ack) {
V (1, ("Message spooled\n"));
ret = True;
break;
} else {
switch (f -> b.a.ec) {
default:
ptr = "unknown error";
break;
case 1:
ptr = "checksum error";
break;
case 2:
ptr = "syntax error";
break;
case 3:
ptr = "operation not supported by system";
break;
case 4:
ptr = "operation not allowed (at this point)";
break;
case 5:
ptr = "call barring active";
break;
case 6:
ptr = "AdC invalid";
break;
case 7:
ptr = "authentication failure";
break;
case 8:
ptr = "legitimisation code for all calls, failure";
break;
case 9:
ptr = "GA not valid";
break;
case 10:
ptr = "repetition not allowed";
break;
case 11:
ptr = "legitimisation code for repetition, failure";
break;
case 12:
ptr = "priority call not allowed";
break;
case 13:
ptr = "legitimisation code for priority, failure";
break;
case 14:
ptr = "urgent message not allowed";
break;
case 15:
ptr = "legitimisation code for urgent message, failure";
break;
case 16:
ptr = "reveerse charging not allowed";
break;
case 17:
ptr = "legitimisation code for reverse charging, failure";
break;
case 18:
ptr = "deferred delivery not allowed";
break;
case 19:
ptr = "new AC not valid";
break;
case 20:
ptr = "new legitimisation code not valid";
break;
case 21:
ptr = "standard text not valid";
break;
case 22:
ptr = "time period not valid";
break;
case 23:
ptr = "message type not supported by system";
break;
case 24:
ptr = "message too long";
break;
case 25:
ptr = "requested standard text not valid";
break;
case 26:
ptr = "message type not valid for pager type";
break;
case 27:
ptr = "message not found in SMSC";
break;
case 30:
ptr = "subscriber hang-up";
break;
case 31:
ptr = "fax group not supported";
break;
case 32:
ptr = "fax message type not supported";
break;
case 33:
ptr = "address already in list (60 series)";
break;
case 34:
ptr = "address not in list (60 series)";
break;
case 35:
ptr = "list full (60 series)";
break;
}
V (1, ("Invalid message (error %d) %s\n", f -> b.a.ec, (ptr ? ptr : "")));
switch (f -> b.a.ec) {
case -1:
case 1: case 2: case 3:
case 6: case 7: case 8:
case 9: case 10: case 11:
case 12: case 13: case 14:
case 15: case 16: case 17:
case 18: case 19: case 20:
case 21: case 22: case 23:
case 24: case 25: case 26:
case 27: case 31: case 32:
case 33: case 34: case 35:
*err = ERR_FAIL;
break;
default:
*err = ERR_FATAL;
break;
}
}
break;
case 'O':
if (n && wds && (f -> ot == 53)) {
if (u -> logger) {
switch (f -> b.e.dst) {
default: ptr = NULL; break;
case 0: ptr = "delivered"; break;
case 1: ptr = "buffered"; break;
}
if (ptr)
(*u -> logger) (LG_PROTO, "UCP: message %s", ptr);
}
printf ("Message ");
switch (f -> b.e.dst) {
case 0: printf ("delivered"); break;
case 1: printf ("buffered"); break;
case 2: printf ("not delivered"); break;
default:
printf ("failed");
break;
}
printf (" (%d)", f -> b.e.rsn);
switch (f -> b.e.rsn) {
default:
ptr = "unknown error";
break;
case 0x01:
ptr = "successful delivered";
break;
case 0x02: case 0x03: case 0x04:
case 0x05: case 0x06: case 0x07:
ptr = "temporary no service";
break;
case 0x09:
ptr = "unknown service";
break;
case 0x0a:
ptr = "network timeout";
break;
case 0x32:
ptr = "storing time expired";
break;
case 0x64:
ptr = "service not supported";
break;
case 0x65:
ptr = "receiver unknown";
break;
case 0x66:
ptr = "service not available";
break;
case 0x67:
ptr = "call locked";
break;
case 0x68:
ptr = "operation locked";
break;
case 0x69:
ptr = "service center overrun";
break;
case 0x6a:
ptr = "service not supported";
break;
case 0x6b:
ptr = "receiver temporary not reachable";
break;
case 0x6c:
ptr = "delivering error";
break;
case 0x6d:
ptr = "receiver run out of memory";
break;
case 0x6e:
ptr = "protocol error";
break;
case 0x6f:
ptr = "receiver does not support service";
break;
case 0x70:
ptr = "unknown serice center";
break;
case 0x71:
ptr = "service center overrun";
break;
case 0x72:
ptr = "illegal receiving device";
break;
case 0x73:
ptr = "receiver no customer";
break;
case 0x74:
ptr = "error in receiving device";
break;
case 0x75:
ptr = "lower protocol not available";
break;
case 0x76:
ptr = "system error";
break;
case 0x77:
ptr = "PLMN system error";
break;
case 0x78:
ptr = "HLR system error";
break;
case 0x79:
ptr = "VLR system error";
break;
case 0x7a:
ptr = "previous VLR system error";
break;
case 0x7b:
ptr = "error on delivering (check receiver ID)";
break;
case 0x7c:
ptr = "VMSC system error";
break;
case 0x7d:
ptr = "EIR system error";
break;
case 0x7e:
ptr = "system error";
break;
case 0x7f:
ptr = "unexpected data";
break;
case 0xc8:
ptr = "addressing error for service center";
break;
case 0xc9:
ptr = "invalid absolute storing time";
break;
case 0xca:
ptr = "message too large";
break;
case 0xcb:
ptr = "GDM message cannot be extracted";
break;
case 0xcc:
ptr = "translation into IA5 not possible";
break;
case 0xcd:
ptr = "invalid format of storing time";
break;
case 0xce:
ptr = "invalid receiver address";
break;
case 0xcf:
ptr = "message sent twice";
break;
case 0xd0:
ptr = "invalid message type";
break;
}
if (ptr)
printf (" reason is %s", ptr);
if (f -> b.e.msg)
printf (": %s", schar (f -> b.e.msg));
printf ("\n");
} else {
if (! n)
--n;
interpret_originate (u, f);
}
if (ans = new_frame ('R', f -> ot)) {
ans -> trn = f -> trn;
an = & ans -> b.a;
an -> adc = u -> callid ? sextract (u -> callid) : NULL;
dat_localtime (& an -> scts);
switch (f -> ot) {
case 1:
an -> ack = False;
an -> ec = 23;
break;
case 31:
an -> ack = True;
dosend = True;
break;
case 51:
an -> ack = False;
an -> ec = 23;
break;
case 52:
an -> ack = True;
break;
case 53:
an -> ack = True;
break;
case 55:
an -> ack = False;
an -> ec = 23;
break;
case 56:
an -> ack = False;
an -> ec = 23;
break;
case 57:
an -> ack = True;
break;
case 58:
an -> ack = True;
break;
}
if (astr = assemble_frame (u, ans)) {
if (tty_send (u -> sp, astr -> str, astr -> len) != astr -> len) {
V (1, ("Unable to send answer\n"));
*err = ERR_FAIL;
}
sfree (astr);
}
free_frame (ans);
}
break;
}
free_frame (f);
if (*err != NO_ERR)
break;
}
}
return ret;
}
/*}}}*/
/*{{{ login/logout/transmit */
int
ucp_login (void *up, string_t *callid)
{
ucp *u = (ucp *) up;
MCHK (u);
if ((! u) || (! u -> sp))
return ERR_ABORT;
u -> cnr = 0;
u -> callid = sfree (u -> callid);
if (callid && (! (u -> callid = snew (callid -> str, callid -> len))))
return ERR_ABORT;
return NO_ERR;
}
int
ucp_logout (void *up)
{
MCHK ((ucp *) up);
return NO_ERR;
}
int
ucp_transmit (void *up, string_t *pagerid, string_t *msg, Bool last)
{
ucp *u = (ucp *) up;
int n, err;
Bool done;
string_t *smsg;
MCHK (u);
if ((! u) || (! u -> sp))
return ERR_FATAL;
err = NO_ERR;
tty_set_line_callback (u -> sp, grabline, "\x03", (void *) u);
for (n = 0; n < u -> send_retry; ++n)
if (smsg = convert_ucp (u, last, pagerid, msg)) {
done = send_msg (u, smsg, (u -> delay.day > 0 ? False : u -> rds), & err);
sfree (smsg);
if (done || (err != NO_ERR))
break;
}
if ((n == u -> send_retry) || (err != NO_ERR)) {
if (err == NO_ERR)
err = ERR_FAIL;
V (1, ("Unable to send message\n"));
}
tty_set_line_callback (u -> sp, NULL, NULL, NULL);
if (u -> uline) {
free (u -> uline);
u -> uline = NULL;
}
return err;
}
/*}}}*/
/*{{{ configuration */
void
ucp_config (void *up, void (*logger) (char, char *, ...),
Bool xtend, int stout, int retry, int rtout,
date_t *delay, date_t *expire, Bool rds)
{
ucp *u = (ucp *) up;
MCHK (u);
if (u) {
u -> logger = logger;
u -> xtend = xtend;
if (u -> xtend)
u -> rds = rds;
else {
u -> rds = False;
dat_clear (& u -> delay);
dat_clear (& u -> expire);
}
if (stout >= 0)
u -> send_tout = stout;
if (retry >= 0)
u -> send_retry = retry;
if (rtout >= 0)
u -> rds_tout = rtout;
if (u -> xtend) {
if (delay)
u -> delay = *delay;
if (expire)
u -> expire = *expire;
}
}
}
void
ucp_set_convtable (void *up, void *ctab)
{
ucp *u = (ucp *) up;
MCHK (u);
if (u) {
if (u -> ctab)
cv_free (u -> ctab);
u -> ctab = ctab;
}
}
void
ucp_add_convtable (void *up, void *ctab)
{
ucp *u = (ucp *) up;
MCHK (u);
if (u) {
if (! u -> ctab)
u -> ctab = cv_new ();
if (u -> ctab)
cv_merge (u -> ctab, ctab, True);
}
}
/*}}}*/
/*{{{ new/free/etc */
void *
ucp_new (void *sp)
{
ucp *u;
if (u = (ucp *) malloc (sizeof (ucp))) {
# ifndef NDEBUG
u -> magic = MAGIC;
# endif /* NDEBUG */
u -> sp = sp;
u -> ctab = NULL;
u -> logger = NULL;
u -> uline = NULL;
u -> callid = NULL;
u -> xtend = False;
u -> send_tout = 60;
u -> send_retry = 3;
u -> rds_tout = 40;
dat_clear (& u -> delay);
dat_clear (& u -> expire);
u -> rds = False;
u -> cnr = 0;
}
return (void *) u;
}
void *
ucp_free (void *up)
{
ucp *u = (ucp *) up;
MCHK (u);
if (u) {
if (u -> ctab)
cv_free (u -> ctab);
if (u -> uline)
free (u -> uline);
if (u -> callid)
sfree (u -> callid);
free (u);
}
return NULL;
}
int
ucp_preinit (void)
{
return 0;
}
void
ucp_postdeinit (void)
{
}
/*}}}*/