static void __verboser(const char *stuff, int opos, int replacelast, int complete) { char *s2[2]; struct timeval tv; int ms; s2[0] = (char *)stuff; s2[1] = NULL; gtk_clist_freeze(GTK_CLIST(verb)); if (replacelast) gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1); gtk_clist_append(GTK_CLIST(verb), s2); if (!ast_tvzero(last)) { gdk_threads_leave(); gettimeofday(&tv, NULL); if (cleanupid > -1) gtk_timeout_remove(cleanupid); ms = ast_tvdiff_ms(tv, last); if (ms < 100) { /* We just got a message within 100ms, so just schedule an update in the near future */ cleanupid = gtk_timeout_add(200, cleanup, NULL); } else { cleanup(&cleanupid); } last = tv; } else { gettimeofday(&last, NULL); } }
/*! \brief Observer callback for when a contact is created */ static void contact_expiration_observer_created(const void *object) { const struct ast_sip_contact *contact = object; struct contact_expiration *expiration; int expires = MAX(0, ast_tvdiff_ms(contact->expiration_time, ast_tvnow())); if (ast_tvzero(contact->expiration_time)) { return; } expiration = ao2_alloc_options(sizeof(*expiration), contact_expiration_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!expiration) { return; } expiration->contact = (struct ast_sip_contact*)contact; ao2_ref(expiration->contact, +1); ao2_ref(expiration, +1); if ((expiration->sched = ast_sched_add(sched, expires, contact_expiration_expire, expiration)) < 0) { ao2_ref(expiration, -1); ast_log(LOG_ERROR, "Scheduled expiration for contact '%s' could not be performed, contact may persist past life\n", ast_sorcery_object_get_id(contact)); } else { ao2_link(contact_autoexpire, expiration); } ao2_ref(expiration, -1); }
static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) { struct ast_cdr *cdr; struct ast_cdr *newcdr; struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS }; cdr = ast_channel_cdr(chan); while (cdr->next) cdr = cdr->next; if (!(newcdr = ast_cdr_dup_unique(cdr))) return; /* * End the original CDR if requested BEFORE appending the new CDR * otherwise we incorrectly end the new CDR also. */ if (ast_test_flag(&optflags, OPT_ENDCDR)) { ast_cdr_end(cdr); } ast_cdr_append(cdr, newcdr); if (!ast_test_flag(&optflags, OPT_NORESET)) ast_cdr_reset(newcdr, &flags); if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) ast_cdr_free_vars(cdr, 0); if (!ast_strlen_zero(set)) { char *varname = ast_strdupa(set), *varval; varval = strchr(varname,'='); if (varval) { *varval = 0; varval++; ast_cdr_setvar(cdr, varname, varval, 0); } } if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer)) newcdr->answer = newcdr->start; if (ast_test_flag(&optflags, OPT_SETDISP)) newcdr->disposition = cdr->disposition; if (ast_test_flag(&optflags, OPT_RESETDEST)) newcdr->dstchannel[0] = 0; if (ast_test_flag(&optflags, OPT_ANSLOCK)) ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED); if (ast_test_flag(&optflags, OPT_DONTOUCH)) ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH); ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); }
static void ast_cdr_fork(struct ast_channel *chan, struct ast_flags optflags, char *set) { struct ast_cdr *cdr; struct ast_cdr *newcdr; struct ast_flags flags = { AST_CDR_FLAG_KEEP_VARS }; cdr = chan->cdr; while (cdr->next) cdr = cdr->next; if (!(newcdr = ast_cdr_dup(cdr))) return; ast_cdr_append(cdr, newcdr); if (!ast_test_flag(&optflags, OPT_NORESET)) ast_cdr_reset(newcdr, &flags); if (!ast_test_flag(cdr, AST_CDR_FLAG_KEEP_VARS)) ast_cdr_free_vars(cdr, 0); if (!ast_strlen_zero(set)) { char *varname = ast_strdupa(set), *varval; varval = strchr(varname,'='); if (varval) { *varval = 0; varval++; ast_cdr_setvar(cdr, varname, varval, 0); } } if (ast_test_flag(&optflags, OPT_SETANS) && !ast_tvzero(cdr->answer)) newcdr->answer = newcdr->start; if (ast_test_flag(&optflags, OPT_SETDISP)) newcdr->disposition = cdr->disposition; if (ast_test_flag(&optflags, OPT_RESETDEST)) newcdr->dstchannel[0] = 0; if (ast_test_flag(&optflags, OPT_ENDCDR)) ast_cdr_end(cdr); if (ast_test_flag(&optflags, OPT_ANSLOCK)) ast_set_flag(cdr, AST_CDR_FLAG_ANSLOCKED); if (ast_test_flag(&optflags, OPT_DONTOUCH)) ast_set_flag(cdr, AST_CDR_FLAG_DONT_TOUCH); ast_set_flag(cdr, AST_CDR_FLAG_CHILD | AST_CDR_FLAG_LOCKED); }
/*! \brief Callback function which adds non-permanent contacts to a container */ static int registrar_add_non_permanent(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; struct ao2_container *container = arg; if (ast_tvzero(contact->expiration_time)) { return 0; } ao2_link(container, contact); return 0; }
/* * given the last event *tv and the offset in milliseconds 'when', * computes the next value, */ static int sched_settime(struct timeval *tv, int when) { struct timeval now = ast_tvnow(); /*ast_log(LOG_DEBUG, "TV -> %lu,%lu\n", tv->tv_sec, tv->tv_usec);*/ if (ast_tvzero(*tv)) /* not supplied, default to now */ *tv = now; *tv = ast_tvadd(*tv, ast_samp2tv(when, 1000)); if (ast_tvcmp(*tv, now) < 0) { ast_log(LOG_DEBUG, "Request to schedule in the past?!?!\n"); *tv = now; } return 0; }
/*! \brief Callback function for finding a contact */ static int registrar_find_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; const struct registrar_contact_details *details = arg; pjsip_uri *contact_uri; if (ast_tvzero(contact->expiration_time)) { return 0; } contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0); return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0; }
/*! \brief complete a buffer from the local video source. * Called by get_video_frames(), in turn called by the video thread. */ static struct fbuf_t *grabber_read(struct video_out_desc *v) { struct timeval now = ast_tvnow(); if (v->grabber == NULL) /* not initialized */ return 0; /* check if it is time to read */ if (ast_tvzero(v->last_frame)) v->last_frame = now; if (ast_tvdiff_ms(now, v->last_frame) < 1000/v->fps) return 0; /* too early */ v->last_frame = now; /* XXX actually, should correct for drift */ return v->grabber->read(v->grabber_data); }
static int append_date(char *buf, struct timeval tv, size_t bufsize) { char tmp[80] = ""; struct tm tm; time_t t; t = tv.tv_sec; if (strlen(buf) > bufsize - 3) return -1; if (ast_tvzero(tv)) { strncat(buf, ",", bufsize - strlen(buf) - 1); return 0; } localtime_r(&t,&tm); strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); return append_string(buf, tmp, bufsize); }
/*! * \brief Retrieve a ast_sip_contact_status object from sorcery creating * one if not found. */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; SCOPED_MUTEX(lock, &creation_lock); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (status) { return status; } status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return NULL; } ast_string_field_set(status, uri, contact->uri); status->rtt_start = ast_tv(0, 0); status->rtt = 0; if (ast_sorcery_create(ast_sip_get_sorcery(), status)) { ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n", contact->uri); ao2_ref(status, -1); return NULL; } /* The permanent contact added after asterisk start should be qualified. */ if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED) && ast_tvzero(contact->expiration_time)) { /* * The FULLY_BOOTED to filter out contacts that already existed when asterisk started. * The zero expiration_time to select only permanent contacts. */ ao2_ref((struct ast_sip_contact *) contact, +1); if (ast_sip_push_task(NULL, qualify_and_schedule_aor_contact, (struct ast_sip_contact *) contact)) { ao2_ref((struct ast_sip_contact *) contact, -1); } } ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(status->status)); return status; }
static int timeout_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct timeval myt; if (!chan) return -1; if (!data) { ast_log(LOG_ERROR, "Must specify type of timeout to get.\n"); return -1; } switch (*data) { case 'a': case 'A': if (ast_tvzero(*ast_channel_whentohangup(chan))) { ast_copy_string(buf, "0", len); } else { myt = ast_tvnow(); snprintf(buf, len, "%.3f", ast_tvdiff_ms(*ast_channel_whentohangup(chan), myt) / 1000.0); } break; case 'r': case 'R': if (ast_channel_pbx(chan)) { snprintf(buf, len, "%.3f", ast_channel_pbx(chan)->rtimeoutms / 1000.0); } break; case 'd': case 'D': if (ast_channel_pbx(chan)) { snprintf(buf, len, "%.3f", ast_channel_pbx(chan)->dtimeoutms / 1000.0); } break; default: ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); return -1; } return 0; }
static int append_date(char *buf, struct timeval when, size_t bufsize) { char tmp[80] = ""; struct ast_tm tm; if (strlen(buf) > bufsize - 3) return -1; if (ast_tvzero(when)) { strncat(buf, ",", bufsize - strlen(buf) - 1); return 0; } ast_localtime(&when, &tm, usegmtime ? "GMT" : NULL); ast_strftime(tmp, sizeof(tmp), DATE_FORMAT, &tm); return append_string(buf, tmp, bufsize); }
static void get_date(char *dateField, struct timeval tv) { struct tm tm; time_t t; char buf[80]; /* To make sure we have date variable if not insert null to SQL */ if (!ast_tvzero(tv)) { t = tv.tv_sec; localtime_r(&t, &tm); strftime(buf, 80, DATE_FORMAT, &tm); sprintf(dateField, "'%s'", buf); } else { strcpy(dateField, "null"); } }
/*! \brief Internal function used to delete a contact from an AOR */ static int registrar_delete_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; const char *aor_name = arg; /* Permanent contacts can't be deleted */ if (ast_tvzero(contact->expiration_time)) { return 0; } ast_sip_location_delete_contact(contact); if (!ast_strlen_zero(aor_name)) { ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact->uri, aor_name, contact->user_agent); } return CMP_MATCH; }
static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; static u_char bits_ret[2]; static char string_ret[256]; struct ast_channel *chan, *bridge; struct timeval tval; u_char *ret = NULL; int i, bit; struct ast_str *out = ast_str_alloca(2048); struct ast_channel_iterator *iter; if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels())) return NULL; i = name[*length - 1] - 1; if (!(iter = ast_channel_iterator_all_new())) { return NULL; } while ((chan = ast_channel_iterator_next(iter)) && i) { ast_channel_unref(chan); i--; } iter = ast_channel_iterator_destroy(iter); if (chan == NULL) { return NULL; } *var_len = sizeof(long_ret); ast_channel_lock(chan); switch (vp->magic) { case ASTCHANINDEX: long_ret = name[*length - 1]; ret = (u_char *)&long_ret; break; case ASTCHANNAME: if (!ast_strlen_zero(ast_channel_name(chan))) { ast_copy_string(string_ret, ast_channel_name(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANLANGUAGE: if (!ast_strlen_zero(ast_channel_language(chan))) { ast_copy_string(string_ret, ast_channel_language(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANTYPE: ast_copy_string(string_ret, ast_channel_tech(chan)->type, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMUSICCLASS: if (!ast_strlen_zero(ast_channel_musicclass(chan))) { ast_copy_string(string_ret, ast_channel_musicclass(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANBRIDGE: if ((bridge = ast_bridged_channel(chan)) != NULL) { ast_copy_string(string_ret, ast_channel_name(bridge), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANMASQ: if (ast_channel_masq(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masq(chan)))) { ast_copy_string(string_ret, ast_channel_name(ast_channel_masq(chan)), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANMASQR: if (ast_channel_masqr(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masqr(chan)))) { ast_copy_string(string_ret, ast_channel_name(ast_channel_masqr(chan)), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANWHENHANGUP: if (!ast_tvzero(*ast_channel_whentohangup(chan))) { gettimeofday(&tval, NULL); long_ret = difftime(ast_channel_whentohangup(chan)->tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000; ret= (u_char *)&long_ret; } break; case ASTCHANAPP: if (ast_channel_appl(chan)) { ast_copy_string(string_ret, ast_channel_appl(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANDATA: if (ast_channel_data(chan)) { ast_copy_string(string_ret, ast_channel_data(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCONTEXT: ast_copy_string(string_ret, ast_channel_context(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROCONTEXT: ast_copy_string(string_ret, ast_channel_macrocontext(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROEXTEN: ast_copy_string(string_ret, ast_channel_macroexten(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROPRI: long_ret = ast_channel_macropriority(chan); ret = (u_char *)&long_ret; break; case ASTCHANEXTEN: ast_copy_string(string_ret, ast_channel_exten(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANPRI: long_ret = ast_channel_priority(chan); ret = (u_char *)&long_ret; break; case ASTCHANACCOUNTCODE: if (!ast_strlen_zero(ast_channel_accountcode(chan))) { ast_copy_string(string_ret, ast_channel_accountcode(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANFORWARDTO: if (!ast_strlen_zero(ast_channel_call_forward(chan))) { ast_copy_string(string_ret, ast_channel_call_forward(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANUNIQUEID: ast_copy_string(string_ret, ast_channel_uniqueid(chan), sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANCALLGROUP: long_ret = ast_channel_callgroup(chan); ret = (u_char *)&long_ret; break; case ASTCHANPICKUPGROUP: long_ret = ast_channel_pickupgroup(chan); ret = (u_char *)&long_ret; break; case ASTCHANSTATE: long_ret = ast_channel_state(chan) & 0xffff; ret = (u_char *)&long_ret; break; case ASTCHANMUTED: long_ret = ast_channel_state(chan) & AST_STATE_MUTE ? 1 : 2; ret = (u_char *)&long_ret; break; case ASTCHANRINGS: long_ret = ast_channel_rings(chan); ret = (u_char *)&long_ret; break; case ASTCHANCIDDNID: if (ast_channel_dialed(chan)->number.str) { ast_copy_string(string_ret, ast_channel_dialed(chan)->number.str, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDNUM: if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) { ast_copy_string(string_ret, ast_channel_caller(chan)->id.number.str, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDNAME: if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) { ast_copy_string(string_ret, ast_channel_caller(chan)->id.name.str, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDANI: if (ast_channel_caller(chan)->ani.number.valid && ast_channel_caller(chan)->ani.number.str) { ast_copy_string(string_ret, ast_channel_caller(chan)->ani.number.str, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDRDNIS: if (ast_channel_redirecting(chan)->from.number.valid && ast_channel_redirecting(chan)->from.number.str) { ast_copy_string(string_ret, ast_channel_redirecting(chan)->from.number.str, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDPRES: long_ret = ast_party_id_presentation(&ast_channel_caller(chan)->id); ret = (u_char *)&long_ret; break; case ASTCHANCIDANI2: long_ret = ast_channel_caller(chan)->ani2; ret = (u_char *)&long_ret; break; case ASTCHANCIDTON: long_ret = ast_channel_caller(chan)->id.number.plan; ret = (u_char *)&long_ret; break; case ASTCHANCIDTNS: long_ret = ast_channel_dialed(chan)->transit_network_select; ret = (u_char *)&long_ret; break; case ASTCHANAMAFLAGS: long_ret = ast_channel_amaflags(chan); ret = (u_char *)&long_ret; break; case ASTCHANADSI: long_ret = ast_channel_adsicpe(chan); ret = (u_char *)&long_ret; break; case ASTCHANTONEZONE: if (ast_channel_zone(chan)) { ast_copy_string(string_ret, ast_channel_zone(chan)->country, sizeof(string_ret)); *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANHANGUPCAUSE: long_ret = ast_channel_hangupcause(chan); ret = (u_char *)&long_ret; break; case ASTCHANVARIABLES: if (pbx_builtin_serialize_variables(chan, &out)) { *var_len = ast_str_strlen(out); ret = (u_char *)ast_str_buffer(out); } break; case ASTCHANFLAGS: bits_ret[0] = 0; for (bit = 0; bit < 8; bit++) bits_ret[0] |= ((ast_channel_flags(chan)->flags & (1 << bit)) >> bit) << (7 - bit); bits_ret[1] = 0; for (bit = 0; bit < 8; bit++) bits_ret[1] |= (((ast_channel_flags(chan)->flags >> 8) & (1 << bit)) >> bit) << (7 - bit); *var_len = 2; ret = bits_ret; break; case ASTCHANTRANSFERCAP: long_ret = ast_channel_transfercapability(chan); ret = (u_char *)&long_ret; default: break; } ast_channel_unlock(chan); chan = ast_channel_unref(chan); return ret; }
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted) { pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256), }; if (!details.pool) { return -1; } while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { int expiration = registrar_get_expiration(aor, contact, rdata); RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup); if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ if ((expiration != 0) || previous) { pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } continue; } else if (previous && previous->star) { /* If there is a previous contact and it is a '*' this is a deal breaker */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } previous = contact; if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { continue; } details.uri = pjsip_uri_get_uri(contact->uri); /* Determine if this is an add, update, or delete for policy enforcement purposes */ if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) { if (expiration) { (*added)++; } } else if (expiration) { (*updated)++; } else { (*deleted)++; } } /* The provided contacts are acceptable, huzzah! */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return 0; } /*! \brief Callback function which prunes static contacts */ static int registrar_prune_static(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0; } /*! \brief Internal function used to delete all contacts from an AOR */ static int registrar_delete_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; const char *aor_name = arg; ast_sip_location_delete_contact(contact); if (!ast_strlen_zero(aor_name)) { ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s", contact->uri, aor_name); } return 0; } /*! \brief Internal function which adds a contact to a response */ static int registrar_add_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; pjsip_tx_data *tdata = arg; pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool); pj_str_t uri; pj_strdup2_with_null(tdata->pool, &uri, contact->uri); hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR); hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); return 0; } /*! \brief Helper function which adds a Date header to a response */ static void registrar_add_date_header(pjsip_tx_data *tdata) { char date[256]; struct tm tm; time_t t = time(NULL); gmtime_r(&t, &tm); strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm); ast_sip_add_header(tdata, "Date", date); }
static int sqlite_log(struct ast_cdr *cdr) { int res = 0; char *zErr = 0; char startstr[80], answerstr[80], endstr[80]; int count; #if LOG_HRTIME double hrbillsec = 0.0; double hrduration; #endif ast_mutex_lock(&sqlite_lock); format_date(startstr, sizeof(startstr), &cdr->start); format_date(answerstr, sizeof(answerstr), &cdr->answer); format_date(endstr, sizeof(endstr), &cdr->end); #if LOG_HRTIME if (!ast_tvzero(cdr->answer)) { hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0; } hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0; #endif for(count=0; count<5; count++) { res = sqlite_exec_printf(db, "INSERT INTO cdr (" "clid,src,dst,dcontext," "channel,dstchannel,lastapp,lastdata, " "start,answer,end," "duration,billsec,disposition,amaflags, " "accountcode" # if LOG_UNIQUEID ",uniqueid" # endif # if LOG_USERFIELD ",userfield" # endif ") VALUES (" "'%q', '%q', '%q', '%q', " "'%q', '%q', '%q', '%q', " "'%q', '%q', '%q', " #if LOG_HRTIME "%f, %f, %d, %d, " #else "%d, %d, %d, %d, " #endif "'%q'" # if LOG_UNIQUEID ",'%q'" # endif # if LOG_USERFIELD ",'%q'" # endif ")", NULL, NULL, &zErr, cdr->clid, cdr->src, cdr->dst, cdr->dcontext, cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata, startstr, answerstr, endstr, #if LOG_HRTIME hrduration, hrbillsec, cdr->disposition, cdr->amaflags, #else cdr->duration, cdr->billsec, cdr->disposition, cdr->amaflags, #endif cdr->accountcode # if LOG_UNIQUEID ,cdr->uniqueid # endif # if LOG_USERFIELD ,cdr->userfield # endif ); if (res != SQLITE_BUSY && res != SQLITE_LOCKED) break; usleep(200); } if (zErr) { ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr); ast_free(zErr); } ast_mutex_unlock(&sqlite_lock); return res; }
static char *cli_show_tasks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ao2_iterator i; struct ast_sip_sched_task *schtd; const char *log_format = ast_logger_get_dateformat(); struct ast_tm tm; char queued[32]; char last_start[32]; char last_end[32]; int datelen; struct timeval now = ast_tvnow(); const char *separator = "======================================"; switch (cmd) { case CLI_INIT: e->command = "pjsip show scheduled_tasks"; e->usage = "Usage: pjsip show scheduled_tasks\n" " Show all scheduled tasks\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != 3) { return CLI_SHOWUSAGE; } ast_localtime(&now, &tm, NULL); datelen = ast_strftime(queued, sizeof(queued), log_format, &tm); ast_cli(a->fd, "PJSIP Scheduled Tasks:\n\n"); ast_cli(a->fd, " %1$-24s %2$-8s %3$-9s %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", "Task Name", "Interval", "Times Run", "State", datelen, "Queued", "Last Started", "Last Ended"); ast_cli(a->fd, " %1$-24.24s %2$-8.8s %3$-9.9s %4$-7.7s %6$-*5$.*5$s %7$-*5$.*5$s %8$-*5$.*5$s\n", separator, separator, separator, separator, datelen, separator, separator, separator); ao2_ref(tasks, +1); ao2_rdlock(tasks); i = ao2_iterator_init(tasks, 0); while ((schtd = ao2_iterator_next(&i))) { ast_localtime(&schtd->when_queued, &tm, NULL); ast_strftime(queued, sizeof(queued), log_format, &tm); if (ast_tvzero(schtd->last_start)) { strcpy(last_start, "not yet started"); } else { ast_localtime(&schtd->last_start, &tm, NULL); ast_strftime(last_start, sizeof(last_start), log_format, &tm); } if (ast_tvzero(schtd->last_end)) { if (ast_tvzero(schtd->last_start)) { strcpy(last_end, "not yet started"); } else { strcpy(last_end, "running"); } } else { ast_localtime(&schtd->last_end, &tm, NULL); ast_strftime(last_end, sizeof(last_end), log_format, &tm); } ast_cli(a->fd, " %1$-24.24s %2$-8.3f %3$-9d %4$-7s %6$-*5$s %7$-*5$s %8$-*5$s\n", schtd->name, schtd->interval / 1000.0, schtd->run_count, schtd->is_running ? "running" : "waiting", datelen, queued, last_start, last_end); ao2_cleanup(schtd); } ao2_iterator_destroy(&i); ao2_unlock(tasks); ao2_ref(tasks, -1); ast_cli(a->fd, "\n"); return CLI_SUCCESS; }
struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume) { struct ast_trans_pvt *p; struct ast_frame *out; struct timeval delivery; p = path; /* Feed the first frame into the first translator */ p->step->framein(p->state, f); if (!ast_tvzero(f->delivery)) { if (!ast_tvzero(path->nextin)) { /* Make sure this is in line with what we were expecting */ if (!ast_tveq(path->nextin, f->delivery)) { /* The time has changed between what we expected and this most recent time on the new packet. If we have a valid prediction adjust our output time appropriately */ if (!ast_tvzero(path->nextout)) { path->nextout = ast_tvadd(path->nextout, ast_tvsub(f->delivery, path->nextin)); } path->nextin = f->delivery; } } else { /* This is our first pass. Make sure the timing looks good */ path->nextin = f->delivery; path->nextout = f->delivery; } /* Predict next incoming sample */ path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, 8000)); } delivery = f->delivery; if (consume) ast_frfree(f); while(p) { out = p->step->frameout(p->state); /* If we get nothing out, return NULL */ if (!out) return NULL; /* If there is a next state, feed it in there. If not, return this frame */ if (p->next) p->next->step->framein(p->next->state, out); else { if (!ast_tvzero(delivery)) { /* Regenerate prediction after a discontinuity */ if (ast_tvzero(path->nextout)) path->nextout = ast_tvnow(); /* Use next predicted outgoing timestamp */ out->delivery = path->nextout; /* Predict next outgoing timestamp from samples in this frame. */ path->nextout = ast_tvadd(path->nextout, ast_samp2tv( out->samples, 8000)); } else { out->delivery = ast_tv(0, 0); } /* Invalidate prediction if we're entering a silence period */ if (out->frametype == AST_FRAME_CNG) path->nextout = ast_tv(0, 0); return out; } p = p->next; } ast_log(LOG_WARNING, "I should never get here...\n"); return NULL; }
static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method) { static unsigned long long_ret; static u_char bits_ret[2]; static char string_ret[256]; struct ast_channel *chan, *bridge; struct timeval tval; u_char *ret = NULL; int i, bit; struct ast_str *out = ast_str_alloca(2048); if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels())) return NULL; i = name[*length - 1] - 1; for (chan = ast_channel_walk_locked(NULL); chan && i; chan = ast_channel_walk_locked(chan), i--) ast_channel_unlock(chan); if (chan == NULL) return NULL; *var_len = sizeof(long_ret); switch (vp->magic) { case ASTCHANINDEX: long_ret = name[*length - 1]; ret = (u_char *)&long_ret; break; case ASTCHANNAME: if (!ast_strlen_zero(chan->name)) { strncpy(string_ret, chan->name, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANLANGUAGE: if (!ast_strlen_zero(chan->language)) { strncpy(string_ret, chan->language, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANTYPE: strncpy(string_ret, chan->tech->type, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMUSICCLASS: if (!ast_strlen_zero(chan->musicclass)) { strncpy(string_ret, chan->musicclass, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANBRIDGE: if ((bridge = ast_bridged_channel(chan)) != NULL) { strncpy(string_ret, bridge->name, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANMASQ: if (chan->masq && !ast_strlen_zero(chan->masq->name)) { strncpy(string_ret, chan->masq->name, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANMASQR: if (chan->masqr && !ast_strlen_zero(chan->masqr->name)) { strncpy(string_ret, chan->masqr->name, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANWHENHANGUP: if (!ast_tvzero(chan->whentohangup)) { gettimeofday(&tval, NULL); long_ret = difftime(chan->whentohangup.tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000; ret= (u_char *)&long_ret; } break; case ASTCHANAPP: if (chan->appl) { strncpy(string_ret, chan->appl, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANDATA: if (chan->data) { strncpy(string_ret, chan->data, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCONTEXT: strncpy(string_ret, chan->context, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROCONTEXT: strncpy(string_ret, chan->macrocontext, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROEXTEN: strncpy(string_ret, chan->macroexten, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANMACROPRI: long_ret = chan->macropriority; ret = (u_char *)&long_ret; break; case ASTCHANEXTEN: strncpy(string_ret, chan->exten, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANPRI: long_ret = chan->priority; ret = (u_char *)&long_ret; break; case ASTCHANACCOUNTCODE: if (!ast_strlen_zero(chan->accountcode)) { strncpy(string_ret, chan->accountcode, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANFORWARDTO: if (!ast_strlen_zero(chan->call_forward)) { strncpy(string_ret, chan->call_forward, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANUNIQUEID: strncpy(string_ret, chan->uniqueid, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; break; case ASTCHANCALLGROUP: long_ret = chan->callgroup; ret = (u_char *)&long_ret; break; case ASTCHANPICKUPGROUP: long_ret = chan->pickupgroup; ret = (u_char *)&long_ret; break; case ASTCHANSTATE: long_ret = chan->_state & 0xffff; ret = (u_char *)&long_ret; break; case ASTCHANMUTED: long_ret = chan->_state & AST_STATE_MUTE ? 1 : 2; ret = (u_char *)&long_ret; break; case ASTCHANRINGS: long_ret = chan->rings; ret = (u_char *)&long_ret; break; case ASTCHANCIDDNID: if (chan->cid.cid_dnid) { strncpy(string_ret, chan->cid.cid_dnid, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDNUM: if (chan->cid.cid_num) { strncpy(string_ret, chan->cid.cid_num, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDNAME: if (chan->cid.cid_name) { strncpy(string_ret, chan->cid.cid_name, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDANI: if (chan->cid.cid_ani) { strncpy(string_ret, chan->cid.cid_ani, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDRDNIS: if (chan->cid.cid_rdnis) { strncpy(string_ret, chan->cid.cid_rdnis, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANCIDPRES: long_ret = chan->cid.cid_pres; ret = (u_char *)&long_ret; break; case ASTCHANCIDANI2: long_ret = chan->cid.cid_ani2; ret = (u_char *)&long_ret; break; case ASTCHANCIDTON: long_ret = chan->cid.cid_ton; ret = (u_char *)&long_ret; break; case ASTCHANCIDTNS: long_ret = chan->cid.cid_tns; ret = (u_char *)&long_ret; break; case ASTCHANAMAFLAGS: long_ret = chan->amaflags; ret = (u_char *)&long_ret; break; case ASTCHANADSI: long_ret = chan->adsicpe; ret = (u_char *)&long_ret; break; case ASTCHANTONEZONE: if (chan->zone) { strncpy(string_ret, chan->zone->country, sizeof(string_ret)); string_ret[sizeof(string_ret) - 1] = '\0'; *var_len = strlen(string_ret); ret = (u_char *)string_ret; } break; case ASTCHANHANGUPCAUSE: long_ret = chan->hangupcause; ret = (u_char *)&long_ret; break; case ASTCHANVARIABLES: if (pbx_builtin_serialize_variables(chan, &out)) { *var_len = ast_str_strlen(out); ret = (u_char *)ast_str_buffer(out); } break; case ASTCHANFLAGS: bits_ret[0] = 0; for (bit = 0; bit < 8; bit++) bits_ret[0] |= ((chan->flags & (1 << bit)) >> bit) << (7 - bit); bits_ret[1] = 0; for (bit = 0; bit < 8; bit++) bits_ret[1] |= (((chan->flags >> 8) & (1 << bit)) >> bit) << (7 - bit); *var_len = 2; ret = bits_ret; break; case ASTCHANTRANSFERCAP: long_ret = chan->transfercapability; ret = (u_char *)&long_ret; default: break; } ast_channel_unlock(chan); return ret; }
static SQLHSTMT execute_cb(struct odbc_obj *obj, void *data) { struct ast_cdr *cdr = data; SQLRETURN ODBC_res; char sqlcmd[2048] = "", timestr[128]; struct ast_tm tm; SQLHSTMT stmt; ast_localtime(&cdr->start, &tm, ast_test_flag(&config, CONFIG_USEGMTIME) ? "GMT" : NULL); ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp," "lastdata,duration,billsec,disposition,amaflags,accountcode,uniqueid,userfield) " "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr); } else { snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s " "(calldate,clid,src,dst,dcontext,channel,dstchannel,lastapp,lastdata," "duration,billsec,disposition,amaflags,accountcode) " "VALUES ({ts '%s'},?,?,?,?,?,?,?,?,?,?,?,?,?)", table, timestr); } ODBC_res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb(11, "cdr_odbc: Failure in AllocStatement %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->clid), 0, cdr->clid, 0, NULL); SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->src), 0, cdr->src, 0, NULL); SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dst), 0, cdr->dst, 0, NULL); SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dcontext), 0, cdr->dcontext, 0, NULL); SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->channel), 0, cdr->channel, 0, NULL); SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->dstchannel), 0, cdr->dstchannel, 0, NULL); SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastapp), 0, cdr->lastapp, 0, NULL); SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->lastdata), 0, cdr->lastdata, 0, NULL); if (ast_test_flag(&config, CONFIG_HRTIME)) { double hrbillsec = 0.0; double hrduration; if (!ast_tvzero(cdr->answer)) { hrbillsec = (double) ast_tvdiff_us(cdr->end, cdr->answer) / 1000000.0; } hrduration = (double) ast_tvdiff_us(cdr->end, cdr->start) / 1000000.0; SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrduration, 0, NULL); SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_FLOAT, 0, 0, &hrbillsec, 0, NULL); } else { SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->duration, 0, NULL); SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->billsec, 0, NULL); } if (ast_test_flag(&config, CONFIG_DISPOSITIONSTRING)) SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ast_cdr_disp2str(cdr->disposition)) + 1, 0, ast_cdr_disp2str(cdr->disposition), 0, NULL); else SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->disposition, 0, NULL); SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &cdr->amaflags, 0, NULL); SQLBindParameter(stmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->accountcode), 0, cdr->accountcode, 0, NULL); if (ast_test_flag(&config, CONFIG_LOGUNIQUEID)) { SQLBindParameter(stmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->uniqueid), 0, cdr->uniqueid, 0, NULL); SQLBindParameter(stmt, 15, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(cdr->userfield), 0, cdr->userfield, 0, NULL); } ODBC_res = SQLExecDirect(stmt, (unsigned char *)sqlcmd, SQL_NTS); if ((ODBC_res != SQL_SUCCESS) && (ODBC_res != SQL_SUCCESS_WITH_INFO)) { ast_verb(11, "cdr_odbc: Error in ExecDirect: %d\n", ODBC_res); SQLFreeHandle(SQL_HANDLE_STMT, stmt); return NULL; } return stmt; }
static int timeout_write(struct ast_channel *chan, const char *cmd, char *data, const char *value) { double x = 0.0; long sec = 0L; char timestr[64]; struct ast_tm myt; struct timeval when = {0,}; int res; if (!chan) return -1; if (!data) { ast_log(LOG_ERROR, "Must specify type of timeout to set.\n"); return -1; } if (!value) return -1; res = sscanf(value, "%30ld%30lf", &sec, &x); if (res == 0 || sec < 0) { when.tv_sec = 0; when.tv_usec = 0; } else if (res == 1) { when.tv_sec = sec; } else if (res == 2) { when.tv_sec = sec; when.tv_usec = x * 1000000; } switch (*data) { case 'a': case 'A': ast_channel_lock(chan); ast_channel_setwhentohangup_tv(chan, when); ast_channel_unlock(chan); if (VERBOSITY_ATLEAST(3)) { if (!ast_tvzero(*ast_channel_whentohangup(chan))) { when = ast_tvadd(when, ast_tvnow()); ast_strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S.%3q %Z", ast_localtime(&when, &myt, NULL)); ast_verb(3, "Channel will hangup at %s.\n", timestr); } else { ast_verb(3, "Channel hangup cancelled.\n"); } } break; case 'r': case 'R': if (ast_channel_pbx(chan)) { ast_channel_pbx(chan)->rtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000; ast_verb(3, "Response timeout set to %.3f\n", ast_channel_pbx(chan)->rtimeoutms / 1000.0); } break; case 'd': case 'D': if (ast_channel_pbx(chan)) { ast_channel_pbx(chan)->dtimeoutms = when.tv_sec * 1000 + when.tv_usec / 1000; ast_verb(3, "Digit timeout set to %.3f\n", ast_channel_pbx(chan)->dtimeoutms / 1000.0); } break; default: ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); break; } return 0; }