Icinga-core 1.4.0
next gen monitoring
base/notifications.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * NOTIFICATIONS.C - Service and host notification functions for Icinga
00004  *
00005  * Copyright (c) 1999-2008 Ethan Galstad (egalstad@nagios.org)
00006  * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors
00007  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00008  *
00009  * License:
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License version 2 as
00013  * published by the Free Software Foundation.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023  *
00024  *****************************************************************************/
00025 
00026 #include "../include/config.h"
00027 #include "../include/common.h"
00028 #include "../include/objects.h"
00029 #include "../include/statusdata.h"
00030 #include "../include/macros.h"
00031 #include "../include/icinga.h"
00032 #include "../include/broker.h"
00033 #include "../include/neberrors.h"
00034 
00035 extern notification    *notification_list;
00036 extern contact         *contact_list;
00037 extern serviceescalation *serviceescalation_list;
00038 extern hostescalation  *hostescalation_list;
00039 
00040 extern time_t          program_start;
00041 
00042 extern int             interval_length;
00043 extern int             log_notifications;
00044 
00045 extern int             enable_notifications;
00046 
00047 extern int             notification_timeout;
00048 
00049 extern unsigned long   next_notification_id;
00050 
00051 extern char            *generic_summary;
00052 
00053 int check_escalation_condition(escalation_condition*);
00054 
00055 int dummy;      /* reduce compiler warnings */
00056 
00057 /******************************************************************/
00058 /***************** SERVICE NOTIFICATION FUNCTIONS *****************/
00059 /******************************************************************/
00060 
00061 
00062 /* notify contacts about a service problem or recovery */
00063 int service_notification(service *svc, int type, char *not_author, char *not_data, int options){
00064         host *temp_host=NULL;
00065         notification *temp_notification=NULL;
00066         contact *temp_contact=NULL;
00067         time_t current_time;
00068         struct timeval start_time;
00069         struct timeval end_time;
00070         int escalated=FALSE;
00071         int result=OK;
00072         int contacts_notified=0;
00073         int increment_notification_number=FALSE;
00074         icinga_macros *mac; /* XXX: global macros */
00075         int neb_result;
00076 
00077         mac = get_global_macros();
00078 
00079         log_debug_info(DEBUGL_FUNCTIONS,0,"service_notification()\n");
00080 
00081         /* get the current time */
00082         time(&current_time);
00083         gettimeofday(&start_time,NULL);
00084 
00085         log_debug_info(DEBUGL_NOTIFICATIONS,0,"** Service Notification Attempt ** Host: '%s', Service: '%s', Type: %d, Options: %d, Current State: %d, Last Notification: %s",svc->host_name,svc->description,type,options,svc->current_state,ctime(&svc->last_notification));
00086 
00087         /* if we couldn't find the host, return an error */
00088         if((temp_host=svc->host_ptr)==NULL){
00089                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Couldn't find the host associated with this service, so we won't send a notification!\n");
00090                 return ERROR;
00091                 }
00092 
00093         /* check the viability of sending out a service notification */
00094         if(check_service_notification_viability(svc,type,options)==ERROR){
00095                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test failed.  No notification will be sent out.\n");
00096                 return OK;
00097                 }
00098 
00099         log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test passed.\n");
00100 
00101         /* should the notification number be increased? */
00102         if(type==NOTIFICATION_NORMAL || (options & NOTIFICATION_OPTION_INCREMENT)){
00103                 svc->current_notification_number++;
00104 
00105 #ifdef USE_ST_BASED_ESCAL_RANGES
00106                 /* also increment the warning/critical/unknown state counter */
00107                 if (svc->current_state == STATE_WARNING) {
00108                         svc->current_warning_notification_number++;
00109                 }
00110                 if (svc->current_state == STATE_CRITICAL) {
00111                         svc->current_critical_notification_number++;
00112                 }
00113                 if (svc->current_state == STATE_UNKNOWN) {
00114                         svc->current_unknown_notification_number++;
00115                 }
00116 #endif
00117                 increment_notification_number=TRUE;
00118                 }
00119 
00120         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current notification number: %d (%s)\n",svc->current_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged");
00121 
00122 #ifdef USE_ST_BASED_ESCAL_RANGES
00123         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current warning notification number: %d (%s)\n",svc->current_warning_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged");
00124         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current critical notification number: %d (%s)\n",svc->current_critical_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged");
00125         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current unknown notification number: %d (%s)\n",svc->current_unknown_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged");
00126 #endif
00127 
00128         /* save and increase the current notification id */
00129         svc->current_notification_id=next_notification_id;
00130         next_notification_id++;
00131 
00132         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Creating list of contacts to be notified.\n");
00133 
00134         /* create the contact notification list for this service */
00135         create_notification_list_from_service(mac, svc,options,&escalated);
00136 
00137 #ifdef USE_EVENT_BROKER
00138         /* send data to event broker */
00139         end_time.tv_sec=0L;
00140         end_time.tv_usec=0L;
00141         neb_result=broker_notification_data(NEBTYPE_NOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,not_author,not_data,escalated,0,NULL);
00142         if(NEBERROR_CALLBACKCANCEL==neb_result)
00143                 return ERROR;
00144         else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
00145                 return OK;
00146 #endif
00147 
00148         /* XXX: crazy indent */
00149         /* we have contacts to notify... */
00150         if(notification_list!=NULL){
00151 
00152                 /* grab the macro variables */
00153                 grab_host_macros_r(mac, temp_host);
00154                 grab_service_macros_r(mac, svc);
00155 
00156                 /* if this notification has an author, attempt to lookup the associated contact */
00157                 if(not_author!=NULL){
00158 
00159                         /* see if we can find the contact - first by name, then by alias */
00160                         if((temp_contact=find_contact(not_author))==NULL){
00161                                 for(temp_contact=contact_list;temp_contact!=NULL;temp_contact=temp_contact->next){
00162                                         if(!strcmp(temp_contact->alias,not_author))
00163                                                 break;
00164                                         }
00165                                 }
00166 
00167                         }
00168 
00169                 /* get author and comment macros */
00170                 my_free(mac->x[MACRO_NOTIFICATIONAUTHOR]);
00171                 if(not_author)
00172                         mac->x[MACRO_NOTIFICATIONAUTHOR]=(char *)strdup(not_author);
00173                 my_free(mac->x[MACRO_NOTIFICATIONAUTHORNAME]);
00174                 my_free(mac->x[MACRO_NOTIFICATIONAUTHORALIAS]);
00175                 if(temp_contact!=NULL){
00176                         mac->x[MACRO_NOTIFICATIONAUTHORNAME]=(char *)strdup(temp_contact->name);
00177                         mac->x[MACRO_NOTIFICATIONAUTHORALIAS]=(char *)strdup(temp_contact->alias);
00178                         }
00179                 my_free(mac->x[MACRO_NOTIFICATIONCOMMENT]);
00180                 if(not_data)
00181                         mac->x[MACRO_NOTIFICATIONCOMMENT]=(char *)strdup(not_data);
00182 
00183                 /* NOTE: these macros are deprecated and will likely disappear in future major releases */
00184                 /* if this is an acknowledgement, get author and comment macros */
00185                 if(type==NOTIFICATION_ACKNOWLEDGEMENT){
00186 
00187                         my_free(mac->x[MACRO_SERVICEACKAUTHOR]);
00188                         if(not_author)
00189                                 mac->x[MACRO_SERVICEACKAUTHOR]=(char *)strdup(not_author);
00190 
00191                         my_free(mac->x[MACRO_SERVICEACKCOMMENT]);
00192                         if(not_data)
00193                                 mac->x[MACRO_SERVICEACKCOMMENT]=(char *)strdup(not_data);
00194                         my_free(mac->x[MACRO_SERVICEACKAUTHORNAME]);
00195                         my_free(mac->x[MACRO_SERVICEACKAUTHORALIAS]);
00196                         if(temp_contact!=NULL){
00197                                 mac->x[MACRO_SERVICEACKAUTHORNAME]=(char *)strdup(temp_contact->name);
00198                                 mac->x[MACRO_SERVICEACKAUTHORALIAS]=(char *)strdup(temp_contact->alias);
00199                                 }
00200                         }
00201 
00202                 /* set the notification type macro */
00203                 my_free(mac->x[MACRO_NOTIFICATIONTYPE]);
00204                 if(type==NOTIFICATION_ACKNOWLEDGEMENT)
00205                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("ACKNOWLEDGEMENT");
00206                 else if(type==NOTIFICATION_FLAPPINGSTART)
00207                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTART");
00208                 else if(type==NOTIFICATION_FLAPPINGSTOP)
00209                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTOP");
00210                 else if(type==NOTIFICATION_FLAPPINGDISABLED)
00211                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGDISABLED");
00212                 else if(type==NOTIFICATION_DOWNTIMESTART)
00213                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMESTART");
00214                 else if(type==NOTIFICATION_DOWNTIMEEND)
00215                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMEEND");
00216                 else if(type==NOTIFICATION_DOWNTIMECANCELLED)
00217                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMECANCELLED");
00218                 else if(type==NOTIFICATION_CUSTOM)
00219                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("CUSTOM");
00220                 else if(svc->current_state==STATE_OK)
00221                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("RECOVERY");
00222                 else
00223                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("PROBLEM");
00224 
00225                 /* set the notification number macro */
00226                 my_free(mac->x[MACRO_SERVICENOTIFICATIONNUMBER]);
00227                 dummy=asprintf(&mac->x[MACRO_SERVICENOTIFICATIONNUMBER],"%d",svc->current_notification_number);
00228 
00229                 /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */
00230                 my_free(mac->x[MACRO_NOTIFICATIONNUMBER]);
00231                 mac->x[MACRO_NOTIFICATIONNUMBER]=(char *)strdup((mac->x[MACRO_SERVICENOTIFICATIONNUMBER]==NULL)?"":mac->x[MACRO_SERVICENOTIFICATIONNUMBER]);
00232 
00233                 /* set the notification id macro */
00234                 my_free(mac->x[MACRO_SERVICENOTIFICATIONID]);
00235                 dummy=asprintf(&mac->x[MACRO_SERVICENOTIFICATIONID],"%lu",svc->current_notification_id);
00236 
00237                 /* notify each contact (duplicates have been removed) */
00238                 for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){
00239 
00240                         /* grab the macro variables for this contact */
00241                         grab_contact_macros_r(mac, temp_notification->contact);
00242 
00243                         /* clear summary macros (they are customized for each contact) */
00244                         clear_summary_macros_r(mac);
00245 
00246                         /* notify this contact */
00247                         result=notify_contact_of_service(mac, temp_notification->contact,svc,type,not_author,not_data,options,escalated);
00248 
00249                         /* keep track of how many contacts were notified */
00250                         if(result==OK)
00251                                 contacts_notified++;
00252                         }
00253 
00254                 /* free memory allocated to the notification list */
00255                 free_notification_list();
00256 
00257                 /* clear summary macros so they will be regenerated without contact filters when needed next */
00258                 clear_summary_macros_r(mac);
00259 
00260                 if(type==NOTIFICATION_NORMAL){
00261 
00262                         /* adjust last/next notification time and notification flags if we notified someone */
00263                         if(contacts_notified>0){
00264 
00265                                 /* calculate the next acceptable re-notification time */
00266                                 svc->next_notification=get_next_service_notification_time(svc,current_time);
00267 
00268                                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.  Next possible notification time: %s",contacts_notified,ctime(&svc->next_notification));
00269 
00270                                 /* update the last notification time for this service (this is needed for rescheduling later notifications) */
00271                                 svc->last_notification=current_time;
00272 
00273                                 /* update notifications flags */
00274                                 if(svc->current_state==STATE_UNKNOWN)
00275                                         svc->notified_on_unknown=TRUE;
00276                                 else if(svc->current_state==STATE_WARNING)
00277                                         svc->notified_on_warning=TRUE;
00278                                 else if(svc->current_state==STATE_CRITICAL)
00279                                         svc->notified_on_critical=TRUE;
00280                                 }
00281 
00282                         /* we didn't end up notifying anyone */
00283                         else if(increment_notification_number==TRUE){
00284 
00285                                 /* adjust current notification number */
00286                                 svc->current_notification_number--;
00287 
00288 #ifdef USE_ST_BASED_ESCAL_RANGES
00289                                 if (svc->current_state == STATE_WARNING) {
00290                                         svc->current_warning_notification_number--;
00291                                 }
00292                                 if (svc->current_state == STATE_CRITICAL) {
00293                                         svc->current_critical_notification_number--;
00294                                 }
00295                                 if (svc->current_state == STATE_UNKNOWN) {
00296                                         svc->current_unknown_notification_number--;
00297                                 }
00298 #endif
00299 
00300                                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were notified.  Next possible notification time: %s",ctime(&svc->next_notification));
00301                                 }
00302 
00303                         }
00304 
00305                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.\n",contacts_notified);
00306                 }
00307 
00308         /* there were no contacts, so no notification really occurred... */
00309         else{
00310 
00311                 /* readjust current notification number, since one didn't go out */
00312                 if(increment_notification_number==TRUE) {
00313                         svc->current_notification_number--;
00314 
00315 #ifdef USE_ST_BASED_ESCAL_RANGES
00316                         if (svc->current_state == STATE_WARNING) {
00317                                 svc->current_warning_notification_number--;
00318                         }
00319                         if (svc->current_state == STATE_CRITICAL) {
00320                                 svc->current_critical_notification_number--;
00321                         }
00322                         if (svc->current_state == STATE_UNKNOWN) {
00323                                 svc->current_unknown_notification_number--;
00324                         }
00325 #endif
00326                 }
00327 
00328                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were found for notification purposes.  No notification was sent out.\n");
00329                 }
00330 
00331         /* get the time we finished */
00332         gettimeofday(&end_time,NULL);
00333 
00334 #ifdef USE_EVENT_BROKER
00335         /* send data to event broker */
00336         broker_notification_data(NEBTYPE_NOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,not_author,not_data,escalated,contacts_notified,NULL);
00337 #endif
00338 
00339         /* update the status log with the service information */
00340         update_service_status(svc,FALSE);
00341 
00342         return OK;
00343 }
00344 
00345 
00346 
00347 /* checks the viability of sending out a service alert (top level filters) */
00348 int check_service_notification_viability(service *svc, int type, int options){
00349         host *temp_host=NULL;
00350         timeperiod *temp_period=NULL;
00351         time_t current_time;
00352         time_t timeperiod_start;
00353         time_t first_problem_time;
00354 
00355         log_debug_info(DEBUGL_FUNCTIONS,0,"check_service_notification_viability()\n");
00356 
00357         /* forced notifications bust through everything */
00358         if(options & NOTIFICATION_OPTION_FORCED){
00359                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced service notification, so we'll send it out.\n");
00360                 return OK;
00361                 }
00362 
00363         /* get current time */
00364         time(&current_time);
00365 
00366         /* are notifications enabled? */
00367         if(enable_notifications==FALSE){
00368                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are disabled, so service notifications will not be sent out.\n");
00369                 return ERROR;
00370                 }
00371 
00372         /* find the host this service is associated with */
00373         if((temp_host=(host *)svc->host_ptr)==NULL)
00374                 return ERROR;
00375 
00376         /* if we couldn't find the host, return an error */
00377         if(temp_host==NULL){
00378                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Couldn't find the host associated with this service, so we won't send a notification.\n");
00379                 return ERROR;
00380                 }
00381 
00382         /* if the service has no notification period, inherit one from the host */
00383         temp_period = svc->notification_period_ptr;
00384         if(temp_period == NULL){
00385                 temp_period = temp_host->notification_period_ptr;
00386         }
00387 
00388         /* see if the service can have notifications sent out at this time */
00389         if(check_time_against_period(current_time,temp_period)==ERROR){
00390 
00391                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service shouldn't have notifications sent out at this time.\n");
00392 
00393                 /* calculate the next acceptable notification time, once the next valid time range arrives... */
00394                 if(type==NOTIFICATION_NORMAL){
00395 
00396                         get_next_valid_time(current_time,&timeperiod_start,svc->notification_period_ptr);
00397 
00398                         /* looks like there are no valid notification times defined, so schedule the next one far into the future (one year)... */
00399                         if(timeperiod_start==(time_t)0)
00400                                 svc->next_notification=(time_t)(current_time+(60*60*24*365));
00401 
00402                         /* else use the next valid notification time */
00403                         else
00404                                 svc->next_notification=timeperiod_start;
00405 
00406                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next possible notification time: %s\n",ctime(&svc->next_notification));
00407                         }
00408 
00409                 return ERROR;
00410                 }
00411 
00412         /* are notifications temporarily disabled for this service? */
00413         if(svc->notifications_enabled==FALSE){
00414                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are temporarily disabled for this service, so we won't send one out.\n");
00415                 return ERROR;
00416                 }
00417 
00418 
00419         /*********************************************/
00420         /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/
00421         /*********************************************/
00422 
00423         /* custom notifications are good to go at this point... */
00424         if(type==NOTIFICATION_CUSTOM) {
00425                 if(svc->scheduled_downtime_depth>0 || temp_host->scheduled_downtime_depth>0){
00426                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't send custom notification during scheduled downtime.\n");
00427                         return ERROR;
00428                 }
00429                 return OK;
00430         }
00431 
00432 
00433         /****************************************/
00434         /*** SPECIAL CASE FOR ACKNOWLEGEMENTS ***/
00435         /****************************************/
00436 
00437         /* acknowledgements only have to pass three general filters, although they have another test of their own... */
00438         if(type==NOTIFICATION_ACKNOWLEDGEMENT){
00439 
00440                 /* don't send an acknowledgement if there isn't a problem... */
00441                 if(svc->current_state==STATE_OK){
00442                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"The service is currently OK, so we won't send an acknowledgement.\n");
00443                         return ERROR;
00444                         }
00445 
00446                 /* acknowledgement viability test passed, so the notification can be sent out */
00447                 return OK;
00448                 }
00449 
00450 
00451         /****************************************/
00452         /*** SPECIAL CASE FOR FLAPPING ALERTS ***/
00453         /****************************************/
00454 
00455         /* flapping notifications only have to pass three general filters */
00456         if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){
00457 
00458                 /* don't send a notification if we're not supposed to... */
00459                 if(svc->notify_on_flapping==FALSE){
00460                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events for this service.\n");
00461                         return ERROR;
00462                         }
00463 
00464                 /* don't send notifications during scheduled downtime */
00465                 if(svc->scheduled_downtime_depth>0 || temp_host->scheduled_downtime_depth>0){
00466                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events during scheduled downtime.\n");
00467                         return ERROR;
00468                         }
00469 
00470                 /* flapping viability test passed, so the notification can be sent out */
00471                 return OK;
00472                 }
00473 
00474 
00475         /****************************************/
00476         /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/
00477         /****************************************/
00478 
00479         /* downtime notifications only have to pass three general filters */
00480         if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){
00481 
00482                 /* don't send a notification if we're not supposed to... */
00483                 if(svc->notify_on_downtime==FALSE){
00484                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events for this service.\n");
00485                         return ERROR;
00486                         }
00487 
00488                 /* don't send notifications during scheduled downtime (for service only, not host) */
00489                 if(svc->scheduled_downtime_depth>0){
00490                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events during scheduled downtime.\n");
00491                         return ERROR;
00492                         }
00493 
00494                 /* downtime viability test passed, so the notification can be sent out */
00495                 return OK;
00496                 }
00497 
00498 
00499         /****************************************/
00500         /*** NORMAL NOTIFICATIONS ***************/
00501         /****************************************/
00502 
00503         /* is this a hard problem/recovery? */
00504         if(svc->state_type==SOFT_STATE){
00505                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is in a soft state, so we won't send a notification out.\n");
00506                 return ERROR;
00507                 }
00508 
00509         /* has this problem already been acknowledged? */
00510         if(svc->problem_has_been_acknowledged==TRUE){
00511                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service problem has already been acknowledged, so we won't send a notification out.\n");
00512                 return ERROR;
00513                 }
00514 
00515         /* check service notification dependencies */
00516         if(check_service_dependencies(svc,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){
00517                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification dependencies for this service have failed, so we won't sent a notification out.\n");
00518                 return ERROR;
00519                 }
00520 
00521         /* check host notification dependencies */
00522         if(check_host_dependencies(temp_host,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){
00523                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Host notification dependencies for this service have failed, so we won't sent a notification out.\n");
00524                 return ERROR;
00525                 }
00526 
00527         /* see if we should notify about problems with this service */
00528         if(svc->current_state==STATE_UNKNOWN && svc->notify_on_unknown==FALSE){
00529                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about UNKNOWN states for this service.\n");
00530                 return ERROR;
00531                 }
00532         if(svc->current_state==STATE_WARNING && svc->notify_on_warning==FALSE){
00533                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about WARNING states for this service.\n");
00534                 return ERROR;
00535                 }
00536         if(svc->current_state==STATE_CRITICAL && svc->notify_on_critical==FALSE){
00537                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about CRITICAL states for this service.\n");
00538                 return ERROR;
00539                 }
00540         if(svc->current_state==STATE_OK){
00541                 if(svc->notify_on_recovery==FALSE){
00542                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about RECOVERY states for this service.\n");
00543                         return ERROR;
00544                         }
00545                 if(!(svc->notified_on_unknown==TRUE || svc->notified_on_warning==TRUE || svc->notified_on_critical==TRUE)){
00546                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about this recovery.\n");
00547                         return ERROR;
00548                         }
00549                 }
00550 
00551         /* see if enough time has elapsed for first notification (Mathias Sundman) */
00552         /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time ok (or program start) in calculation */
00553         /* it is reasonable to assume that if the host was never up, the program start time should be used in this calculation */
00554         if(type==NOTIFICATION_NORMAL && svc->current_notification_number==0 && svc->current_state!=STATE_OK){
00555 
00556                 /* determine the time to use of the first problem point */
00557                 first_problem_time=svc->last_time_ok; /* not accurate, but its the earliest time we could use in the comparison */
00558 
00559                 if((svc->last_time_warning < first_problem_time) && (svc->last_time_warning > svc->last_time_ok))
00560                         first_problem_time=svc->last_time_warning;
00561                 if((svc->last_time_unknown < first_problem_time) && (svc->last_time_unknown > svc->last_time_ok))
00562                         first_problem_time=svc->last_time_unknown;
00563                 if((svc->last_time_critical < first_problem_time) && (svc->last_time_critical > svc->last_time_ok))
00564                         first_problem_time=svc->last_time_critical;
00565 
00566                 if(current_time < (time_t)((first_problem_time==(time_t)0L)?program_start:first_problem_time) + (time_t)(svc->first_notification_delay*interval_length)){
00567                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Not enough time has elapsed since the service changed to a non-OK state, so we should not notify about this problem yet\n");
00568                         return ERROR;
00569                 }
00570         }
00571 
00572         /* if this service is currently flapping, don't send the notification */
00573         if(svc->is_flapping==TRUE){
00574                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is currently flapping, so we won't send notifications.\n");
00575                 return ERROR;
00576                 }
00577 
00578         /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/
00579         if(svc->current_state==STATE_OK)
00580                 return OK;
00581 
00582         /* don't notify contacts about this service problem again if the notification interval is set to 0 */
00583         if(svc->no_more_notifications==TRUE){
00584                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't re-notify contacts about this service problem.\n");
00585                 return ERROR;
00586                 }
00587 
00588         /* if the host is down or unreachable, don't notify contacts about service failures */
00589         if(temp_host->current_state!=HOST_UP){
00590                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host is either down or unreachable, so we won't notify contacts about this service.\n");
00591                 return ERROR;
00592                 }
00593 
00594         /* don't notify if we haven't waited long enough since the last time (and the service is not marked as being volatile) */
00595         if((current_time < svc->next_notification)){
00596                 if (svc->is_volatile==FALSE || svc->is_volatile==VOLATILE_WITH_RENOTIFICATION_INTERVAL) {
00597                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We haven't waited long enough to re-notify contacts about this service.\n");
00598                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next valid notification time: %s",ctime(&svc->next_notification));
00599                         return ERROR;
00600                         }
00601                 }
00602 
00603         /* if this service is currently in a scheduled downtime period, don't send the notification */
00604         if(svc->scheduled_downtime_depth>0){
00605                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This service is currently in a scheduled downtime, so we won't send notifications.\n");
00606                 return ERROR;
00607                 }
00608 
00609         /* if this host is currently in a scheduled downtime period, don't send the notification */
00610         if(temp_host->scheduled_downtime_depth>0){
00611                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host this service is associated with is currently in a scheduled downtime, so we won't send notifications.\n");
00612                 return ERROR;
00613                 }
00614 
00615         return OK;
00616         }
00617 
00618 
00619 
00620 /* check viability of sending out a service notification to a specific contact (contact-specific filters) */
00621 int check_contact_service_notification_viability(contact *cntct, service *svc, int type, int options){
00622 
00623         log_debug_info(DEBUGL_FUNCTIONS,0,"check_contact_service_notification_viability()\n");
00624 
00625         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Checking service notification viability for contact '%s'...\n",cntct->name);
00626 
00627         /* forced notifications bust through everything */
00628         if(options & NOTIFICATION_OPTION_FORCED){
00629                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced service notification, so we'll send it out to this contact.\n");
00630                 return OK;
00631                 }
00632 
00633         /* are notifications enabled? */
00634         if(cntct->service_notifications_enabled==FALSE){
00635                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Service notifications are disabled for this contact.\n");
00636                 return ERROR;
00637                 }
00638 
00639         /* see if the contact can be notified at this time */
00640         if(check_time_against_period(time(NULL),cntct->service_notification_period_ptr)==ERROR){
00641                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This contact shouldn't be notified at this time.\n");
00642                 return ERROR;
00643                 }
00644 
00645         /*********************************************/
00646         /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/
00647         /*********************************************/
00648 
00649         /* custom notifications are good to go at this point... */
00650         if(type==NOTIFICATION_CUSTOM)
00651                 return OK;
00652 
00653 
00654         /****************************************/
00655         /*** SPECIAL CASE FOR FLAPPING ALERTS ***/
00656         /****************************************/
00657 
00658         if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){
00659 
00660                 if(cntct->notify_on_service_flapping==FALSE){
00661                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about FLAPPING service events.\n");
00662                         return ERROR;
00663                         }
00664 
00665                 return OK;
00666                 }
00667 
00668         /****************************************/
00669         /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/
00670         /****************************************/
00671 
00672         if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){
00673 
00674                 if(cntct->notify_on_service_downtime==FALSE){
00675                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWNTIME service events.\n");
00676                         return ERROR;
00677                         }
00678 
00679                 return OK;
00680                 }
00681 
00682         /*************************************/
00683         /*** ACKS AND NORMAL NOTIFICATIONS ***/
00684         /*************************************/
00685 
00686         /* see if we should notify about problems with this service */
00687         if(svc->current_state==STATE_UNKNOWN && cntct->notify_on_service_unknown==FALSE){
00688                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about UNKNOWN service states.\n");
00689                 return ERROR;
00690                 }
00691 
00692         if(svc->current_state==STATE_WARNING && cntct->notify_on_service_warning==FALSE){
00693                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about WARNING service states.\n");
00694                 return ERROR;
00695                 }
00696 
00697         if(svc->current_state==STATE_CRITICAL && cntct->notify_on_service_critical==FALSE){
00698                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about CRITICAL service states.\n");
00699                 return ERROR;
00700                 }
00701 
00702         if(svc->current_state==STATE_OK){
00703 
00704                 if(cntct->notify_on_service_recovery==FALSE){
00705                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about RECOVERY service states.\n");
00706                         return ERROR;
00707                         }
00708 
00709                 if(!((svc->notified_on_unknown==TRUE && cntct->notify_on_service_unknown==TRUE) || (svc->notified_on_warning==TRUE && cntct->notify_on_service_warning==TRUE) || (svc->notified_on_critical==TRUE && cntct->notify_on_service_critical==TRUE))){
00710                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify about this recovery.\n");
00711                         return ERROR;
00712                         }
00713                 }
00714 
00715         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Service notification viability for contact '%s' PASSED.\n",cntct->name);
00716 
00717         return OK;
00718         }
00719 
00720 
00721 
00722 /* notify a specific contact about a service problem or recovery */
00723 int notify_contact_of_service(icinga_macros *mac, contact *cntct, service *svc, int type, char *not_author, char *not_data, int options, int escalated){
00724         commandsmember *temp_commandsmember=NULL;
00725         char *command_name=NULL;
00726         char *command_name_ptr=NULL;
00727         char *raw_command=NULL;
00728         char *processed_command=NULL;
00729         char *temp_buffer=NULL;
00730         char *processed_buffer=NULL;
00731         int early_timeout=FALSE;
00732         double exectime;
00733         struct timeval start_time,end_time;
00734         struct timeval method_start_time,method_end_time;
00735         int macro_options=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS;
00736         int neb_result;
00737 
00738         log_debug_info(DEBUGL_FUNCTIONS,0,"notify_contact_of_service()\n");
00739         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Attempting to notifying contact '%s'...\n",cntct->name);
00740 
00741         /* check viability of notifying this user */
00742         /* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */
00743         if(check_contact_service_notification_viability(cntct,svc,type,options)==ERROR)
00744                 return ERROR;
00745 
00746         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Notifying contact '%s'\n",cntct->name);
00747 
00748         /* get start time */
00749         gettimeofday(&start_time,NULL);
00750 
00751 #ifdef USE_EVENT_BROKER
00752         /* send data to event broker */
00753         end_time.tv_sec=0L;
00754         end_time.tv_usec=0L;
00755         neb_result=broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,cntct,not_author,not_data,escalated,NULL);
00756         if(NEBERROR_CALLBACKCANCEL==neb_result)
00757                 return ERROR;
00758         else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
00759                 return OK;
00760 #endif
00761 
00762         /* process all the notification commands this user has */
00763         for(temp_commandsmember=cntct->service_notification_commands;temp_commandsmember!=NULL;temp_commandsmember=temp_commandsmember->next){
00764 
00765                 /* get start time */
00766                 gettimeofday(&method_start_time,NULL);
00767 
00768 #ifdef USE_EVENT_BROKER
00769                 /* send data to event broker */
00770                 method_end_time.tv_sec=0L;
00771                 method_end_time.tv_usec=0L;
00772                 neb_result=broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_START,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,method_start_time,method_end_time,(void *)svc,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL);
00773                 if(NEBERROR_CALLBACKCANCEL==neb_result)
00774                         break ;
00775                 else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
00776                         continue ;
00777 #endif
00778 
00779                 /* get the raw command line */
00780                 get_raw_command_line_r(mac, temp_commandsmember->command_ptr,temp_commandsmember->command,&raw_command,macro_options);
00781                 if(raw_command==NULL)
00782                         continue;
00783 
00784                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Raw notification command: %s\n",raw_command);
00785 
00786                 /* process any macros contained in the argument */
00787                 process_macros_r(mac, raw_command,&processed_command,macro_options);
00788                 if(processed_command==NULL)
00789                         continue;
00790 
00791                 /* get the command name */
00792                 command_name=(char *)strdup(temp_commandsmember->command);
00793                 command_name_ptr=strtok(command_name,"!");
00794 
00795                 /* run the notification command... */
00796 
00797                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Processed notification command: %s\n",processed_command);
00798 
00799                 /* log the notification to program log file */
00800                 if(log_notifications==TRUE){
00801                         switch(type){
00802                         case NOTIFICATION_CUSTOM:
00803                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;CUSTOM ($SERVICESTATE$);%s;$SERVICEOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00804                                 break;
00805                         case NOTIFICATION_ACKNOWLEDGEMENT:
00806                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;ACKNOWLEDGEMENT ($SERVICESTATE$);%s;$SERVICEOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00807                                 break;
00808                         case NOTIFICATION_FLAPPINGSTART:
00809                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGSTART ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00810                                 break;
00811                         case NOTIFICATION_FLAPPINGSTOP:
00812                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGSTOP ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00813                                 break;
00814                         case NOTIFICATION_FLAPPINGDISABLED:
00815                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;FLAPPINGDISABLED ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00816                                 break;
00817                         case NOTIFICATION_DOWNTIMESTART:
00818                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMESTART ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00819                                 break;
00820                         case NOTIFICATION_DOWNTIMEEND:
00821                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMEEND ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00822                                 break;
00823                         case NOTIFICATION_DOWNTIMECANCELLED:
00824                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;DOWNTIMECANCELLED ($SERVICESTATE$);%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00825                                 break;
00826                         default:
00827                                 dummy=asprintf(&temp_buffer,"SERVICE NOTIFICATION: %s;%s;%s;$SERVICESTATE$;%s;$SERVICEOUTPUT$\n",cntct->name,svc->host_name,svc->description,command_name_ptr);
00828                                 break;
00829                                 }
00830 
00831                         process_macros_r(mac, temp_buffer,&processed_buffer,0);
00832                         write_to_all_logs(processed_buffer,NSLOG_SERVICE_NOTIFICATION);
00833 
00834                         my_free(temp_buffer);
00835                         my_free(processed_buffer);
00836                         }
00837 
00838                 /* run the notification command */
00839                 my_system_r(mac, processed_command,notification_timeout,&early_timeout,&exectime,NULL,0);
00840 
00841                 /* check to see if the notification command timed out */
00842                 if(early_timeout==TRUE){
00843                         logit(NSLOG_SERVICE_NOTIFICATION | NSLOG_RUNTIME_WARNING,TRUE,"Warning: Contact '%s' service notification command '%s' timed out after %d seconds\n",cntct->name,processed_command,notification_timeout);
00844                         }
00845 
00846                 /* free memory */
00847                 my_free(command_name);
00848                 my_free(raw_command);
00849                 my_free(processed_command);
00850 
00851                 /* get end time */
00852                 gettimeofday(&method_end_time,NULL);
00853 
00854 #ifdef USE_EVENT_BROKER
00855                 /* send data to event broker */
00856                 broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,method_start_time,method_end_time,(void *)svc,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL);
00857 #endif
00858                 }
00859 
00860         /* get end time */
00861         gettimeofday(&end_time,NULL);
00862 
00863         /* update the contact's last service notification time */
00864         cntct->last_service_notification=start_time.tv_sec;
00865 
00866 #ifdef USE_EVENT_BROKER
00867         /* send data to event broker */
00868         broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,SERVICE_NOTIFICATION,type,start_time,end_time,(void *)svc,cntct,not_author,not_data,escalated,NULL);
00869 #endif
00870 
00871         return OK;
00872 }
00873 
00874 
00875 /* checks to see if a service escalation entry is a match for the current service notification */
00876 int is_valid_escalation_for_service_notification(service *svc, serviceescalation *se, int options){
00877         int notification_number=0;
00878 #ifdef USE_ST_BASED_ESCAL_RANGES
00879         int warning_notification_number=0;
00880         int critical_notification_number=0;
00881         int unknown_notification_number=0;
00882         int widematch=1;
00883 #endif
00884         time_t current_time=0L;
00885         service *temp_service=NULL;
00886 
00887         log_debug_info(DEBUGL_FUNCTIONS,0,"is_valid_escalation_for_service_notification()\n");
00888 
00889         /* get the current time */
00890         time(&current_time);
00891 
00892         /* if this is a recovery, really we check for who got notified about a previous problem */
00893         if(svc->current_state==STATE_OK)
00894                 notification_number=svc->current_notification_number-1;
00895         else
00896                 notification_number=svc->current_notification_number;
00897 
00898 #ifdef USE_ST_BASED_ESCAL_RANGES
00899         /* These will not be incremented in the case of a recovery, so use the current values regardless of the state */
00900         warning_notification_number=svc->current_warning_notification_number;
00901         critical_notification_number=svc->current_critical_notification_number;
00902         unknown_notification_number=svc->current_unknown_notification_number;
00903 #endif
00904 
00905         /* this entry if it is not for this service */
00906         temp_service=se->service_ptr;
00907         if(temp_service==NULL || temp_service!=svc)
00908                 return FALSE;
00909 
00910         /*** EXCEPTION ***/
00911         /* broadcast options go to everyone, so this escalation is valid */
00912         if(options & NOTIFICATION_OPTION_BROADCAST)
00913                 return TRUE;
00914 
00915 #ifndef USE_ST_BASED_ESCAL_RANGES
00916         /* skip this escalation if it happens later */
00917         if(se->first_notification > notification_number)
00918                 return FALSE;
00919 #else
00920         /* skip this escalation if it happens later
00921          * Only skip if none of the notifications numbers match */
00922 
00923         if(se->first_notification == -2 || se->first_notification > notification_number)
00924                 widematch=0;
00925 
00926         if (!widematch){
00927                 switch (svc->current_state){
00928                         case STATE_WARNING:{
00929                                 if (se->first_warning_notification == -2 || se->first_warning_notification > warning_notification_number)
00930                                         return FALSE;
00931                                 break;
00932                         }
00933                         case STATE_CRITICAL:{
00934                                 if (se->first_critical_notification == -2 || se->first_critical_notification > critical_notification_number)
00935                                         return FALSE;
00936                                 break;
00937                         }
00938                         case STATE_UNKNOWN:{
00939                                 if (se->first_unknown_notification == -2 || se->first_unknown_notification > unknown_notification_number)
00940                                         return FALSE;
00941                                 break;
00942                         }
00943                 }
00944         }
00945 #endif
00946 
00947 
00948 #ifndef USE_ST_BASED_ESCAL_RANGES
00949         /* skip this escalation if it has already passed */
00950         if(se->last_notification!=0 && se->last_notification < notification_number)
00951                 return FALSE;
00952 #else
00953         /* skip this escalation if it has already passed
00954          * only skip if none of the notifications numbers match */
00955 
00956         widematch=1;
00957         if(se->last_notification == -2 || ((se->last_notification!=0) && (se->last_notification < notification_number)))
00958                 widematch=0;
00959 
00960 
00961         if (!widematch){
00962                 switch (svc->current_state){
00963                         case STATE_WARNING:{
00964                                 if (se->last_warning_notification == -2 || ((se->last_warning_notification!=0) && (se->last_warning_notification < warning_notification_number)))
00965                                         return FALSE;
00966                                 break;
00967                         }
00968                         case STATE_CRITICAL:{
00969                                 if (se->last_critical_notification == -2 || ((se->last_critical_notification!=0) && (se->last_critical_notification < critical_notification_number)))
00970                                         return FALSE;
00971                                 break;
00972                         }
00973                         case STATE_UNKNOWN:{
00974                                 if (se->last_unknown_notification == -2 || ((se->last_unknown_notification!=0) && (se->last_unknown_notification < unknown_notification_number)))
00975                                         return FALSE;
00976                                 break;
00977                         }
00978                 }
00979         }
00980 #endif
00981 
00982         /* skip this escalation if it has a timeperiod and the current time isn't valid */
00983         if(se->escalation_period!=NULL && check_time_against_period(current_time,se->escalation_period_ptr)==ERROR)
00984                 return FALSE;
00985 
00986         /* skip this escalation if the state options don't match */
00987         if(svc->current_state==STATE_OK && se->escalate_on_recovery==FALSE)
00988                 return FALSE;
00989         else if(svc->current_state==STATE_WARNING && se->escalate_on_warning==FALSE)
00990                 return FALSE;
00991         else if(svc->current_state==STATE_UNKNOWN && se->escalate_on_unknown==FALSE)
00992                 return FALSE;
00993         else if(svc->current_state==STATE_CRITICAL && se->escalate_on_critical==FALSE)
00994                 return FALSE;
00995 
00996        /* skip this escalation if the conditions don't match */
00997        else if(check_escalation_condition(se->condition)==FALSE)
00998                return FALSE;
00999 
01000         return TRUE;
01001         }
01002 
01003 /* internal help function checks if all conditions in an escalation condition list match the status of hosts/services */
01004 int check_escalation_condition(escalation_condition *cond){
01005         int resultAll = TRUE;
01006         int connector = EC_CONNECTOR_NO;
01007         escalation_condition *cnd = cond; // first condition in list
01008 
01009         log_debug_info(DEBUGL_FUNCTIONS,0,"check_escalation_condition()");
01010 
01011         while(cnd!=NULL) {
01012                 int result = TRUE;
01013 
01014                 /* service condition */
01015                 if(cnd->service_description!=NULL && strcmp(cnd->service_description,"")
01016                                         && cnd->host_name!=NULL && strcmp(cnd->host_name,"")) {
01017 
01018                         /* try to find the service */
01019                         service *svc = find_service(cnd->host_name, cnd->service_description);
01020                         if (svc == NULL) {
01021                                 result = FALSE;
01022                         }
01023                         else {
01024                                 if(svc->current_state==STATE_OK && cnd->escalate_on_ok==FALSE)
01025                                         result = FALSE;
01026                                 else if(svc->current_state==STATE_WARNING && cnd->escalate_on_warning==FALSE)
01027                                         result = FALSE;
01028                                 else if(svc->current_state==STATE_UNKNOWN && cnd->escalate_on_unknown==FALSE)
01029                                         result = FALSE;
01030                                 else if(svc->current_state==STATE_CRITICAL && cnd->escalate_on_critical==FALSE)
01031                                         result = FALSE;
01032                         }
01033                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Check service escalation condition %s.%s = %d.\n", svc->host_name, svc->description, result);
01034                 }
01035 
01036                 /* host condition */
01037                 else if(cnd->host_name!=NULL && strcmp(cnd->host_name,"")) {
01038 
01039                         /* try to find the host */
01040                         host *hst = find_host(cnd->host_name);
01041                         if (hst==NULL) {
01042                                 result = FALSE;
01043                         }
01044                         else {
01045                                 if(hst->current_state==HOST_UP && cnd->escalate_on_ok==FALSE)
01046                                         result = FALSE;
01047                                 else if(hst->current_state==HOST_DOWN && cnd->escalate_on_down==FALSE)
01048                                         result = FALSE;
01049                                 else if(hst->current_state==HOST_UNREACHABLE && cnd->escalate_on_unreachable==FALSE)
01050                                         result = FALSE;
01051                         }
01052                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Check host escalation condition %s = %d.\n", hst->name, result);
01053                 }
01054 
01055                 /* connect the result with the result of previous conditions */
01056                 switch(connector) {
01057                         case EC_CONNECTOR_NO:
01058                                 // goes here when looking at the first condition!
01059                                 resultAll = result;
01060                                 break;
01061                         case EC_CONNECTOR_AND:
01062                                 resultAll = resultAll && result;
01063                                 break;
01064                         case EC_CONNECTOR_OR:
01065                                 resultAll = resultAll || result;
01066                                 break;
01067                         default:
01068                                 // this should not happen
01069                                 return FALSE;
01070                                 break;
01071                 }
01072                 connector = cnd->connector;
01073                 cnd = cnd->next;
01074         }
01075         return resultAll;
01076 }
01077 
01078 /* checks to see whether a service notification should be escalation */
01079 int should_service_notification_be_escalated(service *svc){
01080         serviceescalation *temp_se=NULL;
01081         void *ptr=NULL;
01082 
01083         log_debug_info(DEBUGL_FUNCTIONS,0,"should_service_notification_be_escalated()\n");
01084 
01085         /* search the service escalation list */
01086         for(temp_se=get_first_serviceescalation_by_service(svc->host_name,svc->description,&ptr);temp_se!=NULL;temp_se=get_next_serviceescalation_by_service(svc->host_name,svc->description,&ptr)){
01087 
01088                 /* we found a matching entry, so escalate this notification! */
01089                 if(is_valid_escalation_for_service_notification(svc,temp_se,NOTIFICATION_OPTION_NONE)==TRUE){
01090                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification WILL be escalated.\n");
01091                         return TRUE;
01092                         }
01093                 }
01094 
01095         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Service notification will NOT be escalated.\n");
01096 
01097         return FALSE;
01098         }
01099 
01100 
01101 /* given a service, create a list of contacts to be notified, removing duplicates */
01102 int create_notification_list_from_service(icinga_macros *mac, service *svc, int options, int *escalated){
01103         serviceescalation *temp_se=NULL;
01104         contactsmember *temp_contactsmember=NULL;
01105         contact *temp_contact=NULL;
01106         contactgroupsmember *temp_contactgroupsmember=NULL;
01107         contactgroup *temp_contactgroup=NULL;
01108         int escalate_notification=FALSE;
01109         void *ptr=NULL;
01110 
01111         log_debug_info(DEBUGL_FUNCTIONS,0,"create_notification_list_from_service()\n");
01112 
01113         /* see if this notification should be escalated */
01114         escalate_notification=should_service_notification_be_escalated(svc);
01115 
01116         /* set the escalation flag */
01117         *escalated=escalate_notification;
01118 
01119         /* set the escalation macro */
01120         my_free(mac->x[MACRO_NOTIFICATIONISESCALATED]);
01121         dummy=asprintf(&mac->x[MACRO_NOTIFICATIONISESCALATED],"%d",escalate_notification);
01122 
01123         if(options & NOTIFICATION_OPTION_BROADCAST)
01124                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This notification will be BROADCAST to all (escalated and normal) contacts...\n");
01125 
01126         /* use escalated contacts for this notification */
01127         if(escalate_notification==TRUE || (options & NOTIFICATION_OPTION_BROADCAST)){
01128 
01129                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding contacts from service escalation(s) to notification list.\n");
01130 
01131                 /* search all the escalation entries for valid matches */
01132                 for(temp_se=get_first_serviceescalation_by_service(svc->host_name,svc->description,&ptr);temp_se!=NULL;temp_se=get_next_serviceescalation_by_service(svc->host_name,svc->description,&ptr)){
01133 
01134                         /* skip this entry if it isn't appropriate */
01135                         if(is_valid_escalation_for_service_notification(svc,temp_se,options)==FALSE)
01136                                 continue;
01137 
01138                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts from service escalation(s) to notification list.\n");
01139 
01140                         /* add all individual contacts for this escalation entry */
01141                         for(temp_contactsmember=temp_se->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
01142                                 if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
01143                                         continue;
01144                                 add_notification(mac, temp_contact);
01145                                 }
01146 
01147                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups from service escalation(s) to notification list.\n");
01148 
01149                         /* add all contacts that belong to contactgroups for this escalation */
01150                         for(temp_contactgroupsmember=temp_se->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){
01151                                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for service escalation to notification list.\n",temp_contactgroupsmember->group_name);
01152                                 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL)
01153                                         continue;
01154                                 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
01155                                         if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
01156                                                 continue;
01157                                         add_notification(mac, temp_contact);
01158                                         }
01159                                 }
01160                         }
01161                 }
01162 
01163         /* else use normal, non-escalated contacts */
01164         if(escalate_notification==FALSE || (options & NOTIFICATION_OPTION_BROADCAST)){
01165 
01166                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding normal contacts for service to notification list.\n");
01167 
01168                 /* add all individual contacts for this service */
01169                 for(temp_contactsmember=svc->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
01170                         if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
01171                                 continue;
01172                         add_notification(mac, temp_contact);
01173                         }
01174 
01175                 /* add all contacts that belong to contactgroups for this service */
01176                 for(temp_contactgroupsmember=svc->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){
01177                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for service to notification list.\n",temp_contactgroupsmember->group_name);
01178                         if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL)
01179                                 continue;
01180                         for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
01181                                 if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
01182                                         continue;
01183                                 add_notification(mac, temp_contact);
01184                                 }
01185                         }
01186                 }
01187 
01188         return OK;
01189         }
01190 
01191 
01192 
01193 
01194 /******************************************************************/
01195 /******************* HOST NOTIFICATION FUNCTIONS ******************/
01196 /******************************************************************/
01197 
01198 
01199 
01200 /* notify all contacts for a host that the entire host is down or up */
01201 int host_notification(host *hst, int type, char *not_author, char *not_data, int options){
01202         notification *temp_notification=NULL;
01203         contact *temp_contact=NULL;
01204         time_t current_time;
01205         struct timeval start_time;
01206         struct timeval end_time;
01207         int escalated=FALSE;
01208         int result=OK;
01209         int contacts_notified=0;
01210         int increment_notification_number=FALSE;
01211         icinga_macros *mac; /* XXX: global macros */
01212         int neb_result;
01213 
01214         /* get the current time */
01215         time(&current_time);
01216         gettimeofday(&start_time,NULL);
01217 
01218         log_debug_info(DEBUGL_NOTIFICATIONS,0,"** Host Notification Attempt ** Host: '%s', Type: %d, Options: %d, Current State: %d, Last Notification: %s",hst->name,type,options,hst->current_state,ctime(&hst->last_host_notification));
01219 
01220 
01221         /* check viability of sending out a host notification */
01222         if(check_host_notification_viability(hst,type,options)==ERROR){
01223                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test failed.  No notification will be sent out.\n");
01224                 return OK;
01225                 }
01226 
01227         /* clear volatile macros */
01228         mac = get_global_macros();
01229         clear_volatile_macros_r(mac);
01230 
01231         log_debug_info(DEBUGL_NOTIFICATIONS,0,"Notification viability test passed.\n");
01232 
01233         /* should the notification number be increased? */
01234         if(type==NOTIFICATION_NORMAL || (options & NOTIFICATION_OPTION_INCREMENT)){
01235                 hst->current_notification_number++;
01236 
01237 #ifdef USE_ST_BASED_ESCAL_RANGES
01238                 /* also increment down/unreachable state counter */
01239                 if (hst->current_state == HOST_DOWN) {
01240                         hst->current_down_notification_number++;
01241                 }
01242                 if (hst->current_state == HOST_UNREACHABLE) {
01243                         hst->current_unreachable_notification_number++;
01244                 }
01245 #endif
01246                 increment_notification_number=TRUE;
01247                 }
01248 
01249         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Current notification number: %d (%s)\n",hst->current_notification_number,(increment_notification_number==TRUE)?"incremented":"unchanged");
01250 
01251         /* save and increase the current notification id */
01252         hst->current_notification_id=next_notification_id;
01253         next_notification_id++;
01254 
01255         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Creating list of contacts to be notified.\n");
01256 
01257         /* create the contact notification list for this host */
01258         create_notification_list_from_host(mac, hst,options,&escalated);
01259 
01260 #ifdef USE_EVENT_BROKER
01261         /* send data to event broker */
01262         end_time.tv_sec=0L;
01263         end_time.tv_usec=0L;
01264         neb_result=broker_notification_data(NEBTYPE_NOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,not_author,not_data,escalated,0,NULL);
01265         if(NEBERROR_CALLBACKCANCEL==neb_result)
01266                 return ERROR;
01267         else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
01268                 return OK;
01269 #endif
01270 
01271         /* XXX: crazy indent */
01272         /* there are contacts to be notified... */
01273         if(notification_list!=NULL){
01274 
01275                 /* grab the macro variables */
01276                 grab_host_macros_r(mac, hst);
01277 
01278                 /* if this notification has an author, attempt to lookup the associated contact */
01279                 if(not_author!=NULL){
01280 
01281                         /* see if we can find the contact - first by name, then by alias */
01282                         if((temp_contact=find_contact(not_author))==NULL){
01283                                 for(temp_contact=contact_list;temp_contact!=NULL;temp_contact=temp_contact->next){
01284                                         if(!strcmp(temp_contact->alias,not_author))
01285                                                 break;
01286                                         }
01287                                 }
01288 
01289                         }
01290 
01291                 /* get author and comment macros */
01292                 my_free(mac->x[MACRO_NOTIFICATIONAUTHOR]);
01293                 if(not_author)
01294                         mac->x[MACRO_NOTIFICATIONAUTHOR]=(char *)strdup(not_author);
01295                 my_free(mac->x[MACRO_NOTIFICATIONAUTHORNAME]);
01296                 my_free(mac->x[MACRO_NOTIFICATIONAUTHORALIAS]);
01297                 if(temp_contact!=NULL){
01298                         mac->x[MACRO_NOTIFICATIONAUTHORNAME]=(char *)strdup(temp_contact->name);
01299                         mac->x[MACRO_NOTIFICATIONAUTHORALIAS]=(char *)strdup(temp_contact->alias);
01300                         }
01301                 my_free(mac->x[MACRO_NOTIFICATIONCOMMENT]);
01302                 if(not_data)
01303                         mac->x[MACRO_NOTIFICATIONCOMMENT]=(char *)strdup(not_data);
01304 
01305                 /* NOTE: these macros are deprecated and will likely disappear in Icinga 4.x */
01306                 /* if this is an acknowledgement, get author and comment macros */
01307                 if(type==NOTIFICATION_ACKNOWLEDGEMENT){
01308 
01309                         my_free(mac->x[MACRO_HOSTACKAUTHOR]);
01310                         if(not_author)
01311                                 mac->x[MACRO_HOSTACKAUTHOR]=(char *)strdup(not_author);
01312 
01313                         my_free(mac->x[MACRO_HOSTACKCOMMENT]);
01314                         if(not_data)
01315                                 mac->x[MACRO_HOSTACKCOMMENT]=(char *)strdup(not_data);
01316 
01317                         my_free(mac->x[MACRO_SERVICEACKAUTHORNAME]);
01318                         my_free(mac->x[MACRO_SERVICEACKAUTHORALIAS]);
01319                         if(temp_contact!=NULL){
01320                                 mac->x[MACRO_SERVICEACKAUTHORNAME]=(char *)strdup(temp_contact->name);
01321                                 mac->x[MACRO_SERVICEACKAUTHORALIAS]=(char *)strdup(temp_contact->alias);
01322                                 }
01323                         }
01324 
01325                 /* set the notification type macro */
01326                 my_free(mac->x[MACRO_NOTIFICATIONTYPE]);
01327                 if(type==NOTIFICATION_ACKNOWLEDGEMENT)
01328                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("ACKNOWLEDGEMENT");
01329                 else if(type==NOTIFICATION_FLAPPINGSTART)
01330                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTART");
01331                 else if(type==NOTIFICATION_FLAPPINGSTOP)
01332                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGSTOP");
01333                 else if(type==NOTIFICATION_FLAPPINGDISABLED)
01334                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("FLAPPINGDISABLED");
01335                 else if(type==NOTIFICATION_DOWNTIMESTART)
01336                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMESTART");
01337                 else if(type==NOTIFICATION_DOWNTIMEEND)
01338                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMEEND");
01339                 else if(type==NOTIFICATION_DOWNTIMECANCELLED)
01340                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("DOWNTIMECANCELLED");
01341                 else if(type==NOTIFICATION_CUSTOM)
01342                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("CUSTOM");
01343                 else if(hst->current_state==HOST_UP)
01344                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("RECOVERY");
01345                 else
01346                         mac->x[MACRO_NOTIFICATIONTYPE]=(char *)strdup("PROBLEM");
01347 
01348                 /* set the notification number macro */
01349                 my_free(mac->x[MACRO_HOSTNOTIFICATIONNUMBER]);
01350                 dummy=asprintf(&mac->x[MACRO_HOSTNOTIFICATIONNUMBER],"%d",hst->current_notification_number);
01351 
01352                 /* the $NOTIFICATIONNUMBER$ macro is maintained for backward compatability */
01353                 my_free(mac->x[MACRO_NOTIFICATIONNUMBER]);
01354                 mac->x[MACRO_NOTIFICATIONNUMBER]=(char *)strdup((mac->x[MACRO_HOSTNOTIFICATIONNUMBER]==NULL)?"":mac->x[MACRO_HOSTNOTIFICATIONNUMBER]);
01355 
01356                 /* set the notification id macro */
01357                 my_free(mac->x[MACRO_HOSTNOTIFICATIONID]);
01358                 dummy=asprintf(&mac->x[MACRO_HOSTNOTIFICATIONID],"%lu",hst->current_notification_id);
01359 
01360                 /* notify each contact (duplicates have been removed) */
01361                 for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){
01362 
01363                         /* grab the macro variables for this contact */
01364                         grab_contact_macros_r(mac, temp_notification->contact);
01365 
01366                         /* clear summary macros (they are customized for each contact) */
01367                         clear_summary_macros_r(mac);
01368 
01369                         /* notify this contact */
01370                         result=notify_contact_of_host(mac, temp_notification->contact,hst,type,not_author,not_data,options,escalated);
01371 
01372                         /* keep track of how many contacts were notified */
01373                         if(result==OK)
01374                                 contacts_notified++;
01375                         }
01376 
01377                 /* free memory allocated to the notification list */
01378                 free_notification_list();
01379 
01380                 /* clear summary macros so they will be regenerated without contact filters when needednext */
01381                 clear_summary_macros_r(mac);
01382 
01383                 if(type==NOTIFICATION_NORMAL){
01384 
01385                         /* adjust last/next notification time and notification flags if we notified someone */
01386                         if(contacts_notified>0){
01387 
01388                                 /* calculate the next acceptable re-notification time */
01389                                 hst->next_host_notification=get_next_host_notification_time(hst,current_time);
01390 
01391                                 /* update the last notification time for this host (this is needed for scheduling the next problem notification) */
01392                                 hst->last_host_notification=current_time;
01393 
01394                                 /* update notifications flags */
01395                                 if(hst->current_state==HOST_DOWN)
01396                                         hst->notified_on_down=TRUE;
01397                                 else if(hst->current_state==HOST_UNREACHABLE)
01398                                         hst->notified_on_unreachable=TRUE;
01399 
01400                                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.  Next possible notification time: %s",contacts_notified,ctime(&hst->next_host_notification));
01401                                 }
01402 
01403                         /* we didn't end up notifying anyone */
01404                         else if(increment_notification_number==TRUE){
01405 
01406                                 /* adjust current notification number */
01407                                 hst->current_notification_number--;
01408 
01409 #ifdef USE_ST_BASED_ESCAL_RANGES
01410                                 if (hst->current_state == HOST_DOWN) {
01411                                         hst->current_down_notification_number--;
01412                                 }
01413                                 if (hst->current_state == HOST_UNREACHABLE) {
01414                                         hst->current_unreachable_notification_number--;
01415                                 }
01416 #endif
01417 
01418                                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were notified.  Next possible notification time: %s",ctime(&hst->next_host_notification));
01419                                 }
01420                         }
01421 
01422                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"%d contacts were notified.\n",contacts_notified);
01423                 }
01424 
01425         /* there were no contacts, so no notification really occurred... */
01426         else{
01427 
01428                 /* adjust notification number, since no notification actually went out */
01429                 if(increment_notification_number==TRUE) {
01430                         hst->current_notification_number--;
01431 
01432 #ifdef USE_ST_BASED_ESCAL_RANGES
01433                         if (hst->current_state == HOST_DOWN) {
01434                                 hst->current_down_notification_number--;
01435                         }
01436                         if (hst->current_state == HOST_UNREACHABLE) {
01437                                 hst->current_unreachable_notification_number--;
01438                         }
01439 #endif
01440                 }
01441 
01442                 log_debug_info(DEBUGL_NOTIFICATIONS,0,"No contacts were found for notification purposes.  No notification was sent out.\n");
01443                 }
01444 
01445         /* get the time we finished */
01446         gettimeofday(&end_time,NULL);
01447 
01448 #ifdef USE_EVENT_BROKER
01449         /* send data to event broker */
01450         broker_notification_data(NEBTYPE_NOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,not_author,not_data,escalated,contacts_notified,NULL);
01451 #endif
01452 
01453         /* update the status log with the host info */
01454         update_host_status(hst,FALSE);
01455 
01456         return OK;
01457         }
01458 
01459 
01460 
01461 /* checks viability of sending a host notification */
01462 int check_host_notification_viability(host *hst, int type, int options){
01463         time_t current_time;
01464         time_t timeperiod_start;
01465         time_t first_problem_time;
01466 
01467         log_debug_info(DEBUGL_FUNCTIONS,0,"check_host_notification_viability()\n");
01468 
01469         /* forced notifications bust through everything */
01470         if(options & NOTIFICATION_OPTION_FORCED){
01471                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This is a forced host notification, so we'll send it out.\n");
01472                 return OK;
01473                 }
01474 
01475         /* get current time */
01476         time(&current_time);
01477 
01478         /* are notifications enabled? */
01479         if(enable_notifications==FALSE){
01480                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are disabled, so host notifications will not be sent out.\n");
01481                 return ERROR;
01482                 }
01483 
01484         /* see if the host can have notifications sent out at this time */
01485         if(check_time_against_period(current_time,hst->notification_period_ptr)==ERROR){
01486 
01487                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host shouldn't have notifications sent out at this time.\n");
01488 
01489                 /* if this is a normal notification, calculate the next acceptable notification time, once the next valid time range arrives... */
01490                 if(type==NOTIFICATION_NORMAL){
01491 
01492                         get_next_valid_time(current_time,&timeperiod_start,hst->notification_period_ptr);
01493 
01494                         /* it looks like there is no notification time defined, so schedule next one far into the future (one year)... */
01495                         if(timeperiod_start==(time_t)0)
01496                                 hst->next_host_notification=(time_t)(current_time+(60*60*24*365));
01497 
01498                         /* else use the next valid notification time */
01499                         else
01500                                 hst->next_host_notification=timeperiod_start;
01501 
01502                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next possible notification time: %s\n",ctime(&hst->next_host_notification));
01503                         }
01504 
01505                 return ERROR;
01506                 }
01507 
01508         /* are notifications temporarily disabled for this host? */
01509         if(hst->notifications_enabled==FALSE){
01510                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notifications are temporarily disabled for this host, so we won't send one out.\n");
01511                 return ERROR;
01512                 }
01513 
01514 
01515         /*********************************************/
01516         /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/
01517         /*********************************************/
01518 
01519         /* custom notifications are good to go at this point... */
01520         if(type==NOTIFICATION_CUSTOM)
01521                 return OK;
01522 
01523 
01524         /****************************************/
01525         /*** SPECIAL CASE FOR ACKNOWLEGEMENTS ***/
01526         /****************************************/
01527 
01528         /* acknowledgements only have to pass three general filters, although they have another test of their own... */
01529         if(type==NOTIFICATION_ACKNOWLEDGEMENT){
01530 
01531                 /* don't send an acknowledgement if there isn't a problem... */
01532                 if(hst->current_state==HOST_UP){
01533                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"The host is currently UP, so we won't send an acknowledgement.\n");
01534                         return ERROR;
01535                         }
01536 
01537                 /* acknowledgement viability test passed, so the notification can be sent out */
01538                 return OK;
01539                 }
01540 
01541 
01542         /*****************************************/
01543         /*** SPECIAL CASE FOR FLAPPING ALERTS ***/
01544         /*****************************************/
01545 
01546         /* flapping notifications only have to pass three general filters */
01547         if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){
01548 
01549                 /* don't send a notification if we're not supposed to... */
01550                 if(hst->notify_on_flapping==FALSE){
01551                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events for this host.\n");
01552                         return ERROR;
01553                         }
01554 
01555                 /* don't send notifications during scheduled downtime */
01556                 if(hst->scheduled_downtime_depth>0){
01557                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about FLAPPING events during scheduled downtime.\n");
01558                         return ERROR;
01559                         }
01560 
01561                 /* flapping viability test passed, so the notification can be sent out */
01562                 return OK;
01563                 }
01564 
01565 
01566         /*****************************************/
01567         /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/
01568         /*****************************************/
01569 
01570         /* flapping notifications only have to pass three general filters */
01571         if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){
01572 
01573                 /* don't send a notification if we're not supposed to... */
01574                 if(hst->notify_on_downtime==FALSE){
01575                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events for this host.\n");
01576                         return ERROR;
01577                         }
01578 
01579                 /* don't send notifications during scheduled downtime */
01580                 if(hst->scheduled_downtime_depth>0){
01581                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWNTIME events during scheduled downtime!\n");
01582                         return ERROR;
01583                         }
01584 
01585                 /* downtime viability test passed, so the notification can be sent out */
01586                 return OK;
01587                 }
01588 
01589 
01590         /****************************************/
01591         /*** NORMAL NOTIFICATIONS ***************/
01592         /****************************************/
01593 
01594         /* is this a hard problem/recovery? */
01595         if(hst->state_type==SOFT_STATE){
01596                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is in a soft state, so we won't send a notification out.\n");
01597                 return ERROR;
01598                 }
01599 
01600         /* has this problem already been acknowledged? */
01601         if(hst->problem_has_been_acknowledged==TRUE){
01602                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host problem has already been acknowledged, so we won't send a notification out!\n");
01603                 return ERROR;
01604                 }
01605 
01606         /* check notification dependencies */
01607         if(check_host_dependencies(hst,NOTIFICATION_DEPENDENCY)==DEPENDENCIES_FAILED){
01608                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Notification dependencies for this host have failed, so we won't sent a notification out!\n");
01609                 return ERROR;
01610                 }
01611 
01612         /* see if we should notify about problems with this host */
01613         if(hst->current_state==HOST_UNREACHABLE && hst->notify_on_unreachable==FALSE){
01614                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about UNREACHABLE status for this host.\n");
01615                 return ERROR;
01616                 }
01617         if(hst->current_state==HOST_DOWN && hst->notify_on_down==FALSE){
01618                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about DOWN states for this host.\n");
01619                 return ERROR;
01620                 }
01621         if(hst->current_state==HOST_UP){
01622 
01623                 if(hst->notify_on_recovery==FALSE){
01624                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about RECOVERY states for this host.\n");
01625                         return ERROR;
01626                        }
01627                 if(!(hst->notified_on_down==TRUE || hst->notified_on_unreachable==TRUE)){
01628                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't notify about this recovery.\n");
01629                         return ERROR;
01630                         }
01631 
01632                 }
01633 
01634         /* see if enough time has elapsed for first notification (Mathias Sundman) */
01635         /* 10/02/07 don't place restrictions on recoveries or non-normal notifications, must use last time up (or program start) in calculation */
01636         /* it is reasonable to assume that if the host was never up, the program start time should be used in this calculation */
01637         if(type==NOTIFICATION_NORMAL && hst->current_notification_number==0 && hst->current_state!=HOST_UP){
01638 
01639                 /* determine the time to use of the first problem point */
01640                 first_problem_time=hst->last_time_up; /* not accurate, but its the earliest time we could use in the comparison */
01641 
01642                 if((hst->last_time_down < first_problem_time) && (hst->last_time_down > hst->last_time_up))
01643                         first_problem_time=hst->last_time_down;
01644                 if((hst->last_time_unreachable < first_problem_time) && (hst->last_time_unreachable > hst->last_time_unreachable))
01645                         first_problem_time=hst->last_time_unreachable;
01646 
01647                 if(current_time < (time_t)((first_problem_time==(time_t)0L)?program_start:first_problem_time) + (time_t)(hst->first_notification_delay*interval_length)){
01648                         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Not enough time has elapsed since the host changed to a non-UP state (or since program start), so we shouldn't notify about this problem yet.\n");
01649                         return ERROR;
01650                 }
01651         }
01652 
01653         /* if this host is currently flapping, don't send the notification */
01654         if(hst->is_flapping==TRUE){
01655                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is currently flapping, so we won't send notifications.\n");
01656                 return ERROR;
01657                 }
01658 
01659         /***** RECOVERY NOTIFICATIONS ARE GOOD TO GO AT THIS POINT *****/
01660         if(hst->current_state==HOST_UP)
01661                 return OK;
01662 
01663         /* if this host is currently in a scheduled downtime period, don't send the notification */
01664         if(hst->scheduled_downtime_depth>0){
01665                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This host is currently in a scheduled downtime, so we won't send notifications.\n");
01666                 return ERROR;
01667                 }
01668 
01669         /* check if we shouldn't renotify contacts about the host problem */
01670         if(hst->no_more_notifications==TRUE){
01671                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"We shouldn't re-notify contacts about this host problem.\n");
01672                 return ERROR;
01673                 }
01674 
01675         /* check if its time to re-notify the contacts about the host... */
01676         if(current_time < hst->next_host_notification){
01677                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Its not yet time to re-notify the contacts about this host problem...\n");
01678                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Next acceptable notification time: %s",ctime(&hst->next_host_notification));
01679                 return ERROR;
01680                 }
01681 
01682         return OK;
01683         }
01684 
01685 
01686 
01687 /* checks the viability of notifying a specific contact about a host */
01688 int check_contact_host_notification_viability(contact *cntct, host *hst, int type, int options){
01689 
01690         log_debug_info(DEBUGL_FUNCTIONS,0,"check_contact_host_notification_viability()\n");
01691 
01692         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Checking host notification viability for contact '%s'...\n",cntct->name);
01693 
01694         /* forced notifications bust through everything */
01695         if(options & NOTIFICATION_OPTION_FORCED){
01696                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This is a forced host notification, so we'll send it out for this contact.\n");
01697                 return OK;
01698                 }
01699 
01700         /* are notifications enabled? */
01701         if(cntct->host_notifications_enabled==FALSE){
01702                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Host notifications are disabled for this contact.\n");
01703                 return ERROR;
01704                 }
01705 
01706         /* see if the contact can be notified at this time */
01707         if(check_time_against_period(time(NULL),cntct->host_notification_period_ptr)==ERROR){
01708                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"This contact shouldn't be notified at this time.\n");
01709                 return ERROR;
01710                 }
01711 
01712 
01713         /*********************************************/
01714         /*** SPECIAL CASE FOR CUSTOM NOTIFICATIONS ***/
01715         /*********************************************/
01716 
01717         /* custom notifications are good to go at this point... */
01718         if(type==NOTIFICATION_CUSTOM)
01719                 return OK;
01720 
01721 
01722         /****************************************/
01723         /*** SPECIAL CASE FOR FLAPPING ALERTS ***/
01724         /****************************************/
01725 
01726         if(type==NOTIFICATION_FLAPPINGSTART || type==NOTIFICATION_FLAPPINGSTOP || type==NOTIFICATION_FLAPPINGDISABLED){
01727 
01728                 if(cntct->notify_on_host_flapping==FALSE){
01729                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about FLAPPING host events.\n");
01730                         return ERROR;
01731                         }
01732 
01733                 return OK;
01734                 }
01735 
01736 
01737         /****************************************/
01738         /*** SPECIAL CASE FOR DOWNTIME ALERTS ***/
01739         /****************************************/
01740 
01741         if(type==NOTIFICATION_DOWNTIMESTART || type==NOTIFICATION_DOWNTIMEEND || type==NOTIFICATION_DOWNTIMECANCELLED){
01742 
01743                 if(cntct->notify_on_host_downtime==FALSE){
01744                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWNTIME host events.\n");
01745                         return ERROR;
01746                         }
01747 
01748                 return OK;
01749                 }
01750 
01751 
01752         /*************************************/
01753         /*** ACKS AND NORMAL NOTIFICATIONS ***/
01754         /*************************************/
01755 
01756         /* see if we should notify about problems with this host */
01757         if(hst->current_state==HOST_DOWN && cntct->notify_on_host_down==FALSE){
01758                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about DOWN states.\n");
01759                 return ERROR;
01760                 }
01761 
01762         if(hst->current_state==HOST_UNREACHABLE && cntct->notify_on_host_unreachable==FALSE){
01763                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about UNREACHABLE states,\n");
01764                 return ERROR;
01765                 }
01766 
01767         if(hst->current_state==HOST_UP){
01768 
01769                 if(cntct->notify_on_host_recovery==FALSE){
01770                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify this contact about RECOVERY states.\n");
01771                         return ERROR;
01772                         }
01773 
01774                 if(!((hst->notified_on_down==TRUE && cntct->notify_on_host_down==TRUE) || (hst->notified_on_unreachable==TRUE && cntct->notify_on_host_unreachable==TRUE))){
01775                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"We shouldn't notify about this recovery.\n");
01776                         return ERROR;
01777                         }
01778 
01779                 }
01780 
01781         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Host notification viability for contact '%s' PASSED.\n",cntct->name);
01782 
01783         return OK;
01784         }
01785 
01786 
01787 
01788 /* notify a specific contact that an entire host is down or up */
01789 int notify_contact_of_host(icinga_macros *mac, contact *cntct, host *hst, int type, char *not_author, char *not_data, int options, int escalated){
01790         commandsmember *temp_commandsmember=NULL;
01791         char *command_name=NULL;
01792         char *command_name_ptr=NULL;
01793         char *temp_buffer=NULL;
01794         char *processed_buffer=NULL;
01795         char *raw_command=NULL;
01796         char *processed_command=NULL;
01797         int early_timeout=FALSE;
01798         double exectime;
01799         struct timeval start_time;
01800         struct timeval end_time;
01801         struct timeval method_start_time;
01802         struct timeval method_end_time;
01803         int macro_options=STRIP_ILLEGAL_MACRO_CHARS|ESCAPE_MACRO_CHARS;
01804         int neb_result;
01805 
01806         log_debug_info(DEBUGL_FUNCTIONS,0,"notify_contact_of_host()\n");
01807         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Attempting to notifying contact '%s'...\n",cntct->name);
01808 
01809         /* check viability of notifying this user about the host */
01810         /* acknowledgements are no longer excluded from this test - added 8/19/02 Tom Bertelson */
01811         if(check_contact_host_notification_viability(cntct,hst,type,options)==ERROR)
01812                 return ERROR;
01813 
01814         log_debug_info(DEBUGL_NOTIFICATIONS,2,"** Notifying contact '%s'\n",cntct->name);
01815 
01816         /* get start time */
01817         gettimeofday(&start_time,NULL);
01818 
01819 #ifdef USE_EVENT_BROKER
01820         /* send data to event broker */
01821         end_time.tv_sec=0L;
01822         end_time.tv_usec=0L;
01823         neb_result=broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,cntct,not_author,not_data,escalated,NULL);
01824         if(NEBERROR_CALLBACKCANCEL==neb_result)
01825                 return ERROR;
01826         else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
01827                 return OK;
01828 #endif
01829 
01830         /* process all the notification commands this user has */
01831         for(temp_commandsmember=cntct->host_notification_commands;temp_commandsmember!=NULL;temp_commandsmember=temp_commandsmember->next){
01832 
01833                 /* get start time */
01834                 gettimeofday(&method_start_time,NULL);
01835 
01836 #ifdef USE_EVENT_BROKER
01837                 /* send data to event broker */
01838                 method_end_time.tv_sec=0L;
01839                 method_end_time.tv_usec=0L;
01840                 neb_result=broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_START,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,method_start_time,method_end_time,(void *)hst,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL);
01841                 if(NEBERROR_CALLBACKCANCEL==neb_result)
01842                         break;
01843                 else if(NEBERROR_CALLBACKOVERRIDE==neb_result)
01844                         continue;
01845 #endif
01846 
01847                 /* get the raw command line */
01848                 get_raw_command_line_r(mac, temp_commandsmember->command_ptr,temp_commandsmember->command,&raw_command,macro_options);
01849                 if(raw_command==NULL)
01850                         continue;
01851 
01852                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Raw notification command: %s\n",raw_command);
01853 
01854                 /* process any macros contained in the argument */
01855                 process_macros_r(mac, raw_command,&processed_command,macro_options);
01856                 if(processed_command==NULL)
01857                         continue;
01858 
01859                 /* get the command name */
01860                 command_name=(char *)strdup(temp_commandsmember->command);
01861                 command_name_ptr=strtok(command_name,"!");
01862 
01863                 /* run the notification command... */
01864 
01865                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Processed notification command: %s\n",processed_command);
01866 
01867                 /* log the notification to program log file */
01868                 if(log_notifications==TRUE){
01869                         switch(type){
01870                         case NOTIFICATION_CUSTOM:
01871                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;CUSTOM ($HOSTSTATE$);%s;$HOSTOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,hst->name,command_name_ptr);
01872                                 break;
01873                         case NOTIFICATION_ACKNOWLEDGEMENT:
01874                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;ACKNOWLEDGEMENT ($HOSTSTATE$);%s;$HOSTOUTPUT$;$NOTIFICATIONAUTHOR$;$NOTIFICATIONCOMMENT$\n",cntct->name,hst->name,command_name_ptr);
01875                                 break;
01876                         case NOTIFICATION_FLAPPINGSTART:
01877                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGSTART ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01878                                 break;
01879                         case NOTIFICATION_FLAPPINGSTOP:
01880                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGSTOP ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01881                                 break;
01882                         case NOTIFICATION_FLAPPINGDISABLED:
01883                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;FLAPPINGDISABLED ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01884                                 break;
01885                         case NOTIFICATION_DOWNTIMESTART:
01886                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMESTART ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01887                                 break;
01888                         case NOTIFICATION_DOWNTIMEEND:
01889                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMEEND ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01890                                 break;
01891                         case NOTIFICATION_DOWNTIMECANCELLED:
01892                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;DOWNTIMECANCELLED ($HOSTSTATE$);%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01893                                 break;
01894                         default:
01895                                 dummy=asprintf(&temp_buffer,"HOST NOTIFICATION: %s;%s;$HOSTSTATE$;%s;$HOSTOUTPUT$\n",cntct->name,hst->name,command_name_ptr);
01896                                 break;
01897                                 }
01898 
01899                         process_macros_r(mac, temp_buffer,&processed_buffer,0);
01900                         write_to_all_logs(processed_buffer,NSLOG_HOST_NOTIFICATION);
01901 
01902                         my_free(temp_buffer);
01903                         my_free(processed_buffer);
01904                         }
01905 
01906                 /* run the notification command */
01907                 my_system_r(mac, processed_command,notification_timeout,&early_timeout,&exectime,NULL,0);
01908 
01909                 /* check to see if the notification timed out */
01910                 if(early_timeout==TRUE){
01911                         logit(NSLOG_HOST_NOTIFICATION | NSLOG_RUNTIME_WARNING,TRUE,"Warning: Contact '%s' host notification command '%s' timed out after %d seconds\n", cntct->name,processed_command,notification_timeout);
01912                         }
01913 
01914                 /* free memory */
01915                 my_free(command_name);
01916                 my_free(raw_command);
01917                 my_free(processed_command);
01918 
01919                 /* get end time */
01920                 gettimeofday(&method_end_time,NULL);
01921 
01922 #ifdef USE_EVENT_BROKER
01923                 /* send data to event broker */
01924                 broker_contact_notification_method_data(NEBTYPE_CONTACTNOTIFICATIONMETHOD_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,method_start_time,method_end_time,(void *)hst,cntct,temp_commandsmember->command,not_author,not_data,escalated,NULL);
01925 #endif
01926                 }
01927 
01928         /* get end time */
01929         gettimeofday(&end_time,NULL);
01930 
01931         /* update the contact's last host notification time */
01932         cntct->last_host_notification=start_time.tv_sec;
01933 
01934 #ifdef USE_EVENT_BROKER
01935         /* send data to event broker */
01936         broker_contact_notification_data(NEBTYPE_CONTACTNOTIFICATION_END,NEBFLAG_NONE,NEBATTR_NONE,HOST_NOTIFICATION,type,start_time,end_time,(void *)hst,cntct,not_author,not_data,escalated,NULL);
01937 #endif
01938 
01939         return OK;
01940 }
01941 
01942 
01943 /* checks to see if a host escalation entry is a match for the current host notification */
01944 int is_valid_escalation_for_host_notification(host *hst, hostescalation *he, int options){
01945         int notification_number=0;
01946 
01947 #ifdef USE_ST_BASED_ESCAL_RANGES
01948         int down_notification_number=0;
01949         int unreachable_notification_number=0;
01950         int widematch=1;
01951 #endif
01952 
01953         time_t current_time=0L;
01954         host *temp_host=NULL;
01955 
01956         log_debug_info(DEBUGL_FUNCTIONS,0,"is_valid_escalation_for_host_notification()\n");
01957 
01958         /* get the current time */
01959         time(&current_time);
01960 
01961         /* if this is a recovery, really we check for who got notified about a previous problem */
01962         if(hst->current_state==HOST_UP)
01963                 notification_number=hst->current_notification_number-1;
01964         else
01965                 notification_number=hst->current_notification_number;
01966 
01967 #ifdef USE_ST_BASED_ESCAL_RANGES
01968         /* these are not incremented in the case of recovery, so don't need special handling */
01969         down_notification_number=hst->current_down_notification_number;
01970         unreachable_notification_number=hst->current_unreachable_notification_number;
01971 #endif
01972 
01973         /* find the host this escalation entry is associated with */
01974         temp_host=he->host_ptr;
01975         if(temp_host==NULL || temp_host!=hst)
01976                 return FALSE;
01977 
01978         /*** EXCEPTION ***/
01979         /* broadcast options go to everyone, so this escalation is valid */
01980         if(options & NOTIFICATION_OPTION_BROADCAST)
01981                 return TRUE;
01982 
01983 #ifndef USE_ST_BASED_ESCAL_RANGES
01984         if(he->first_notification > notification_number)
01985                 return FALSE;
01986 #else
01987         /* skip this escalation if it happens later */
01988         if(he->first_notification == -2 || he->first_notification > notification_number)
01989                 widematch=0;
01990 
01991         if (!widematch){
01992                 switch (hst->current_state){
01993                         case HOST_DOWN:{
01994                                 if (he->first_down_notification == -2 || he->first_down_notification > down_notification_number)
01995                                         return FALSE;
01996                                 break;
01997                         }
01998                         case HOST_UNREACHABLE:{
01999                                 if (he->first_unreachable_notification == -2 || he->first_unreachable_notification > unreachable_notification_number)
02000                                         return FALSE;
02001                                 break;
02002                         }
02003                 }
02004         }
02005 #endif
02006 
02007 #ifndef USE_ST_BASED_ESCAL_RANGES
02008         /* skip this escalation if it has already passed */
02009         if(he->last_notification!=0 && he->last_notification < notification_number)
02010                 return FALSE;
02011 #else
02012         /* skip this escalation if it has already passed. only skip if none match */
02013         widematch=1;
02014         if((he->last_notification == -2) || ((he->last_notification!=0) && (he->last_notification < notification_number)))
02015                 widematch=0;
02016 
02017         if (!widematch){
02018                 switch (hst->current_state){
02019                         case HOST_DOWN:{
02020                                 if ((he->last_down_notification == -2) || ((he->last_down_notification!=0) && (he->last_down_notification < down_notification_number)))
02021                                         return FALSE;
02022                                 break;
02023                         }
02024                         case HOST_UNREACHABLE:{
02025                                 if ((he->last_unreachable_notification == -2) || ((he->last_unreachable_notification) && (he->last_unreachable_notification < unreachable_notification_number)))
02026                                         return FALSE;
02027                                 break;
02028                         }
02029                 }
02030         }
02031 #endif
02032         /* skip this escalation if it has a timeperiod and the current time isn't valid */
02033         if(he->escalation_period!=NULL && check_time_against_period(current_time,he->escalation_period_ptr)==ERROR)
02034                 return FALSE;
02035 
02036         /* skip this escalation if the state options don't match */
02037         if(hst->current_state==HOST_UP && he->escalate_on_recovery==FALSE)
02038                 return FALSE;
02039         else if(hst->current_state==HOST_DOWN && he->escalate_on_down==FALSE)
02040                 return FALSE;
02041         else if(hst->current_state==HOST_UNREACHABLE && he->escalate_on_unreachable==FALSE)
02042                 return FALSE;
02043 
02044         /* skip this escalation if the conditions don't match */
02045         else if(check_escalation_condition(he->condition)==FALSE)
02046                 return FALSE;
02047 
02048         return TRUE;
02049         }
02050 
02051 
02052 
02053 /* checks to see whether a host notification should be escalation */
02054 int should_host_notification_be_escalated(host *hst){
02055         hostescalation *temp_he=NULL;
02056         void *ptr=NULL;
02057 
02058         log_debug_info(DEBUGL_FUNCTIONS,0,"should_host_notification_be_escalated()\n");
02059 
02060         if(hst==NULL)
02061                 return FALSE;
02062 
02063         /* search the host escalation list */
02064         for(temp_he=get_first_hostescalation_by_host(hst->name,&ptr);temp_he!=NULL;temp_he=get_next_hostescalation_by_host(hst->name,&ptr)){
02065 
02066                 /* we found a matching entry, so escalate this notification! */
02067                 if(is_valid_escalation_for_host_notification(hst,temp_he,NOTIFICATION_OPTION_NONE)==TRUE)
02068                         return TRUE;
02069                 }
02070 
02071         log_debug_info(DEBUGL_NOTIFICATIONS,1,"Host notification will NOT be escalated.\n");
02072 
02073         return FALSE;
02074         }
02075 
02076 
02077 /* given a host, create a list of contacts to be notified, removing duplicates */
02078 int create_notification_list_from_host(icinga_macros *mac, host *hst, int options, int *escalated){
02079         hostescalation *temp_he=NULL;
02080         contactsmember *temp_contactsmember=NULL;
02081         contact *temp_contact=NULL;
02082         contactgroupsmember *temp_contactgroupsmember=NULL;
02083         contactgroup *temp_contactgroup=NULL;
02084         int escalate_notification=FALSE;
02085         void *ptr=NULL;
02086 
02087         log_debug_info(DEBUGL_FUNCTIONS,0,"create_notification_list_from_host()\n");
02088 
02089         /* see if this notification should be escalated */
02090         escalate_notification=should_host_notification_be_escalated(hst);
02091 
02092         /* set the escalation flag */
02093         *escalated=escalate_notification;
02094 
02095         /* set the escalation macro */
02096         my_free(mac->x[MACRO_NOTIFICATIONISESCALATED]);
02097         dummy=asprintf(&mac->x[MACRO_NOTIFICATIONISESCALATED],"%d",escalate_notification);
02098 
02099         if(options & NOTIFICATION_OPTION_BROADCAST)
02100                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"This notification will be BROADCAST to all (escalated and normal) contacts...\n");
02101 
02102         /* use escalated contacts for this notification */
02103         if(escalate_notification==TRUE || (options & NOTIFICATION_OPTION_BROADCAST)){
02104 
02105                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding contacts from host escalation(s) to notification list.\n");
02106 
02107                 /* check all the host escalation entries */
02108                 for(temp_he=get_first_hostescalation_by_host(hst->name,&ptr);temp_he!=NULL;temp_he=get_next_hostescalation_by_host(hst->name,&ptr)){
02109 
02110                         /* see if this escalation if valid for this notification */
02111                         if(is_valid_escalation_for_host_notification(hst,temp_he,options)==FALSE)
02112                                 continue;
02113 
02114                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts from host escalation(s) to notification list.\n");
02115 
02116                         /* add all individual contacts for this escalation */
02117                         for(temp_contactsmember=temp_he->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
02118                                 if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
02119                                         continue;
02120                                 add_notification(mac, temp_contact);
02121                                 }
02122 
02123                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups from host escalation(s) to notification list.\n");
02124 
02125                         /* add all contacts that belong to contactgroups for this escalation */
02126                         for(temp_contactgroupsmember=temp_he->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){
02127                                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for host escalation to notification list.\n",temp_contactgroupsmember->group_name);
02128                                 if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL)
02129                                         continue;
02130                                 for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
02131                                         if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
02132                                                 continue;
02133                                         add_notification(mac, temp_contact);
02134                                         }
02135                                 }
02136                         }
02137                 }
02138 
02139         /* use normal, non-escalated contacts for this notification */
02140         if(escalate_notification==FALSE  || (options & NOTIFICATION_OPTION_BROADCAST)){
02141 
02142                 log_debug_info(DEBUGL_NOTIFICATIONS,1,"Adding normal contacts for host to notification list.\n");
02143 
02144                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding individual contacts for host to notification list.\n");
02145 
02146                 /* add all individual contacts for this host */
02147                 for(temp_contactsmember=hst->contacts;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
02148                         if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
02149                                 continue;
02150                         add_notification(mac, temp_contact);
02151                         }
02152 
02153                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact groups for host to notification list.\n");
02154 
02155                 /* add all contacts that belong to contactgroups for this host */
02156                 for(temp_contactgroupsmember=hst->contact_groups;temp_contactgroupsmember!=NULL;temp_contactgroupsmember=temp_contactgroupsmember->next){
02157                         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding members of contact group '%s' for host to notification list.\n",temp_contactgroupsmember->group_name);
02158 
02159                         if((temp_contactgroup=temp_contactgroupsmember->group_ptr)==NULL)
02160                                 continue;
02161                         for(temp_contactsmember=temp_contactgroup->members;temp_contactsmember!=NULL;temp_contactsmember=temp_contactsmember->next){
02162                                 if((temp_contact=temp_contactsmember->contact_ptr)==NULL)
02163                                         continue;
02164                                 add_notification(mac, temp_contact);
02165                                 }
02166                         }
02167                 }
02168 
02169         return OK;
02170 }
02171 
02172 
02173 
02174 
02175 /******************************************************************/
02176 /***************** NOTIFICATION TIMING FUNCTIONS ******************/
02177 /******************************************************************/
02178 
02179 
02180 /* calculates next acceptable re-notification time for a service */
02181 time_t get_next_service_notification_time(service *svc, time_t offset){
02182         time_t next_notification=0L;
02183         double interval_to_use=0.0;
02184         serviceescalation *temp_se=NULL;
02185         int have_escalated_interval=FALSE;
02186 
02187         log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_service_notification_time()\n");
02188 
02189         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Calculating next valid notification time...\n");
02190 
02191         /* default notification interval */
02192         interval_to_use=svc->notification_interval;
02193 
02194         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Default interval: %f\n",interval_to_use);
02195 
02196         /* search all the escalation entries for valid matches for this service (at its current notification number) */
02197         for(temp_se=serviceescalation_list;temp_se!=NULL;temp_se=temp_se->next){
02198 
02199                 /* interval < 0 means to use non-escalated interval */
02200                 if(temp_se->notification_interval<0.0)
02201                         continue;
02202 
02203                 /* skip this entry if it isn't appropriate */
02204                 if(is_valid_escalation_for_service_notification(svc,temp_se,NOTIFICATION_OPTION_NONE)==FALSE)
02205                         continue;
02206 
02207                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Found a valid escalation w/ interval of %f\n",temp_se->notification_interval);
02208 
02209                 /* if we haven't used a notification interval from an escalation yet, use this one */
02210                 if(have_escalated_interval==FALSE){
02211                         have_escalated_interval=TRUE;
02212                         interval_to_use=temp_se->notification_interval;
02213                         }
02214 
02215                 /* else use the shortest of all valid escalation intervals */
02216                 else if(temp_se->notification_interval<interval_to_use)
02217                         interval_to_use=temp_se->notification_interval;
02218 
02219                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"New interval: %f\n",interval_to_use);
02220                 }
02221 
02222         /* if notification interval is 0, we shouldn't send any more problem notifications (unless service is volatile) */
02223         if(interval_to_use==0.0 && svc->is_volatile==FALSE)
02224                 svc->no_more_notifications=TRUE;
02225         else
02226                 svc->no_more_notifications=FALSE;
02227 
02228         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Interval used for calculating next valid notification time: %f\n",interval_to_use);
02229 
02230         /* calculate next notification time */
02231         next_notification=offset+(interval_to_use*interval_length);
02232 
02233         return next_notification;
02234         }
02235 
02236 
02237 
02238 /* calculates next acceptable re-notification time for a host */
02239 time_t get_next_host_notification_time(host *hst, time_t offset){
02240         time_t next_notification=0L;
02241         double interval_to_use=0.0;
02242         hostescalation *temp_he=NULL;
02243         int have_escalated_interval=FALSE;
02244 
02245 
02246         log_debug_info(DEBUGL_FUNCTIONS,0,"get_next_host_notification_time()\n");
02247 
02248         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Calculating next valid notification time...\n");
02249 
02250         /* default notification interval */
02251         interval_to_use=hst->notification_interval;
02252 
02253         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Default interval: %f\n",interval_to_use);
02254 
02255         /* check all the host escalation entries for valid matches for this host (at its current notification number) */
02256         for(temp_he=hostescalation_list;temp_he!=NULL;temp_he=temp_he->next){
02257 
02258                 /* interval < 0 means to use non-escalated interval */
02259                 if(temp_he->notification_interval<0.0)
02260                         continue;
02261 
02262                 /* skip this entry if it isn't appropriate */
02263                 if(is_valid_escalation_for_host_notification(hst,temp_he,NOTIFICATION_OPTION_NONE)==FALSE)
02264                         continue;
02265 
02266                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"Found a valid escalation w/ interval of %f\n",temp_he->notification_interval);
02267 
02268                 /* if we haven't used a notification interval from an escalation yet, use this one */
02269                 if(have_escalated_interval==FALSE){
02270                         have_escalated_interval=TRUE;
02271                         interval_to_use=temp_he->notification_interval;
02272                         }
02273 
02274                 /* else use the shortest of all valid escalation intervals  */
02275                 else if(temp_he->notification_interval<interval_to_use)
02276                         interval_to_use=temp_he->notification_interval;
02277 
02278                 log_debug_info(DEBUGL_NOTIFICATIONS,2,"New interval: %f\n",interval_to_use);
02279                 }
02280 
02281         /* if interval is 0, no more notifications should be sent */
02282         if(interval_to_use==0.0)
02283                 hst->no_more_notifications=TRUE;
02284         else
02285                 hst->no_more_notifications=FALSE;
02286 
02287         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Interval used for calculating next valid notification time: %f\n",interval_to_use);
02288 
02289         /* calculate next notification time */
02290         next_notification=offset+(interval_to_use*interval_length);
02291 
02292         return next_notification;
02293         }
02294 
02295 
02296 
02297 /******************************************************************/
02298 /***************** NOTIFICATION OBJECT FUNCTIONS ******************/
02299 /******************************************************************/
02300 
02301 
02302 /* given a contact name, find the notification entry for them for the list in memory */
02303 notification * find_notification(contact *cntct){
02304         notification *temp_notification=NULL;
02305 
02306         log_debug_info(DEBUGL_FUNCTIONS,0,"find_notification() start\n");
02307 
02308         if(cntct==NULL)
02309                 return NULL;
02310 
02311         for(temp_notification=notification_list;temp_notification!=NULL;temp_notification=temp_notification->next){
02312                 if(temp_notification->contact==cntct)
02313                         return temp_notification;
02314                 }
02315 
02316         /* we couldn't find the contact in the notification list */
02317         return NULL;
02318         }
02319 
02320 
02321 
02322 /* add a new notification to the list in memory */
02323 int add_notification(icinga_macros *mac, contact *cntct){
02324         notification *new_notification=NULL;
02325         notification *temp_notification=NULL;
02326 
02327         log_debug_info(DEBUGL_FUNCTIONS,0,"add_notification() start\n");
02328 
02329         if(cntct==NULL)
02330                 return ERROR;
02331 
02332         log_debug_info(DEBUGL_NOTIFICATIONS,2,"Adding contact '%s' to notification list.\n",cntct->name);
02333 
02334         /* don't add anything if this contact is already on the notification list */
02335         if((temp_notification=find_notification(cntct))!=NULL)
02336                 return OK;
02337 
02338         /* allocate memory for a new contact in the notification list */
02339         if((new_notification=malloc(sizeof(notification)))==NULL)
02340                 return ERROR;
02341 
02342         /* fill in the contact info */
02343         new_notification->contact=cntct;
02344 
02345         /* add new notification to head of list */
02346         new_notification->next=notification_list;
02347         notification_list=new_notification;
02348 
02349         /* add contact to notification recipients macro */
02350         if(mac->x[MACRO_NOTIFICATIONRECIPIENTS]==NULL)
02351                 mac->x[MACRO_NOTIFICATIONRECIPIENTS]=(char *)strdup(cntct->name);
02352         else{
02353                 if((mac->x[MACRO_NOTIFICATIONRECIPIENTS]=(char *)realloc(mac->x[MACRO_NOTIFICATIONRECIPIENTS],strlen(mac->x[MACRO_NOTIFICATIONRECIPIENTS])+strlen(cntct->name)+2))){
02354                         strcat(mac->x[MACRO_NOTIFICATIONRECIPIENTS],",");
02355                         strcat(mac->x[MACRO_NOTIFICATIONRECIPIENTS],cntct->name);
02356                         }
02357                 }
02358 
02359         return OK;
02360 }
02361 
 All Data Structures Files Functions Variables Typedefs Defines