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 |