📄 yaps.c
字号:
/* -*- mode: c; mode: fold -*- *//*{{{ includes */# include "config.h"# include <stdio.h># include <stdlib.h># include <stdarg.h># include <ctype.h># include <unistd.h># include <string.h># include <signal.h># include <time.h># include <setjmp.h># include <sys/types.h># include <sys/stat.h># if HAVE_LOCALE_H# include <locale.h># endif /* HAVE_LOCALE_H */# if HAVE_GETOPT_H# include <getopt.h># endif /* HAVE_GETOPT_H */# include "pager.h"# include "valid.h"/*}}}*//*{{{ general definitions */# define VERSION "0.96 (alpha software)"# ifndef LIBDIR# define LIBDIR NULL# endif /* LIBDIR */# if HAVE_SIGSETJMP# undef jmp_buf# define jmp_buf sigjmp_buf# undef setjmp# define setjmp(xx) sigsetjmp ((xx), 1)# undef longjmp# define longjmp(xx,vv) siglongjmp ((xx), (vv))# endif /* HAVE_SIGSETJMP */# define SPLIT_TERM " ..."# define SPLIT_INIT "... "# define OOM fprintf (stderr, "Out of memory in line %d, aborted\n", __LINE__)/*}}}*//*{{{ configuration file entry names and default values */# define CONFIG_SEP ","# define SEC_ALIAS "alias"# define CFG_SERVICES "services"# define CFG_CALLID "call-id"# define CFG_SIG "signature"# define CFG_USESIG "use-signature"# define CFG_VERBOSE "verbose"# define CFG_LOGFILE "logfile"# define CFG_LOGSTR "logstring"# define CFG_MODEMS "modems"# define CFG_FREPORT "final-report"# define CFG_SPEED "speed"# define CFG_BPB "bits-per-byte"# define CFG_PARITY "parity"# define CFG_SB "stopbits"# define CFG_PHONE "phone"# define CFG_PROTOCOL "protocol"# define CFG_MAXSIZE "max-size"# define CFG_MAYSPLIT "may-split"# define CFG_MAXMSGS "max-messages"# define CFG_TRUNCATE "truncate"# define CFG_USECID "use-call-id"# define CFG_RMCID "rm-invalids-cid,remove-invalid-character-call-id"# define CFG_RMPID "rm-invalids-pid,remove-invalid-character-pager-id"# define CFG_INSPID "insert-pager-id"# define CFG_CHPID "change-pid,change-pager-id"# define CFG_VALPID "valid-pid,valid-pager-id"# define CFG_CHCID "change-cid,change-call-id"# define CFG_VALCID "valid-cid,valid-call-id"# define CFG_CONVTAB "conv-table"# define CFG_CONVERT "convert"# define CFG_COST "cost"# define CFG_FORCE "force"# define CFG_CANDELAY "can-delay"# define CFG_CANEXP "can-expire"# define CFG_CANRDS "can-rds,can-request-delivery-status"# define CFG_DORDS "rds,request-delivery-status"# define CFG_CHKCID "check-call-id"# define CFG_CHKPID "check-pager-id"# define CFG_DEVICE "device"# define CFG_LCKPRE "lock-prefix"# define CFG_LCKMETHOD "lock-method"# define CFG_INIT "init"# define CFG_LINIT "local-init"# define CFG_DIAL "dial"# define CFG_TIMEOUT "timeout"# define CFG_RESET "reset"# define DEF_SPEED 38400# define DEF_BPB 8# define DEF_PARITY "n"# define DEF_SB 1# define DEF_USECID False# define DEF_INSPID False# define DEF_CONVTAB NULL# define DEF_CONVERT NULL# define DEF_DEVICE "/dev/modem"# define DEF_LCKPRE "/usr/spool/uucp/LCK.."# define DEF_LCKMETHOD NULL# define DEF_INIT "\\r !d ATZ\\r <OK ATE0V1Q0\\r <OK"# define DEF_LINIT NULL# define DEF_DIAL "ATD%L\\r <60CONNECT|BUSY|NO\\sCARRIER|NO\\sDIALTONE"# define DEF_TIMEOUT 10# define DEF_RESET "ATZ\\r <OK"/*{{{{ ASCII protocol *//* * ASCII protocol specific */# define CFG_ATOUT "asc-timeout"# define CFG_ALOGIN "asc-login"# define CFG_ALOGOUT "asc-logout"# define CFG_APID "asc-pagerid"# define CFG_AMSG "asc-message" # define CFG_ANEXT "asc-next"# define CFG_ASYNC "asc-sync"# define DEF_ATOUT -1# define DEF_ALOGIN NULL# define DEF_ALOGOUT NULL# define DEF_APID "\\P\\r"# define DEF_AMSG "\\M\\r" # define DEF_ANEXT NULL# define DEF_ASYNC "!f"/*}}}*//*{{{ Script protocol *//* * Script specific */# define CFG_STYP "script-type"# define CFG_SNAME "script-name"# define CFG_SLOGIN "scr-login"# define CFG_SLOGOUT "scr-logout"# define CFG_SPID "scr-pagerid"# define CFG_SMSG "scr-message"# define CFG_SNEXT "scr-next"# define CFG_SSYNC "scr-sync"# define DEF_STYP NULL# define DEF_SNAME NULL# define DEF_SLOGIN "login"# define DEF_SLOGOUT "logout"# define DEF_SPID "pagerid"# define DEF_SMSG "message"# define DEF_SNEXT "next"# define DEF_SSYNC "sync"/*}}}*//*{{{ TAP *//* * TAP specific */# define CFG_TOLD "tap-old"# define CFG_T1 "tap-t1,tap-init-timeout"# define CFG_T2 "tap-t2"# define CFG_T3 "tap-t3,tap-timeout"# define CFG_T4 "tap-t4"# define CFG_T5 "tap-t5"# define CFG_N1 "tap-n1,tap-init-count"# define CFG_N2 "tap-n2,tap-transmit-count"# define CFG_N3 "tap-n3"# define CFG_TLICNT "tap-login-count"# define CFG_TLOCNT "tap-logout-count"# define DEF_TOLD False# define DEF_T1 -1# define DEF_T2 -1# define DEF_T3 -1# define DEF_T4 -1# define DEF_T5 -1# define DEF_N1 -1# define DEF_N2 -1# define DEF_N3 -1# define DEF_TLICNT -1# define DEF_TLOCNT -1/*}}}*//*{{{ UCP *//* * UCP specific */# define CFG_USTOUT "ucp-timeout"# define CFG_URETRY "ucp-retry"# define CFG_UXTEND "ucp-extend"# define CFG_URTOUT "ucp-ds-timeout,ucp-delivery-status-timeout"# define DEF_USTOUT -1# define DEF_URETRY -1# define DEF_UXTEND False# define DEF_URTOUT -1/*}}}*//*}}}*//*{{{ typedefs and statics */typedef enum { NotTried, CantDial, NotSend, CantSend} Reason;typedef struct { Bool success; Reason reason; char *rmsg;} status;typedef struct _serv { char *name; valid_t *pchk; valid_t *cchk; struct _serv *next;} serv;typedef struct { int nr; char *callid; char *alias; char *pid; char *service; Protocol prot; string_t *msg; serv *s; /* Status for each message */ status st;} message;static Bool dojump;static Bool jumpdone;static jmp_buf env, termenv;static char *logfile;static char *logstr;/*}}}*//*{{{ signal handler & logging */static# if SIG_VOID_RETURNvoid# endif /* SIG_VOID_RETURN */# if SIG_INT_RETURNint# endif /* SIG_INT_RETURN */handler (int sig){# if SYSV_SIGNAL signal (sig, handler);# endif /* SYSV_SIGNAL */ switch (sig) { case SIGINT: case SIGHUP: if (dojump) { dojump = False; longjmp (env, sig); } break; case SIGQUIT: case SIGTERM: if (! jumpdone) { jumpdone = True; if (dojump) { dojump = False; longjmp (env, sig); } else longjmp (termenv, sig); } break; }# if SIG_INT_RETURN return 0;# endif /* SIG_INT_RETURN */}static voiddo_log (char typ, char *fmt, ...){ va_list par; FILE *fp; int omask; time_t tim; struct tm *tt; va_start (par, fmt); omask = umask (003); if (logfile && ((! logstr) || strchr (logstr, typ)) && (fp = fopen (logfile, "a"))) { time (& tim); if (tt = localtime (& tim)) fprintf (fp, "[%2d.%02d.%04d %02d:%02d:%02d] %c ", tt -> tm_mday, tt -> tm_mon + 1, tt -> tm_year + 1900, tt -> tm_hour, tt -> tm_min, tt -> tm_sec, typ); vfprintf (fp, fmt, par); fprintf (fp, "\n"); fclose (fp); } umask (omask); va_end (par);}/*}}}*//*{{{ dialing */static char *mkrealphone (char *phone, char *pagerid){ char *dst; int siz, n, len; char *ptr; siz = strlen (phone) + 16; if (dst = malloc (siz + 2)) { for (n = 0; *phone; ) if (*phone == '%') { ++phone; if (*phone) { ptr = NULL; switch (*phone) { case 'P': ptr = pagerid; break; } if (ptr) { len = strlen (ptr); if (n + len >= siz) { siz = n + len + 64; if (! (dst = Realloc (dst, siz + 2))) break; } strcpy (dst + n, ptr); n += len; } ++phone; } } else { if (n >= siz) { siz += 32; if (! (dst = Realloc (dst, siz + 2))) break; } dst[n++] = *phone++; } if (dst) dst[n] = '\0'; } return dst;}static void *do_dial (void *cfg, char *service, char *pagerid, char **modem){ void *sp; char *tmp, *sav, *ptr; char *t2, *s2, *p2; char *device, *lckpre, *lckmethod; int speed, rspeed, bpb, parity, sb; int tout; char *minit, *linit, *dial, *reset, *phone; int siz, len; int n, m; sp = NULL; *modem = NULL; if ((! (tmp = cfg_get (cfg, service, CFG_MODEMS, NULL))) || (! (tmp = strdup (tmp)))) return NULL; speed = cfg_iget (cfg, service, CFG_SPEED, DEF_SPEED); bpb = cfg_iget (cfg, service, CFG_BPB, DEF_BPB); if (ptr = cfg_get (cfg, service, CFG_PARITY, DEF_PARITY)) parity = *ptr; else parity = '\0'; sb = cfg_iget (cfg, service, CFG_SB, DEF_SB); dial = NULL; reset = NULL; tout = 0; for (ptr = tmp; *ptr; ) { sav = ptr; ptr = skipch (ptr, ','); device = cfg_get (cfg, sav, CFG_DEVICE, DEF_DEVICE); lckpre = cfg_get (cfg, sav, CFG_LCKPRE, DEF_LCKPRE); lckmethod = cfg_get (cfg, sav, CFG_LCKMETHOD, DEF_LCKMETHOD); minit = cfg_get (cfg, sav, CFG_INIT, DEF_INIT); linit = cfg_get (cfg, sav, CFG_LINIT, DEF_LINIT); dial = cfg_get (cfg, sav, CFG_DIAL, DEF_DIAL); reset = cfg_get (cfg, sav, CFG_RESET, NULL); tout = cfg_iget (cfg, sav, CFG_TIMEOUT, DEF_TIMEOUT); rspeed = cfg_block_iget (cfg, sav, CFG_SPEED, speed); if (device && (t2 = strdup (device))) { for (p2 = t2; *p2; ) { s2 = p2; p2 = skipch (p2, ','); V (3, ("Trying to open %s for modem %s\n", s2, sav)); if (sp = tty_open (s2, lckpre, lckmethod)) { if (tty_setup (sp, True, True, rspeed, bpb, sb, parity) != -1) { if (! (n = setjmp (env))) { dojump = True; tty_hangup (sp, 500); if (((! minit) || (tty_send_expect (sp, tout, minit, NULL) != -1)) && ((! linit) || (tty_send_expect (sp, tout, linit, NULL) != -1))) { dojump = False; V (3, ("Using modem %s at %d bps, %d%c%d over %s\n", sav, rspeed, bpb, parity, sb, s2)); *modem = strdup (sav); break; } } else { V (2, ("\n")); if ((n == SIGTERM) || (n == SIGQUIT)) longjmp (termenv, n); } dojump = False; } sp = tty_close (sp); } } free (t2); } if (sp) break; } free (tmp); if (sp && dial && (phone = cfg_get (cfg, service, CFG_PHONE, NULL)) && (phone = mkrealphone (phone, pagerid))) { if (! (n = setjmp (env))) { dojump = True; for (p2 = phone; *p2; ) { s2 = p2; p2 = skipch (p2, ','); siz = strlen (dial) + strlen (phone) + 64; if (tmp = malloc (siz + 2)) { for (n = 0, m = 0; dial[n]; ) { if (dial[n] == '%') { ++n; if (dial[n]) { ptr = NULL; switch (dial[n]) { case 'L': ptr = phone; break; } if (ptr) { len = strlen (ptr); if (m + len >= siz) { siz += len + 64; if (! (tmp = Realloc (tmp, siz + 2))) break; } strcpy (tmp + m, ptr); m += len; } ++n; } } else { if (m + 1 >= siz) { siz += 128; if (! (tmp = Realloc (tmp, siz + 2))) break; } switch (dial[n]) { case '-': tmp[m++] = ','; break; default: tmp[m++] = dial[n]; break; } ++n; } } if (tmp) { tmp[m] = '\0'; V (3, ("Trying do dial %s\n", s2)); if (tty_send_expect (sp, tout, tmp, NULL) != -1) { V (1, ("Dial successful\n")); tty_drain (sp, 1); while (*p2) ++p2; } else { if (*p2) tty_hangup (sp, 500); else sp = tty_close (sp); } free (tmp); } } } } else { V (2, ("\n")); if (sp) { tty_send (sp, "x\r", 2); tty_hangup (sp, 500); if (reset) tty_send_expect (sp, tout, reset, NULL); sp = tty_close (sp); } if ((n == SIGTERM) || (n == SIGQUIT)) longjmp (termenv, n); } dojump = False; free (phone); } return sp;}/*}}}*//*{{{ send ASCII */static intasc_send (void *sp, void *ctab, string_t *callid, message *mg, int mcnt, void *cfg, char *service, date_t *delay, date_t *expire, Bool rds){ int ret; void *ap; int n; int err, nerr; int atout; char *alin, *alout, *apid, *amsg, *anext, *async; char *tmp; ret = 0; if (ap = asc_new (sp)) { atout = cfg_iget (cfg, service, CFG_ATOUT, DEF_ATOUT); alin = cfg_get (cfg, service, CFG_ALOGIN, DEF_ALOGIN); alout = cfg_get (cfg, service, CFG_ALOGOUT, DEF_ALOGOUT); apid = cfg_get (cfg, service, CFG_APID, DEF_APID); amsg = cfg_get (cfg, service, CFG_AMSG, DEF_AMSG); anext = cfg_get (cfg, service, CFG_ANEXT, DEF_ANEXT); async = cfg_get (cfg, service, CFG_ASYNC, DEF_ASYNC); asc_config (ap, do_log, atout, alin, alout, apid, amsg, anext, async, delay, expire, rds); if (ctab) { asc_add_convtable (ap, ctab); ctab = cv_free (ctab); } if ((err = asc_login (ap, callid)) == NO_ERR) { for (n = 0; n < mcnt; ++n) { tmp = schar (mg[n].msg); if (tmp) err = asc_transmit (ap, mg[n].pid, tmp); else err = ERR_FATAL; if (err == NO_ERR) mg[n].st.success = True; else mg[n].st.reason = CantSend; do_log ((err == NO_ERR ? LGS_SENT : LGF_SENT), "ASCII Message %ssent to %s via %s: %s", (err == NO_ERR ? "" : "NOT "), (mg[n].alias ? mg[n].alias : (mg[n].pid ? mg[n].pid : "")), service, (tmp ? tmp : "")); if (ESTOP (err)) break; if (n + 1 < mcnt) { if (err == NO_ERR) err = asc_next (ap); else err = asc_sync (ap); if (ESTOP (err)) break; else if (err != NO_ERR) if ((nerr = asc_sync (ap)) != NO_ERR) { if (nerr < err) err = nerr; break; } } } if (n < mcnt) ret = 1; if ((err != ERR_ABORT) && (asc_logout (ap) != NO_ERR)) ret = 1; } else ret = 1; asc_free (ap); } else ret = 1; return ret;}/*}}}*//*{{{ send script */static intscr_send (void *sp, void *ctab, string_t *callid, message *mg, int mcnt, void *cfg, char *service, date_t *delay, date_t *expire, Bool rds){ int ret; void *s; char *typ; char *name; char *scr; char *slogin, *slogout, *spid, *smsg, *snext, *ssync; char *tmp; int n, err, nerr; ret = 1; typ = cfg_get (cfg, service, CFG_STYP, DEF_STYP); if (s = scr_new (sp, typ, LIBDIR)) { scr_config (s, do_log, delay, expire, rds); name = cfg_get (cfg, service, CFG_SNAME, DEF_SNAME); if (name) if ((*name == '/') || (*name == '+')) { if (*name == '+') ++name; if (scr_load_file (s, name) == NO_ERR) ret = 0; } else if (scr = cfg_get (cfg, service, name, NULL)) if (scr_load_string (s, scr) == NO_ERR) ret = 0; if (! ret) { slogin = cfg_get (cfg, service, CFG_SLOGIN, DEF_SLOGIN); slogout = cfg_get (cfg, service, CFG_SLOGOUT, DEF_SLOGOUT); spid = cfg_get (cfg, service, CFG_SPID, DEF_SPID); smsg = cfg_get (cfg, service, CFG_SMSG, DEF_SMSG); snext = cfg_get (cfg, service, CFG_SNEXT, DEF_SNEXT); ssync = cfg_get (cfg, service, CFG_SSYNC, DEF_SSYNC); if (ctab) { scr_add_convtable (s, ctab); ctab = cv_free (ctab); } if (scr_execute (s, slogin, schar (callid)) == NO_ERR) { err = NO_ERR; for (n = 0; n < mcnt; ++n) { err = scr_execute (s, spid, mg[n].pid); do_log ((err == NO_ERR ? LGS_INF : LGF_INF), "SCRIPT pagerid %s %ssent via %s", (mg[n].alias ? mg[n].alias : (mg[n].pid ? mg[n].pid : "")), (err == NO_ERR ? "" : "NOT "), service); if (ESTOP (err)) break; else if (err == NO_ERR) { tmp = schar (mg[n].msg); if (tmp)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -