/* -------------------------------------------------------------------- */ /* SMS Client, send messages to mobile phones and pagers */ /* */ /* sms_client.c */ /* */ /* Copyright (C) 1997,1998,1999 Angelo Masci */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Library General Public */ /* License as published by the Free Software Foundation; either */ /* version 2 of the License, or (at your option) any later version. */ /* */ /* This library is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* Library General Public License for more details. */ /* */ /* You should have received a copy of the GNU Library General Public */ /* License along with this library; if not, write to the Free */ /* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* */ /* You can contact the author at this e-mail address: */ /* */ /* angelo@styx.demon.co.uk */ /* */ /* -------------------------------------------------------------------- */ /* $Id$ -------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include #if defined(LINUX) #include #endif #if defined(NEXT) #include #endif #include "error.h" #include "sms_list.h" #include "logfile/logfile.h" #include "expand.h" #include "driver/driver.h" #include "comms/comms.h" #include "common/common.h" #include "lock/lock.h" #include "resource/resource.h" #include "version.h" /* -------------------------------------------------------------------- */ #if !defined(MVERSION) #error "MVERSION undefined" #else #define VERSION MVERSION #endif #if !defined(MLOGFILE) #error "MLOGFILE undefined" #else #define LOGFILE MLOGFILE #endif #if !defined(MLOGLEVEL) #error "MLOGLEVEL undefined" #else #define LOGLEVEL MLOGLEVEL #endif #if !defined(MSERVICEDIR) #error "MSERVICEDIR undefined" #else #define SERVICEDIR MSERVICEDIR #endif #define CONFIG_FILE (MSERVICEDIR "/sms_config") #define SMSLOCK_FILE (MSERVICEDIR "/smslock") /* -------------------------------------------------------------------- */ static char *SMS_lock_action, *SMS_lockfile, *SMS_default_service; static char *current_message = NULL; static long SMS_lock_retry_delay, SMS_service_timeout; /* -------------------------------------------------------------------- */ #define MAXMESSAGELEN 150 #define MAXMESSAGES 256 #define SERVICETIMEOUT SMS_service_timeout /* -------------------------------------------------------------------- */ static RESOURCE resource_list[] = { { RESOURCE_STRING, "SMS_default_service", 0, 1, NULL, 0, "CELLNET", 0, &SMS_default_service }, { RESOURCE_STRING, "SMS_lock_action", 0, 1, NULL, 0, "BLOCK", 0, &SMS_lock_action }, { RESOURCE_NUMERIC, "SMS_lock_retry_delay", 0, 0, NULL, 0, NULL, 5000000, &SMS_lock_retry_delay }, { RESOURCE_STRING, "SMS_lockfile", 0, 1, NULL, 0, SMSLOCK_FILE, 0, &SMS_lockfile }, { RESOURCE_NUMERIC, "SMS_service_timeout", 0, 1, NULL, 0, NULL, 300, &SMS_service_timeout }, { RESOURCE_NULL, NULL, 0, 1, NULL, 0, NULL, 0, NULL } }; /* -------------------------------------------------------------------- */ void get_message(char *message); void usage(char *file); int main(int, char *[]); /* -------------------------------------------------------------------- */ static volatile sig_atomic_t child_flag, alarm_flag; int child_status; void trap_child(int signo) { child_flag = TRUE; } void trap_alarm(int signo) { alarm_flag = TRUE; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ void get_message(char *message) { int i, c; if (isatty(fileno(stdin))) { printf("Enter your message and end with Control-D\n"); } for (i=0; iinit)(mservice, device) == -1) { lprintf(LOG_ERROR, "Driver Initialization Failed\n"); delivery_error = EDELIVERY; } else { access_set_message(NULL, message); (*device->main)(list, access_get_first, access_get_next, access_get_number, access_get_message, access_set_delivery, device->env); time(&driver_end_time); lprintf(LOG_STANDARD, "%s Service Time: %d Seconds\n", mservice, (int)(driver_end_time - driver_start_time)); delivered = list; while (delivered != NULL) { if (get_delivery(delivered)) { lprintf(LOG_WARNING, "Could not deliver message %d to %s on %s delivery code %d\n", message_num, get_name(delivered), get_number(delivered), get_delivery(delivered)); delivery_error = EDELIVERY; } lprintf(LOG_STANDARD, "[%03d] %s:%s \"%s\"\n", get_delivery(delivered), get_service(delivered), get_number(delivered), access_get_message(delivered)); delivered = get_next(delivered); } } return delivery_error; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int main(int argc, char *argv[]) { DEVICE_ENTRY *device; char *mservice, message[MAXMESSAGES][MAXMESSAGELEN +1], *ptr, *protocol, *progname; int i, num_messages; SMS_parent_list *parent_node, *parent_list; SMS_list *list, *numbers; TOKEN_HEAP *global, *local; int num_args, nind, mind, c, delivery_error = 0; time_t start_time, end_time; pid_t pid; sigset_t newmask, zeromask, origmask, parentmask; void (* prev_sigalrm)(int); void (* prev_sigchld)(int); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } /* ---------------------------- */ set_logfile(LOGFILE); set_loglevel(LOGLEVEL); set_consolelog(TRUE); /* ---------------------------- */ while ((c = getopt (argc, argv, "vql:m:d")) != -1) { switch (c) { case 'q': set_consolelog(FALSE); break; case 'd': display_drivers(); exit(0); case 'v': lprintf(LOG_STANDARD, "%s %s\n", progname, VERSION); exit(0); case 'l': set_loglevel((int)strtol(optarg, &ptr, 10)); if (ptr == optarg) { lprintf(LOG_ERROR, "Option l requires an argument\n"); usage(progname); exit(EUSAGE); } break; case '?': #if !defined(NEXT) lprintf(LOG_ERROR, "Unknown option `-%c'\n", optopt); #endif usage(progname); exit(EUSAGE); default: abort (); } } /* ---------------------------- */ num_args = argc - optind; if (num_args < 1) { usage(progname); exit(EUSAGE); } nind = optind; mind = optind +1; /* ---------------------------- */ lprintf(LOG_VERYVERBOSE, "Version Information: '%s'\n", VERSION); /* ---------------------------- */ if (read_resource_file(CONFIG_FILE, resource_list, TRUE) != RESOURCE_FILE_OK) { lprintf(LOG_ERROR, "Unrecoverable Failure Parsing file '%s'\n", CONFIG_FILE); exit(1); } /* ---------------------------- */ /* Get and expand NAMES|NUMBERS */ if (SMS_dual_openrc(&global, &local) == -1) { exit(-1); } numbers = SMS_expandnumber(global, local, "", argv[nind], SMS_default_service); SMS_dual_closerc(global, local); /* ---------------------------- */ /* Check NAMES|NUMBERS */ if (SMS_validate_expanded_numbers(numbers)) { lprintf(LOG_ERROR, "Expanding names\n"); exit(ENAMEEXPANSION); } /* ---------------------------- */ if (num_args >= 2) { for (i=mind; i MAXMESSAGELEN) { lprintf(LOG_ERROR, "Message %d too long\n", (i - mind +1)); exit(EMESSAGETOOLONG); } strcpy(message[i - mind], argv[i]); } num_messages = argc - mind; } else { get_message(message[0]); num_messages = 1; } /* ------------------------------------------------------------ */ /* If sms_lock_action is set to BLOCK any other instances of */ /* sms_client which are running will cause this one to block. */ /* When the other instances have finished executing and the */ /* lockfile has been released this instance can attemp to */ /* get the lockfile and run */ /* ------------------------------------------------------------ */ if (SMS_obtain_lock(SMS_lockfile) == -1) { exit(-1); } /* ------------------------------------------------------------ */ time(&start_time); parent_list = gather(numbers); for (parent_node = get_first_parent(parent_list); parent_node != NULL; parent_node = get_next_parent(parent_node)) { list = get_child(parent_node); mservice = get_service(list); protocol = get_protocol(mservice); if (protocol == NULL) { lprintf(LOG_ERROR, "Service '%s' does not have a valid protocol entry\n", mservice); continue; } device = get_device(protocol); if (device == NULL) { lprintf(LOG_ERROR, "Driver for service '%s' NOT found\n", mservice); } else { /* ------------------------------------ */ /* Add SIGCHLD to set of blocked */ /* signals. */ /* ------------------------------------ */ sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); lprintf(LOG_VERYVERBOSE, "SIGCHLD is being blocked\n"); if (sigprocmask(SIG_BLOCK, &newmask, &origmask) == -1) { exit(-1); } lprintf(LOG_VERYVERBOSE, "Installing signal handler for SIGCHLD\n"); prev_sigchld = signal(SIGCHLD, trap_child); if (prev_sigchld == SIG_ERR) { exit(-1); } /* ------------------------------------ */ lprintf(LOG_VERBOSE, "Forking process for service '%s'\n", mservice); pid = fork(); switch (pid) { case 0: /* Child */ { /* -------------------------------------------- */ /* Return child process' signal mask back */ /* to it's original state. */ /* -------------------------------------------- */ if (signal(SIGCHLD, prev_sigchld) == SIG_ERR) { exit(-1); } if (sigprocmask(SIG_SETMASK, &origmask, NULL) == -1) { exit(-1); } /* -------------------------------------------- */ lprintf(LOG_VERBOSE, "Started process for service '%s'\n", mservice); for (i=0; i