/* -------------------------------------------------------------------- */ /* SMS Client, send messages to mobile phones and pagers */ /* */ /* process.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 "common/common.h" #include "logfile/logfile.h" #include "process.h" #include "parser/gs_token.h" #include "parser/gs_translate.h" #include "driver/driver.h" #include "fread.h" #include "error.h" /* -------------------------------------------------------------------- */ #define MAX_PATH 256 /* -------------------------------------------------------------------- */ #define TF_UNKNOWN 0 #define TF_CONTROL 1 #define TF_DATA 2 /* -------------------------------------------------------------------- */ struct file_list_struct { char *name, *data, *dest_id; int type, data_len; time_t mtime; TOKEN_HEAP *heap; struct file_list_struct *next; }; typedef struct file_list_struct FILE_LIST; /* -------------------------------------------------------------------- */ static FILE_LIST *add_front_file_item(FILE_LIST *list, char *name, time_t mtime, int type); static FILE_LIST *qsort_list(FILE_LIST *list); static FILE_LIST *get_first_control_file(FILE_LIST *list); static FILE_LIST *get_next_control_file(FILE_LIST *list); static void dump_list(FILE_LIST *list); static void free_list(FILE_LIST *list); static int reject_file(char *file, char *queue_dir, char *error_dir); static int remove_file(char *file, char *queue_dir, char *error_dir); static int num_items_in_list(FILE_LIST *list); static int file_item_compare(const void *item1, const void *item2); static FILE_LIST *generate_file_list(int *num, char *queue); /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static FILE_LIST *add_front_file_item(FILE_LIST *list, char *name, time_t mtime, int type) { FILE_LIST *item; item = (FILE_LIST *)malloc(sizeof(FILE_LIST)); if (item == NULL) { lprintf(LOG_ERROR, "malloc() failed\n"); exit(EMALLOC); } item->name = (char *)malloc(sizeof(char) * (strlen(name) +1)); if (item->name == NULL) { lprintf(LOG_ERROR, "malloc() failed\n"); exit(EMALLOC); } strcpy(item->name, name); item->mtime = mtime; item->type = type; item->next = list; item->heap = NULL; item->data = NULL; return item; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static int num_items_in_list(FILE_LIST *list) { int count; FILE_LIST *item; count = 0; item = list; while(item != NULL) { count++; item = item->next; } return count; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static int file_item_compare(const void *item1, const void *item2) { time_t mtime_1, mtime_2; mtime_1 = (*(FILE_LIST **)item1)->mtime; mtime_2 = (*(FILE_LIST **)item2)->mtime; if (mtime_1 > mtime_2) { return 1; } if (mtime_1 < mtime_2) { return -1; } return strcmp((*(FILE_LIST **)item1)->name, (*(FILE_LIST **)item2)->name); } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static FILE_LIST *qsort_list(FILE_LIST *list) { int count, i; FILE_LIST **file_list_array, *item; if (list == NULL) { return NULL; } count = num_items_in_list(list); file_list_array = (FILE_LIST **)malloc(sizeof(FILE_LIST *) * count); if (file_list_array == NULL) { lprintf(LOG_ERROR, "malloc() failed\n"); exit(EMALLOC); } item = list; for (i=0; item != NULL; i++) { file_list_array[i] = item; item = item->next; } qsort(file_list_array, count, sizeof(FILE_LIST *), file_item_compare); list = file_list_array[0]; for (i=0; inext = file_list_array[i+1]; } file_list_array[i]->next = NULL; free(file_list_array); return list; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static void dump_list(FILE_LIST *list) { FILE_LIST *item; char *stype; if (list == NULL) { return; } item = list; while(item != NULL) { if (item->type == TF_CONTROL) { stype = "CONTROL"; } else if (item->type == TF_DATA) { stype = "DATA"; } else { stype = "UNKNOWN"; } lprintf(LOG_VERBOSE, "%s %d %s\n", item->name, (int)item->mtime, stype); item = item->next; } } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static FILE_LIST *get_first_control_file(FILE_LIST *list) { FILE_LIST *item; item = list; while (item != NULL) { if (strncmp(item->name, "cf", 2) == 0) { return item; } item = item->next; } return NULL; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static FILE_LIST *get_next_control_file(FILE_LIST *list) { FILE_LIST *item; if (list == NULL) { return NULL; } item = list->next; while (item != NULL) { if (strncmp(item->name, "cf", 2) == 0) { return item; } item = item->next; } return NULL; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static void free_list(FILE_LIST *list) { FILE_LIST *prev_item, *item; if (list == NULL) { return; } item = list; while(item != NULL) { prev_item = item; item = item->next; if (prev_item->heap != NULL) { free_heap(prev_item->heap); } free(prev_item->name); free(prev_item); } } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ extern char queue_queuedir[], queue_errordir[]; static void *access_get_first(void *list); static void *access_get_next(void *node); static char *access_get_number(void *node); static char *access_get_message(void *node); static void *access_get_first(void *list) { /* check item is valid else get next*/ lprintf(LOG_VERYVERBOSE, "Getting first file\n"); return (void *)get_first_control_file((FILE_LIST *)list); } static void *access_get_next(void *node) { /* check item is valid else get next*/ FILE_LIST *item, *new_list; int num; item = get_next_control_file((FILE_LIST *)node); if (item == NULL) { /* ------------------------------------------------------------ */ /* We have processed all of the file in the list. */ /* We should now check that new files/items haven't been added */ /* while we were busy sending. If they were then we want to add */ /* them to out list of files left to process. */ /* */ /* NOTE - As files which contained error have been moved to the */ /* appropriate errors directory we needn't worry about */ /* processing the same file twice. */ /* ------------------------------------------------------------ */ lprintf(LOG_VERYVERBOSE, "Last item processed, checking for additional files...\n"); new_list = generate_file_list(&num, queue_queuedir); if (new_list == NULL) { if (num != 0) { lprintf(LOG_ERROR, "Generating file list\n"); exit(-1); } } else { lprintf(LOG_VERYVERBOSE, "Found %d additional files\n", num); } /* ------------------------------------------------------------ */ /* We must skip to the end of our list as the current */ /* item may not be the last! */ /* Now we append the new list if any. */ /* ------------------------------------------------------------ */ item = (FILE_LIST *)node; while(item->next != NULL) { item = item->next; } item->next = new_list; item = item->next; } return item; } static char *access_get_number(void *node) { return get_strvalue(((FILE_LIST *)node)->heap, "destination_id"); } static char *access_get_message(void *node) { #if 0 sleep(5); #endif return ((FILE_LIST *)node)->data; } static void access_set_delivery(void *node, int result) { FILE_LIST *item; item = (FILE_LIST *)node; /* if delivery successful, remove file. */ /* if failed move to error directory */ if (result == 0) { lprintf(LOG_VERBOSE, "Successfully delivered '%s'\n", item->name); if (remove_file(item->name, queue_queuedir, queue_errordir) == -1) { lprintf(LOG_WARNING, "Failed to Remove '%s'\n", item->name); exit(-1); } } else { lprintf(LOG_WARNING, "Failed to deliver '%s'\n", item->name); if (reject_file(item->name, queue_queuedir, queue_errordir) == -1) { lprintf(LOG_WARNING, "Failed to Move '%s'\n", item->name); exit(-1); } } } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ int process_queue(char *queue, char *error, DEVICE_ENTRY *device) { FILE_LIST *file_list = NULL; int num; while ((file_list = generate_file_list(&num, queue)) != NULL) { /* ------------------------------------------------------------ */ /* Dispatch driver function to deliver messages. */ /* ------------------------------------------------------------ */ (*device->main)(file_list, access_get_first, access_get_next, access_get_number, access_get_message, access_set_delivery, device->env); lprintf(LOG_VERYVERBOSE, "Finished sending messages.\n"); /* ------------------------------------------------------------ */ free_list(file_list); } if (num == 0) { lprintf(LOG_VERBOSE, "No files to process.\n"); } else { lprintf(LOG_ERROR, "Processing queue '%s'.\n", queue); return -1; } return 0; } /* -------------------------------------------------------------------- */ /* Remove file from from 'queue' directory */ /* */ /* Return Values: */ /* 0 Success */ /* -1 Failure */ /* -------------------------------------------------------------------- */ static int remove_file(char *file, char *queue_dir, char *error_dir) { char nname[512], dname[512]; int dfres, cfres; if ((file[0] == 'c') && (file[1] == 'f')) { strcpy(dname, file); dname[0] = 'd'; dname[1] = 'f'; lprintf(LOG_VERBOSE, "Removing '%s'\n", dname); strcpy(nname, queue_dir); libcommon_strfcat(nname, dname); dfres = unlink(nname); } lprintf(LOG_VERBOSE, "Removing '%s'\n", file); strcpy(nname, queue_dir); libcommon_strfcat(nname, file); cfres = unlink(nname); return (dfres || cfres); } /* -------------------------------------------------------------------- */ /* Move file from from 'queue' directory into 'error' directory */ /* */ /* Return Values: */ /* 0 Success */ /* -1 Failure */ /* -------------------------------------------------------------------- */ static int reject_file(char *file, char *queue_dir, char *error_dir) { char nname[512], oname[512], dname[512]; int dfres, cfres; if ((file[0] == 'c') && (file[1] == 'f')) { strcpy(dname, file); dname[0] = 'd'; dname[1] = 'f'; lprintf(LOG_WARNING, "Moving '%s' to '%s'\n", dname, queue_errordir); strcpy(oname, queue_dir); libcommon_strfcat(oname, dname); strcpy(nname, error_dir); libcommon_strfcat(nname, dname); dfres = rename(oname, nname); } lprintf(LOG_WARNING, "Moving '%s' to '%s'\n", file, queue_errordir); strcpy(oname, queue_dir); libcommon_strfcat(oname, file); strcpy(nname, error_dir); libcommon_strfcat(nname, file); cfres = rename(oname, nname); return (dfres || cfres); } /* -------------------------------------------------------------------- */ /* Generate sorted list of entries in queue directory. */ /* Parse each entry and add a token_heap to it. */ /* */ /* Return Values: */ /* NULL and 'num' set to -1 on error */ /* -------------------------------------------------------------------- */ static FILE_LIST *generate_file_list(int *num, char *queue) { DIR *dir; struct dirent *entry; struct stat status; char cwd[MAX_PATH+1]; char dname[512], *data, *dest_id; FILE_LIST *file_list = NULL; int type, data_len; TOKEN_HEAP *heap; *num = 0; dir = opendir(queue); if (dir == NULL) { *num = -1; lprintf(LOG_ERROR, "Failed to open directory '%s'\n", queue); return NULL; } if (getcwd(cwd, MAX_PATH+1) == NULL) { *num = -1; lprintf(LOG_ERROR, "getcwd() failed\n"); return NULL; } if (chdir(queue) != 0) { *num = -1; lprintf(LOG_ERROR, "chdir() failed\n"); return NULL; } while((entry = readdir(dir)) != NULL) { if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) { if (stat(entry->d_name, &status) != 0) { lprintf(LOG_ERROR, "stat() failed\n"); return NULL; } if (!S_ISDIR(status.st_mode)) { if (strncmp(entry->d_name, "cf", 2) == 0) { type = TF_CONTROL; } else if (strncmp(entry->d_name, "df", 2) == 0) { type = TF_DATA; } else { type = TF_UNKNOWN; } if (type != TF_UNKNOWN) { if (type == TF_CONTROL) { /* IF file is a control file parse it. */ /* IF control file is invalid DO NOT add it */ /* to the file list. */ heap = gs_parse_file(entry->d_name); if (heap == NULL) { lprintf(LOG_WARNING, "Rejecting file '%s'\n", entry->d_name); if (reject_file(entry->d_name, queue_queuedir, queue_errordir) == -1) { lprintf(LOG_WARNING, "Failed to Move '%s'\n", entry->d_name); exit(-1); } } else { /* validate entries in control file. */ /* IF not valid DO NOT add to list. */ /* It might be nice to slurp the contents */ /* of the data file into 'item' */ if ((dest_id = get_strvalue(heap, "destination_id")) == NULL) { lprintf(LOG_VERBOSE, "Could not find 'destination_id'\n"); if (reject_file(entry->d_name, queue_queuedir, queue_errordir) == -1) { lprintf(LOG_WARNING, "Failed to Move '%s'\n", entry->d_name); exit(-1); } } else { strcpy(dname, entry->d_name); dname[0] = 'd'; dname[1] = 'f'; lprintf(LOG_VERBOSE, "Reading Datafile '%s'\n", dname); data = slurp_file(dname, &data_len); if (data == NULL) { lprintf(LOG_VERBOSE, "Failed to read datafile '%s'\n", dname); if (reject_file(entry->d_name, queue_queuedir, queue_errordir) == -1) { lprintf(LOG_WARNING, "Failed to Move '%s'\n", entry->d_name); exit(-1); } } else { file_list = add_front_file_item(file_list, entry->d_name, status.st_mtime, type); file_list->heap = heap; file_list->data = data; file_list->data_len = data_len; file_list->dest_id = dest_id; *num = *num +1; } } } } } else { lprintf(LOG_WARNING, "Found file '%s', expecting Control or Data File\n", entry->d_name); } } } } if (closedir(dir) != 0) { *num = -1; lprintf(LOG_ERROR, "closedir() failed\n"); return NULL; } if (file_list != NULL) { file_list = qsort_list(file_list); } if (chdir(cwd) != 0) { *num = -1; lprintf(LOG_ERROR, "chdir() failed\n"); return NULL; } dump_list(file_list); return file_list; }