"Fossies" - the Fresh Open Source Software Archive

Member "smslink-0.56b-3/server/dd.c" (15 Nov 2005, 36116 Bytes) of package /linux/misc/old/smslink-0.56b-3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dd.c" see the Fossies "Dox" file reference documentation.

    1 /*==========================================================
    2  * Program : dd.c                          Project : smslink
    3  * Author  : Andrew Worsley <epaanwo@asac.ericsson.se>.
    4  * Date    : 25/11/03
    5  * Version : 0.13b
    6  * Notice  : (c) Andrew Worsley.
    7  * Comment : Dedicated daemon code.
    8  *
    9  * Modification History :
   10  * - 0.01b (18/02/01) : Initial release.
   11  * - 0.02b (19/02/01) : Moved all #define to sms_serv.h.
   12  *   Cosmetics.
   13  * - 0.03b (05/03/01) : Replaced control of all debug info by
   14  *   global flags.
   15  * - 0.04b (06/03/01) : Modified the way a new PIN is selected if
   16  *   we have to provide the PUK: now sets PIN to the one we have in
   17  *   conf in order to avoid the need to store the new one (thanks
   18  *   to Shay Kalderon <shay_kalderon@creoscitex.com> for the
   19  *   hint). Eventually implemented Andrew's hack to make sure
   20  *   all messages are always removed from the SIM card (created
   21  *   a device-level flag 'r4' to control it).
   22  * - 0.05b (02/04/01) : Modified calls to get_gsm_answer() to
   23  *   include the struct gsms_def field.
   24  * - 0.06b (04/05/01) : Improved handling of +CREG-returned
   25  *   registration status in dd_clear_msgs() & dd_send_sms().
   26  * - 0.07b (08/05/01) : Added a pause in dd_init() after PIN
   27  *   processing when using "fast" mode to try and solve the
   28  *   "+CMS ERROR: 515" issue. Modified dd_init() to also use
   29  *   the new get_gsm_resp() calls. Cosmetics.
   30  * - 0.08b (07/10/01) : Replaced calls to blopen_mdm_line()
   31  *   by calls to lopen_mdm_line(). Advantage being that this
   32  *   version uses the max. supported speed by the device by
   33  *   default (the one defined in /etc/modems).
   34  * - 0.09b (17/05/01) : Modified dd_spawn(), dd_init() and
   35  *   dd_input() to update the stats counter fields in struct
   36  *   gsms_def.
   37  * - 0.10b (05/01/01) : Improved error handling around the
   38  *   call to set_cpms(). Replaced the AT+CMEE dialog with a
   39  *   call to set_cmee(). Idem for AT+CPIN, AT+CMGF, AT+CSDH
   40  *   AT+CREG & AT+CSCA.
   41  * - 0.11b (23/01/02) : Implemented support for default GSM
   42  *   alphabet. Replaced static PIN post-processing sleep time
   43  *   by device-level param. (PINpause).
   44  * - 0.12b (07/11/02) : Re-engineering of "dd" mode to allow
   45  *   for parallel use of multiple devices when all of them are
   46  *   in dd mode.
   47  * - 0.13b (25/11/03) : Added  test on NO_CREG_CHECK flag to
   48  *   support Motorola A008 device. Contributed by Nicki de Wet
   49  *   <nickidw@mighty.co.za>.
   50  *========================================================*/
   51 #include <unistd.h>
   52 #include <fcntl.h>                        /* for fcntl () */
   53 #include <stdio.h>
   54 #include <stdlib.h>
   55 #include <errno.h>
   56 #include <string.h>               /* for strcpy & friends */
   57 #include <termios.h>         /* for baudrates definitions */
   58 #include <dial/modems.h>           /* requires 'libmodem' */
   59 #include <sys/time.h>
   60 #include <sys/types.h>
   61 #include <sys/socket.h>
   62 #include <sys/un.h>
   63 
   64 #include "sms_serv.h"
   65 #include "gsmdev.h"
   66 #include "pdu.h"
   67 
   68 /*========================================================*/
   69 /* For debugging purposes only - comment out for normal compile */
   70 /* #define INCL_DEBUG_CODE */
   71 
   72 /*========================================================*/
   73 /**********           GLOBAL VARIABLES             ********/
   74 /*========================================================*/
   75 extern int debug;                    /* debug level/flags */
   76 extern int context;              /* global server context */
   77 extern struct symbols symbols;       /* msg-specific data */
   78 extern int csfd;                      /* client socket FD */
   79 extern int use_fast;        /* enable fast modem response */
   80 extern int default_alphabet;
   81 extern int shmem_sem;
   82 
   83 
   84 /*========================================================*/
   85 /**********               FUNCTIONS                ********/
   86 /*========================================================*/
   87 void dd_spawn (struct gsms_def *dev)
   88 /*
   89  * fork and start executing the dedicated daemon code on this device.
   90  * basically will listen for input from the modem line or commands from the
   91  * command port and immeadiately call the appropriate routine to process
   92  * the data.
   93  */
   94 {
   95   int fd;
   96   fd_set rfds;
   97   int retval;
   98   struct sockaddr_un s_addr;     /* server socket address */
   99   struct sockaddr_un c_addr;     /* client socket address */
  100   int ssfd, csfd;                   /* socket descriptors */
  101   int c_addr_len;
  102   int nfd = 0;
  103   int sockflags;
  104 
  105   /*-------------------------First, let's become a daemon */
  106   int pid = fork ();
  107   if (pid == -1)
  108     syserr ("dd_spawn(): can't fork dedicated daemon");
  109   else if (pid != 0) {
  110     return;                             /* parent returns */
  111   }
  112 
  113   /* set context */
  114   context = CONTEXT_DDMN;
  115   if (debug & DEBUG_PRINTF) {
  116     printf ("PID <%d>, context set to <%d>\n", getpid (), context);
  117   }
  118   
  119   /* open connection with the syslog daemon - announce */
  120   closelog ();
  121   openlog ("sms_dd", (LOG_CONS | LOG_PID), FACILITY);
  122   syslog ((FACILITY | LOG_INFO), "dedicated sms daemon starting on device %s",
  123          dev->device);
  124 
  125   /* Update struct gsms_def */
  126   if (sem_wait (shmem_sem) == -1)
  127     syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  128   
  129   dev->owner = getpid ();
  130   dev->dd_busy = TRUE;
  131 
  132   if (sem_signal (shmem_sem) == -1)
  133     syserr ("dd_spawn(): can't signal shared mem. semaphore");
  134 
  135   /* set up the modem line */
  136   if ((fd = dd_init (dev)) < 0) {
  137     syslog ((FACILITY | LOG_ERR), "Unable to initialise modem (%d)", fd);
  138     exit (1);
  139   }
  140   if (debug & DEBUG_PRINTF) {
  141     printf ("Initialised modem - fd=%d sms\n", fd);
  142   }
  143 
  144   /* Flag device as idle again */
  145   if (sem_wait (shmem_sem) == -1)
  146     syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  147   
  148   dev->dd_busy = FALSE;
  149 
  150   if (sem_signal (shmem_sem) == -1)
  151     syserr ("dd_spawn(): can't signal shared mem. semaphore");
  152 
  153   /* create the Unix domain socket */
  154   /* see man 4 unix - on linux for doco */
  155   s_addr.sun_family = AF_LOCAL;
  156   strncpy (s_addr.sun_path, "/var/spool/smslink/", UNIX_PATH_MAX);
  157   strncat (s_addr.sun_path, dev->device, UNIX_PATH_MAX);
  158 
  159   /* let's create the socket */
  160   unlink (s_addr.sun_path); /* remove any old - existing one */
  161   if ((ssfd = socket (AF_LOCAL, SOCK_STREAM, 0)) == -1)
  162     syserr ("dd_spawn(): can't create socket(AF_LOCAL, SOCK_STREAM, 0)");
  163 
  164   /* now bind the socket to the server address */
  165   if (bind (ssfd, (struct sockaddr *) &s_addr, sizeof (s_addr)) == -1) {
  166     syslog ((FACILITY | LOG_ERR), "can't bind socket - %s", s_addr.sun_path);
  167     syserr ("dd_spawn(): can't bind socket");
  168   }
  169 
  170   /* create the client queue on the socket */
  171   if (listen (ssfd, MAXCLIENTCONN) == -1) {
  172     syslog ((FACILITY | LOG_ERR), "can't listen to that many connections (%d)", MAXCLIENTCONN);
  173     syserr ("dd_spawn(): can't listen to that many connections");
  174   }
  175 
  176   syslog ((FACILITY | LOG_INFO), "unix domain socket %s now ready.",
  177          s_addr.sun_path);
  178 
  179   /* set the flags to make the socket "non-blocking" */
  180   if ((sockflags = fcntl (ssfd, F_GETFL, 0)) == -1)
  181     syserr ("dd_spawn(): can't get unix domain socket descriptor attributes");
  182   if (fcntl (ssfd, F_SETFL, (O_NONBLOCK | sockflags)) == -1)
  183     syserr ("dd_spawn(): can't set socket descriptor attributes on unix domain socket");
  184 
  185   if (fd > ssfd)
  186     nfd = fd + 1;
  187   else
  188     nfd = ssfd + 1;
  189 
  190   for (;;) {
  191     FD_ZERO(&rfds);
  192     FD_SET(fd, &rfds);
  193     FD_SET(ssfd, &rfds);
  194 
  195     retval = select (nfd, &rfds, NULL, NULL, (struct timeval *)0);
  196 
  197     if (retval < 0) {
  198       syslog ((FACILITY | LOG_ERR), "select() failed: %m");
  199       exit (1);
  200     }
  201 
  202     if (retval == 0) {
  203       syslog ((FACILITY | LOG_ERR), "select() timedout? trying again...");
  204       continue;
  205     }
  206     /* input from modem */
  207     if (FD_ISSET (fd, &rfds)) { 
  208       dd_input (dev, fd);         /* return value ignored */
  209     }
  210 
  211     /* input from Unix domain socket */
  212     if (FD_ISSET(ssfd, &rfds)) { 
  213       c_addr_len = sizeof (c_addr);
  214       if ((csfd = accept (ssfd, (struct sockaddr *) &c_addr, &c_addr_len))
  215       == -1) {
  216     /* no connection - check the reason of the "error" */
  217     syserr ("dd_spawn(): accept failed on unix domain socket!");
  218       }
  219       else {
  220     FILE *fp = fdopen (csfd, "r+");
  221     char *p, *s;
  222     char buf[BIGGERBUFF];
  223 
  224     syslog ((FACILITY | LOG_INFO), "accepted Unix domain socket connection");
  225 
  226     /* allocate space for the symbols */
  227     symbols.smsc = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
  228     symbols.destgsm = (char *) malloc ((MAXPHNUMLEN + 1) * sizeof (char));
  229     symbols.message = (char *) malloc ((MAXMSGLEN + 1) * sizeof (char));
  230     symbols.pdu = NULL; /* allocated only as needed */
  231     symbols.user = (char *) malloc ((MAXUIDLEN + 1) * sizeof (char));
  232 
  233     /* set those symbols to their default values */
  234     strcpy (symbols.smsc, DEFAULTSMSC);
  235     symbols.destgsm[0] = '\0';
  236     symbols.message[0] = '\0';
  237     symbols.user[0] = '\0';
  238     symbols.mode = SMS_MODE_DEFAULT;
  239 
  240     /* parse input for parameters for the request */
  241     /* Note: ad-hoc protocol on the unix-domain socket. */
  242     /* Sender part is in dd_send_wrapper(). */
  243     while ((s = fgets (buf, BIGGERBUFF, fp)) != 0) {
  244           if (debug & DEBUG_PRINTF) {
  245             fprintf (stderr, "Read '%s'\n", buf);
  246           }
  247       if (p = strchr (buf, '=')) {
  248         /* we have a variable assignment */
  249         *p++ = '\0';
  250         if (s = strchr (p, '\n'))
  251           *s = '\0';
  252         if (strcasecmp (buf, "smsc") == 0)
  253           strcpy (symbols.smsc, p);
  254         else if (strcasecmp (buf, "dest") == 0)
  255           strcpy (symbols.destgsm, p);
  256         else if (strcasecmp (buf, "user") == 0)
  257           strcpy (symbols.user, p);
  258         else if (strcasecmp (buf, "message") == 0)
  259           strcpy (symbols.message, p);
  260         else if (strcasecmp (buf, "mode") == 0)
  261           symbols.mode = atoi (p);
  262         else {
  263           fprintf (fp, "Unknown parameter ignored: %s\n", buf);
  264           fflush (fp);
  265         }
  266         continue;
  267       }                 /* if (p = strchr (buf, '=')) */
  268           if (strncasecmp (buf, "send", 4) == 0) {
  269         break;
  270       }
  271       /* send complaint i - ignoring unknown command */
  272       fprintf (fp, "Unknown command ignored: %s", buf);
  273       fflush (fp);
  274     }                                        /* while */
  275     if (s) {         /* only if connection not closed */
  276       /* Flag device busy */
  277       if (sem_wait (shmem_sem) == -1)
  278         syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  279 
  280       dev->dd_busy = TRUE;
  281 
  282           if (sem_signal (shmem_sem) == -1)
  283             syserr ("dd_spawn(): can't signal shared mem. semaphore");
  284 
  285       fflush (fp); /* clear any pending output for dd_send_sms */
  286       if (dd_send_sms (dev, fd, &symbols, csfd) < 0) {
  287         fprintf (fp, "Transmission failed!\n");
  288         /* Update counters */
  289         if (sem_wait (shmem_sem) == -1)
  290           syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  291         dev->out_fail++;
  292             if (sem_signal (shmem_sem) == -1)
  293               syserr ("dd_spawn(): can't signal shared mem. semaphore");
  294       }
  295       else {
  296         fprintf (fp, "Transmission Successful\n");
  297         /* Update counters */
  298         if (sem_wait (shmem_sem) == -1)
  299           syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  300         dev->out_ok++;
  301             if (sem_signal (shmem_sem) == -1)
  302               syserr ("dd_spawn(): can't signal shared mem. semaphore");
  303       }
  304       fclose (fp);
  305       if (dd_notify (dev, fd) < 0) {
  306         cleanup_mdm ("Unable to switch on notifications", fd);
  307         closelog ();
  308         exit (1);
  309       }
  310       /* Flag device idle again */
  311       if (sem_wait (shmem_sem) == -1)
  312         syserr ("dd_spawn(): failed to wait on shared mem. semaphore");
  313 
  314       dev->dd_busy = FALSE;
  315 
  316           if (sem_signal (shmem_sem) == -1)
  317             syserr ("dd_spawn(): can't signal shared mem. semaphore");
  318 
  319     }                                       /* if (s) */
  320 
  321     /* free the symbols struct members */
  322     if (symbols.smsc) {
  323       free (symbols.smsc);
  324     }
  325     if (symbols.destgsm) {
  326       free (symbols.destgsm);
  327     }
  328     if (symbols.message) {
  329       free (symbols.message);
  330     }
  331     if (symbols.pdu) {
  332       free (symbols.pdu);
  333     }
  334     if (symbols.user) {
  335       free (symbols.user);
  336     }
  337       }                   /* if ((csfd = accept (ssfd,... */
  338     }                       /* if (FD_ISSET(ssfd, &rfds)) */
  339 
  340     /* process other file descriptors if any */
  341   }                                           /* for (;;) */
  342 
  343   /* fixup - free up the device */
  344   syslog ((FACILITY | LOG_INFO), "closing down");
  345   cleanup_mdm ((char *)0, fd);
  346   closelog ();
  347   exit (0);
  348 }                                          /* dd_spawn () */
  349 /*========================================================*/
  350 int dd_init (struct gsms_def *gsm)
  351 /*
  352  * Initialise the modem line for the dedicated daemon - want new message
  353  * notifications enabled.
  354  * Returns the file descriptor of the modem line or negative number if it
  355  * fails.
  356  */
  357 {
  358   int fd = -1;
  359   int pin_just_in;
  360   int nmsgin;
  361 
  362   /*--------------------------------------Initialisations */
  363   pin_just_in = FALSE; /* set to true if PIN needed be provided */
  364 
  365   /* open modem line */
  366   fd = lopen_mdm_line (gsm->device);
  367   if (fd < 0) {
  368     syslog ((FACILITY | LOG_ERR), "call to lopen_mdm_line() failed.");
  369     mdmperror ("sms_dd: lopen_mdm_line() failed");
  370     return (-1);
  371   }
  372 
  373   use_fast = (gsm->flags & FAST_RESPONSE);
  374 
  375   /*------------set GSM to "verbose" error reporting mode */
  376   if (set_cmee (gsm, fd, 0) == -1) {
  377     return (-1);
  378   }
  379   
  380   /*---------------------------then, check for SIM status */
  381   if (checkset_cpin (gsm, fd, 0, &pin_just_in) == -1) {
  382     return (-1);
  383   }
  384   
  385   /*--------------------------------------sleep if needed */
  386   /* There seems to be a timing issue in "fast" mode when
  387    * the AT+CNMI command is issued too fast after the last
  388    * AT+CPIN? and we get a "+CMS ERROR: 515" (= module
  389    * not ready or busy processing command). Try sleeping a
  390    * few secs to solve that. */
  391   if (use_fast && pin_just_in) {
  392     if (debug & DEBUG_PRINTF) {
  393       fprintf (stderr, "DD: (pause %d secs. for PIN code post-processing)\n",
  394               gsm->PINpause);
  395     }
  396     sleep (gsm->PINpause);
  397   }
  398   
  399   /* clear messages and enable new message notifications */
  400   if ((nmsgin = dd_clear_msgs (gsm, fd)) < 0) {
  401     /* increment the error counter */
  402     if (sem_wait (shmem_sem) == -1)
  403       syserr ("dd_init(): failed to wait on shared mem. semaphore");
  404     gsm->in_fail++;
  405     if (sem_signal (shmem_sem) == -1)
  406       syserr ("dd_init(): can't signal shared mem. semaphore");
  407     /* cleanup */
  408     mdm_unlock (mdmopendevice);
  409     hangup (fd);
  410     syslog ((FACILITY | LOG_ERR), "Unable to switch on notifications.");
  411     mdmperror ("Unable to switch on notifications");
  412     return (-1);
  413   }
  414   else {
  415     /* update the "in" counter */
  416     if (sem_wait (shmem_sem) == -1)
  417       syserr ("dd_init(): failed to wait on shared mem. semaphore");
  418     gsm->in_ok += nmsgin;
  419     if (sem_signal (shmem_sem) == -1)
  420       syserr ("dd_init(): can't signal shared mem. semaphore");
  421   }
  422 
  423   return (fd);
  424 }                                           /* dd_init () */
  425 /*========================================================*/
  426 int dd_notify (struct gsms_def *gsm, int fd)
  427 /*
  428  * switch on notifications from the modem
  429  */
  430 {
  431   char* scratch = (char *) malloc ((BIGBUFF + 1) * sizeof (char));
  432 
  433   if (!scratch)
  434     syserr ("dd_notify(): can't allocate scratch space");
  435   memset (scratch, 0, (BIGBUFF + 1));
  436   
  437   use_fast = (gsm->flags & FAST_RESPONSE);
  438 
  439   /*---------------set "notify for incoming SMS messages" */
  440   if (set_cnmi_on (gsm, fd, 0) == -1) {
  441     return (-1);
  442   }
  443 
  444   /* fixup - should check for any stored messages and return +ve number so we
  445    * can pick up messages that arrived while the notifications where switched
  446    * off
  447    */
  448 
  449   free (scratch);
  450   return (0);
  451 }                                         /* dd_notify () */
  452 /*========================================================*/
  453 int dd_input (struct gsms_def *dev, int fd)
  454 /*
  455  * read in some spontanous input data from the modem - if it's a new message
  456  * notification process it otherwise just consume it and return.
  457  */
  458 {
  459   char *scratch = (char *) malloc ((BIGBUFF + 1) * sizeof (char));
  460   char *p;
  461   int nmsgin;
  462   size_t len;
  463   cpl_list cpl;
  464 
  465   cpl_list_init (&cpl);
  466   cpl_list_insert (&cpl, dev->capmatrix.line_sep);
  467   cpl_list_insert (&cpl, "\n");
  468   
  469   if (!scratch)
  470     syserr ("dd_input(): can't allocate scratch space");
  471   memset (scratch, 0, (BIGBUFF + 1));
  472 
  473   use_fast = (dev->flags & FAST_RESPONSE);
  474 
  475   /* grab first line */
  476   if (!get_gsm_resp (fd, scratch, BIGBUFF, 2, cpl)) {
  477       cleanup_mdm ("unable to read input data from modem", fd);
  478       free_cpl_list (&cpl);
  479       return (-1);
  480   }
  481   /* if (!get_gsm_sleep (fd, scratch, BIGBUFF, 2)) {
  482    * if (!get_gsm_resp (fd, scratch, BIGBUFF, 2, "\r\n")) {
  483     not reliable because new message notification has 2 \r\n pairs!
  484    */
  485   p = strstr (scratch, dev->capmatrix.line_sep);
  486   len = strlen (scratch);
  487   if (!strstr (p + 2, dev->capmatrix.line_sep) &&
  488       !get_gsm_resp (fd, scratch + len, BIGBUFF - len, 2, cpl)) {
  489     cleanup_mdm ("unable to read 2nd new line data from new notication", fd);
  490     free_cpl_list (&cpl);
  491     return (-1);
  492   }
  493   /* expect new message notifications with the form: +CMTI: "ME",1
  494    *  where 1 is the message index and "ME" is the memory area it is in
  495    */
  496   if (strstr (scratch, "+CMTI:")) {
  497     syslog ((FACILITY | LOG_INFO), "new message : %s", scratch);
  498     free_cpl_list (&cpl);
  499 
  500     /* Flag device busy */
  501     if (sem_wait (shmem_sem) == -1)
  502       syserr ("dd_input(): failed to wait on shared mem. semaphore");
  503 
  504     dev->dd_busy = TRUE;
  505 
  506     if (sem_signal (shmem_sem) == -1)
  507       syserr ("dd_input(): can't signal shared mem. semaphore");
  508 
  509     if ((nmsgin = dd_clear_msgs (dev, fd)) < 0) {
  510       /* increment the error counter */
  511       if (sem_wait (shmem_sem) == -1)
  512         syserr ("dd_input(): failed to wait on shared mem. semaphore");
  513       dev->in_fail++;
  514       if (sem_signal (shmem_sem) == -1)
  515         syserr ("dd_input(): can't signal shared mem. semaphore");
  516     }
  517     else {
  518       /* update the "in" counter */
  519       if (sem_wait (shmem_sem) == -1)
  520         syserr ("dd_input(): failed to wait on shared mem. semaphore");
  521       dev->in_ok += nmsgin;
  522       if (sem_signal (shmem_sem) == -1)
  523         syserr ("dd_input(): can't signal shared mem. semaphore");
  524     }
  525     /* Flag device idle again */
  526     if (sem_wait (shmem_sem) == -1)
  527       syserr ("dd_input(): failed to wait on shared mem. semaphore");
  528 
  529     dev->dd_busy = FALSE;
  530 
  531     if (sem_signal (shmem_sem) == -1)
  532       syserr ("dd_input(): can't signal shared mem. semaphore");
  533 
  534     return (nmsgin);
  535   }
  536   syslog ((FACILITY | LOG_ERR), "unexpected input from modem ignored '%s'",
  537          scratch);
  538 
  539   free_cpl_list (&cpl);
  540   return (-1);
  541 }                                          /* dd_input () */
  542 /*========================================================*/
  543 int dd_clear_msgs (struct gsms_def *gsm, int fd)
  544 /*
  545  * clear out all pending SMS messages 
  546  */
  547 {
  548   int nmsgin = 0;
  549   char *p1;
  550   char *p2;
  551   char *cmsgid;
  552   int nread;
  553   struct mbox_item *message;
  554   mbox_list mailbox;
  555   int i;
  556   char* scratch = (char *) malloc ((BIGBUFF + 1) * sizeof (char));
  557 
  558 
  559   if (!scratch)
  560     syserr ("dd_clear_msgs(): can't allocate scratch space");
  561   memset (scratch, 0, (BIGBUFF + 1));
  562   mbox_list_init (&mailbox);
  563 
  564   use_fast = (gsm->flags & FAST_RESPONSE);
  565 
  566   /*------------set "no notify for incoming SMS messages" */
  567   if (set_cnmi_off (gsm, fd, 0) == -1) {
  568     return (-1);
  569   }
  570   
  571   /*-----------set message format to device-level default */
  572   if (checkset_cmgf (gsm, fd, 0, gsm->defmode) == -1) {
  573     return (-1);
  574   }
  575   
  576   /*-------------------------set "full SMS header detail" */
  577   /* Beware: only meaningfull (and supported) in text mode AND */
  578   /* even so only on specific models ! (specifically not the */
  579   /* PCFF900). */
  580   if ((gsm->defmode == SMS_MODE_TEXT) &&
  581       (gsm->capmatrix.capflags & HAS_CSDH_1)) {
  582     if (set_csdh (gsm, fd, 0) == -1) {
  583       return (-1);
  584     }
  585   }                 /* if (gsm->defmode == SMS_MODE_TEXT) */
  586   
  587   /*----------------Check stored SCA against default SMSC */
  588   if (checkset_csca (gsm, fd, 0, gsm->defsca) == -1) {
  589     return (-1);
  590   }
  591   
  592   /*---------------------Am I registered on the network ? */
  593   if (!(gsm->capmatrix.capflags & NO_CREG_CHECK))
  594   {
  595     if (check_creg (gsm, fd, 0) == -1) {
  596       return (-1);
  597     }
  598   }
  599   
  600   /*------------------------------------Set message store */
  601   /* make sure the message store is accessible */
  602   if (gsm->capmatrix.capflags & SET_MSG_STORE) {
  603     if (set_cpms (gsm, fd, 0) == -1) {
  604       return (-1);
  605     }
  606   }
  607 
  608   /*-----------------------Now loop and read incoming SMS */
  609   if (gsm->defmode == SMS_MODE_TEXT) {
  610     if (gsm->flags & SMS_READ_ALL) {
  611       /* hack to clear messages in SIM memory */
  612       sprintf (scratch, "AT+CMGL=\"ALL\"\r");
  613     }
  614     else {
  615       sprintf (scratch, "AT+CMGL=\"REC UNREAD\"\r");
  616     }
  617   }
  618   else {
  619     /* SMS_MODE_PDU */
  620     if (gsm->flags & SMS_READ_ALL) {
  621       /* hack to clear messages in SIM memory */
  622       sprintf (scratch, "AT+CMGL=4\r");
  623     }
  624     else {
  625       sprintf (scratch, "AT+CMGL=0\r");
  626     }
  627   }                 /* if (gsm->defmode == SMS_MODE_TEXT) */
  628   tell_gsm (fd, scratch);
  629   memset (scratch, 0, (BIGBUFF + 1));
  630   if (get_gsm_answer (fd, scratch, BIGBUFF, 1, gsm)) {
  631     if (debug & DEBUG_PRINTF) {
  632       fprintf (stderr, "%s\n", scratch);
  633     }
  634     /*....................look for "+CMGL:" in GSM answer */
  635     p1 = scratch;
  636     while (p1 && ((p1 = strstr (p1, "+CMGL:")) != NULL)) {
  637       /* got new message - isolate it from the batch */
  638       p2 = (p1 + 6);
  639       if ((p2 = strstr (p2, "+CMGL:")) != NULL) {
  640         /* there's another one behind */
  641     p1[((p2 - p1) - 1)] = '\0';
  642       }
  643       if (gsm->defmode == SMS_MODE_TEXT) {
  644         message = mbparse (p1, gsm->capmatrix);
  645       }
  646       else {
  647         /* SMS_MODE_PDU */
  648         message = mbparsePDU (p1, gsm->capmatrix);
  649       }             /* if (gsm->defmode == SMS_MODE_TEXT) */
  650       if (message == NULL) {
  651     free (scratch);
  652     syslog ((FACILITY | LOG_ERR), "mbparse() failed - internal error.");
  653     return (-1);
  654       }
  655       mbox_list_insert (&mailbox, message);
  656       nmsgin++;
  657       p1 = p2;
  658     }                              /* while ((msgstart... */
  659     if (nmsgin) {
  660       /*............dump all messages to the mailbox file */
  661       if (dumptofile (&mailbox, gsm->device, gsm) != nmsgin) {
  662     syslog ((FACILITY | LOG_ERR), "failed to save messages to inbox file.");
  663     mdmperror ("sms_serv: failed to save messages to inbox file");
  664       }
  665       /*.................remove the messages from the SIM */
  666       message = mailbox.head;
  667       while (message != NULL) {
  668     sprintf (scratch, "AT+CMGD=%d\r", message->msgid);
  669     tell_gsm (fd, scratch);
  670     memset (scratch, 0, (BIGBUFF + 1));
  671     if (get_gsm_answer (fd, scratch, BIGBUFF, 1, gsm)) {
  672           if (debug & DEBUG_PRINTF) {
  673         fprintf (stderr, "%s\n", scratch);
  674           }
  675       /* check for "OK" */
  676       if (strstr (scratch, "OK") == NULL) {
  677         free (scratch);
  678         syslog ((FACILITY | LOG_ERR), "error after sending AT+CMGD command.");
  679         mdmperror ("sms_serv: error after sending AT+CMGD command");
  680         return (-1);
  681       }
  682     }
  683     else {
  684       free (scratch);
  685       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  686       mdmperror ("sms_serv: GSM not responding");
  687       return (-1);
  688     }
  689         message = message->next;
  690       }                        /* while (message != NULL) */
  691       /*...............clean the mailbox list from memory */
  692       free_mbox_list (&mailbox);
  693     }                                      /* if (nmsgin) */
  694   }
  695   else {
  696     free (scratch);
  697     syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  698     mdmperror ("sms_serv: GSM not responding");
  699     return (-1);
  700   }
  701 
  702   if (dd_notify (gsm, fd) < 0) {
  703     free (scratch);
  704     syslog ((FACILITY | LOG_ERR), "Unable to switch on notifications.");
  705     mdmperror ("sms_serv: Unable to switch on notifications");
  706     return (-1);
  707   }
  708 
  709   free (scratch);
  710   return (nmsgin);
  711   
  712 }                                     /* dd_clear_msgs () */
  713 /*========================================================*/
  714 int dd_send_sms (struct gsms_def *gsm, int fd, struct symbols *pSMS, int csfd)
  715 /*
  716  * send an SMS message based on the given parameters. Return negative number on
  717  * failure otherwise return's the message id. 
  718  *  gsm - device we are talking to
  719  *  fd - file descriptor of modem line
  720  *  pMSM - pointer to definition of SMS request
  721  *  csfd - file descriptor to report progress to
  722  */
  723 {
  724   char *scratch;
  725   char *ptr;
  726   char *cmsgid;
  727   int nread;
  728   int msgid;
  729   char reqsca[MAXPHNUMLEN + 1];
  730   int reqmode;
  731   int pdubytes;
  732   char reqmodestr[10];
  733   cpl_list cpl;
  734   char subprompt[4];
  735   
  736   scratch = (char *) malloc ((BIGBUFF + 1) * sizeof (char));
  737   if (!scratch)
  738     syserr ("dd_send_sms(): can't allocate scratch space");
  739   memset (scratch, 0, (BIGBUFF + 1));
  740   
  741   use_fast = (gsm->flags & FAST_RESPONSE);
  742 
  743   /*------------set "no notify for incoming SMS messages" */
  744   if (set_cnmi_off (gsm, fd, csfd) == -1) {
  745     return (-1);
  746   }
  747   
  748   /*--------------Check stored SCA against requested SMSC */
  749   /* Which SMSC do we require ? */
  750   if (strcmp (pSMS->smsc, DEFAULTSMSC) == 0) {
  751     /* user kept default value - let's use device-level default */
  752     strcpy (reqsca, gsm->defsca);
  753   }
  754   else {
  755     /* user requested specific SMSC - let's use it */
  756     strcpy (reqsca, pSMS->smsc);
  757   }
  758   if (checkset_csca (gsm, fd, csfd, reqsca) == -1) {
  759     return (-1);
  760   }
  761   
  762   /*-------------Check stored mode against requested mode */
  763   /* Which mode do we require ? */
  764   if (pSMS->mode == SMS_MODE_DEFAULT) {
  765     /* user kept default value - let's use device-level default */
  766     reqmode = gsm->defmode;
  767   }
  768   else {
  769     /* user requested specific mode - let's use it */
  770     reqmode = pSMS->mode;
  771   }
  772   if (checkset_cmgf (gsm, fd, csfd, reqmode) == -1) {
  773     return (-1);
  774   }
  775   
  776   /*---------------------Am I registered on the network ? */
  777   if (check_creg (gsm, fd, csfd) == -1) {
  778     return (-1);
  779   }
  780   
  781   /*------------------------Now actually send SMS message */
  782   cpl_list_init (&cpl);
  783   strcpy (subprompt, gsm->capmatrix.line_sep);
  784   strcat (subprompt, ">");
  785   cpl_list_insert (&cpl, subprompt);
  786   
  787   switch (reqmode) {
  788     case SMS_MODE_TEXT:
  789       if (gsm->capmatrix.capflags & SUBPROMPT_IN_CMGS) {
  790         /* first send AT command and dest GSM */
  791         sprintf (scratch, "AT+CMGS=\"%s\"\r", pSMS->destgsm);
  792     tell_gsm (fd, scratch);
  793     memset (scratch, 0, (BIGBUFF + 1));
  794     if (get_gsm_resp (fd, scratch, BIGBUFF, 4, cpl)) {
  795       tellsock (csfd, scratch);
  796       /* check for ">" (subprompt char.) */
  797       if (strstr (scratch, ">") == NULL) {
  798         free (scratch);
  799             free_cpl_list (&cpl);
  800         syslog ((FACILITY | LOG_ERR), "error getting AT+CMGS subprompt.");
  801         mdmperror ("sms_serv: error getting AT+CMGS subprompt");
  802         return (-1);
  803       }
  804     }
  805     else {
  806       free (scratch);
  807           free_cpl_list (&cpl);
  808       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  809       mdmperror ("sms_serv: GSM not responding");
  810       return (-1);
  811     }
  812     /* then send the message proper... */
  813         sprintf (scratch, "%s%s", pSMS->message, CTRL_Z);
  814     tell_gsm (fd, scratch);
  815     memset (scratch, 0, (BIGBUFF + 1));
  816     if (get_gsm_answer (fd, scratch, BIGBUFF, 4, gsm)) {
  817       tellsock (csfd, scratch);
  818       /* check for "OK" */
  819       if (strstr (scratch, "OK") == NULL) {
  820         free (scratch);
  821             free_cpl_list (&cpl);
  822         syslog ((FACILITY | LOG_ERR), "error when sending SMS message.");
  823         mdmperror ("sms_serv: error when sending SMS message");
  824         return (-1);
  825       }
  826     }
  827     else {
  828       free (scratch);
  829           free_cpl_list (&cpl);
  830       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  831       mdmperror ("sms_serv: GSM not responding");
  832       return (-1);
  833     }
  834       }
  835       else {
  836         sprintf (scratch, "AT+CMGS=\"%s\"\r%s%s", pSMS->destgsm,
  837                 pSMS->message, CTRL_Z);
  838     tell_gsm (fd, scratch);
  839     memset (scratch, 0, (BIGBUFF + 1));
  840     if (get_gsm_answer (fd, scratch, BIGBUFF, 4, gsm)) {
  841       tellsock (csfd, scratch);
  842       /* check for "OK" */
  843       if (strstr (scratch, "OK") == NULL) {
  844         free (scratch);
  845             free_cpl_list (&cpl);
  846         syslog ((FACILITY | LOG_ERR), "error when sending SMS message.");
  847         mdmperror ("sms_serv: error when sending SMS message");
  848         return (-1);
  849       }
  850     }
  851     else {
  852       free (scratch);
  853           free_cpl_list (&cpl);
  854       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  855       mdmperror ("sms_serv: GSM not responding");
  856       return (-1);
  857     }
  858       }                                 /* if (SUBPROMPT) */
  859       break;
  860       
  861     case SMS_MODE_PDU:
  862       /* Convert message to PDU if required */
  863       sprintf (scratch, "converting message to PDU format... ");
  864       tellsock (csfd, scratch);
  865       if ((pSMS->pdu = encode_pdu (pSMS, default_alphabet)) == NULL) {
  866     sprintf (scratch, "Fail\r\n");
  867     tellsock (csfd, scratch);
  868     free (scratch);
  869         free_cpl_list (&cpl);
  870     return (-1);
  871     /* exit */
  872       }
  873       sprintf (scratch, "Ok\r\n");
  874       tellsock (csfd, scratch);
  875     
  876       pdubytes = (strlen (pSMS->pdu) / 2);
  877       if (gsm->capmatrix.capflags & SUBPROMPT_IN_CMGS) {
  878         /* first send AT command and PDU length */
  879         sprintf (scratch, "AT+CMGS=%d\r", pdubytes);
  880     tell_gsm (fd, scratch);
  881     memset (scratch, 0, (BIGBUFF + 1));
  882     if (get_gsm_resp (fd, scratch, BIGBUFF, 4, cpl)) {
  883       tellsock (csfd, scratch);
  884       /* check for ">" (subprompt char.) */
  885       if (strstr (scratch, ">") == NULL) {
  886         free (scratch);
  887             free_cpl_list (&cpl);
  888         syslog ((FACILITY | LOG_ERR), "error getting AT+CMGS subprompt.");
  889         mdmperror ("sms_serv: error getting AT+CMGS subprompt");
  890         return (-1);
  891       }
  892     }
  893     else {
  894       free (scratch);
  895           free_cpl_list (&cpl);
  896       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  897       mdmperror ("sms_serv: GSM not responding");
  898       return (-1);
  899     }
  900     /* then send the PDU string proper... */
  901     if (gsm->capmatrix.capflags & HAS_SCA_IN_PDU) {
  902           /* inserts "00" before PDU : GenSM/SM20 specific, means no SCA */
  903           sprintf (scratch, "00%s%s", pSMS->pdu, CTRL_Z);
  904     }
  905     else {
  906           /* GSM 03.40 compliant PDU format */
  907           sprintf (scratch, "%s%s", pSMS->pdu, CTRL_Z);
  908     }                              /* if (SCA_IN_PDU) */
  909     tell_gsm (fd, scratch);
  910     memset (scratch, 0, (BIGBUFF + 1));
  911     if (get_gsm_answer (fd, scratch, BIGBUFF, 10, gsm)) {
  912       tellsock (csfd, scratch);
  913       /* check for "OK" */
  914       if (strstr (scratch, "OK") == NULL) {
  915         free (scratch);
  916             free_cpl_list (&cpl);
  917         syslog ((FACILITY | LOG_ERR), "error when sending SMS message.");
  918         mdmperror ("sms_serv: error when sending SMS message");
  919         return (-1);
  920       }
  921     }
  922     else {
  923       free (scratch);
  924           free_cpl_list (&cpl);
  925       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  926       mdmperror ("sms_serv: GSM not responding");
  927       return (-1);
  928     }
  929       }
  930       else {
  931         /* no subprompt */
  932     if (gsm->capmatrix.capflags & HAS_SCA_IN_PDU) {
  933           /* inserts "00" before PDU : GenSM/SM20 specific, means no SCA */
  934           sprintf (scratch, "AT+CMGS=%d\r00%s%s", pdubytes,
  935                   pSMS->pdu, CTRL_Z);
  936     }
  937     else {
  938           /* GSM 03.40 compliant PDU format */
  939           sprintf (scratch, "AT+CMGS=%d\r%s%s", pdubytes,
  940                   pSMS->pdu, CTRL_Z);
  941     }                              /* if (SCA_IN_PDU) */
  942     tell_gsm (fd, scratch);
  943     memset (scratch, 0, (BIGBUFF + 1));
  944     if (get_gsm_answer (fd, scratch, BIGBUFF, 4, gsm)) {
  945       tellsock (csfd, scratch);
  946       /* check for "OK" */
  947       if (strstr (scratch, "OK") == NULL) {
  948         free (scratch);
  949             free_cpl_list (&cpl);
  950         syslog ((FACILITY | LOG_ERR), "error when sending SMS message.");
  951         mdmperror ("sms_serv: error when sending SMS message");
  952         return (-1);
  953       }
  954     }
  955     else {
  956       free (scratch);
  957           free_cpl_list (&cpl);
  958       syslog ((FACILITY | LOG_ERR), "GSM module not responding.");
  959       mdmperror ("sms_serv: GSM not responding");
  960       return (-1);
  961     }
  962       }                          /* if (SUBPROMPT_IN_PDU) */
  963       break;
  964       
  965     default:
  966       free (scratch);
  967       free_cpl_list (&cpl);
  968       syslog ((FACILITY | LOG_ERR), "internal error: unsupported mode <%d>.",
  969              reqmode);
  970       mdmperror ("sms_serv: internal error: unsupported mode");
  971       return (-1);
  972   }                                     /* switch reqmode */
  973   free_cpl_list (&cpl);
  974   
  975   /* we have the answer - now extract the message ID from it */
  976   if ((ptr = strstr (scratch, "+CMGS:")) == NULL) {
  977     free (scratch);
  978     syslog ((FACILITY | LOG_ERR), "can't find '+CMGS:' before OK in modem response.");
  979     mdmperror ("sms_serv: can't find '+CMGS:' before OK in modem response");
  980     return (-1);
  981   }
  982   ptr += 6;                        /* jumps to next space */
  983   if ((cmsgid = strtok (ptr, " \t\n\r")) == NULL) {
  984     free (scratch);
  985     syslog ((FACILITY | LOG_ERR), "can't find message ID (no CrLfHt) after '+CMGS:'.");
  986     mdmperror ("sms_serv: can't find message ID (no CrLfHt) after '+CMGS:'");
  987     return (-1);
  988   }
  989   else {
  990     msgid = atoi (cmsgid);
  991   }                            /* if ((cmsgid = strtok... */
  992     
  993   /*----------------------------------Close communication */
  994   free (scratch);
  995   return (msgid);
  996 }                                       /* dd_send_sms () */
  997 /*========================================================*/
  998 void dd_send_wrapper (struct gsms_def *dev)
  999 /*
 1000  * Send an SMS via the dedicated daemon through it's Local Domain socket
 1001  * opens socket and sends parameters one per line.
 1002  * newlines changed to spaces in data. -> simple hack.
 1003  * copy back the results to the requisite socket if available.
 1004  * return success/failure of request
 1005  */
 1006 {
 1007   int   fd;
 1008   struct sockaddr_un s_addr;     /* server socket address */
 1009   int ssfd;                          /* socket descriptor */
 1010   char *p, *s;
 1011   char buf[BIGGERBUFF];
 1012   FILE *fp;
 1013 
 1014   /* attempt to connect to the Unix domain socket */
 1015   /* see man 4 unix - on linux for doco */
 1016   s_addr.sun_family = AF_LOCAL;
 1017   strncpy (s_addr.sun_path, "/var/spool/smslink/", UNIX_PATH_MAX);
 1018   strncat (s_addr.sun_path, dev->device, UNIX_PATH_MAX);
 1019 
 1020   if ((ssfd = socket (AF_LOCAL, SOCK_STREAM, 0)) == -1)
 1021     syserr ("dd_send_wrapper(): can't create socket(AF_LOCAL, SOCK_STREAM, 0)");
 1022 
 1023   /* now bind the socket to the server address */
 1024   if (connect (ssfd, (struct sockaddr *) &s_addr, sizeof (s_addr)) == -1) {
 1025     syslog ((FACILITY | LOG_ERR), "can't connect to socket - %s",
 1026        s_addr.sun_path);
 1027     return;
 1028   }
 1029 
 1030   syslog ((FACILITY | LOG_INFO), "connection to '%s'", s_addr.sun_path);
 1031 
 1032   if ((fp = fdopen (ssfd, "r+")) == 0) {
 1033     syslog ((FACILITY | LOG_ERR), "can't open FILE on socket - %d", ssfd);
 1034     return;
 1035   }
 1036 
 1037   /* some default stuff to stop dd_send_wrapper() from core dumping */
 1038   if (symbols.smsc == 0)
 1039       symbols.smsc = strdup (dev->defsca);
 1040   if (symbols.destgsm == 0)
 1041       symbols.destgsm = strdup ("61414200951");
 1042   if (symbols.user == 0)
 1043       symbols.user = strdup ("Andrew");
 1044   if (symbols.message == 0)
 1045       symbols.message = strdup ("This is a test SMS message");
 1046 
 1047   /* replace newlines with spaces - messages send over socket use newlines
 1048    * as seperators - paranoia
 1049    * could switch to using null if both ends are modified to understand
 1050    * this -> requires implementing something for fgets() call then.
 1051    */
 1052   trChar (symbols.smsc, '\n', ' ');
 1053   trChar (symbols.destgsm, '\n', ' ');
 1054   trChar (symbols.user, '\n', ' ');
 1055   trChar (symbols.message, '\n', ' ');
 1056 
 1057   fprintf (fp, "dest=%s\n", symbols.destgsm);
 1058   fprintf (fp, "user=%s\n", symbols.user);
 1059   fprintf (fp, "message=%s\n", symbols.message);
 1060   fprintf (fp, "smsc=%s\n", symbols.smsc);
 1061   fprintf (fp, "mode=%d\n", symbols.mode);
 1062   fprintf (fp, "send\n"); /* command */
 1063   fflush (fp);
 1064 
 1065   /* now just dump out what the daemon sends to us */
 1066   while ((s = fgets (buf, BIGGERBUFF, fp)) != 0) {
 1067     if (debug & DEBUG_PRINTF) {
 1068       fprintf (stderr, "Read '%s'\n", buf);
 1069     }
 1070     tellsock (csfd, buf);
 1071   }                             /* while ((s = fgets (... */
 1072   fclose (fp);
 1073 
 1074   syslog ((FACILITY | LOG_INFO), "connection to dedicated daemon closed");
 1075   return;
 1076 }                                   /* dd_send_wrapper () */
 1077 /*==========================================================
 1078  * EOF : dd.c
 1079  *===================*/