server.y
上传用户:eo_sii
上传日期:2007-01-05
资源大小:91k
文件大小:39k
源码类别:

手机短信编程

开发平台:

Unix_Linux

  1. %{
  2. /*==========================================================
  3.  * Program : server.y                      Project : smslink
  4.  * Author  : Philippe Andersson.
  5.  * Date    : 02/12/99
  6.  * Version : 0.35b
  7.  * Notice  : (c) Les Ateliers du Heron, 1998 for Scitex Europe, S.A.
  8.  * Comment : Parser module for SMS server
  9.  *
  10.  * Modification History :
  11.  * - 0.01a (19/08/98) : Initial release.
  12.  * - 0.02a (21/08/98) : Implemented "variable" assignment and
  13.  *   individual clearing.
  14.  * - 0.03a (21/08/98) : Added support for prompt.
  15.  * - 0.04a (21/08/98) : Added dequoting for strings.
  16.  * - 0.05a (22/08/98) : Added detailed help handling and individ.
  17.  *   show for items. Also implemented a separate exit function.
  18.  * - 0.06a (24/08/98) : Completed help system. Also stuffed the
  19.  *   conclude() function a bit.
  20.  * - 0.10a (27/08/98) : Merged the parser module into the main
  21.  *   sms_serv program. Moved yyerror () to server.l.
  22.  * - 0.11a (01/09/98) : Completed output migration to socket
  23.  *   (printf's to sprintf's).
  24.  * - 0.12a (01/09/98) : Start implementing restricted access
  25.  *   to non-sharable resources (modems) through semaphores.
  26.  * - 0.13a (03/09/98) : Completed implementation of crit.
  27.  *   sections through semaphores and shared memory.
  28.  * - 0.14a (06/09/98) : Inserted #ifdef's to have it compile
  29.  *   under RedHat (GNU Libc 6). Also implemented minimal validation
  30.  *   on message parameters (presence checking).
  31.  * - 0.15a (24/09/98) : Changed [LF] to [CR][LF] in messages
  32.  *   sent through the socket.
  33.  * - 0.16a (27/09/98) : Added positive acknowledgement for
  34.  *   variable setting ("Ok") for error checking on client side.
  35.  *   Improved some help messages in give_help().
  36.  * - 0.17a (01/10/98) : Added logging detail (variable setting).
  37.  * - 0.18a (19/10/98) : Changed 'struct modem_def' to 'struct
  38.  *   gsms_def' and 'modemsdef' to 'gsmdevices'. Cosmetics.
  39.  * - 0.20a (20/10/98) : Merge the 'spit.c' source into this.
  40.  *   Implement the actual SMS sending code.
  41.  * - 0.21a (20/10/98) : Implemented 'devicelist' command.
  42.  * - 0.22a (21/10/98) : Added a signal trap for SIGPIPE, in
  43.  *   order to avoid getting locked GSM modules when a client
  44.  *   dies or quits unexpectedly (in the critical section).
  45.  * ++++ Switched to Beta ++++
  46.  * - 0.23b (21/10/98) : Added deslashdot() function to clean
  47.  *   phone numbers before sending them to the GSM.
  48.  * - 0.24b (22/10/98) : Improved SIGPIPE handling by adding
  49.  *   'instance_is_set' variable telling whether the value of
  50.  *   'instance' should be considered relevant.
  51.  * - 0.25b (23/10/98) : Added handling for 'user' parameter,
  52.  *   and improved checking on phone number validity. 'user'
  53.  *   parameter also be made required. Corrected timeout values
  54.  *   in PIN / PUK transmission, and a bug in CSCA-related sprintf
  55.  *   format.
  56.  * - 0.26b (05/11/98) : Corrected an inconsistency in the error
  57.  *   message related to catching SIGPIPE signal.
  58.  * - 0.27b (13/12/98) : Moved to sigaction() signal handling.
  59.  *   Added handler for SIGTERM in crit. section. Included
  60.  *   handling of new member "owner" in struct gsms_def.
  61.  * - 0.28b (14/12/98) : Corrected a boundary-checking bug in the
  62.  *   search for a free GSM instance loop.
  63.  * - 0.29b (16/05/99) : Added "uptime" command.
  64.  * - 0.30b (18/05/99) : Refined the uptime display. Solved a
  65.  *   bug related to the buffer length in "help" command.
  66.  * - 0.31b (06/06/99) : Added "days" counter to uptime display.
  67.  *   Adapted on-line help accordingly. Also added a command to 
  68.  *   turn off notification for incoming SMS messages in send_sms().
  69.  * - 0.32b (28/06/99) : In send_sms(), moved the AT+CNMI command
  70.  *   after the PIN check routine. PIN-Activated SIM is required
  71.  *   for AT+CNMI.
  72.  * - 0.33b (29/06/99) : Moved 3 functions over to stuff.c and
  73.  *   made them public (misc. string handling functions).
  74.  * - 0.34b (20/09/99) : Improved the "show" command to also
  75.  *   display the current length of the message string.
  76.  * - 0.35b (02/12/99) : Improved default SMSC handling in
  77.  *   send_sms(). Now takes its default value from the configuration
  78.  *   file only (/etc/gsmdevices). Adapted on-line help accordingly.
  79.  *   Added "aclist" command and related help. Cosmetics.
  80.  *========================================================*/
  81. /* must be defined before the usual includes (stdlib.h) */
  82. #define RAND_MAX 9999   /* max val. for random PIN */
  83. #include <stdio.h>
  84. #include <stdlib.h>                  /* for errno & div() */
  85. #ifdef LINUX_LC6
  86. #  include <errno.h>
  87. #endif                                /* #ifdef LINUX_LC6 */
  88. #include <strings.h>
  89. #include <signal.h>
  90. #include <time.h>                       /* for difftime() */
  91. #include <math.h>                            /* for log() */
  92. #include <netinet/in.h>                    /* for ntohl() */
  93. #include <termios.h>         /* for baudrates definitions */
  94. #include <dial/modems.h>           /* requires 'libmodem' */
  95. #include "sms_serv.h"
  96. #define min(a, b)  ( a < b ? a : b )
  97. /*-------------------------------------External variables */
  98. /* for lex & yacc/bison */
  99. extern int errno;
  100. extern int yyleng;
  101. extern char *yytext;
  102. extern char myinput[];
  103. extern char *myinputptr;          /* cur. pos. in myinput */
  104. extern char *myinputlim;                   /* end of data */
  105. /* program specific */
  106. extern int csfd;                      /* client socket FD */
  107. extern char *buffer;    /* scratch space for C/S dialogue */
  108. extern struct symbols symbols;
  109. extern int ngsmdevs;       /* num. configured GSM devices */
  110. /*---------------------------------------Global variables */
  111. char *paramname = NULL;
  112. char *idname = NULL;
  113. /* char *buffer = NULL; */
  114. int i;
  115. int instance;
  116. int instance_is_set = FALSE;
  117. int vtype;
  118. /*------------------------------------For the help system */
  119. /* Be carefull to match the defines here with the array below */
  120. #define H_HELP 0
  121. #define H_CLEAR 1
  122. #define H_SET 2
  123. #define H_SEND 3
  124. #define H_QUIT 4
  125. #define H_EXIT 5
  126. #define H_BYE 6
  127. #define H_SHOW 7
  128. #define H_STATS 8
  129. #define H_DEVLIST 9
  130. #define H_UPTIME        10
  131. #define H_ACLIST        11
  132. #define H_MAX 12            /* keeps (last + 1) */
  133. char *help_topics[(H_MAX + 1)] = {"help",
  134.                                   "clear",
  135.                   "set",
  136.                   "send",
  137.           "quit",
  138.           "exit",
  139.           "bye",
  140.           "show",
  141.           "stats",
  142.           "devicelist",
  143.           "uptime",
  144.   "aclist",
  145.           NULL};
  146. /*----------------------------Local Function declarations */
  147. int shiftleft (char *, int);
  148. int dequote (char *);
  149. int deslashdot (char *);
  150. int give_help (char *);
  151. int help_lookup (char *);
  152. int load_help ();
  153. void free_help ();
  154. void print_device_list ();
  155. void print_access_list ();
  156. void compute_uptime ();
  157. int validate_msg_param (struct symbols *);
  158. int send_sms (struct gsms_def *);
  159. void sms_send_wrapper ();
  160. void unlock_gsm ();
  161. void conclude ();
  162. /*========================================================*/
  163. %}
  164. %union {
  165.   char *string;          /* string buffer for token value */
  166. }
  167. /* commands */
  168. %token T_HELP
  169. %token T_CLEAR
  170. %token T_SEND
  171. %token T_DEVLIST
  172. %token T_ACLIST
  173. %token T_UPTIME
  174. %token T_SET
  175. %token T_QUIT
  176. %token T_STATS
  177. %token T_SHOW
  178. /* others */
  179. %token T_PARAM
  180. %token <string> T_TEXT
  181. %token <string> T_PHNUM
  182. %token T_NAME
  183. %type <string> value
  184. %%
  185. statement: single_command
  186. | param_command
  187. | assignment
  188. | /* allow empty input */
  189. ;
  190. single_command: T_HELP {
  191. sprintf (buffer, "rnSMS Server Helprn"
  192.         "===============rn"
  193.         "he | help [command] : displays helprn"
  194.         "set item = value    : sets message parametersrn"
  195.         "clear [item]        : clears item (all items)rn"
  196.         "send                : sends SMSrn");
  197. tellsock (csfd, buffer);
  198. sprintf (buffer, "dl | devicelist     : lists configured GSM devicesrn"
  199. "acl | aclist        : dumps the registered ACL's to screenrn"
  200. "ut | uptime         : displays server uptimern"
  201.         "quit | exit | bye   : closes connection and exitsrn"
  202.         "stats               : displays server statsrn"
  203.         "sh | show [item]    : displays item (all items)rnrn");
  204. tellsock (csfd, buffer);
  205. }
  206. | T_CLEAR {
  207. strcpy (symbols.smsc, DEFAULTSMSC);
  208. symbols.destgsm[0] = '';
  209. symbols.user[0] = '';
  210. symbols.message[0] = '';
  211. sprintf (buffer, "All items cleared...rn");
  212. tellsock (csfd, buffer);
  213. }
  214. | T_SEND {
  215. if (validate_msg_param (&symbols))
  216.   sms_send_wrapper ();
  217. else {
  218.   sprintf (buffer, "ERROR: Not all required items are filled in.rn");
  219.   tellsock (csfd, buffer);
  220. }
  221. }
  222. | T_DEVLIST {
  223. print_device_list ();
  224. }
  225. | T_ACLIST {
  226. print_access_list ();
  227. }
  228. | T_UPTIME {
  229. compute_uptime ();
  230. }
  231. | T_STATS {
  232. sprintf (buffer, "Statistics are not implemented yet.rn");
  233. tellsock (csfd, buffer);
  234. }
  235. | T_SHOW {
  236. sprintf (buffer, "rnCurrent settings:rn"); 
  237. tellsock (csfd, buffer);
  238. sprintf (buffer, "smsc = [%s]rn", symbols.smsc);
  239. tellsock (csfd, buffer);
  240. sprintf (buffer, "user = [%s]rn", symbols.user);
  241. tellsock (csfd, buffer);
  242. sprintf (buffer, "dest = [%s]rn", symbols.destgsm);
  243. tellsock (csfd, buffer);
  244. sprintf (buffer, "msg  = [%s] - Length: %drnrn", 
  245.          symbols.message, strlen (symbols.message));
  246. tellsock (csfd, buffer);
  247. }
  248. | T_QUIT { conclude (); }
  249. ;
  250. param_command:  T_HELP parameter
  251. {
  252. give_help (paramname);
  253. free (paramname);
  254. paramname = NULL;
  255. }
  256. | T_SHOW parameter
  257. {
  258. if (strcmp (paramname, "msg") == 0) {
  259.   free (paramname);
  260.   paramname = (char *) malloc (8 * sizeof (char));
  261.   strcpy (paramname, "message");
  262. }
  263.   
  264. if (strcmp (paramname, "smsc") == 0) {
  265.   sprintf (buffer, "smsc = [%s]rn", symbols.smsc);
  266.   tellsock (csfd, buffer);
  267. }
  268. else if (strcmp (paramname, "user") == 0) {
  269.   sprintf (buffer, "user = [%s]rn", symbols.user);
  270.   tellsock (csfd, buffer);
  271. }
  272. else if (strcmp (paramname, "dest") == 0) {
  273.   sprintf (buffer, "dest = [%s]rn", symbols.destgsm);
  274.   tellsock (csfd, buffer);
  275. }
  276. else if (strcmp (paramname, "message") == 0) {
  277.   sprintf (buffer, "msg  = [%s] - Length: %drn", 
  278.            symbols.message, strlen (symbols.message));
  279.   tellsock (csfd, buffer);
  280. }
  281. else {
  282.   sprintf (buffer, "ERROR: unknown item <%s>rn", paramname);
  283.   tellsock (csfd, buffer);
  284. }
  285. free (paramname);
  286. paramname = NULL;
  287. }
  288. | T_CLEAR parameter
  289. {
  290. if (strcmp (paramname, "msg") == 0) {
  291.   free (paramname);
  292.   paramname = (char *) malloc (8 * sizeof (char));
  293.   strcpy (paramname, "message");
  294. }
  295.   
  296. if (strcmp (paramname, "smsc") == 0) {
  297.   strcpy (symbols.smsc, DEFAULTSMSC);
  298. }
  299. else if (strcmp (paramname, "user") == 0) {
  300.   symbols.user[0] = '';
  301. }
  302. else if (strcmp (paramname, "dest") == 0) {
  303.   symbols.destgsm[0] = '';
  304. }
  305. else if (strcmp (paramname, "message") == 0) {
  306.   symbols.message[0] = '';
  307. }
  308. else {
  309.   sprintf (buffer, "ERROR: unknown item <%s>rn", paramname);
  310.   tellsock (csfd, buffer);
  311. }
  312. free (paramname);
  313. paramname = NULL;
  314. }
  315. ;
  316. assignment: T_SET variable '=' value
  317. {
  318. if (strcmp (idname, "msg") == 0) {
  319.   free (idname);
  320.   idname = (char *) malloc (8 * sizeof (char));
  321.   strcpy (idname, "message");
  322. }
  323.   
  324. if (strcmp (idname, "smsc") == 0) {
  325.   /* Assign smsc */
  326.   if (strlen ($4) > MAXPHNUMLEN) {
  327.     strncpy (symbols.smsc, $4, MAXPHNUMLEN);
  328.     symbols.smsc[MAXPHNUMLEN] = '';
  329.     sprintf (buffer, "WARNING: max. smsc length is %d, value now truncatedrn",
  330.            MAXPHNUMLEN);
  331.             tellsock (csfd, buffer);
  332.   }
  333.   else
  334.     strcpy (symbols.smsc, $4);
  335.   sprintf (buffer, "Okrn");
  336.   tellsock (csfd, buffer);
  337.                                   syslog ((FACILITY | LOG_NOTICE),
  338.          "got new smsc <%s>.", symbols.smsc);
  339. }
  340. else if (strcmp (idname, "user") == 0) {
  341.   /* Assign user */
  342.   if (strlen ($4) > MAXUIDLEN) {
  343.     strncpy (symbols.user, $4, MAXUIDLEN);
  344.     symbols.user[MAXUIDLEN] = '';
  345.     sprintf (buffer, "WARNING: max. sender ID length is %d, value now truncatedrn",
  346.            MAXUIDLEN);
  347.             tellsock (csfd, buffer);
  348.   }
  349.   else
  350.     strcpy (symbols.user, $4);
  351.   sprintf (buffer, "Okrn");
  352.   tellsock (csfd, buffer);
  353.                                   syslog ((FACILITY | LOG_NOTICE),
  354.          "sender ID is [%s].", symbols.user);
  355. }
  356. else if (strcmp (idname, "dest") == 0) {
  357.   /* Check whether we have a T_PHNUM */
  358.   if (vtype != T_PHNUM) {
  359.     sprintf (buffer, "Expected a phone numberrn");
  360.     tellsock (csfd, buffer);
  361.   }
  362.   else {
  363.     /* Assign dest */
  364.     if (strlen ($4) > MAXPHNUMLEN) {
  365.       strncpy (symbols.destgsm, $4, MAXPHNUMLEN);
  366.       symbols.destgsm[MAXPHNUMLEN] = '';
  367.       sprintf (buffer, "WARNING: max. dest length is %d, value now truncatedrn",
  368.              MAXPHNUMLEN);
  369.               tellsock (csfd, buffer);
  370.     }
  371.     else {
  372.       strcpy (symbols.destgsm, $4);
  373.     }
  374.     sprintf (buffer, "Okrn");
  375.     tellsock (csfd, buffer);
  376.                                     syslog ((FACILITY | LOG_NOTICE),
  377.            "got destgsm <%s>.", symbols.destgsm);
  378.           }
  379. }
  380. else if (strcmp (idname, "message") == 0) {
  381.   /* Assign message */
  382.   if (strlen ($4) > MAXMSGLEN) {
  383.     strncpy (symbols.message, $4, MAXMSGLEN);
  384.     symbols.message[MAXMSGLEN] = '';
  385.     sprintf (buffer, "WARNING: max. message length is %d, value now truncatedrn",
  386.            MAXMSGLEN);
  387.             tellsock (csfd, buffer);
  388.   }
  389.   else
  390.     strcpy (symbols.message, $4);
  391.   sprintf (buffer, "Okrn");
  392.   tellsock (csfd, buffer);
  393.                                   syslog ((FACILITY | LOG_NOTICE),
  394.          "message to transmit is set.");
  395. }
  396. else {
  397.   sprintf (buffer, "ERROR: unknown item <%s>rn", idname);
  398.   tellsock (csfd, buffer);
  399. }
  400. free (idname);
  401. idname = NULL;
  402. free ($4);
  403. }
  404. ;
  405. parameter: T_PARAM { if (paramname)
  406.     free (paramname);
  407. paramname = (char *) malloc ((yyleng + 1) * sizeof (char));
  408. paramname[0] = '';
  409. strcpy (paramname, yytext);
  410. }
  411. ;
  412. variable: T_NAME { if (idname)
  413.     free (idname);
  414.  idname = (char *) malloc ((yyleng + 1) * sizeof (char));
  415.  idname[0] = '';
  416.  strcpy (idname, yytext);
  417.  }
  418. ;
  419. value: T_TEXT {
  420. /* let's dequote here */
  421. dequote ($1);
  422. vtype = T_TEXT;
  423. }
  424. | T_PHNUM {
  425. /* let's dequote and remove [/.] here */
  426. dequote ($1);
  427. deslashdot ($1);
  428. vtype = T_PHNUM;
  429. }
  430. ;
  431. %%
  432. /*########################################################*/
  433. /* Main entry point for the parser module                 */
  434. int parser ()
  435. {
  436.   /*======================================Initialisations */
  437.   /*==============================Main Call to the Parser */
  438.   yyparse ();
  439. }                                            /* parser () */
  440. /*########################################################*/
  441. /*========================================================*/
  442. /*                     Local Functions                    */
  443. /*========================================================*/
  444. int my_yyinput (buf, max_size)
  445. char *buf;
  446. int max_size;
  447. {
  448.   int n = min (max_size, (myinputlim - myinputptr));
  449.   
  450.   if (n > 0) {
  451.     memcpy (buf, myinputptr, n);
  452.     myinputptr += n;
  453.   }
  454.   
  455.   return (n);
  456. }                                        /* my_yyinput () */
  457. /*========================================================*/
  458. int give_help (p)
  459. char *p;
  460. {
  461.   int topic_id;
  462.   topic_id = help_lookup (p);
  463.   switch (topic_id) {
  464.     case H_HELP: {
  465.       sprintf (buffer, "rnSyntax: he | help [command]rn"
  466.               "Used with no option, gives a list of all available commands.rn"
  467.               "When a command is provided, gives detailed help on this command.rnrn");
  468.       tellsock (csfd, buffer);
  469.       break;
  470.     }
  471.     case H_CLEAR: {
  472.       sprintf (buffer, "rnSyntax: clear [item]rn"
  473.               "Where [item] is one of:rn"
  474.               "- smsc: SMS Message Center (reverts it to "%s")rn"
  475.               "- user: sender identification (user name) for logging purposesrn"
  476.               "- dest: destination GSM numberrn"
  477.               "- message | msg: message text to be sent to destinationrn"
  478.               "Used with no option, clears all items.rn"
  479.               "When an item is specified, clears only this one.rnrn",
  480.       DEFAULTSMSC);
  481.       tellsock (csfd, buffer);
  482.       break;
  483.     }
  484.     case H_SET: {
  485.       sprintf (buffer, "rnSyntax: set item = valuern"
  486.               "Where [item] is one of:rn"
  487.               "- smsc: SMS Message Center (see your provider or use default)rn"
  488.               "- user: sender identification (user name) for logging purposesrn"
  489.               "- dest: destination GSM numberrn"
  490.               "- message | msg: message text to be sent to destinationrnrn");
  491.       tellsock (csfd, buffer);
  492.       sprintf (buffer, "Note 1: text must be quoted, GSM numbers can be quoted, GSM numbers canrn"
  493.               "contain any of [/.-+].rnrn"
  494.       "Note 2: for SMSC, a value of "%s" means the default SMSCrn"
  495.       "as defined per device in %s. Set it to a valid phonern"
  496.       "number to use a different one. Use the "clear" command to reset itrn"
  497.       "to "%s".rnrn", DEFAULTSMSC, GSMDEVFILE, DEFAULTSMSC);
  498.       tellsock (csfd, buffer);
  499.       break;
  500.     }
  501.     case H_SEND: {
  502.       sprintf (buffer, "rnSyntax: sendrn"
  503.               "When all parameters are filled in as required, use this command torn"
  504.               "send the SMS message. You'll wait during the time it takes to send.rn"
  505.               "An acknowlegment will be returned when done.rnrn");
  506.       tellsock (csfd, buffer);
  507.       break;
  508.     }
  509.     case H_QUIT: {
  510.       /* just jump to next */
  511.     }
  512.     case H_EXIT: {
  513.       /* just jump to next */
  514.     }
  515.     case H_BYE: {
  516.       sprintf (buffer, "rnSyntax: quit | exit | byern"
  517.               "Closes the connection and leaves the program.rnrn");
  518.       tellsock (csfd, buffer);
  519.       break;
  520.     }
  521.     case H_SHOW: {
  522.       sprintf (buffer, "rnSyntax: sh | show [item]rn"
  523.               "Where [item] is one of:rn"
  524.               "- smsc: SMS Message Center (see your provider or use default)rn"
  525.               "- user: sender identification (user name) for logging purposesrn"
  526.               "- dest: destination GSM numberrn"
  527.               "- message | msg: message text to be sent to destinationrn"
  528.               "Used without parameter, the command displays the current settingrn"
  529.               "for all items. When an item is specified, only this one isrn"
  530.               "displayed.rnrn");
  531.       tellsock (csfd, buffer);
  532.       break;
  533.     }
  534.     case H_STATS: {
  535.       sprintf (buffer, "rnStatistics are not implemented yet.rnrn");
  536.       tellsock (csfd, buffer);
  537.       break;
  538.     }
  539.     case H_DEVLIST: {
  540.       sprintf (buffer, "rnSyntax: devicelist | dlrn"
  541.               "Lists registered GSM devices.rn"
  542.       "Those are usually configured through <%s>.rn"
  543.       "The fields provided in the output are:rn", GSMDEVFILE);
  544.       tellsock (csfd, buffer);
  545.       sprintf (buffer, "- owner:    pid owning a lock on it (0 = not locked)rn"
  546.       "- device:   Unix device namern"
  547.       "- CallerID: the GSM's network addr. (its phone number)rn"
  548.       "- Def SCA:  the default Service Center Addr. (or SMSC)rn"
  549.       "- Provider: Network Provider Namernrn");
  550.       tellsock (csfd, buffer);
  551.       break;
  552.     }
  553.     case H_ACLIST: {
  554.       sprintf (buffer, "rnSyntax: aclist | aclrn"
  555.               "Dumps the registered ACL entries to screen.rn"
  556.       "ACL's are Access Control Lists that define which machinern"
  557.       "is allowed to use the server and which isn't. ACL's arern"
  558.       "usually configured through <%s>.rn"
  559.       "man 5 gsmaccess for more details.rnrn", ACCESSFILE);
  560.       tellsock (csfd, buffer);
  561.       break;
  562.     }
  563.     case H_UPTIME: {
  564.       sprintf (buffer, "rnSyntax: uptime | utrn"
  565.               "Displays the SMS server process uptime in days, hours, rn"
  566.       "minutes and seconds.rnrn");
  567.       tellsock (csfd, buffer);
  568.       break;
  569.     }
  570.     default: {
  571.       sprintf (buffer, "ERROR: don't know about <%s>. Can't help.rn", p);
  572.       tellsock (csfd, buffer);
  573.       break;
  574.     }
  575.   }                                  /* switch (topic_id) */
  576.   return (topic_id);
  577. }                                         /* give_help () */
  578. /*========================================================*/
  579. int help_lookup (p)
  580. char *p;
  581. {
  582.   int i;
  583.   for (i = 0; (help_topics[i] != NULL) && (strcmp (p, help_topics[i]) != 0); i++);
  584.   return (i);
  585. }                                       /* help_lookup () */
  586. /*========================================================*/
  587. void print_device_list ()
  588. {
  589.   extern int shmem_sem;
  590.   extern struct gsms_def *gsmdevices;
  591.   sprintf (buffer, "rn"
  592.                    "L | Owner | Device        | CallerID       | Def. SCA       | Provider   rn"
  593.                    "--+-------+---------------+----------------+----------------+------------rn");
  594.   tellsock (csfd, buffer);
  595.   
  596.   /* get exclusive access to shared mem. for safety's sake */
  597.   if (sem_wait (shmem_sem) == -1)
  598.     syserr ("sms_serv: failed to wait on shared mem. semaphore");
  599.   /* ---- Begin Crit. Sect. #4 ---- */
  600.   for (i = 0; i < ngsmdevs; i++) {
  601.     sprintf (buffer, "%s | %5d | /dev/%-8s | %-14s | %-14s | %srn",
  602.              (gsmdevices[i].free ? "." : "*"),
  603.      gsmdevices[i].owner,
  604.      gsmdevices[i].device,
  605.              gsmdevices[i].addr,
  606.              gsmdevices[i].defsca,
  607.              gsmdevices[i].provider);
  608.     tellsock (csfd, buffer);
  609.   }                                          /* for (i... */
  610.   /* leave crit. sect. */
  611.   if (sem_signal (shmem_sem) == -1)
  612.     syserr ("sms_serv: can't signal shared mem. semaphore");
  613.   /* ---- End Crit. Sect. #4 ---- */
  614.   
  615.   sprintf (buffer, "rn");
  616.   tellsock (csfd, buffer);
  617. }                                 /* print_device_list () */
  618. /*========================================================*/
  619. void print_access_list ()
  620. {
  621.   extern acl_list gsm_acl;
  622.   struct acl_item *cursor;
  623.   unsigned long nomask;
  624.   int netmask;
  625.   double power;
  626.   sprintf (buffer, "rnCurrent Access Control List:rn"
  627.           "============================rn");
  628.   tellsock (csfd, buffer);
  629.   if (!empty_acl_list (gsm_acl)) {
  630.     cursor = gsm_acl.head;
  631.     /* convert mask value */
  632.     nomask = ntohl (cursor->nomask);
  633.     if (nomask < (unsigned long) 4294967295) {
  634.       nomask++;
  635.       power = (log (nomask) / log (2));
  636.       netmask = (32 - power);
  637.     }
  638.     else {
  639.       netmask = 0;
  640.     }
  641.     sprintf (buffer, "%-5s : [%s] / %drn", 
  642.             (cursor->action == ACL_ALLOW) ? "ALLOW" : "DENY", 
  643.     inet_ntoa (cursor->network),
  644.             netmask);
  645.     tellsock (csfd, buffer);
  646.     while (cursor->next != NULL) {
  647.       cursor = cursor->next;
  648.       /* convert mask value */
  649.       nomask = ntohl (cursor->nomask);
  650.       if (nomask < (unsigned long) 4294967295) {
  651. nomask++;
  652. power = (log (nomask) / log (2));
  653. netmask = (32 - power);
  654.       }
  655.       else {
  656. netmask = 0;
  657.       }
  658.       sprintf (buffer, "%-5s : [%s] / %drn", 
  659.               (cursor->action == ACL_ALLOW) ? "ALLOW" : "DENY", 
  660.       inet_ntoa (cursor->network),
  661.               netmask);
  662.     tellsock (csfd, buffer);
  663.     }
  664.   }
  665.   else {
  666.     sprintf (buffer, "Nothing to print: empty 'ACL' list.rn");
  667.     tellsock (csfd, buffer);
  668.   }
  669.   sprintf (buffer, "rn");
  670.   tellsock (csfd, buffer);
  671. }                                 /* print_access_list () */
  672. /*========================================================*/
  673. void compute_uptime ()
  674. {
  675.   extern time_t starttime;
  676.   double upsecs;
  677.   int days;
  678.   int hours;
  679.   int rem;
  680.   div_t dt;
  681.   /* compute the uptime in seconds */
  682.   upsecs = difftime (time (NULL), starttime);
  683.   
  684.   /* first extract the number of days */
  685.   dt = div ((int) upsecs, 86400);
  686.   days = dt.quot;
  687.   rem = dt.rem;
  688.   /* now extract the number of hours */
  689.   dt = div (rem, 3600);
  690.   hours = dt.quot;
  691.   rem = dt.rem;
  692.   
  693.   /* then extract the number of minutes and seconds */
  694.   dt = div (rem, 60);
  695.   
  696.   sprintf (buffer, "rnServer uptime: %d days %d hours %d min %d secs.rnrn", 
  697.           days, hours, dt.quot, dt.rem);
  698.   tellsock (csfd, buffer);
  699. }                                    /* compute_uptime () */
  700. /*========================================================*/
  701. int validate_msg_param (struct symbols *msg)
  702. {
  703.   int retval;
  704.   retval = ((msg->smsc[0] != '') && (msg->destgsm[0] != '') && 
  705.            (msg->message[0] != '') && (msg->user[0] != ''));
  706.   return (retval);
  707. }                                /* validate_msg_param () */
  708. /*========================================================*/
  709. int send_sms (struct gsms_def *gsm)
  710. {
  711.   int fd, retval = 0;
  712.   char *scratch;
  713.   char *ptr;
  714.   char *cmsgid;
  715.   int nread;
  716.   int newpin;
  717.   int retries;
  718.   int msgid;
  719.   char reqsca[MAXPHNUMLEN + 1];
  720.   
  721.   scratch = (char *) malloc ((BIGBUFF + 1) * sizeof (char));
  722.   if (!scratch)
  723.     syserr ("sms_serv: can't allocate scratch space");
  724.   memset (scratch, 0, (BIGBUFF + 1));
  725.   
  726.   /* open modem line */
  727.   fd = blopen_mdm_line (gsm->device, B9600);
  728.   if (fd < 0) {
  729.     syslog ((FACILITY | LOG_ERR), "call to blopen_mdm_line() failed.");
  730.     mdmperror ("sms_serv: blopen_mdm_line() failed");
  731.     free (scratch);
  732.     return (-1);
  733.   }
  734.   
  735.   /*------------set GSM to "verbose" error reporting mode */
  736.   sprintf (scratch, "at+cmee=1r");
  737.   tell_gsm (fd, scratch);
  738.   memset (scratch, 0, (BIGBUFF + 1));
  739.   if (get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  740.     tellsock (csfd, scratch);
  741.     /* check for "OK" */
  742.     if (strstr (scratch, "OK") == NULL) {
  743.       mdm_unlock (mdmopendevice);
  744.       hangup (fd);
  745.       free (scratch);
  746.       syslog ((FACILITY | LOG_ERR), "error after sending AT+CMEE command.");
  747.       mdmperror ("sms_serv: error after sending AT+CMEE command");
  748.       return (-1);
  749.     }
  750.   }
  751.   else {
  752.     mdm_unlock (mdmopendevice);
  753.     hangup (fd);
  754.     free (scratch);
  755.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  756.     mdmperror ("sms_serv: GSM not responding");
  757.     return (-1);
  758.   }
  759.   
  760.   /*---------------------------then, check for SIM status */
  761.   sprintf (scratch, "at+cpin?r");
  762.   tell_gsm (fd, scratch);
  763.   memset (scratch, 0, (BIGBUFF + 1));
  764.   if (get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  765.     tellsock (csfd, scratch);
  766.     /* check for "READY" -- if not, make it so */
  767.     retries = MAXATTEMPTS;
  768.     while ((strstr (scratch, "READY") == NULL) && retries--) {
  769.       /* not ready yet -> asking for PIN or PUK ? */
  770.       if (strstr (scratch, "SIM PIN")) {
  771.         /* send PIN */
  772. sprintf (scratch, "at+cpin=%sr", gsm->PIN);
  773. tell_gsm (fd, scratch);
  774. memset (scratch, 0, (BIGBUFF + 1));
  775. if (get_gsm_answer (fd, scratch, BIGBUFF, 15)) {
  776.           tellsock (csfd, scratch);
  777.   /* check for "OK" */
  778.   if (strstr (scratch, "OK") == NULL) {
  779.     mdm_unlock (mdmopendevice);
  780.     hangup (fd);
  781.     free (scratch);
  782.             syslog ((FACILITY | LOG_ERR), "can't send PIN to GSM or wrong PIN.");
  783.     mdmperror ("sms_serv: can't send PIN to GSM or wrong PIN");
  784.     return (-1);
  785.   }
  786. }
  787. else {
  788.   mdm_unlock (mdmopendevice);
  789.   hangup (fd);
  790.   free (scratch);
  791.           syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  792.   mdmperror ("sms_serv: GSM not responding");
  793.   return (-1);
  794. }
  795.       }
  796.       else if (strstr (scratch, "SIM PUK")) {
  797.         /* send PUK - set new random PIN */
  798. srand (getpid ());
  799. newpin = rand ();
  800. syslog ((FACILITY | LOG_WARNING), "I'll try to set new PIN for </dev/%s>.", gsm->device);
  801. sprintf (scratch, "at+cpin="%s","%04d"r", gsm->PUK, newpin);
  802. tell_gsm (fd, scratch);
  803. memset (scratch, 0, (BIGBUFF + 1));
  804. if (get_gsm_answer (fd, scratch, BIGBUFF, 20)) {
  805.           tellsock (csfd, scratch);
  806.   /* check for "OK" */
  807.   if (strstr (scratch, "OK") == NULL) {
  808.     mdm_unlock (mdmopendevice);
  809.     hangup (fd);
  810.     free (scratch);
  811.             syslog ((FACILITY | LOG_ERR), "can't send PUK to GSM or wrong PUK.");
  812.     mdmperror ("sms_serv: can't send PUK to GSM or wrong PUK");
  813.     return (-1);
  814.   }
  815. }
  816. else {
  817.   mdm_unlock (mdmopendevice);
  818.   hangup (fd);
  819.   free (scratch);
  820.           syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  821.   mdmperror ("sms_serv: GSM not responding");
  822.   return (-1);
  823. }
  824. /* store new PIN in conf. file (GSMDEVFILE) */
  825. /* log it */
  826. syslog ((FACILITY | LOG_WARNING), "new PIN for </dev/%s> set to [%04d].", gsm->device, newpin);
  827.       }
  828.       else {                                     /* ERROR */
  829. mdm_unlock (mdmopendevice);
  830. hangup (fd);
  831. free (scratch);
  832.         syslog ((FACILITY | LOG_ERR), "unable to get SIM status info.");
  833. mdmperror ("sms_serv: unable to get SIM status info");
  834. return (-1);
  835.       }                 /* if "PIN" elseif "PUK" else ... */
  836.       /* query the status again */
  837.       sprintf (scratch, "at+cpin?r");
  838.       tell_gsm (fd, scratch);
  839.       memset (scratch, 0, (BIGBUFF + 1));
  840.       if (!get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  841. mdm_unlock (mdmopendevice);
  842. hangup (fd);
  843. free (scratch);
  844.         syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  845. mdmperror ("sms_serv: GSM not responding");
  846. return (-1);
  847.       }
  848.       tellsock (csfd, scratch);
  849.     }                                 /* while (!"READY") */
  850.   }
  851.   else {
  852.     mdm_unlock (mdmopendevice);
  853.     hangup (fd);
  854.     free (scratch);
  855.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  856.     mdmperror ("sms_serv: GSM not responding");
  857.     return (-1);
  858.   }
  859.   
  860.   /*------------set "no notify for incoming SMS messages" */
  861.   sprintf (scratch, "at+cnmi=0,0,0,0,0r");
  862.   tell_gsm (fd, scratch);
  863.   memset (scratch, 0, (BIGBUFF + 1));
  864.   if (get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  865.     tellsock (csfd, scratch);
  866.     /* check for "OK" */
  867.     if (strstr (scratch, "OK") == NULL) {
  868.       mdm_unlock (mdmopendevice);
  869.       hangup (fd);
  870.       free (scratch);
  871.       syslog ((FACILITY | LOG_ERR), "error after sending AT+CNMI command.");
  872.       mdmperror ("sms_serv: error after sending AT+CNMI command");
  873.       return (-1);
  874.     }
  875.   }
  876.   else {
  877.     mdm_unlock (mdmopendevice);
  878.     hangup (fd);
  879.     free (scratch);
  880.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  881.     mdmperror ("sms_serv: GSM not responding");
  882.     return (-1);
  883.   }
  884.   
  885.   /*--------------Check stored SCA against requested SMSC */
  886.   /* Which SMSC do we require ? */
  887.   if (strcmp (symbols.smsc, DEFAULTSMSC) == 0) {
  888.     /* user kept default value - let's use device-level default */
  889.     strcpy (reqsca, gsm->defsca);
  890.   }
  891.   else {
  892.     /* user requested specific SMSC - let's use it */
  893.     strcpy (reqsca, symbols.smsc);
  894.   }
  895.   sprintf (scratch, "at+csca?r");
  896.   tell_gsm (fd, scratch);
  897.   memset (scratch, 0, (BIGBUFF + 1));
  898.   if (get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  899.     tellsock (csfd, scratch);
  900.     /* compare with requested SMSC */
  901.     if (strstr (scratch, reqsca) == NULL) {
  902.       /* let's set it then */
  903.       sprintf (scratch, "at+csca="%s"r", reqsca);
  904.       tell_gsm (fd, scratch);
  905.       memset (scratch, 0, (BIGBUFF + 1));
  906.       if (get_gsm_answer (fd, scratch, BIGBUFF, 2)) {
  907.         tellsock (csfd, scratch);
  908. /* check for "OK" */
  909. if (strstr (scratch, "OK") == NULL) {
  910.   mdm_unlock (mdmopendevice);
  911.   hangup (fd);
  912.   free (scratch);
  913.           syslog ((FACILITY | LOG_ERR), "error after sending AT+CSCA= command.");
  914.   mdmperror ("sms_serv: error after sending AT+CSCA= command");
  915.   return (-1);
  916. }
  917.       }
  918.       else {
  919. mdm_unlock (mdmopendevice);
  920. hangup (fd);
  921. free (scratch);
  922.         syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  923. mdmperror ("sms_serv: GSM not responding");
  924. return (-1);
  925.       }
  926.     }
  927.   }
  928.   else {
  929.     mdm_unlock (mdmopendevice);
  930.     hangup (fd);
  931.     free (scratch);
  932.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  933.     mdmperror ("sms_serv: GSM not responding");
  934.     return (-1);
  935.   }
  936.   
  937.   /*---------------------Am I registered on the network ? */
  938.   sprintf (scratch, "at+creg?r");
  939.   tell_gsm (fd, scratch);
  940.   memset (scratch, 0, (BIGBUFF + 1));
  941.   if (get_gsm_answer (fd, scratch, BIGBUFF, 1)) {
  942.     tellsock (csfd, scratch);
  943.     /* check for "0,1" status */
  944.     if (strstr (scratch, "+CREG: 0,1") == NULL) {
  945.       mdm_unlock (mdmopendevice);
  946.       hangup (fd);
  947.       free (scratch);
  948.       syslog ((FACILITY | LOG_ERR), "not registered on the network - can't send.");
  949.       mdmperror ("sms_serv: not registered on the network - can't send");
  950.       return (-1);
  951.     }
  952.   }
  953.   else {
  954.     mdm_unlock (mdmopendevice);
  955.     hangup (fd);
  956.     free (scratch);
  957.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  958.     mdmperror ("sms_serv: GSM not responding");
  959.     return (-1);
  960.   }
  961.   
  962.   /*------------------------Now actually send SMS message */
  963.   sprintf (scratch, "at+cmgs="%s"r%s%s", symbols.destgsm, symbols.message, CTRL_Z);
  964.   tell_gsm (fd, scratch);
  965.   memset (scratch, 0, (BIGBUFF + 1));
  966.   if (get_gsm_answer (fd, scratch, BIGBUFF, 4)) {
  967.     tellsock (csfd, scratch);
  968.     /* check for "OK" */
  969.     if (strstr (scratch, "OK") == NULL) {
  970.       mdm_unlock (mdmopendevice);
  971.       hangup (fd);
  972.       free (scratch);
  973.       syslog ((FACILITY | LOG_ERR), "error when sending SMS message.");
  974.       mdmperror ("sms_serv: error when sending SMS message");
  975.       return (-1);
  976.     }
  977.   }
  978.   else {
  979.     mdm_unlock (mdmopendevice);
  980.     hangup (fd);
  981.     free (scratch);
  982.     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  983.     mdmperror ("sms_serv: GSM not responding");
  984.     return (-1);
  985.   }
  986.   /* we have the answer - now extract the message ID from it */
  987.   if ((ptr = strstr (scratch, "+CMGS:")) == NULL) {
  988.   }
  989.   ptr += 6;                        /* jumps to next space */
  990.   cmsgid = strtok (ptr, " tnr");
  991.   msgid = atoi (cmsgid);
  992.     
  993.   /*----------------------------------Close communication */
  994.   mdm_unlock (mdmopendevice);
  995.   hangup (fd);
  996.   free (scratch);
  997.   return (msgid);
  998. }                                          /* send_sms () */
  999. /*========================================================*/
  1000. void sms_send_wrapper ()
  1001. {
  1002.   extern int global_sem;
  1003.   extern int shmem_sem;
  1004.   extern struct gsms_def *gsmdevices;
  1005.   int nwaitsecs = 0;
  1006.   int last_errno;
  1007.   int retval;
  1008.   /* int instance; */
  1009.   char device[MAXDEVLEN];
  1010.   struct gsms_def gsm;
  1011.   int msgid;
  1012.   struct sigaction sa_c;
  1013.   
  1014.   sprintf (buffer, "Waiting for a free GSM instance...rn");
  1015.   tellsock (csfd, buffer);
  1016.   sprintf (buffer, ".");
  1017.   
  1018.   while (((retval = sem_decreq (global_sem)) == -1) &&
  1019.         (errno == EAGAIN) &&
  1020. (nwaitsecs < M_TIMEOUT)) {
  1021.     sleep (W_STEP);
  1022.     nwaitsecs += W_STEP;
  1023.     tellsock (csfd, buffer);               /* display dot */
  1024.   }                                        /* while (...) */
  1025.   last_errno = errno;
  1026.   sprintf (buffer, "rn");
  1027.   tellsock (csfd, buffer);
  1028.   
  1029.   if (retval == -1) {            /* failed to get a modem */
  1030.     switch (last_errno) {
  1031.       case EAGAIN: {
  1032.         syslog ((FACILITY | LOG_WARNING), "timeout expired (all GSMs busy).");
  1033.         sprintf (buffer, "timeout expired (all GSMs busy) - try again laterrn");
  1034.         tellsock (csfd, buffer);
  1035.         break;
  1036.       }
  1037.       default: {
  1038.         syserr ("sms_serv: can't decrease global semaphore");
  1039. break;
  1040.       }
  1041.     }                              /* switch (last_errno) */
  1042.   }
  1043.   else {                 /* ---- Begin Crit. Sect. #1 --- */
  1044.     /* at least 1 GSM module is free - find it */
  1045.     if (sem_wait (shmem_sem) == -1)
  1046.       syserr ("sms_serv: failed to wait on shared mem. semaphore");
  1047.     /* ---- Begin Crit. Sect. #2 ---- */
  1048.     /* Signal Handling */
  1049.     sa_c.sa_handler = unlock_gsm;
  1050.     if (sigfillset (&sa_c.sa_mask) == -1)
  1051.       syserr ("sms_serv: can't fill signal set");
  1052.     sa_c.sa_flags = 0;
  1053.     /* catch SIGTERM to handle child's death while GSM's locked */
  1054.     if (sigaction (SIGTERM, &sa_c, NULL) == -1)
  1055.       syserr ("sms_serv: can't catch SIGTERM");
  1056.     /* catch SIGPIPE to handle client disconnect while GSM's locked */
  1057.     if (sigaction (SIGPIPE, &sa_c, NULL) == -1)
  1058.       syserr ("sms_serv: can't catch SIGPIPE");
  1059.     /* search free instance */
  1060.     instance = 0;
  1061.     while (instance < ngsmdevs) {
  1062.       if (gsmdevices[instance].free) {
  1063.         /* let's process this one */
  1064. break;
  1065.       }
  1066.       instance++;
  1067.     }                               /* while (instance...) */
  1068.     if (instance >= ngsmdevs)
  1069.       fatal ("sms_serv: can't get a free GSM - internal error");
  1070.     
  1071.     /* got it - now lock it (device lockfile handled by libmodem) */
  1072.     instance_is_set = TRUE;
  1073.     gsmdevices[instance].free = FALSE;
  1074.     gsmdevices[instance].owner = getpid ();
  1075.     
  1076.     /* copy to "local" space, to avoid the shmem balagan */
  1077.     if (gsmdevcpy (&gsm, &gsmdevices[instance]) == -1)
  1078.       syserr ("sms_serv: error copying GSM instance");
  1079.     
  1080.     /* leave crit. sect. */
  1081.     if (sem_signal (shmem_sem) == -1)
  1082.       syserr ("sms_serv: can't signal shared mem. semaphore");
  1083.     /* ---- End Crit. Sect. #2 ---- */
  1084.     /* log it */
  1085.     syslog ((FACILITY | LOG_NOTICE), "using device </dev/%s>.", gsm.device);
  1086.     sprintf (buffer, "got </dev/%s>, now sending...rn", gsm.device);
  1087.     tellsock (csfd, buffer);
  1088.     
  1089.     /* ---->>> Actual SEND <<<---- */
  1090.     if ((msgid = send_sms (&gsm)) != -1) {
  1091.       syslog ((FACILITY | LOG_NOTICE), "message sent OK, message ID is <%d>.", msgid);
  1092.       sprintf (buffer, "message sent OK, message ID is <%d>rn", msgid);
  1093.       tellsock (csfd, buffer);
  1094.     }
  1095.     else { /* some error occured */
  1096.       syslog ((FACILITY | LOG_WARNING), "ERROR: failed to send message.");
  1097.       sprintf (buffer, "ERROR: failed to send message - try again laterrn");
  1098.       tellsock (csfd, buffer);
  1099.     }
  1100.     
  1101.     /* now free the modem again */
  1102.     if (sem_wait (shmem_sem) == -1)
  1103.       syserr ("sms_serv: failed to wait on shared mem. semaphore");
  1104.     /* ---- Begin Crit. Sect. #3 ---- */
  1105.     gsmdevices[instance].free = TRUE;
  1106.     gsmdevices[instance].owner = 0;
  1107.     instance_is_set = FALSE;
  1108.     /* leave crit. sect. */
  1109.     if (sem_signal (shmem_sem) == -1)
  1110.       syserr ("sms_serv: can't signal shared mem. semaphore");
  1111.     /* ---- End Crit. Sect. #3 ---- */
  1112.     /* leave main crit. sect. */
  1113.     if (sem_signal (global_sem) == -1)
  1114.       syserr ("sms_serv: can't signal global semaphore");
  1115.   }                        /* ---- End Crit. Sect. #1 --- */
  1116. }                                  /* sms_send_wrapper () */
  1117. /*========================================================*/
  1118. void unlock_gsm ()
  1119. {
  1120.   extern int shmem_sem;
  1121.   extern struct gsms_def *gsmdevices;
  1122.   syslog ((FACILITY | LOG_WARNING), "Socket connection unexpectedly lost.");
  1123.   /* set the allocated GSM module back to 'free' status */
  1124.   if (instance_is_set) {
  1125.     if (sem_wait (shmem_sem) == -1)
  1126.       syserr ("sms_serv: failed to wait on shared mem. semaphore");
  1127.     /* ---- Begin Crit. Sect. #5 ---- */
  1128.     if (!gsmdevices[instance].free) {
  1129.       gsmdevices[instance].free = TRUE;
  1130.       gsmdevices[instance].owner = 0;
  1131.       syslog ((FACILITY | LOG_WARNING), "GSM instance </dev/%s> has been unlocked.",
  1132.              gsmdevices[instance].device);
  1133.     }
  1134.     /* leave crit. sect. */
  1135.     if (sem_signal (shmem_sem) == -1)
  1136.       syserr ("sms_serv: can't signal shared mem. semaphore");
  1137.     /* ---- End Crit. Sect. #5 ---- */
  1138.   }
  1139.   /* free what's need to be freed and exit */
  1140.   free (symbols.smsc);
  1141.   free (symbols.destgsm);
  1142.   free (symbols.message);
  1143.   free (buffer);
  1144.   /*------------------------------------------------------*/
  1145.   exit (0);
  1146. }                                        /* unlock_gsm () */
  1147. /*========================================================*/
  1148. void conclude ()
  1149. {
  1150.   syslog ((FACILITY | LOG_NOTICE), "Connection closed by client.");
  1151.   /* free what's need to be freed and exit */
  1152.   free (symbols.smsc);
  1153.   free (symbols.destgsm);
  1154.   free (symbols.message);
  1155.   free (buffer);
  1156.   /*------------------------------------------------------*/
  1157.   exit (0);
  1158. }                                          /* conclude () */
  1159. /*========================================================*/
  1160. /*==========================================================
  1161.  * EOF : server.y
  1162.  *===================*/