1 | /*************************************** 2 | $Revision: 1.11 $ 3 | 4 | NT (Notifications) module 5 | 6 | Status: REVIEWED, NOT TESTED 7 | 8 | Author(s): Engin Gunduz 9 | 10 | ******************/ /****************** 11 | Modification History: 12 | engin (06/07/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 | 38 | 39 | 40 | #include "notification.h" 41 | extern int supress_ack_notif; 42 | extern char * defmail; 43 | extern int reading_from_mail; 44 | extern char * forwlog; 45 | 46 | /* Generates a unique file name and returns the full path of the filename 47 | for storing notification message. Creates the file at the same time. 48 | May use PID or time or both to ensure uniqueness. */ 49 | 50 | char * NT_ntfy_filename_generate( const char * tmpdir, const char * e_mail) 51 | { 52 | FILE * ntfy_file; 53 | char * name; 54 | char * replaced_notimailtxt; 55 | char * replaced_notinetworktxt; 56 | 57 | /* allocate space for name. 32 should be enough for PID */ 58 | name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("notify") +36 ); 59 | 60 | sprintf(name, "%s/%s-%s.%i", tmpdir, "notify", e_mail, (int)(getpid()) ); 61 | 62 | /* create the file */ 63 | if (( ntfy_file = fopen(name, "w")) == NULL) 64 | { 65 | fprintf(stderr, "Can't open notification file for creating, %s", name); 66 | } 67 | 68 | fprintf(ntfy_file, "To: %s\nFrom: %s\nSubject: Notification of RIPE Database changes\nReply-To: %s\n\n%s\n", e_mail, humailbox, humailbox, notitxt); 69 | if (reading_from_mail) 70 | { 71 | replaced_notimailtxt = UP_replace_globals(notimailtxt); 72 | fprintf(ntfy_file, "%s\n\n", replaced_notimailtxt); 73 | free(replaced_notimailtxt); 74 | } 75 | 76 | if (networkupdate) 77 | { 78 | replaced_notinetworktxt = UP_replace_globals(notinetworktxt); 79 | fprintf(ntfy_file, "%s\n\n", replaced_notinetworktxt); 80 | free(replaced_notinetworktxt); 81 | } 82 | 83 | /* close it */ 84 | fclose(ntfy_file); 85 | 86 | return name; 87 | } 88 | 89 | 90 | 91 | 92 | /* Generates a unique file name and returns the full path of the filename 93 | for storing forwarded message. Creates the file at the same time. */ 94 | char * NT_forwd_filename_generate( const char * tmpdir, const char * e_mail) 95 | { 96 | FILE * forwd_file; 97 | char * name; 98 | char * replaced_fwmailtxt; 99 | 100 | /* allocate space for name. 32 should be enough for PID */ 101 | name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("forwd") +36 ); 102 | 103 | sprintf(name, "%s/%s-%s.%i", tmpdir, "forwd", e_mail, (int)(getpid()) ); 104 | /* create the file */ 105 | if (( forwd_file = fopen(name, "w")) == NULL) 106 | { 107 | fprintf(stderr, "Can't open forward file, %s", name); 108 | } 109 | 110 | fprintf(forwd_file, "To: %s\nFrom: %s\nSubject: Requested RIPE database object changes \nReply-To: %s\n\n%s\n", e_mail, humailbox, humailbox, fwtxt); 111 | if (reading_from_mail) 112 | { 113 | replaced_fwmailtxt = UP_replace_globals(fwmailtxt); 114 | fprintf(forwd_file, "\n%s\n", replaced_fwmailtxt); 115 | free(replaced_fwmailtxt); 116 | } 117 | 118 | /* close it */ 119 | fclose(forwd_file); 120 | 121 | return name; 122 | } 123 | 124 | 125 | 126 | 127 | /* Generates a unique file name and returns the full path of the filename 128 | for storing cross notification message. Creates the file at the same time. */ 129 | char * NT_cross_filename_generate( const char * tmpdir, const char * e_mail, int mode) 130 | { 131 | FILE * cross_file; 132 | char * name; 133 | 134 | /* allocate space for name. 32 should be enough for PID */ 135 | name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("cross") +36 ); 136 | 137 | sprintf(name, "%s/%s-%s.%i", tmpdir, "cross", e_mail, (int)(getpid()) ); 138 | /* create the file */ 139 | if (( cross_file = fopen(name, "w")) == NULL) 140 | { 141 | fprintf(stderr, "Can't open cross notif file, %s", name); 142 | } 143 | 144 | if (mode == ADDITION) 145 | { 146 | fprintf(cross_file, "To: %s\nFrom: %s\n%s\nReply-To: %s\n\n", e_mail, humailbox, cno_subject_add, humailbox); 147 | } 148 | else 149 | { 150 | fprintf(cross_file, "To: %s\nFrom: %s\n%s\nReply-To: %s\n\n", e_mail, humailbox, cno_subject_del, humailbox); 151 | } 152 | 153 | /* close it */ 154 | fclose(cross_file); 155 | 156 | return name; 157 | } 158 | 159 | 160 | 161 | 162 | 163 | /* Generates a unique file name and returns the full path of the filename for 164 | storing notification message. Creates the file at the same time. */ 165 | char * NT_crossntfy_filename_generate( const char * tmpdir, const char * e_mail) 166 | { 167 | FILE * cross_file; 168 | char * name; 169 | 170 | /* allocate space for name. 32 should be enough for PID */ 171 | name = (char*)malloc(strlen(tmpdir) + strlen(e_mail) + strlen("cross") +36 ); 172 | 173 | sprintf(name, "%s/%s-%s.%i", tmpdir, "cross", e_mail, (int)(getpid()) ); 174 | 175 | /* create the file */ 176 | if (( cross_file = fopen(name, "w")) == NULL) 177 | { 178 | fprintf(stderr, "Can't open cross file, %s", name); 179 | } 180 | 181 | /* close it */ 182 | fclose(cross_file); 183 | 184 | return name; 185 | } 186 | 187 | 188 | 189 | /* Adds the e-mail to the notify hash, generating appropriate temp files */ 190 | void NT_add_to_ntfy_hash(GHashTable * ntfy_hash, char * e_mail) 191 | { 192 | if (g_hash_table_lookup(ntfy_hash ,e_mail) == NULL) 193 | { /* there is no such entry, so create it */ 194 | 195 | g_hash_table_insert(ntfy_hash, strdup(e_mail), NT_ntfy_filename_generate(tmpdir, e_mail)); 196 | } 197 | } 198 | 199 | 200 | 201 | /* Adds the e-mail to the forw hash, generating appropriate temp files */ 202 | void NT_add_to_frwd_hash(GHashTable * frwd_hash, char * e_mail) 203 | { 204 | if (g_hash_table_lookup(frwd_hash ,e_mail) == NULL) 205 | { /* there is no such entry, so create it */ 206 | g_hash_table_insert(frwd_hash, strdup(e_mail), NT_forwd_filename_generate(tmpdir, e_mail)); 207 | } 208 | 209 | } 210 | 211 | 212 | 213 | /* Adds the e-mail to the cross hash, generating appropriate temp files */ 214 | void NT_add_to_cross_hash(GHashTable * cross_hash, const char * e_mail, int mode) 215 | { 216 | /* if e-mail is NULL, immediately return */ 217 | if (e_mail == NULL) 218 | { 219 | return; 220 | } 221 | 222 | if (g_hash_table_lookup(cross_hash ,e_mail) == NULL) 223 | { /* there is no such entry, so create it */ 224 | g_hash_table_insert(cross_hash, strdup(e_mail), NT_cross_filename_generate(tmpdir, e_mail, mode)); 225 | } 226 | } 227 | 228 | 229 | 230 | /* Adds the e-mails in a linked list to the hash */ 231 | void NT_add_to_ntfy_hash_list(GHashTable * ntfy_hash, GList * e_mail_list) 232 | { 233 | GList * temp = NULL; 234 | 235 | for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp)) 236 | { 237 | NT_add_to_ntfy_hash( ntfy_hash, (char *)(temp->data) ); 238 | } 239 | } 240 | 241 | 242 | 243 | /* Adds the e-mails in a linked list to the hash */ 244 | void NT_add_to_frwd_hash_list(GHashTable * frwd_hash, GList * e_mail_list) 245 | { 246 | GList * temp = NULL; 247 | 248 | for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp)) 249 | { 250 | NT_add_to_frwd_hash(frwd_hash, (char *)temp->data); 251 | } 252 | } 253 | 254 | 255 | 256 | /* Adds the e-mails in a linked list to the hash */ 257 | void NT_add_to_cross_hash_list(GHashTable * cross_hash, GList * e_mail_list, int mode) 258 | { 259 | GList * temp = NULL; 260 | 261 | for (temp = e_mail_list; temp != NULL; temp = g_list_next(temp)) 262 | { 263 | NT_add_to_cross_hash(cross_hash, (char *)temp->data, mode); 264 | } 265 | } 266 | 267 | 268 | 269 | /* Appends the argument strings to the file. */ 270 | void NT_add_to_ntfy( char * filename, char * fmt, ... ) 271 | { 272 | va_list ap; /* points to each unnamed arg in turn */ 273 | FILE * ntfy_file; 274 | 275 | if (tracing) 276 | { 277 | printf("TRACING: NT_add_to_ntfy\n"); 278 | } 279 | if (( ntfy_file = fopen(filename, "a")) == NULL) 280 | { 281 | fprintf(stderr, "Can't open notification file for writing, %s\n", filename); 282 | return; 283 | } 284 | 285 | va_start(ap, fmt); 286 | vfprintf(ntfy_file, fmt, ap); 287 | 288 | va_end(ap); /* clean up */ 289 | fclose(ntfy_file); 290 | } 291 | 292 | 293 | 294 | /* Appends the argument strings to the file. */ 295 | void NT_add_to_cross(const char * e_mail, GHashTable * hash, char * fmt, ...) 296 | { 297 | va_list ap; /* points to each unnamed arg in turn */ 298 | FILE * cross_file = NULL; 299 | char * filename = NULL; 300 | 301 | if (tracing) 302 | { 303 | printf("TRACING: NT_add_to_cross\n"); 304 | } 305 | 306 | /* if e-mail is NULL, immediately return */ 307 | if(e_mail == NULL) 308 | { 309 | return; 310 | } 311 | 312 | if ( (filename = (char *)g_hash_table_lookup(hash, find_email_address(e_mail))) == NULL ) 313 | { 314 | fprintf(stderr, "Can't find a cross notification file for e-mail %s\n", e_mail); 315 | return; 316 | } 317 | 318 | if ( ( cross_file = fopen(filename, "a")) == NULL ) 319 | { 320 | fprintf(stderr, "Can't open cross notification file for writing, %s\n", filename); 321 | } 322 | 323 | va_start(ap, fmt); 324 | vfprintf(cross_file, fmt, ap); 325 | 326 | va_end(ap); /* clean up */ 327 | fclose(cross_file); 328 | } 329 | 330 | 331 | 332 | 333 | /* Appends the argument string to the temp notif files in the list */ 334 | void NT_add_to_ntfy_list(GList * list, GHashTable * hash, char * arg) 335 | { 336 | GList * temp = NULL; 337 | 338 | for(temp = list; temp != NULL; temp = g_list_next(temp)) 339 | { 340 | NT_add_to_ntfy((char *)g_hash_table_lookup(hash, ((char *)temp->data)), "%s", arg); 341 | } 342 | } 343 | 344 | 345 | 346 | /* Sends the notification message which is stored in the temporary filefilename. */ 347 | void NT_send_ntfy( const char * filename, const char * to_address, const char * mailercommand) 348 | { 349 | char * mail_command_line = NULL; 350 | char * supress_file = NULL; 351 | FILE * notif_file, * supr_file_hdl; 352 | char buf[1024]; 353 | 354 | /* if we are not supressing acks and notifs, send the notif */ 355 | if (!supress_ack_notif) 356 | { 357 | if (to_address != NULL) 358 | { 359 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(filename) + 128); 360 | sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename); 361 | system(mail_command_line); 362 | } 363 | } 364 | /* if we are supressing acks and notifs, send notif to DEFMAIL */ 365 | else 366 | { 367 | supress_file = (char *)malloc(strlen(filename) + strlen(".supress") + 2); 368 | sprintf(supress_file, "%s.supress", filename); 369 | if (( supr_file_hdl = fopen(supress_file, "w")) == NULL) 370 | { 371 | fprintf(stderr, "Can't open supress notif file, %s", supress_file); 372 | } 373 | else 374 | { 375 | fprintf(supr_file_hdl, "From: %s\nTo: %s\nSubject: Supressed notif mail\n\n", 376 | humailbox, defmail); 377 | if (( notif_file = fopen(filename, "r")) == NULL) 378 | { 379 | fprintf(stderr, "Can't open notif file for reading, %s", filename); 380 | } 381 | else 382 | { 383 | while (fgets(buf, 1023, notif_file) != NULL) 384 | { 385 | fprintf(supr_file_hdl, buf); 386 | } 387 | fclose(notif_file); 388 | } 389 | } 390 | fclose(supr_file_hdl); 391 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(defmail) 392 | + strlen(supress_file) + 128); 393 | sprintf(mail_command_line, "%s %s < %s", mailercommand, defmail, supress_file); 394 | system(mail_command_line); 395 | unlink(supress_file); 396 | free(supress_file); 397 | } 398 | } 399 | 400 | 401 | 402 | /* Adds the notification message which is in the filename into "logfilename.date". */ 403 | void NT_log_ntfy( const char * filename, const char * logfilename) 404 | { 405 | FILE * notif_file, * log_file; 406 | char * buf; 407 | time_t cur_time; 408 | char * time_str; 409 | char * logfile_date; 410 | char * date; 411 | 412 | if (tracing) 413 | { 414 | printf("TRACING: NT_log_ntfy is running: filename [%s] logfilename [%s]\n", filename, logfilename); 415 | } 416 | 417 | buf = (char *)malloc(1024); 418 | if (( notif_file = fopen(filename, "r")) == NULL) 419 | { 420 | fprintf(stderr, "NT_log_ntfy: Can't open notification file for reading, [%s]\n", filename); 421 | return; 422 | } 423 | 424 | /* construct the "logfilename.date" string */ 425 | logfile_date = (char *)malloc(strlen(logfilename) + 10); 426 | date = UP_get_current_date(); 427 | snprintf(logfile_date, strlen(logfilename) + 10, "%s.%s", logfilename, date); 428 | free(date); 429 | 430 | if (( log_file = fopen(logfile_date, "a")) == NULL) 431 | { 432 | fprintf(stderr, "NT_log_ntfy: Can't open log file, %s\n", logfilename); 433 | return; 434 | } 435 | 436 | /* get time */ 437 | cur_time = time(NULL); 438 | time_str = strdup(ctime(&cur_time)); 439 | /* cut the '\n' at the end */ 440 | time_str[strlen(time_str) - 1] = '\0'; 441 | 442 | fprintf(log_file, ">>> time: %s NOTIF <<<\n\n", time_str); 443 | 444 | 445 | while ( (buf=fgets(buf, 1024, notif_file)) != NULL ) 446 | { 447 | fprintf(log_file, "%s", buf); 448 | } 449 | free(buf); 450 | 451 | fclose(notif_file); 452 | fclose(log_file); 453 | } 454 | 455 | 456 | /* Deletes the temporary notification file. */ 457 | void NT_delete_ntfy( const char * filename) 458 | { 459 | unlink(filename); 460 | } 461 | 462 | 463 | /* The function required for NT_send_ntfy_list */ 464 | void nt_gfunc_send(gpointer key, gpointer value, gpointer user_data) 465 | { 466 | NT_send_ntfy((char *)value, (char *)key, (char *)user_data); 467 | } 468 | 469 | 470 | 471 | /* Sends the notification messages whose temp files are stored in filehash. */ 472 | void NT_send_ntfy_list( GHashTable * filehash, char * mailercommand) 473 | { 474 | g_hash_table_foreach( filehash, (GHFunc)nt_gfunc_send, mailercommand); 475 | } 476 | 477 | 478 | 479 | 480 | /* The function required for NT_log_ntfy_list */ 481 | void nt_gfunc_log(gpointer key, gpointer value, gpointer user_data) 482 | { 483 | NT_log_ntfy((char *)value, (char *)user_data); 484 | } 485 | 486 | 487 | 488 | 489 | /* Logs the notification whose temp files are in filehash to log_file. */ 490 | void NT_log_ntfy_list( GHashTable * filehash, char * log_file) 491 | { 492 | g_hash_table_foreach( filehash, (GHFunc)nt_gfunc_log, log_file); 493 | } 494 | 495 | 496 | 497 | /* The function required for NT_delete_ntfy_list */ 498 | void nt_gfunc_delete(gpointer key, gpointer value, gpointer user_data) 499 | { 500 | NT_delete_ntfy((char *)value); 501 | } 502 | 503 | 504 | 505 | /* Deletes the temporary notification messages in the filehash. Empties and frees 506 | the hash too. */ 507 | void NT_delete_ntfy_list( GHashTable * filehash) 508 | { 509 | g_hash_table_foreach(filehash, (GHFunc)nt_gfunc_delete, NULL); 510 | g_hash_table_destroy(filehash); 511 | } 512 | 513 | 514 | /* to be used with g_hash_table_foreach in NT_unify_list. 515 | Adds the 'value' to the list (a GList) */ 516 | /* void nt_add_to_list(char * key, rpsl_attr_t * value, GList ** list) 517 | { 518 | *list = g_list_append(*list, strdup(value)); 519 | } 520 | */ 521 | 522 | 523 | /* to be used with g_hash_table_foreach in NT_unify_list. 524 | frees the 'key' and 'value' in the list (a GList) */ 525 | void nt_free_list(char * key, char * value, void *nothing) 526 | { 527 | if ( key != NULL ) 528 | free(key); 529 | if ( value != NULL ) 530 | free(value); 531 | } 532 | 533 | 534 | 535 | /* "unifies" a list in a case insensitive manner */ 536 | GList * NT_unify_list(GList * in_list) 537 | { 538 | GHashTable * unification_hash; 539 | GList ** out_list; 540 | GList * temp; 541 | GList *return_list = NULL; 542 | char * key, * value; 543 | int strcmp(); 544 | 545 | /* allocate space for out_list */ 546 | out_list = (GList **)malloc(sizeof(GList *)); 547 | *out_list = NULL; 548 | 549 | /* initialize the hash to be used for unification process */ 550 | unification_hash = g_hash_table_new(g_str_hash, g_str_equal); 551 | 552 | /* first put the list elements into a hash, to unify them */ 553 | for (temp = in_list; temp != NULL; temp = g_list_next(temp)) 554 | { 555 | /* convert the email address into lowercase, for comparison reasons only */ 556 | key = rpsl_attr_get_clean_value((rpsl_attr_t *)(temp->data)); 557 | value = strdup(key); 558 | g_strdown(key); 559 | 560 | if (g_hash_table_lookup(unification_hash, key) == NULL) 561 | { /* if it is not already in the hash table, add to the hash and append to new list */ 562 | g_hash_table_insert(unification_hash, key, value); 563 | *out_list = g_list_insert_sorted( *out_list, strdup(value), strcmp ); 564 | /* *out_list = g_list_append( *out_list, strdup(value) ); */ 565 | } 566 | else 567 | { /* it is a duplicate email address, don't append to new list */ 568 | free(key); 569 | free(value); 570 | } 571 | } 572 | 573 | /* now, delete the elements in the hash */ 574 | g_hash_table_foreach(unification_hash, (GHFunc)nt_free_list, NULL); 575 | 576 | g_hash_table_destroy(unification_hash); 577 | 578 | return_list = *out_list; 579 | free(out_list); 580 | return return_list; 581 | } 582 | 583 | 584 | 585 | /* Gets GLists of irt atributes from old and new object. Compares these 586 | lists and returns a list of diferences */ 587 | 588 | /* if option==1, return list contains only newly deleted irts 589 | if option==2, return list contains only newly added irts 590 | if option==3, return list contains both */ 591 | 592 | GList *NT_compare_lists(GList *old_irts, GList *new_irts, int option) 593 | { 594 | typedef struct irt_details 595 | { 596 | gchar *irt_name; 597 | rpsl_attr_t *irts; 598 | gint matched; 599 | } irt_details_t; 600 | 601 | GList *old_irt_details = NULL; 602 | GList *new_irt_details = NULL; 603 | GList *old_irts_item = NULL; 604 | GList *new_irts_item = NULL; 605 | GList *return_list = NULL; 606 | irt_details_t *irt_details; 607 | char *irt_name; 608 | 609 | if (tracing) 610 | { 611 | printf("TRACING: NT_compare_lists is running: option: [%d]\n", option); 612 | } 613 | 614 | /* collect data from the old_irts */ 615 | for ( old_irts_item = old_irts; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) ) 616 | { 617 | irt_details = (irt_details_t *)malloc(sizeof(irt_details_t)); 618 | /* get irt name from attr */ 619 | irt_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(old_irts_item->data) ); 620 | /* enter details into irt_details structure */ 621 | irt_details->irts = (rpsl_attr_t *)(old_irts_item->data); 622 | irt_details->irt_name = irt_name; 623 | irt_details->matched = 0; 624 | /* append irt_details structure to old_irt_details list */ 625 | old_irt_details = g_list_append(old_irt_details, irt_details); 626 | } 627 | 628 | /* collect data from the new_irts and compare with the old in the same loop */ 629 | for ( new_irts_item = new_irts; new_irts_item != NULL; new_irts_item = g_list_next(new_irts_item) ) 630 | { 631 | irt_details = (irt_details_t *)malloc(sizeof(irt_details_t)); 632 | /* get irt name from attr */ 633 | irt_name = rpsl_attr_get_clean_value( (rpsl_attr_t *)(new_irts_item->data) ); 634 | /* enter details into irt_details structure */ 635 | irt_details->irts = (rpsl_attr_t *)(new_irts_item->data); 636 | irt_details->irt_name = irt_name; 637 | irt_details->matched = 0; 638 | 639 | /* compare the name with the names from the old list */ 640 | for ( old_irts_item = old_irt_details; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) ) 641 | { 642 | if ( ! strcmp(irt_name, ((irt_details_t *)(old_irts_item->data))->irt_name ) ) 643 | { 644 | irt_details->matched = 1; 645 | ((irt_details_t *)(old_irts_item->data))->matched = 1; 646 | break; 647 | } 648 | } 649 | 650 | /* append irt_details structure to new_irt_details list */ 651 | new_irt_details = g_list_append(new_irt_details, irt_details); 652 | } 653 | 654 | /* we now want a list of irts taken from the old and new irt_details lists 655 | where the matched flag is _NOT_ set. These will only exist in one list 656 | and have therefore just been added/deleted */ 657 | /* if option==1, return list contains only newly deleted irts 658 | if option==2, return list contains only newly added irts 659 | if option==3, return list contains both */ 660 | if ( option == 1 || option == 3 ) 661 | { 662 | for ( old_irts_item = old_irt_details; old_irts_item != NULL; old_irts_item = g_list_next(old_irts_item) ) 663 | { 664 | if ( ! ((irt_details_t *)(old_irts_item->data))->matched ) 665 | { 666 | if (tracing) 667 | { 668 | printf("TRACING: NT_compare_lists: adding old irt to return list [%s]\n", ((irt_details_t *)(new_irts_item->data))->irt_name); 669 | } 670 | 671 | return_list = g_list_append(return_list, ((irt_details_t *)(old_irts_item->data))->irts ); 672 | } 673 | free ( ((irt_details_t *)(old_irts_item->data))->irt_name ); 674 | } 675 | } 676 | g_list_free(old_irt_details); 677 | if ( option == 2 || option == 3 ) 678 | { 679 | for ( new_irts_item = new_irt_details; new_irts_item != NULL; new_irts_item = g_list_next(new_irts_item) ) 680 | { 681 | if ( ! ((irt_details_t *)(new_irts_item->data))->matched ) 682 | { 683 | if (tracing) 684 | { 685 | printf("TRACING: NT_compare_lists: adding new irt to return list [%s]\n", ((irt_details_t *)(new_irts_item->data))->irt_name); 686 | } 687 | 688 | return_list = g_list_append(return_list, ((irt_details_t *)(new_irts_item->data))->irts ); 689 | } 690 | free ( ((irt_details_t *)(new_irts_item->data))->irt_name ); 691 | } 692 | } 693 | g_list_free(new_irt_details); 694 | 695 | return return_list; 696 | } 697 | 698 | 699 | /* Gets old and new objects supplied, forms lists of any irt objects referenced 700 | by these. Returns a GList of irt-nfy for any irt objects that heve been added 701 | or deleted. 702 | */ 703 | GList *NT_check_irtnfy(rpsl_object_t *old_obj, rpsl_object_t *new_obj) 704 | { 705 | GList *old_irts = NULL; 706 | GList *new_irts = NULL; 707 | GList *changed_irts = NULL; 708 | 709 | if (old_obj != NULL) 710 | old_irts = get_irts(old_obj); 711 | if (new_obj != NULL) 712 | new_irts = get_irts(new_obj); 713 | 714 | if ( old_irts != NULL && new_irts!= NULL ) 715 | { 716 | /* compare lists for additions and deletions */ 717 | changed_irts = NT_compare_lists(old_irts, new_irts, 3); 718 | return get_irtnfy_vector(changed_irts); 719 | } 720 | else if ( old_irts != NULL ) 721 | { 722 | /* these irts have been deleted */ 723 | return get_irtnfy_vector(old_irts); 724 | } 725 | else if ( new_irts != NULL ) 726 | { 727 | /* these irts have been added */ 728 | return get_irtnfy_vector(new_irts); 729 | } 730 | else 731 | return NULL; /* no irt objects at all */ 732 | } 733 | 734 | 735 | /* Gathers e-mail boxes to which we will send normal notification messages. It 736 | takes old and new object strings, looks up maintainers and less specific inetnums/domains/routes 737 | when necessary, finds the addresses (in mnt-nfy and notify attributes) and returns 738 | a list of email addresses as strings. 739 | Also now checks for irt-nfy in any irt objects that have been added or deleted */ 740 | GList * NT_gather_ntfy_addresses( const char * old_object_str, const char * new_object_str) 741 | { 742 | GList *return_list = NULL, *temp = NULL; 743 | GList *mntners = NULL; 744 | const GList *error_list = NULL; 745 | rpsl_object_t *old_obj = NULL; 746 | rpsl_object_t *new_obj = NULL; 747 | 748 | if (tracing) 749 | { 750 | printf("TRACING: NT_gather_ntfy_addresses is running: old_object_str : [%s]; new_object_str: [%s]\n", old_object_str ? old_object_str : "", new_object_str ? new_object_str : ""); 751 | } 752 | 753 | if (old_object_str != NULL && new_object_str != NULL) 754 | { /* it was an update */ 755 | old_obj = rpsl_object_init(old_object_str); 756 | error_list = rpsl_object_errors(old_obj); 757 | new_obj = rpsl_object_init(new_object_str); 758 | error_list = rpsl_object_errors(old_obj); 759 | 760 | /* start with the 'notify' in the object itself */ 761 | temp = get_attr_list(old_obj, "notify"); 762 | mntners = get_mntners(old_obj); 763 | /* now add the 'mnt-by' from any of the mntners in the old object only */ 764 | temp = g_list_concat(temp, get_mntnfy_vector(mntners)); 765 | /* now add the 'irt-by' from any of the irts in the old and new objects 766 | if they have just been added or deleted */ 767 | temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj)); 768 | } 769 | else if (old_object_str == NULL && new_object_str != NULL) 770 | { /* it was a creation */ 771 | new_obj = rpsl_object_init(new_object_str); 772 | error_list = rpsl_object_errors(new_obj); 773 | 774 | if ( ! rpsl_object_has_error( new_obj, RPSL_ERRLVL_ERROR ) ) 775 | { 776 | /* start with the 'notify' in the object itself */ 777 | temp = get_attr_list(new_obj, "notify"); 778 | mntners = get_mntners(new_obj); 779 | /* now add the 'mnt-by' from any of the mntners in the new object only */ 780 | temp = g_list_concat(temp, get_mntnfy_vector(mntners)); 781 | /* now add the 'irt-by' from any of the irts in the new object 782 | as they have just been added */ 783 | temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj)); 784 | } 785 | } 786 | else if (old_object_str != NULL && new_object_str == NULL) 787 | { /* it was a deletion */ 788 | old_obj = rpsl_object_init(old_object_str); 789 | error_list = rpsl_object_errors(old_obj); 790 | 791 | /* start with the 'notify' in the object itself */ 792 | temp = get_attr_list(old_obj, "notify"); 793 | mntners = get_mntners(old_obj); 794 | /* now add the 'mnt-by' from any of the mntners in the old object only */ 795 | temp = g_list_concat(temp, get_mntnfy_vector(mntners)); 796 | /* now add the 'irt-by' from any of the irts in the old object 797 | as they have just been deleted */ 798 | temp = g_list_concat(temp, NT_check_irtnfy(old_obj, new_obj)); 799 | } 800 | 801 | /* we have to 'unify' the list here!, return_list is now a list of malloc'd email address strings */ 802 | return_list = NT_unify_list(temp); 803 | rpsl_attr_delete_list( temp ); 804 | if ( old_obj ) 805 | rpsl_object_delete(old_obj); 806 | if ( new_obj ) 807 | rpsl_object_delete(new_obj); 808 | 809 | if (tracing) 810 | { 811 | printf( "TRACING: notif email addresses\n" ); 812 | for ( temp=return_list; temp!=NULL; temp=g_list_next(temp) ) 813 | printf( "TRACING: [%s]\n", (char *)(temp->data) ); 814 | } 815 | 816 | return return_list; 817 | } 818 | 819 | 820 | 821 | /* Gathers e-mail boxes to which we will forward messages (or rather, objects). It 822 | an object, looks up maintainers, finds the addresses (in upd-to attributes) and returns 823 | a list of them. */ 824 | GList * NT_gather_frwd_addresses(char * object_str) 825 | { 826 | GList *temp = NULL; 827 | GList *attr_item = NULL; 828 | GList *email_list = NULL; 829 | char *email; 830 | const GList *error_list = NULL; 831 | rpsl_object_t *object; 832 | GList * mntners = NULL; 833 | 834 | object = rpsl_object_init(object_str); 835 | error_list = rpsl_object_errors(object); 836 | 837 | mntners = get_mntners(object); 838 | /* get a list of upd-to attributes */ 839 | temp = get_updto_vector(mntners); 840 | /* now extract the email text strings from the values of these attributes */ 841 | for ( attr_item = temp; attr_item != NULL ; attr_item = g_list_next(attr_item) ) 842 | { 843 | email = rpsl_attr_get_clean_value((rpsl_attr_t *)(attr_item->data)); 844 | printf("NT_gather_frwd_addresses: email [%s]\n", email ); 845 | email_list = g_list_append(email_list, email ); 846 | } 847 | return email_list; 848 | } 849 | 850 | 851 | 852 | /* Accepts a parsed route object and returns a list of overlapping routes */ 853 | overlap_routes get_overlapping_routes_list(rpsl_object_t * object) 854 | { 855 | char * route_prefix = NULL; 856 | GList * tmp_list; 857 | char * result; 858 | char * query_string; 859 | overlap_routes result_routes; 860 | 861 | result_routes.less_spec = NULL; 862 | result_routes.exact_match = NULL; 863 | result_routes.more_spec = NULL; 864 | 865 | tmp_list = rpsl_object_get_attr(object, "route"); 866 | 867 | if (tmp_list != NULL && tmp_list->data != NULL) 868 | { 869 | route_prefix = rpsl_attr_get_clean_value((rpsl_attr_t *)(tmp_list->data)); 870 | } 871 | else 872 | { 873 | return result_routes; /* then, this wasn't a route object */ 874 | } 875 | 876 | /* get the less specific route objects */ 877 | /* form the query string */ 878 | query_string = (char *)malloc(strlen("-Troute -r -l ") + strlen(route_prefix) + 2); 879 | sprintf(query_string, "-Troute -r -l %s", route_prefix); 880 | 881 | /* get the results */ 882 | result = send_and_get(query_host, query_port, query_string); 883 | free(query_string); 884 | 885 | /* and fill in the result field */ 886 | result_routes.less_spec = take_objects(result); 887 | 888 | /* get the exact match route objects */ 889 | /* form the query string */ 890 | query_string = (char *)malloc(strlen("-Troute -r -x ") + strlen(route_prefix) + 2); 891 | sprintf(query_string, "-Troute -r -x %s", route_prefix); 892 | 893 | /* get the results */ 894 | result = send_and_get(query_host, query_port, query_string); 895 | free(query_string); 896 | 897 | 898 | /* filter out the route object itself */ 899 | result = UP_filter_out_same_origins(result, object); 900 | 901 | /* and fill in the result field */ 902 | if (result != NULL) 903 | { 904 | result_routes.exact_match = take_objects(result); 905 | } 906 | 907 | /* get the more specific route objects */ 908 | /* form the query string */ 909 | query_string = (char *)malloc(strlen("-Troute -r -M ") + strlen(route_prefix) + 2); 910 | sprintf(query_string, "-Troute -r -M %s", route_prefix); 911 | 912 | /* get the results */ 913 | result = send_and_get(query_host, query_port, query_string); 914 | free(query_string); 915 | 916 | /* and fill in the result field */ 917 | result_routes.more_spec = take_objects(result); 918 | 919 | /* Return the results */ 920 | return result_routes; 921 | } 922 | 923 | 924 | 925 | /* Gets old and new versions of the object, and creates temporary notification 926 | files when necessary, and then writes appropriate strings into those 927 | temporary files. */ 928 | void NT_write_all_ntfs(char * old_object, char * new_object, char * formatted_object, 929 | const char * tempdir, 930 | GHashTable * ntfy_hash, GHashTable * forwd_hash, GHashTable * cross_hash, 931 | char * from_address) 932 | { 933 | GList * e_mail_list = NULL; 934 | GList * temp = NULL; 935 | const GList *error_list = NULL; 936 | char * e_mail_address = NULL; 937 | overlap_routes overlapping_routes; 938 | rpsl_object_t *object; 939 | char *arg2; 940 | 941 | if ( reading_from_mail ) 942 | { 943 | /* from_address may contain also the name, like "Johnny Bravo <johnny@inter.net>", 944 | so extract the e-mail address from it */ 945 | e_mail_address = find_email_address(from_address); 946 | 947 | if (tracing) 948 | { 949 | printf("TRACING: NT_write_all_ntfs: from_address=[%s], e_mail_address=[%s]\n", from_address, e_mail_address); 950 | } 951 | } 952 | if (old_object != NULL && new_object != NULL) 953 | { 954 | /* it was an update */ 955 | object = rpsl_object_init(formatted_object ? formatted_object : new_object); 956 | error_list = rpsl_object_errors(object); 957 | 958 | if ( UP_remove_override_attr(object) ) 959 | arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN); 960 | else 961 | { 962 | /* there was an override attr in this object and it has not been removed */ 963 | arg2 = (char *)malloc(2); 964 | strcpy(arg2, ""); /* Don't include object in ack/notif msgs */ 965 | } 966 | 967 | rpsl_object_delete(object); 968 | 969 | e_mail_list = NT_gather_ntfy_addresses(old_object, new_object); 970 | NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 971 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nPREVIOUS OBJECT:\n\n"); 972 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, old_object); 973 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n\nREPLACED BY:\n\n"); 974 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2); 975 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n"); 976 | } 977 | else if (old_object == NULL && new_object != NULL) 978 | { 979 | /* it was a creation */ 980 | object = rpsl_object_init(formatted_object ? formatted_object : new_object); 981 | error_list = rpsl_object_errors(object); 982 | 983 | if ( UP_remove_override_attr(object) ) 984 | arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN); 985 | else 986 | { 987 | /* there was an override attr in this object and it has not been removed */ 988 | arg2 = (char *)malloc(2); 989 | strcpy(arg2, ""); /* Don't include object in ack/notif msgs */ 990 | } 991 | 992 | rpsl_object_delete(object); 993 | 994 | e_mail_list = NT_gather_ntfy_addresses(old_object, new_object); 995 | NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 996 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nOBJECT BELOW CREATED:\n\n"); 997 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2); 998 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n"); 999 | 1000 | /* We'll deal with cross notifications only when we create or delete route objects */ 1001 | object = rpsl_object_init(new_object); 1002 | error_list = rpsl_object_errors(object); 1003 | 1004 | if (strcmp(rpsl_object_get_class(object), "route") == 0) 1005 | { 1006 | overlapping_routes = get_overlapping_routes_list(object); 1007 | if (overlapping_routes.less_spec != NULL || overlapping_routes.exact_match != NULL || 1008 | overlapping_routes.more_spec != NULL ) 1009 | { 1010 | NT_add_to_cross_hash(cross_hash, e_mail_address, ADDITION); 1011 | NT_add_to_cross(e_mail_address, cross_hash, "%s\n\n%s\n\n%s\n\n", cno_explain_add, new_object, cno_overlap_add); 1012 | if (overlapping_routes.less_spec != NULL) 1013 | { 1014 | NT_add_to_cross(from_address, cross_hash, "LESS SPECIFIC MATCHES\n\n"); 1015 | for (temp = overlapping_routes.less_spec; temp != NULL; temp = g_list_next(temp)) 1016 | { 1017 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1018 | } 1019 | } 1020 | if (overlapping_routes.exact_match != NULL) 1021 | { 1022 | NT_add_to_cross(from_address, cross_hash, "EXACT MATCHES\n\n"); 1023 | for (temp = overlapping_routes.exact_match; temp != NULL; temp = g_list_next(temp)) 1024 | { 1025 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1026 | } 1027 | } 1028 | if (overlapping_routes.more_spec != NULL) 1029 | { 1030 | NT_add_to_cross(from_address, cross_hash, "MORE SPECIFIC MATCHES\n\n"); 1031 | for (temp = overlapping_routes.more_spec; temp != NULL; temp = g_list_next(temp)) 1032 | { 1033 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1034 | } 1035 | } 1036 | } 1037 | } 1038 | rpsl_object_delete(object); 1039 | } 1040 | else if (old_object != NULL && new_object == NULL) 1041 | { /* it was a deletion */ 1042 | old_object = delete_delete_attrib(old_object); 1043 | object = rpsl_object_init(old_object); 1044 | error_list = rpsl_object_errors(object); 1045 | 1046 | if ( UP_remove_override_attr(object) ) 1047 | arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN); 1048 | else 1049 | { 1050 | /* there was an override attr in this object and it has not been removed */ 1051 | arg2 = (char *)malloc(2); 1052 | strcpy(arg2, ""); /* Don't include object in ack/notif msgs */ 1053 | } 1054 | 1055 | e_mail_list = NT_gather_ntfy_addresses(old_object, new_object); 1056 | NT_add_to_ntfy_hash_list(ntfy_hash, e_mail_list); 1057 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "---\nOBJECT BELOW DELETED:\n\n"); 1058 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, arg2); 1059 | NT_add_to_ntfy_list(e_mail_list, ntfy_hash, "\n"); 1060 | 1061 | /* We'll deal with cross notifications only when we create or delete route objects */ 1062 | if (strcmp(rpsl_object_get_class(object), "route") == 0) 1063 | { 1064 | overlapping_routes = get_overlapping_routes_list(object); 1065 | if (overlapping_routes.less_spec != NULL || overlapping_routes.exact_match != NULL || 1066 | overlapping_routes.more_spec != NULL ) 1067 | { 1068 | NT_add_to_cross_hash(cross_hash, e_mail_address, DELETION); 1069 | NT_add_to_cross(e_mail_address, cross_hash, "%s\n\n%s\n\n%s\n\n", cno_explain_del, old_object, cno_overlap_del); 1070 | if (overlapping_routes.less_spec != NULL) 1071 | { 1072 | NT_add_to_cross(from_address, cross_hash, "LESS SPECIFIC MATCHES\n\n"); 1073 | for (temp = overlapping_routes.less_spec; temp != NULL; temp = g_list_next(temp)) 1074 | { 1075 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1076 | } 1077 | } 1078 | if (overlapping_routes.exact_match != NULL) 1079 | { 1080 | NT_add_to_cross(from_address, cross_hash, "EXACT MATCHES\n\n"); 1081 | for (temp = overlapping_routes.exact_match; temp != NULL; temp = g_list_next(temp)) 1082 | { 1083 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1084 | } 1085 | } 1086 | if (overlapping_routes.more_spec != NULL) 1087 | { 1088 | NT_add_to_cross(from_address, cross_hash, "MORE SPECIFIC MATCHES\n\n"); 1089 | for (temp = overlapping_routes.more_spec; temp != NULL; temp = g_list_next(temp)) 1090 | { 1091 | NT_add_to_cross(from_address, cross_hash, "%s\n\n", (char *)temp->data); 1092 | } 1093 | } 1094 | } 1095 | } 1096 | rpsl_object_delete(object); 1097 | } 1098 | free(arg2); 1099 | } 1100 | 1101 | 1102 | 1103 | /* Gets old and new versions of the object, and creates temporary notification 1104 | files when necessary, and then writes appropriate strings into those 1105 | temporary files. */ 1106 | void NT_write_all_frwds(char * old_object_str, char * new_object_str, const char * tempdir, 1107 | GHashTable * ntfy_hash, GHashTable * forwd_hash, GHashTable * cross_hash, 1108 | const char * from_address) 1109 | { 1110 | GList *e_mail_list = NULL; 1111 | rpsl_object_t *object; 1112 | char *arg2; 1113 | const GList * error_list = NULL; 1114 | 1115 | if (tracing) 1116 | { 1117 | printf("TRACING: NT_write_all_frwds is running\n"); 1118 | } 1119 | 1120 | if ( new_object_str ) 1121 | { 1122 | object = rpsl_object_init(new_object_str); 1123 | error_list = rpsl_object_errors(object); 1124 | 1125 | if ( UP_remove_override_attr(object) ) 1126 | arg2 = rpsl_object_get_text(object, RPSL_STD_COLUMN); 1127 | else 1128 | { 1129 | /* there was an override attr in this object and it has not been removed */ 1130 | arg2 = (char *)malloc(2); 1131 | strcpy(arg2, ""); /* Don't include object in ack/notif msgs */ 1132 | } 1133 | } 1134 | 1135 | if (old_object_str != NULL && new_object_str != NULL) 1136 | { /* it was an update */ 1137 | e_mail_list = NT_gather_frwd_addresses(old_object_str); 1138 | NT_add_to_frwd_hash_list(forwd_hash, e_mail_list); 1139 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nUPDATE REQUESTED FOR:\n\n"); 1140 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, arg2); 1141 | } 1142 | else if (old_object_str == NULL && new_object_str != NULL) 1143 | { /* it was a creation */ 1144 | e_mail_list = NT_gather_frwd_addresses(new_object_str); 1145 | NT_add_to_frwd_hash_list(forwd_hash, e_mail_list); 1146 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nADDITION REQUESTED FOR:\n\n"); 1147 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, arg2); 1148 | } 1149 | else if (old_object_str != NULL && new_object_str == NULL) 1150 | { /* it was a deletion */ 1151 | e_mail_list = NT_gather_frwd_addresses(old_object_str); 1152 | NT_add_to_frwd_hash_list(forwd_hash, e_mail_list); 1153 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, "----\nDELETION REQUESTED FOR:\n\n"); 1154 | NT_add_to_ntfy_list(e_mail_list, forwd_hash, old_object_str); 1155 | } 1156 | } 1157 | 1158 | 1159 | 1160 | /* Sends the creation forward message which is stored in the temporary file filename. */ 1161 | void NT_send_forw_creation( const char * filename, const char * to_address, const char * mailercommand) 1162 | { 1163 | char * mail_command_line = NULL; 1164 | 1165 | if (to_address != NULL) 1166 | { 1167 | mail_command_line = (char *)malloc(strlen(mailercommand) + strlen(filename) + 128); 1168 | sprintf(mail_command_line, "%s %s < %s", mailercommand, to_address, filename); 1169 | system(mail_command_line); 1170 | free(mail_command_line); 1171 | } 1172 | } 1173 | 1174 | 1175 | /* NT_forw_create_req forwards the maintainer, as-block and irt creation requests 1176 | to <HUMAILBOX> */ 1177 | void NT_forw_create_req(const char * object_str) 1178 | { 1179 | FILE * forw_file; 1180 | char * filename; 1181 | char * replaced_mtfwheader; 1182 | char * replaced_mtfwtxt; 1183 | 1184 | /* allocate space for name. 32 should be enough for PID */ 1185 | filename = (char*)malloc(strlen(tmpdir) + strlen("creat-forw") +34 ); 1186 | 1187 | sprintf(filename, "%s/%s.%i", tmpdir, "creat-forw", (int)(getpid()) ); 1188 | 1189 | /* create the file */ 1190 | if (( forw_file = fopen(filename, "w")) == NULL) 1191 | { 1192 | fprintf(stderr, "NT_forw_create_req: Can't open creation forward file for creating, %s", filename); 1193 | } 1194 | 1195 | replaced_mtfwheader = UP_replace_globals(mtfwheader); 1196 | replaced_mtfwtxt = UP_replace_globals(mtfwtxt); 1197 | 1198 | fprintf(forw_file, "%s\n\n", replaced_mtfwheader); 1199 | 1200 | if (reading_from_mail) 1201 | { 1202 | fprintf(forw_file, "%s\n\n", replaced_mtfwtxt); 1203 | } 1204 | 1205 | /* print the object */ 1206 | fprintf(forw_file, "%s\n\n", object_str); 1207 | 1208 | /* close it */ 1209 | fclose(forw_file); 1210 | 1211 | /* send it */ 1212 | NT_send_forw_creation(filename, humailbox, mailcmd); 1213 | 1214 | /* log it */ 1215 | NT_log_ntfy(filename, forwlog); 1216 | 1217 | /* delete it */ 1218 | unlink(filename); 1219 | 1220 | /* free the mem */ 1221 | free(filename); 1222 | free(replaced_mtfwheader); 1223 | free(replaced_mtfwtxt); 1224 | }