29 #include <pjsip_simple.h>
34 #include "asterisk/res_pjsip.h"
35 #include "asterisk/res_pjsip_pubsub.h"
36 #include "asterisk/res_pjsip_presence_xml.h"
37 #include "asterisk/res_pjsip_body_generator_types.h"
46 static void dialog_info_xml_state_destroy(
void *obj)
53 .
type =
"dialog-info+xml",
54 .destroy = dialog_info_xml_state_destroy,
57 static void *dialog_info_allocate_body(
void *data)
61 return ast_sip_presence_xml_create_node(state_data->
pool, NULL,
"dialog-info");
73 struct timeval tv = {0,};
77 for (; (device_state = ao2_iterator_next(&citer));
ao2_ref(device_state, -1)) {
78 if (!device_state->causing_channel || (device_state->device_state !=
AST_DEVICE_RINGING &&
82 ast_channel_lock(device_state->causing_channel);
83 if (
ast_tvzero(tv) ||
ast_tvcmp(ast_channel_creationtime(device_state->causing_channel), tv) < 0) {
84 c = device_state->causing_channel;
85 tv = ast_channel_creationtime(c);
87 ast_channel_unlock(device_state->causing_channel);
93 static int dialog_info_generate_body_content(
void *body,
void *data)
95 pj_xml_node *dialog_info = body, *dialog, *
state;
101 char *pidfstate = NULL, *pidfnote = NULL;
102 enum ast_sip_pidf_state local_state;
103 char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
107 if (!local || !remote || !state_data->
datastores) {
113 const struct ast_json *version_json = NULL;
125 datastore_state = datastore->
data;
127 if (state_data->
sub) {
128 version_json = ast_sip_subscription_get_persistence_data(state_data->
sub);
138 datastore_state = datastore->
data;
143 ast_sip_sanitize_xml(stripped, sanitized,
sizeof(sanitized));
145 if (state_data->
sub && (endpoint = ast_sip_subscription_get_endpoint(state_data->
sub))) {
147 ao2_cleanup(endpoint);
149 ast_sip_presence_exten_state_to_str(state_data->
exten_state, &statestring,
150 &pidfstate, &pidfnote, &local_state, notify_early_inuse_ringing);
152 ast_sip_presence_xml_create_attr(state_data->
pool, dialog_info,
"xmlns",
"urn:ietf:params:xml:ns:dialog-info");
154 snprintf(version_str,
sizeof(version_str),
"%u", datastore_state->
version);
155 ast_sip_presence_xml_create_attr(state_data->
pool, dialog_info,
"version", version_str);
157 if (state_data->
sub) {
161 ast_sip_presence_xml_create_attr(state_data->
pool, dialog_info,
"state",
"full");
162 ast_sip_presence_xml_create_attr(state_data->
pool, dialog_info,
"entity", sanitized);
164 dialog = ast_sip_presence_xml_create_node(state_data->
pool, dialog_info,
"dialog");
165 ast_sip_presence_xml_create_attr(state_data->
pool, dialog,
"id", state_data->
exten);
166 if (!ast_strlen_zero(statestring) && !strcmp(statestring,
"early")) {
168 char local_target[PJSIP_MAX_URL_SIZE + 32] =
"";
169 char *local_cid_name = NULL;
170 pj_xml_node *local_node, *local_identity_node, *local_target_node;
172 ast_sip_presence_xml_create_attr(state_data->
pool, dialog,
"direction",
"recipient");
179 static char *anonymous =
"anonymous";
180 static char *invalid =
"anonymous.invalid";
181 char *remote_cid_name;
182 char *remote_connected_num;
183 int remote_connected_num_restricted;
184 char *local_caller_num;
185 pjsip_dialog *dlg = ast_sip_subscription_get_dialog(state_data->
sub);
186 char remote_target[PJSIP_MAX_URL_SIZE + 32];
187 char dlg_remote_uri[PJSIP_MAX_URL_SIZE];
188 char *from_domain_stripped;
189 char from_domain_sanitized[PJSIP_MAX_URL_SIZE];
190 pj_xml_node *remote_node, *remote_identity_node, *remote_target_node;
193 ast_copy_pj_str(dlg_remote_uri, ast_sip_pjsip_uri_get_hostname(dlg->local.info->uri),
sizeof(dlg_remote_uri));
195 ast_sip_sanitize_xml(from_domain_stripped, from_domain_sanitized,
sizeof(from_domain_sanitized));
197 ast_channel_lock(callee);
202 remote_cid_name =
S_COR(ast_channel_connected(callee)->
id.
name.valid,
203 S_COR((ast_channel_connected(callee)->
id.
name.presentation &
204 AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED, anonymous,
205 ast_channel_connected(callee)->
id.
name.str),
"");
208 AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED;
209 remote_connected_num =
S_COR(ast_channel_connected(callee)->
id.
number.valid,
210 S_COR(remote_connected_num_restricted, anonymous,
211 ast_channel_connected(callee)->
id.
number.str),
"invalid");
213 snprintf(remote_target,
sizeof(remote_target),
"sip:%s@%s", remote_connected_num,
214 remote_connected_num_restricted ? invalid : from_domain_sanitized);
219 local_cid_name =
S_COR(ast_channel_caller(callee)->
id.
name.valid,
220 ast_channel_caller(callee)->
id.
name.str,
"");
221 local_caller_num =
S_COR(ast_channel_caller(callee)->
id.
number.valid,
222 ast_channel_caller(callee)->
id.
number.str,
"invalid");
224 snprintf(local_target,
sizeof(local_target),
"sip:%s@%s", local_caller_num,
225 from_domain_sanitized);
227 ast_channel_unlock(callee);
230 remote_node = ast_sip_presence_xml_create_node(state_data->
pool, dialog,
"remote");
231 remote_identity_node = ast_sip_presence_xml_create_node(state_data->
pool, remote_node,
"identity");
232 remote_target_node = ast_sip_presence_xml_create_node(state_data->
pool, remote_node,
"target");
234 pj_strdup2(state_data->
pool, &remote_identity_node->content, remote_target);
235 if (!ast_strlen_zero(remote_cid_name)) {
236 char display_sanitized[PJSIP_MAX_URL_SIZE];
238 ast_sip_sanitize_xml(remote_cid_name, display_sanitized,
sizeof(display_sanitized));
239 ast_sip_presence_xml_create_attr(state_data->
pool, remote_identity_node,
"display", display_sanitized);
241 ast_sip_presence_xml_create_attr(state_data->
pool, remote_target_node,
"uri", remote_target);
245 local_node = ast_sip_presence_xml_create_node(state_data->
pool, dialog,
"local");
246 local_identity_node = ast_sip_presence_xml_create_node(state_data->
pool, local_node,
"identity");
247 local_target_node = ast_sip_presence_xml_create_node(state_data->
pool, local_node,
"target");
250 pj_strdup2(state_data->
pool, &local_identity_node->content,
S_OR(local_target, sanitized));
251 if (!ast_strlen_zero(local_cid_name)) {
252 char display_sanitized[PJSIP_MAX_URL_SIZE];
254 ast_sip_sanitize_xml(local_cid_name, display_sanitized,
sizeof(display_sanitized));
255 ast_sip_presence_xml_create_attr(state_data->
pool, local_identity_node,
"display", display_sanitized);
258 ast_sip_presence_xml_create_attr(state_data->
pool, local_target_node,
"uri", sanitized);
262 state = ast_sip_presence_xml_create_node(state_data->
pool, dialog,
"state");
263 pj_strdup2(state_data->
pool, &state->content, statestring);
266 pj_xml_node *local_node, *target, *param;
268 local_node = ast_sip_presence_xml_create_node(state_data->
pool, dialog,
"local");
269 target = ast_sip_presence_xml_create_node(state_data->
pool, local_node,
"target");
270 ast_sip_presence_xml_create_attr(state_data->
pool, target,
"uri", sanitized);
271 param = ast_sip_presence_xml_create_node(state_data->
pool, target,
"param");
272 ast_sip_presence_xml_create_attr(state_data->
pool, param,
"pname",
"+sip.rendering");
273 ast_sip_presence_xml_create_attr(state_data->
pool, param,
"pvalue",
"no");
284 #define MAX_STRING_GROWTHS 6
286 static void dialog_info_to_string(
void *body,
struct ast_str **str)
288 pj_xml_node *dialog_info = body;
294 if (size <= AST_PJSIP_XML_PROLOG_LEN) {
298 }
while (size <= AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS);
299 if (size <= AST_PJSIP_XML_PROLOG_LEN) {
300 ast_log(LOG_WARNING,
"dialog-info+xml body text too large\n");
309 .
type =
"application",
310 .subtype =
"dialog-info+xml",
311 .body_type = AST_SIP_EXTEN_STATE_DATA,
312 .allocate_body = dialog_info_allocate_body,
313 .generate_body_content = dialog_info_generate_body_content,
314 .to_string = dialog_info_to_string,
318 static int load_module(
void)
320 if (ast_sip_pubsub_register_body_generator(&dialog_info_body_generator)) {
327 static int unload_module(
void)
329 ast_sip_pubsub_unregister_body_generator(&dialog_info_body_generator);
333 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP Extension State Dialog Info+XML Provider",
334 .support_level = AST_MODULE_SUPPORT_CORE,
336 .unload = unload_module,
338 .requires =
"res_pjsip,res_pjsip_pubsub",
Main Channel structure associated with a channel.
Asterisk main include file. File version handling, generic pbx functions.
int presentation
Q.931 presentation-indicator and screening-indicator encoded fields.
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
struct ast_party_id id
Connected party ID.
#define ast_channel_unref(c)
Decrease channel reference count.
const char * type
Content type In "plain/text", "plain" is the type.
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
int ast_datastores_add(struct ao2_container *datastores, struct ast_datastore *datastore)
Add a data store to a container.
char remote[PJSIP_MAX_URL_SIZE]
Structure for a data store type.
Structure which contains dialog-info+xml state information.
enum ast_extension_states exten_state
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Structure for a data store object.
struct ast_sip_subscription * sub
struct ao2_container * datastores
struct ast_datastore * ast_datastores_find(struct ao2_container *datastores, const char *name)
Find a data store in a container.
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
unsigned int notify_early_inuse_ringing
struct ast_datastore * ast_datastores_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Allocate a datastore for use with the datastores container.
An entity with which Asterisk communicates.
struct ao2_container * device_state_info
char local[PJSIP_MAX_URL_SIZE]
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Support for dynamic strings.
const ast_string_field name
#define ast_calloc(num, len)
A wrapper for calloc()
Module has failed to load, may be in an inconsistent state.
structure used for presence XML bodies
#define ast_channel_ref(c)
Increase channel reference count.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Abstract JSON element (object, array, string, int, ...).
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
unsigned int version
Version to place into the next NOTIFY.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct ast_json * ast_json_integer_create(intmax_t value)
Create a JSON integer.
struct ast_party_number number
Subscriber phone number.