1    | /***************************************
2    |   $Revision: 1.5 $
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 int * reading_from_mail;
46   | extern int networkupdate;
47   | extern up_subject_struct subject_result;
48   | extern int count_successful;
49   | extern int count_unsuccessful;
50   | 
51   | /*
52   | 
53   |   AK_add_to_ack: writes a message to the acknowledgement file.
54   |     Also, prints it out to the stdout if it was a networkupdate
55   |     (networkupdate is run through inetd, so stdout is our socket)
56   | 
57   | */
58   | 
59   | void AK_add_to_ack(const char * filename, char * fmt, ...){
60   | 
61   |   va_list ap;  /* points to each unnamed arg in turn */
62   |   char *p, *sval;
63   |   int ival;
64   |   double dval;
65   |   FILE * ack_file;
66   |   
67   |   if(( ack_file = fopen(filename, "a")) == NULL){
68   |     fprintf(stderr, "Can't open ack file, %s", filename);
69   |   }
70   | 
71   |     
72   |   /* if this is a network update, print it out first to the 
73   |      stdout (which is socket) */ 
74   |   if(networkupdate){
75   |     va_start(ap, fmt);
76   |     vprintf(fmt, ap);
77   |     fflush(stdout);
78   |     va_end(ap); 
79   |   }
80   | 
81   |   /* and then to the file */
82   |   va_start(ap, fmt);
83   |   
84   |   for(p = fmt; *p; p++){
85   |     if (*p != '%') {
86   |       fprintf(ack_file, "%c", *p);
87   |       continue;
88   |     }
89   |     switch(*++p) {
90   |     case 'd':
91   |       ival = va_arg(ap, int);
92   |       fprintf(ack_file, "%d", ival);
93   |       break;
94   |     case 'f':
95   |       dval = va_arg(ap, double);  
96   |       fprintf(ack_file, "%f", dval);
97   |       break;
98   |     case 'X':
99   |       ival = va_arg(ap, int);
100  |       fprintf(ack_file, "%X", ival);
101  |       break;
102  |     case 'x':
103  |       ival = va_arg(ap, int);
104  |       fprintf(ack_file, "%x", ival);
105  |       break;
106  |     case 's':
107  |       sval = va_arg(ap, char *);
108  |       fprintf(ack_file, "%s", sval);
109  |       break;
110  |     default:
111  |       putchar(*p);
112  |       break;
113  |     }
114  |   }
115  | 
116  |   va_end(ap); /* clean up */
117  |   fclose(ack_file);
118  | }
119  | 
120  | 
121  | 
122  | /* Adds a complete file to the ack file */
123  | 
124  | void AK_add_file_to_ack(const char * ackfile, const char * filetoadd){
125  | 
126  |   FILE * ack_file, * file_to_add;
127  |   char   buf[1024];
128  | 
129  |   if(( ack_file = fopen(ackfile, "a")) == NULL){
130  |     fprintf(stderr, "AK_add_file_to_ack: Can't open ack file, %s\n", ackfile);
131  |   }
132  |   
133  |   if(( file_to_add = fopen(filetoadd, "r")) == NULL){
134  |     
135  |     fprintf(stderr, "AK_add_file_to_ack: Can't open file, %s\n", filetoadd);
136  |     fprintf(ack_file, "\nHelp file could not be found.\nPlease notify the database administrator.\n");
137  |     fclose(ack_file);
138  |     free(buf);
139  | 
140  |   }else{
141  |  
142  |     while(fgets(buf, 1023, file_to_add) != NULL){
143  |       fprintf(ack_file, "%s", buf);
144  |     }
145  | 
146  |     fclose(ack_file);
147  |     fclose(file_to_add);
148  |   }
149  | }
150  | 
151  | 
152  | /*
153  | 
154  |   AK_ack_file_name_generate: Generates a unique name for temporary acknowledgement
155  |      files, and also creates it. 
156  | 
157  |       tmpdir: temporary directory (without a trailing '/')
158  |       prefix: prefix for the temp file
159  |       
160  |       returns: the generated name. 
161  | */
162  | 
163  | char * AK_ack_file_name_generate( const char * tmpdir, const char * prefix)
164  | {
165  |    FILE * ack_file;
166  |    char * name;
167  |       
168  |    /* allocate space for name. 32 should be enough for PID */
169  |    name = (char*)malloc(strlen(tmpdir) + strlen(prefix) + 35); 
170  |    
171  |    sprintf(name, "%s/%s.%i", tmpdir, prefix, (int)(getpid()) );
172  | 
173  |    /* create the file */
174  |    if (( ack_file = fopen(name, "w")) == NULL)
175  |    {
176  |      fprintf(stderr, "Can't open ack file, %s", name);
177  |    }
178  | 
179  |    /* close it */
180  |    fclose(ack_file);
181  |     
182  |    return name;
183  | }
184  | 
185  | 
186  | /* 
187  | 
188  | AK_send_ack: post-processes and sends the ack message contained in the temp file.
189  |  
190  |    
191  | */
192  | 
193  | void AK_send_ack( const char * filename, const char * to_address, const char * mailercommand)
194  | {
195  |     char * mail_command_line = NULL;
196  |     char * supress_file = NULL, * temp_file = NULL;
197  |     FILE * ack_file, * supr_file_hdl, * temp_file_hdl;
198  |     char *txt_replaced;
199  |     char buf[1024];
200  | 
201  |     /* first check if we the user specified some non-keyword words in
202  |        the subject line (in addition to some valid keywords) 
203  |        If so, we will add a warning to the ack file */
204  |     if (subject_result.result == UP_SUBJ_UNRECOG)
205  | 	{
206  |       if (( ack_file = fopen(filename, "a")) == NULL)
207  | 	  {
208  |         fprintf(stderr, "Can't open ack file for appending, %s", filename);
209  |       }
210  | 	  else
211  | 	  {
212  |         fprintf(ack_file, "\nWarning: unknown keywords found in subject line:\n"
213  |                    "%s\n"
214  |                    "Thus, all keywords in subject line were ignored.\n",
215  |                     subject_result.word_list ? subject_result.word_list : "" );
216  |         fclose(ack_file);
217  |       }
218  |       
219  |     /* and now check if the user specified an invalid combination of keywords
220  |        in the subject line, and if so, print an appropriate warning to ack */
221  |     }
222  | 	else if (subject_result.result == UP_SUBJ_INVALID_COMB)
223  | 	{
224  |       if (( ack_file = fopen(filename, "a")) == NULL)
225  | 	  {
226  |         fprintf(stderr, "Can't open ack file for appending, %s", filename);
227  |       }
228  | 	  else
229  | 	  {
230  |         fprintf(ack_file, "\nWarning: This combination of keywords in subject line is not allowed.\n"
231  |                    "Thus, all keywords in subject line were ignored.\n");
232  |         fclose(ack_file);
233  |       }
234  |     }
235  | 
236  |     /* if the update didn't contain any objects and was not a request for help, put a warning */
237  |     if (count_successful == 0 && count_unsuccessful == 0 && subject_result.result != UP_SUBJ_HELP_REQ)
238  | 	{
239  |       AK_add_to_ack(filename, "*** Warning: No objects were found in the message ***\n");
240  |     }
241  | 
242  |     /* add the ACKSIG to the ack */
243  |     AK_add_to_ack(filename ,"\n%s", acksig);
244  | 
245  |     /* Here, we will print out the header of the ACK message. It cannot be
246  |        prepared before, since we wouldn't know if the header should use
247  |        SUCCESSTXT or FAILURETXT */
248  |     temp_file = (char *)malloc(strlen(filename) + strlen(".temp") + 2);
249  |     sprintf(temp_file, "%s.temp", filename);
250  |     if(( temp_file_hdl = fopen(temp_file, "w")) == NULL)
251  | 	{
252  |       fprintf(stderr, "Can't open temp ack file, %s\n", temp_file);
253  |     }
254  | 	else
255  | 	{
256  |       if ( subject_result.result == UP_SUBJ_HELP_REQ )
257  |       {
258  |         /* this is a request for help, so we will use the HELPHEADER */
259  |         /* replace the global variables in helpheader */
260  |         txt_replaced = UP_replace_globals(helpheader);
261  |       }
262  |       else if (count_unsuccessful > 0 || (count_successful + count_unsuccessful) == 0)
263  | 	  {
264  |         /* At least one of the objects failed or there wasn't any object in the
265  |         update message. We will use FAILURETXT */
266  |         /* replace the global variables in failuretxt */
267  |         txt_replaced = UP_replace_globals(failuretxt);
268  | 	  }
269  | 	  else
270  | 	  {
271  |         /* All the objects in the update message were successful. So, we will
272  |         use SUCCESSTXT */
273  |         /* replace the global variables in successtxt */
274  |         txt_replaced = UP_replace_globals(successtxt);
275  | 	  }
276  | 
277  |       /* print out the success/failure/help txt */ 
278  |       fprintf(temp_file_hdl, "To: %s\n%s\n\n", to_address, txt_replaced);
279  |       free(txt_replaced);
280  |       /* and now copy over the rest of the ack message */
281  |       if (( ack_file = fopen(filename, "r")) == NULL)
282  | 	  {
283  |         fprintf(stderr, "Can't open ack file for reading, %s", filename);
284  |       }
285  | 	  else
286  | 	  {
287  |         while (fgets(buf, 1024, ack_file) != NULL)
288  | 		{
289  |           fprintf(temp_file_hdl, "%s", buf);
290  |         }
291  |         fclose(ack_file);
292  |       }
293  |       fclose(temp_file_hdl);
294  |       /* and copy rename the temp file  */
295  |       rename(temp_file, filename);
296  |       free(temp_file);
297  |     }
298  | 
299  |     /* if we are not supressing acks and notifs, send the ack */
300  |     if (!supress_ack_notif)
301  | 	{
302  |       if (to_address != NULL)
303  | 	  {
304  |         mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(to_address) 
305  |             + strlen(filename) + 128);
306  |         sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename);
307  |         system(mail_command_line);
308  |       }
309  |     }
310  | 	else
311  | 	{
312  |       /* if we are supressing acks and notifs, send ack to DEFMAIL  */
313  |       supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2); 
314  |       sprintf(supress_file, "%s.supress", filename);
315  |       if (( supr_file_hdl = fopen(supress_file, "w")) == NULL)
316  | 	  {
317  |         fprintf(stderr, "Can't open supress ack file, %s", supress_file);
318  |       }
319  | 	  else
320  | 	  {
321  |         fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed ack mail\n\n",
322  |             humailbox, defmail);
323  |         if (( ack_file = fopen(filename, "r")) == NULL)
324  | 		{
325  |           fprintf(stderr, "Can't open ack file for reading, %s", filename);
326  |         }
327  | 		else
328  | 		{
329  |           while (fgets(buf, 1024, ack_file) != NULL)
330  | 		  {
331  |             fprintf(supr_file_hdl, "%s", buf);
332  |           }
333  |           fclose(ack_file);
334  |         }
335  |     	fclose(supr_file_hdl);
336  |     	mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail) 
337  |               + strlen(supress_file) + 128);
338  |     	sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file);
339  |     	system(mail_command_line);
340  |     	unlink(supress_file);
341  |       }
342  |       free(supress_file);
343  |     }
344  | }
345  | 
346  | 
347  | 
348  | /*
349  | 
350  |   AK_print_ack: Prints out the given file (the ack file) to the standard output
351  | 
352  | */
353  | void AK_print_ack( const char * filename )
354  | {
355  |     FILE * ack_file;
356  |     char buf[1024];
357  | 
358  |     if (( ack_file = fopen(filename, "r")) == NULL)
359  | 	{
360  |       fprintf(stderr, "Can't open ack file for reading, %s", filename);
361  |     }
362  | 	else
363  | 	{
364  |       while (fgets(buf, 1024, ack_file) != NULL)
365  | 	  {
366  |         printf("%s", buf);
367  |       }
368  |       fclose(ack_file);
369  |     }
370  | }
371  | 
372  | 
373  | 
374  | /*
375  | 
376  |   AK_delete_ack: deletes the temporary acknowledgement file.
377  | 
378  | */
379  | 
380  | void AK_delete_ack( const char * filename )
381  | {
382  |    unlink(filename);   
383  | }
384  | 
385  | 
386  | /*
387  | 
388  | AK_log_ack: logs the acknowledgements in the "logfilename.date".
389  | 
390  | */
391  | 
392  | void AK_log_ack(const char * filename, const char * logfilename)
393  | {
394  |   FILE * ack_file, * log_file;
395  |   char   buf[1024];
396  |   time_t cur_time;
397  |   char * time_str;
398  |   char * logfile_date;
399  |   char * date;
400  | 
401  |   if (( ack_file = fopen(filename, "r")) == NULL)
402  |   {
403  |     fprintf(stderr, "Can't open ack file for reading, %s\n", filename);
404  |     return;
405  |   }
406  | 
407  | 
408  |   /* construct the "logfilename.date" string */
409  |   logfile_date = (char *)malloc(strlen(logfilename) + 10);
410  |   date = UP_get_current_date();
411  |   snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date);
412  |   free(date);
413  | 
414  |   if (( log_file = fopen(logfile_date, "a")) == NULL)
415  |   {
416  |     fprintf(stderr, "Can't open log file for appending, %s\n", logfile_date);
417  | 	free(logfile_date);
418  |     return;
419  |   }
420  |   free(logfile_date);
421  | 
422  |   /* get time */
423  |   cur_time = time(NULL);
424  |   time_str = strdup(ctime(&cur_time));
425  |   /* cut the '\n' at the end */
426  |   time_str[strlen(time_str) - 1] = '\0';
427  | 
428  |   if (reading_from_mail)
429  |   {
430  |     fprintf(log_file, ">>> time: %s MAIL ACK <<<\n\n", time_str);
431  |   }
432  |   else if (networkupdate)
433  |   {
434  |     fprintf(log_file, ">>> time: %s NETWORKUPDATE ACK <<<\n\n", time_str);
435  |   }
436  |   else
437  |   {
438  |     fprintf(log_file, ">>> time: %s ACK <<<\n\n", time_str);
439  |   }
440  | 
441  |   while (fgets(buf, 1023, ack_file) != NULL)
442  |   {
443  |     fprintf(log_file, "%s", buf);
444  |   }
445  | 
446  |   free(time_str);
447  |   fclose(ack_file);
448  |   fclose(log_file);
449  | }
450  | 
451  | 
452  | 
453  | 
454  | 
455  | 
456  | 
457  |