Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (Revision 60212) +++ channels/chan_sip.c (Arbeitskopie) @@ -290,11 +290,11 @@ } subscription_types[] = { { NONE, "-", "unknown", "unknown" }, /* RFC 4235: SIP Dialog event package */ - { DIALOG_INFO_XML, "dialog", "application/dialog-info+xml", "dialog-info+xml" }, - { CPIM_PIDF_XML, "presence", "application/cpim-pidf+xml", "cpim-pidf+xml" }, /* RFC 3863 */ - { PIDF_XML, "presence", "application/pidf+xml", "pidf+xml" }, /* RFC 3863 */ - { XPIDF_XML, "presence", "application/xpidf+xml", "xpidf+xml" }, /* Pre-RFC 3863 with MS additions */ - { MWI_NOTIFICATION, "message-summary", "application/simple-message-summary", "mwi" } /* RFC 3842: Mailbox notification */ + { DIALOG_INFO_XML, "dialog" , "application/dialog-info+xml", "dialog-info+xml" }, + { CPIM_PIDF_XML, "presence", "application/cpim-pidf+xml" , "cpim-pidf+xml" }, /* RFC 3863 */ + { PIDF_XML, "presence", "application/pidf+xml" , "pidf+xml" }, /* RFC 3863 */ + { XPIDF_XML, "presence", "application/xpidf+xml" , "xpidf+xml" }, /* Pre-RFC 3863 with MS additions */ + { MWI_NOTIFICATION,"message-summary", "application/simple-message-summary", "mwi"} /* RFC 3842: Mailbox notification */ }; /*! \brief SIP Request methods known by Asterisk */ @@ -1371,7 +1371,7 @@ static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target); /*--- Device monitoring and Device/extension state handling */ -static int cb_extensionstate(char *context, char* exten, int state, void *data); +static int cb_extensionstate(char *context, char* exten, int state, void *data, char *cid_num, char *cid_name); static int sip_devicestate(void *data); static int sip_poke_noanswer(void *data); static int sip_poke_peer(struct sip_peer *peer); @@ -1503,7 +1503,7 @@ static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq); static int get_destination(struct sip_pvt *p, struct sip_request *oreq); static int get_msg_text(char *buf, int len, struct sip_request *req); -static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout); +static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout, char *cid_num, char *cid_name); /*--- Constructing requests and responses */ static void initialize_initreq(struct sip_pvt *p, struct sip_request *req); @@ -2134,7 +2134,7 @@ /* If this is a subscription, tell the phone that we got a timeout */ if (p->subscribed) { - transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, TRUE); /* Send last notification */ + transmit_state_notify(p, AST_EXTENSION_DEACTIVATED, 1, TRUE, NULL, NULL); /* Send last notification */ p->subscribed = NONE; append_history(p, "Subscribestatus", "timeout"); if (option_debug > 2) @@ -3303,6 +3303,7 @@ int outgoing = ast_test_flag(&fup->flags[1], SIP_PAGE2_OUTGOING_CALL); struct sip_user *u = NULL; struct sip_peer *p = NULL; + struct ast_channel *chan; if (option_debug > 2) ast_log(LOG_DEBUG, "Updating call counter for %s call\n", outgoing ? "outgoing" : "incoming"); @@ -3390,7 +3391,14 @@ ast_log(LOG_ERROR, "update_call_counter(%s, %d) called with no event!\n", name, event); } if (p) { - ast_device_state_changed("SIP/%s", p->name); + chan = fup->owner; + if (!chan) + ast_device_state_changed("SIP/%s", p->name); + else { + if (option_debug > 0) + ast_log(LOG_DEBUG, "State of SIP/%s changed - Caller: %s <%s>\n", p->name, chan->cid.cid_name, chan->cid.cid_num); + ast_device_state_changed_with_callerid("SIP/%s", chan->cid.cid_num, chan->cid.cid_name, p->name); + } unref_peer(p); } else /* u must be set */ unref_user(u); @@ -7368,7 +7376,7 @@ } /*! \brief Used in the SUBSCRIBE notification subsystem */ -static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout) +static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout, char *cid_num, char *cid_name) { char tmp[4000], from[256], to[256]; char *t = tmp, *c, *mfrom, *mto; @@ -7381,6 +7389,9 @@ char *pidfstate = "--"; char *pidfnote= "Ready"; + if (!cid_num || ast_strlen_zero(cid_num )) cid_num = "unknown"; + if (!cid_name || ast_strlen_zero(cid_name)) cid_name = "unknown"; + memset(from, 0, sizeof(from)); memset(to, 0, sizeof(to)); memset(tmp, 0, sizeof(tmp)); @@ -7429,7 +7440,7 @@ } subscriptiontype = find_subscription_type(p->subscribed); - + /* Check which device/devices we are watching and if they are registered */ if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) { /* If they are not registered, we will override notification and show no availability */ @@ -7458,7 +7469,6 @@ reqprep(&req, p, SIP_NOTIFY, 0, 1); - add_header(&req, "Event", subscriptiontype->event); add_header(&req, "Content-Type", subscriptiontype->mediatype); switch(state) { @@ -7480,8 +7490,8 @@ add_header(&req, "Subscription-State", "terminated;reason=timeout"); } switch (p->subscribed) { + case CPIM_PIDF_XML: case XPIDF_XML: - case CPIM_PIDF_XML: ast_build_string(&t, &maxbytes, "\n"); ast_build_string(&t, &maxbytes, "\n"); ast_build_string(&t, &maxbytes, "\n"); @@ -7489,12 +7499,18 @@ ast_build_string(&t, &maxbytes, "\n", p->exten); ast_build_string(&t, &maxbytes, "
\n", mto); ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed"); - ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline"); + if (p->subscribed == XPIDF_XML) { /* MS additions */ + ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline"); + } ast_build_string(&t, &maxbytes, "
\n
\n
\n"); break; case PIDF_XML: /* Eyebeam supports this format */ ast_build_string(&t, &maxbytes, "\n"); - ast_build_string(&t, &maxbytes, "\n", mfrom); + ast_build_string(&t, &maxbytes, "\n", mfrom); ast_build_string(&t, &maxbytes, "\n"); if (pidfstate[0] != '-') ast_build_string(&t, &maxbytes, "\n", pidfstate); @@ -7511,16 +7527,19 @@ case DIALOG_INFO_XML: /* SNOM subscribes in this format */ ast_build_string(&t, &maxbytes, "\n"); ast_build_string(&t, &maxbytes, "\n", p->dialogver++, full ? "full":"partial", mto); - if ((state & AST_EXTENSION_RINGING) && global_notifyringing) + if ((state & AST_EXTENSION_RINGING) && global_notifyringing) { ast_build_string(&t, &maxbytes, "\n", p->exten); - else + ast_build_string(&t, &maxbytes, "%s\n", p->exten, mto, mto); + ast_build_string(&t, &maxbytes, "%s\n", cid_name, cid_num, ast_pickup_ext(), p->exten, p->fromdomain); + } else if (state == AST_EXTENSION_ONHOLD) { ast_build_string(&t, &maxbytes, "\n", p->exten); - ast_build_string(&t, &maxbytes, "%s\n", statestring); - if (state == AST_EXTENSION_ONHOLD) { ast_build_string(&t, &maxbytes, "\n\n" "\n" "\n\n", mto); + } else { + ast_build_string(&t, &maxbytes, "\n", p->exten); } + ast_build_string(&t, &maxbytes, "%s\n", statestring); ast_build_string(&t, &maxbytes, "\n\n"); break; case NONE: @@ -8714,7 +8733,7 @@ /*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem \note If you add an "hint" priority to the extension in the dial plan, you will get notifications on device state changes */ -static int cb_extensionstate(char *context, char* exten, int state, void *data) +static int cb_extensionstate(char *context, char* exten, int state, void *data, char *cid_num, char *cid_name) { struct sip_pvt *p = data; @@ -8734,7 +8753,7 @@ break; } if (p->subscribed != NONE) /* Only send state NOTIFY if we know the format */ - transmit_state_notify(p, state, 1, FALSE); + transmit_state_notify(p, state, 1, FALSE, cid_num, cid_name); if (option_verbose > 1) ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %s for Notify User %s\n", exten, ast_extension_state2str(state), p->username); @@ -15198,7 +15217,6 @@ struct sip_pvt *p_old; if ((firststate = ast_extension_state(NULL, p->context, p->exten)) < 0) { - ast_log(LOG_NOTICE, "Got SUBSCRIBE for extension %s@%s from %s, but there is no hint for that extension.\n", p->exten, p->context, ast_inet_ntoa(p->sa.sin_addr)); transmit_response(p, "404 Not found", req); ast_set_flag(&p->flags[0], SIP_NEEDDESTROY); @@ -15206,7 +15224,7 @@ } transmit_response(p, "200 OK", req); - transmit_state_notify(p, firststate, 1, FALSE); /* Send first notification */ + transmit_state_notify(p, firststate, 1, FALSE, NULL, NULL); /* Send first notification */ append_history(p, "Subscribestatus", "%s", ast_extension_state2str(firststate)); /* hide the 'complete' exten/context in the refer_to field for later display */ ast_string_field_build(p, subscribeuri, "%s@%s", p->exten, p->context); Index: apps/app_directed_pickup.c =================================================================== --- apps/app_directed_pickup.c (Revision 60212) +++ apps/app_directed_pickup.c (Arbeitskopie) @@ -48,12 +48,14 @@ static const char *app = "Pickup"; static const char *synopsis = "Directed Call Pickup"; static const char *descrip = -" Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n" -"that is calling the specified extension. If no context is specified, the current\n" -"context will be used. If you use the special string \"PICKUPMARK\" for the context parameter, for example\n" -"10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n" -"as \"extension\"."; +" Pickup(extension[@context][&extension2@context...]): This application\n" +"can pickup any ringing channel that is calling the specified extension. If\n" +"no context is specified, the current context will be used. If you use the\n" +"special string \"PICKUPMARK\" for the context parameter, for example\n" +"10@PICKUPMARK, this application tries to find a channel which has defined a\n" +"channel variable with the same content as \"extension\"."; + /* Perform actual pickup between two channels */ static int pickup_do(struct ast_channel *chan, struct ast_channel *target) { @@ -144,7 +146,7 @@ } u = ast_module_user_add(chan); - + /* Parse extension (and context if there) */ while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) { if ((context = strchr(exten, '@'))) Index: include/asterisk/devicestate.h =================================================================== --- include/asterisk/devicestate.h (Revision 60212) +++ include/asterisk/devicestate.h (Arbeitskopie) @@ -93,6 +93,8 @@ int ast_device_state_changed(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); +int ast_device_state_changed_with_callerid(const char *fmt, const char *cid_num, const char *cid_name, ...) + __attribute__ ((format (printf, 1, 4))); /*! \brief Tells Asterisk the State for Device is changed * \param device devicename like a dialstring @@ -100,7 +102,7 @@ * callbacks for the changed extensions * Returns 0 on success, -1 on failure */ -int ast_device_state_changed_literal(const char *device); +int ast_device_state_changed_literal(const char *device, const char *cid_num, const char *cid_name); /*! \brief Registers a device state change callback * \param callback Callback Index: include/asterisk/pbx.h =================================================================== --- include/asterisk/pbx.h (Revision 60212) +++ include/asterisk/pbx.h (Arbeitskopie) @@ -66,7 +66,7 @@ struct ast_sw; /*! \brief Typedef for devicestate and hint callbacks */ -typedef int (*ast_state_cb_type)(char *context, char* id, enum ast_extension_states state, void *data); +typedef int (*ast_state_cb_type)(char *context, char *id, enum ast_extension_states state, void *data, char *cid_num, char *cid_name); /*! \brief Data structure associated with a custom dialplan function */ struct ast_custom_function { @@ -877,7 +877,7 @@ */ int ast_func_write(struct ast_channel *chan, const char *function, const char *value); -void ast_hint_state_changed(const char *device); +void ast_hint_state_changed(const char *device, char *cid_num, char *cid_name); #if defined(__cplusplus) || defined(c_plusplus) } Index: main/channel.c =================================================================== --- main/channel.c (Revision 60212) +++ main/channel.c (Arbeitskopie) @@ -1113,7 +1113,7 @@ free(chan); AST_LIST_UNLOCK(&channels); - ast_device_state_changed_literal(name); + ast_device_state_changed_literal(name, NULL, NULL); } struct ast_datastore *ast_channel_datastore_alloc(const struct ast_datastore_info *info, char *uid) @@ -3635,7 +3635,7 @@ return 0; chan->_state = state; - ast_device_state_changed_literal(chan->name); + ast_device_state_changed_literal(chan->name, NULL, NULL); /* setstate used to conditionally report Newchannel; this is no more */ manager_event(EVENT_FLAG_CALL, "Newstate", @@ -3652,6 +3652,12 @@ return 0; } +/* ############ +should there be an +int ast_setstate_with_callerid(struct ast_channel *chan, enum ast_channel_state state, char *cid_num, char *cid_name) +? +*/ + /*! \brief Find bridged channel */ struct ast_channel *ast_bridged_channel(struct ast_channel *chan) { Index: main/devicestate.c =================================================================== --- main/devicestate.c (Revision 60212) +++ main/devicestate.c (Arbeitskopie) @@ -162,7 +162,14 @@ struct state_change { AST_LIST_ENTRY(state_change) list; + /* because device is declared a char[1] here, cid_num and cid_name + must come first or would accidentally be written to with + strcpy(change->device, device); */ + char cid_num[AST_MAX_EXTENSION]; + char cid_name[AST_MAX_EXTENSION]; char device[1]; + /* enough space for the state_change struct will be ast_calloc'ed in + __ast_device_state_changed_literal() */ }; /*! \brief The state change queue. State changes are queued @@ -418,7 +425,7 @@ /*! \brief Notify callback watchers of change, and notify PBX core for hint updates Normally executed within a separate thread */ -static void do_state_change(const char *device) +static void do_state_change(const char *device, char *cid_num, char *cid_name) { int state; struct devstate_cb *devcb; @@ -432,10 +439,10 @@ devcb->callback(device, state, devcb->data); AST_RWLIST_UNLOCK(&devstate_cbs); - ast_hint_state_changed(device); + ast_hint_state_changed(device, cid_num, cid_name); } -static int __ast_device_state_changed_literal(char *buf) +static int __ast_device_state_changed_literal(char *buf, char *cid_num, char *cid_name) { char *device, *tmp; struct state_change *change; @@ -450,10 +457,14 @@ if (change_thread == AST_PTHREADT_NULL || !(change = ast_calloc(1, sizeof(*change) + strlen(device)))) { /* we could not allocate a change struct, or */ /* there is no background thread, so process the change now */ - do_state_change(device); + do_state_change(device, cid_num, cid_name); } else { /* queue the change */ strcpy(change->device, device); + if (cid_num) + strncpy(change->cid_num, cid_num, sizeof(change->cid_num)-1); + if (cid_name) + strncpy(change->cid_name, cid_name, sizeof(change->cid_name)-1); AST_LIST_LOCK(&state_changes); AST_LIST_INSERT_TAIL(&state_changes, change, list); ast_cond_signal(&change_pending); @@ -463,15 +474,19 @@ return 1; } -int ast_device_state_changed_literal(const char *dev) +int ast_device_state_changed_literal(const char *dev, const char *cid_num, const char *cid_name) { char *buf; + char *buf_cid_num; + char *buf_cid_name; buf = ast_strdupa(dev); - return __ast_device_state_changed_literal(buf); + if (cid_num ) buf_cid_num = ast_strdupa(cid_num ); + if (cid_name) buf_cid_name = ast_strdupa(cid_name); + return __ast_device_state_changed_literal(buf, buf_cid_num, buf_cid_name); } /*! \brief Accept change notification, add it to change queue */ -int ast_device_state_changed(const char *fmt, ...) +int ast_device_state_changed(const char *fmt, ...) { char buf[AST_MAX_EXTENSION]; va_list ap; @@ -479,9 +494,24 @@ va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); - return __ast_device_state_changed_literal(buf); + return __ast_device_state_changed_literal(buf, NULL, NULL); } +int ast_device_state_changed_with_callerid(const char *fmt, const char *cid_num, const char *cid_name, ...) +{ + char buf[AST_MAX_EXTENSION]; + char *buf_cid_num; + char *buf_cid_name; + va_list ap; + + va_start(ap, cid_name); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (cid_num ) buf_cid_num = ast_strdupa(cid_num ); + if (cid_name) buf_cid_name = ast_strdupa(cid_name); + return __ast_device_state_changed_literal(buf, buf_cid_num, buf_cid_name); +} + /*! \brief Go through the dev state change queue and update changes in the dev state thread */ static void *do_devstate_changes(void *data) { @@ -499,7 +529,7 @@ /* Process each state change */ while ((current = next)) { next = AST_LIST_NEXT(current, list); - do_state_change(current->device); + do_state_change(current->device, current->cid_num, current->cid_name); free(current); } } Index: main/pbx.c =================================================================== --- main/pbx.c (Revision 60212) +++ main/pbx.c (Arbeitskopie) @@ -1900,7 +1900,7 @@ return ast_extension_state2(e); /* Check all devices in the hint */ } -void ast_hint_state_changed(const char *device) +void ast_hint_state_changed(const char *device, char *cid_num, char *cid_name) { struct ast_hint *hint; @@ -1931,11 +1931,11 @@ /* For general callbacks */ for (cblist = statecbs; cblist; cblist = cblist->next) - cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data); + cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, NULL, NULL); /* For extension callbacks */ for (cblist = hint->callbacks; cblist; cblist = cblist->next) - cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data); + cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data, cid_num, cid_name); hint->laststate = state; /* record we saw the change */ } @@ -2129,7 +2129,7 @@ /* Notify with -1 and remove all callbacks */ cbprev = cblist; cblist = cblist->next; - cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data); + cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data, NULL, NULL); free(cbprev); } hint->callbacks = NULL; @@ -3982,7 +3982,7 @@ while (thiscb) { prevcb = thiscb; thiscb = thiscb->next; - prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data); + prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data, NULL, NULL); free(prevcb); } } else { Index: configs/sip.conf.sample =================================================================== --- configs/sip.conf.sample (Revision 60212) +++ configs/sip.conf.sample (Arbeitskopie) @@ -712,7 +712,7 @@ ; Call group and Pickup group should be in the range from 0 to 63 ; ;callgroup=1,3-4 ; We are in caller groups 1,3,4 -;pickupgroup=1,3-5 ; We can do call pick-p for call group 1,3,4,5 +;pickupgroup=1,3-5 ; We can do call pickup for call group 1,3,4,5 ;defaultip=192.168.0.60 ; IP address to use if peer has not registered ;deny=0.0.0.0/0.0.0.0 ; ACL: Control access to this account based on IP address ;permit=192.168.0.60/255.255.255.0 Index: configs/extensions.conf.sample =================================================================== --- configs/extensions.conf.sample (Revision 60212) +++ configs/extensions.conf.sample (Arbeitskopie) @@ -579,3 +579,6 @@ ; 'core show functions" will list all dialplan functions ; 'core show function ' will show you more information about ; one function. Remember that function names are UPPER CASE. + +; Call Pickup (must match pickupexten in features.conf): +;exten => _*8.,1,Pickup(${EXTEN:2}@default)