Source File ak/ack.c

    1    | /***************************************
    2    |   $Revision: 1.7 $
    3    |
    4    |   AK (Acknowledgement) module
    5    |
    6    |   Status: REVIEWED, NOT TESTED
    7    |
    8    |   Author(s):       Engin Gunduz
    9    |
    10   |   ******************/ /******************
    11   |   Modification History:
    12   |         engin (10/06/2000) Created.
    13   | 		denis (25/09/2001) modified for new API
    14   |   ******************/ /******************
    15   |   Copyright (c) 2000,2001,2002                    RIPE NCC
    16   |
    17   |   All Rights Reserved
    18   |
    19   |   Permission to use, copy, modify, and distribute this software and its
    20   |   documentation for any purpose and without fee is hereby granted,
    21   |   provided that the above copyright notice appear in all copies and that
    22   |   both that copyright notice and this permission notice appear in
    23   |   supporting documentation, and that the name of the author not be
    24   |   used in advertising or publicity pertaining to distribution of the
    25   |   software without specific, written prior permission.
    26   |
    27   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    28   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    29   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    30   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    31   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    32   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    33   |  ***************************************/
    34   |
    35   |
    36   |
    37   | #include "ack.h"
    38   | extern int supress_ack_notif;
    39   | extern char * humailbox;
    40   | extern char * failuretxt;
    41   | extern char * helpheader;
    42   | extern char * successtxt;
    43   | extern char * defmail;
    44   | extern char * acksig;
    45   | extern up_subject_struct subject_result;
    46   | extern int count_successful;
    47   | extern int count_unsuccessful;
    48   | extern char *netupdclientIP;
    49   |
    50   | extern int reading_from_mail;
    51   | extern int networkupdate;
    52   |
    53   | /* web update flags */
    54   | extern int webupdate;
    55   | extern int help_requested;
    56   | extern int enforced_new;
    57   |
    58   | /*
    59   |
    60   |   AK_add_to_ack: writes a message to the acknowledgement file.
    61   |     Also, prints it out to the stdout if it was a networkupdate
    62   |     (networkupdate is run through inetd, so stdout is our socket)
    63   |
    64   | */
    65   |
    66   | void AK_add_to_ack(const char * filename, char * fmt, ...){
    67   |
    68   |   va_list ap;  /* points to each unnamed arg in turn */
    69   |   char *p, *sval;
    70   |   int ival;
    71   |   double dval;
    72   |   FILE * ack_file;
    73   |
    74   |   if(( ack_file = fopen(filename, "a")) == NULL){
    75   |     fprintf(stderr, "Can't open ack file, %s", filename);
    76   |   }
    77   |
    78   |
    79   |   /* if this is a network update, print it out first to the
    80   |      stdout (which is socket) */
    81   |   if(networkupdate){
    82   |     va_start(ap, fmt);
    83   |     vprintf(fmt, ap);
    84   |     fflush(stdout);
    85   |     va_end(ap);
    86   |   }
    87   |
    88   |   /* and then to the file */
    89   |   va_start(ap, fmt);
    90   |
    91   |   for(p = fmt; *p; p++){
    92   |     if (*p != '%') {
    93   |       fprintf(ack_file, "%c", *p);
    94   |       continue;
    95   |     }
    96   |     switch(*++p) {
    97   |     case 'd':
    98   |       ival = va_arg(ap, int);
    99   |       fprintf(ack_file, "%d", ival);
    100  |       break;
    101  |     case 'f':
    102  |       dval = va_arg(ap, double);
    103  |       fprintf(ack_file, "%f", dval);
    104  |       break;
    105  |     case 'X':
    106  |       ival = va_arg(ap, int);
    107  |       fprintf(ack_file, "%X", ival);
    108  |       break;
    109  |     case 'x':
    110  |       ival = va_arg(ap, int);
    111  |       fprintf(ack_file, "%x", ival);
    112  |       break;
    113  |     case 's':
    114  |       sval = va_arg(ap, char *);
    115  |       fprintf(ack_file, "%s", sval);
    116  |       break;
    117  |     default:
    118  |       putchar(*p);
    119  |       break;
    120  |     }
    121  |   }
    122  |
    123  |   va_end(ap); /* clean up */
    124  |   fclose(ack_file);
    125  | }
    126  |
    127  |
    128  |
    129  | /* Adds a complete file to the ack file */
    130  |
    131  | void AK_add_file_to_ack(const char * ackfile, const char * filetoadd){
    132  |
    133  |   FILE * ack_file, * file_to_add;
    134  |   char   buf[1024];
    135  |
    136  |   if(( ack_file = fopen(ackfile, "a")) == NULL){
    137  |     fprintf(stderr, "AK_add_file_to_ack: Can't open ack file, %s\n", ackfile);
    138  |   }
    139  |
    140  |   if(( file_to_add = fopen(filetoadd, "r")) == NULL){
    141  |
    142  |     fprintf(stderr, "AK_add_file_to_ack: Can't open file, %s\n", filetoadd);
    143  |     fprintf(ack_file, "\nHelp file could not be found.\nPlease notify the database administrator.\n");
    144  |     fclose(ack_file);
    145  |     free(buf);
    146  |
    147  |   }else{
    148  |
    149  |     while(fgets(buf, 1023, file_to_add) != NULL){
    150  |       fprintf(ack_file, "%s", buf);
    151  |     }
    152  |
    153  |     fclose(ack_file);
    154  |     fclose(file_to_add);
    155  |   }
    156  | }
    157  |
    158  |
    159  | /*
    160  |
    161  |   AK_ack_file_name_generate: Generates a unique name for temporary acknowledgement
    162  |      files, and also creates it.
    163  |
    164  |       tmpdir: temporary directory (without a trailing '/')
    165  |       prefix: prefix for the temp file
    166  |
    167  |       returns: the generated name.
    168  | */
    169  |
    170  | char * AK_ack_file_name_generate( const char * tmpdir, const char * prefix)
    171  | {
    172  |    FILE * ack_file;
    173  |    char * name;
    174  |
    175  |    /* allocate space for name. 32 should be enough for PID */
    176  |    name = (char*)malloc(strlen(tmpdir) + strlen(prefix) + 35);
    177  |
    178  |    sprintf(name, "%s/%s.%i", tmpdir, prefix, (int)(getpid()) );
    179  |
    180  |    /* create the file */
    181  |    if (( ack_file = fopen(name, "w")) == NULL)
    182  |    {
    183  |      fprintf(stderr, "Can't open ack file, %s", name);
    184  |    }
    185  |
    186  |    /* close it */
    187  |    fclose(ack_file);
    188  |
    189  |    return name;
    190  | }
    191  |
    192  |
    193  | /*
    194  |
    195  | AK_send_ack: post-processes and sends the ack message contained in the temp file.
    196  |
    197  |
    198  | */
    199  |
    200  | void AK_send_ack( const char * filename, const char * to_address, const char * mailercommand)
    201  | {
    202  |     char * mail_command_line = NULL;
    203  |     char * supress_file = NULL, * temp_file = NULL;
    204  |     FILE * ack_file, * supr_file_hdl, * temp_file_hdl;
    205  |     char *txt_replaced;
    206  |     char buf[1024];
    207  |
    208  |     /* first check if we the user specified some non-keyword words in
    209  |        the subject line (in addition to some valid keywords)
    210  |        If so, we will add a warning to the ack file */
    211  |     if (subject_result.result == UP_SUBJ_UNRECOG)
    212  | 	{
    213  |       if (( ack_file = fopen(filename, "a")) == NULL)
    214  | 	  {
    215  |         fprintf(stderr, "Can't open ack file for appending, %s", filename);
    216  |       }
    217  | 	  else
    218  | 	  {
    219  |         fprintf(ack_file, "\nWarning: unknown keywords found in subject line:\n"
    220  |                    "%s\n"
    221  |                    "Thus, all keywords in subject line were ignored.\n",
    222  |                     subject_result.word_list ? subject_result.word_list : "" );
    223  |         fclose(ack_file);
    224  |       }
    225  |
    226  |     /* and now check if the user specified an invalid combination of keywords
    227  |        in the subject line, and if so, print an appropriate warning to ack */
    228  |     }
    229  | 	else if (subject_result.result == UP_SUBJ_INVALID_COMB)
    230  | 	{
    231  |       if (( ack_file = fopen(filename, "a")) == NULL)
    232  | 	  {
    233  |         fprintf(stderr, "Can't open ack file for appending, %s", filename);
    234  |       }
    235  | 	  else
    236  | 	  {
    237  |         if ( webupdate )
    238  |         {
    239  |           fprintf(ack_file, "\nWarning: This combination of options of 'help' and 'new' is not allowed.\n"
    240  |                    "Thus, all options were ignored.\n");
    241  |         }
    242  |         else
    243  |         {
    244  |           fprintf(ack_file, "\nWarning: This combination of keywords in subject line is not allowed.\n"
    245  |                    "Thus, all keywords in subject line were ignored.\n");
    246  |         }
    247  |         fclose(ack_file);
    248  |       }
    249  |     }
    250  |
    251  |     /* if the update didn't contain any objects and was not a request for help, put a warning */
    252  |     if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
    253  | 	{
    254  |       AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
    255  |     }
    256  |
    257  |     /* add the ACKSIG to the ack */
    258  |     AK_add_to_ack(filename ,"\n%s", acksig);
    259  |
    260  |     /* Here, we will print out the header of the ACK message. It cannot be
    261  |        prepared before, since we wouldn't know if the header should use
    262  |        SUCCESSTXT or FAILURETXT */
    263  |     temp_file = (char *)malloc(strlen(filename) + strlen(".temp") + 2);
    264  |     sprintf(temp_file, "%s.temp", filename);
    265  |     if(( temp_file_hdl = fopen(temp_file, "w")) == NULL)
    266  | 	{
    267  |       fprintf(stderr, "Can't open temp ack file, %s\n", temp_file);
    268  |     }
    269  | 	else
    270  | 	{
    271  |       if ( subject_result.result == UP_SUBJ_HELP_REQ )
    272  |       {
    273  |         /* this is a request for help, so we will use the HELPHEADER */
    274  |         /* replace the global variables in helpheader */
    275  |         txt_replaced = UP_replace_globals(helpheader);
    276  |       }
    277  |       else if (count_unsuccessful > 0 || (count_successful + count_unsuccessful) == 0)
    278  | 	  {
    279  |         /* At least one of the objects failed or there wasn't any object in the
    280  |         update message. We will use FAILURETXT */
    281  |         /* replace the global variables in failuretxt */
    282  |         txt_replaced = UP_replace_globals(failuretxt);
    283  | 	  }
    284  | 	  else
    285  | 	  {
    286  |         /* All the objects in the update message were successful. So, we will
    287  |         use SUCCESSTXT */
    288  |         /* replace the global variables in successtxt */
    289  |         txt_replaced = UP_replace_globals(successtxt);
    290  | 	  }
    291  |
    292  |       /* print out the success/failure/help txt */
    293  |       fprintf(temp_file_hdl, "To: %s\n%s\n\n", to_address, txt_replaced);
    294  |       free(txt_replaced);
    295  |       /* and now copy over the rest of the ack message */
    296  |       if (( ack_file = fopen(filename, "r")) == NULL)
    297  | 	  {
    298  |         fprintf(stderr, "Can't open ack file for reading, %s", filename);
    299  |       }
    300  | 	  else
    301  | 	  {
    302  |         while (fgets(buf, 1024, ack_file) != NULL)
    303  | 		{
    304  |           fprintf(temp_file_hdl, "%s", buf);
    305  |         }
    306  |         fclose(ack_file);
    307  |       }
    308  |       fclose(temp_file_hdl);
    309  |       /* and copy rename the temp file  */
    310  |       rename(temp_file, filename);
    311  |       free(temp_file);
    312  |     }
    313  |
    314  |     /* if we are not supressing acks and notifs, send the ack */
    315  |     if (!supress_ack_notif)
    316  | 	{
    317  |       if (to_address != NULL)
    318  | 	  {
    319  |         mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(to_address)
    320  |             + strlen(filename) + 128);
    321  |         sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
    322  |         system(mail_command_line);
    323  |       }
    324  |     }
    325  | 	else
    326  | 	{
    327  |       /* if we are supressing acks and notifs, send ack to DEFMAIL  */
    328  |       supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2);
    329  |       sprintf(supress_file, "%s.supress", filename);
    330  |       if (( supr_file_hdl = fopen(supress_file, "w")) == NULL)
    331  | 	  {
    332  |         fprintf(stderr, "Can't open supress ack file, %s", supress_file);
    333  |       }
    334  | 	  else
    335  | 	  {
    336  |         fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed ack mail\n\n",
    337  |             humailbox, defmail);
    338  |         if (( ack_file = fopen(filename, "r")) == NULL)
    339  | 		{
    340  |           fprintf(stderr, "Can't open ack file for reading, %s", filename);
    341  |         }
    342  | 		else
    343  | 		{
    344  |           while (fgets(buf, 1024, ack_file) != NULL)
    345  | 		  {
    346  |             fprintf(supr_file_hdl, "%s", buf);
    347  |           }
    348  |           fclose(ack_file);
    349  |         }
    350  |     	fclose(supr_file_hdl);
    351  |     	mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail)
    352  |               + strlen(supress_file) + 128);
    353  |     	sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file);
    354  |     	system(mail_command_line);
    355  |     	unlink(supress_file);
    356  |       }
    357  |       free(supress_file);
    358  |     }
    359  | }
    360  |
    361  |
    362  |
    363  | /*
    364  |
    365  |   AK_print_ack: Prints out the given file (the ack file) to the standard output
    366  |
    367  | */
    368  | void AK_print_ack( const char * filename )
    369  | {
    370  |     FILE * ack_file;
    371  |     char buf[1024];
    372  |
    373  | 	if (subject_result.result == UP_SUBJ_INVALID_COMB && webupdate)
    374  | 	{
    375  |       if (( ack_file = fopen(filename, "a")) == NULL)
    376  | 	  {
    377  |         fprintf(stderr, "Can't open ack file for appending, %s", filename);
    378  |       }
    379  | 	  else
    380  | 	  {
    381  |         fprintf(ack_file, "\nWarning: This combination of options of 'help' and 'new' is not allowed.\n"
    382  |                    "Thus, all options were ignored.\n");
    383  |         fclose(ack_file);
    384  |       }
    385  |     }
    386  |
    387  |     /* if the update didn't contain any objects and was not a request for help, put a warning */
    388  |     if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
    389  | 	{
    390  |       AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
    391  |     }
    392  |
    393  |     if (( ack_file = fopen(filename, "r")) == NULL)
    394  | 	{
    395  |       fprintf(stderr, "Can't open ack file for reading, %s", filename);
    396  |     }
    397  | 	else
    398  | 	{
    399  |       while (fgets(buf, 1024, ack_file) != NULL)
    400  | 	  {
    401  |         printf("%s", buf);
    402  |       }
    403  |       fclose(ack_file);
    404  |     }
    405  | }
    406  |
    407  |
    408  |
    409  | /*
    410  |
    411  |   AK_delete_ack: deletes the temporary acknowledgement file.
    412  |
    413  | */
    414  |
    415  | void AK_delete_ack( const char * filename )
    416  | {
    417  |    unlink(filename);
    418  | }
    419  |
    420  |
    421  | /*
    422  |
    423  | AK_log_ack: logs the acknowledgements in the "logfilename.date".
    424  |
    425  | */
    426  |
    427  | void AK_log_ack(const char * filename, const char * logfilename)
    428  | {
    429  |   FILE * ack_file, * log_file;
    430  |   char   buf[1024];
    431  |   time_t cur_time;
    432  |   char * time_str;
    433  |   char * logfile_date;
    434  |   char * date;
    435  |
    436  |   if (( ack_file = fopen(filename, "r")) == NULL)
    437  |   {
    438  |     fprintf(stderr, "Can't open ack file for reading, %s\n", filename);
    439  |     return;
    440  |   }
    441  |
    442  |
    443  |   /* construct the "logfilename.date" string */
    444  |   logfile_date = (char *)malloc(strlen(logfilename) + 10);
    445  |   date = UP_get_current_date();
    446  |   snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date);
    447  |   free(date);
    448  |
    449  |   if (( log_file = fopen(logfile_date, "a")) == NULL)
    450  |   {
    451  |     fprintf(stderr, "Can't open log file for appending, %s\n", logfile_date);
    452  | 	free(logfile_date);
    453  |     return;
    454  |   }
    455  |   free(logfile_date);
    456  |
    457  |   /* get time */
    458  |   cur_time = time(NULL);
    459  |   time_str = strdup(ctime(&cur_time));
    460  |   /* cut the '\n' at the end */
    461  |   time_str[strlen(time_str) - 1] = '\0';
    462  |
    463  |   if (reading_from_mail)
    464  |   {
    465  |     fprintf(log_file, ">>> time: %s MAIL ACK <<<\n\n", time_str);
    466  |   }
    467  |   else if (networkupdate)
    468  |   {
    469  |     fprintf(log_file, ">>> time: %s NETWORKUPDATE (%s) ACK <<<\n\n",
    470  |                   time_str, netupdclientIP ? netupdclientIP : "NULL" );
    471  |   }
    472  |   else if (webupdate)
    473  |   {
    474  |     fprintf(log_file, ">>> time: %s WEB UPDATE (%s) ACK <<<\n\n",
    475  |                   time_str, netupdclientIP ? netupdclientIP : "NULL" );
    476  |   }
    477  |   else
    478  |   {
    479  |     fprintf(log_file, ">>> time: %s ACK <<<\n\n", time_str);
    480  |   }
    481  |
    482  |   while (fgets(buf, 1023, ack_file) != NULL)
    483  |   {
    484  |     fprintf(log_file, "%s", buf);
    485  |   }
    486  |
    487  |   free(time_str);
    488  |   fclose(ack_file);
    489  |   fclose(log_file);
    490  | }
    491  |
    492  |
    493  |
    494  |
    495  |
    496  |
    497  |
    498  |