/* * Send typing indication outside dialog. */ PJ_DEF(pj_status_t) pjsua_im_typing( pjsua_acc_id acc_id, const pj_str_t *to, pj_bool_t is_typing, const pjsua_msg_data *msg_data) { const pj_str_t STR_CONTACT = { "Contact", 7 }; pjsua_im_data *im_data; pjsip_tx_data *tdata; pj_str_t contact; pj_status_t status; /* Create request. */ status = pjsip_endpt_create_request( pjsua_var.endpt, &pjsip_message_method, to, &pjsua_var.acc[acc_id].cfg.id, to, NULL, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create request", status); return status; } /* If account is locked to specific transport, then set transport to * the request. */ if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); pjsip_tx_data_set_transport(tdata, &tp_sel); } /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); /* Add contact. */ status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pjsip_tx_data_dec_ref(tdata); return status; } pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_CONTACT, &contact)); /* Create "application/im-iscomposing+xml" msg body. */ tdata->msg->body = pjsip_iscomposing_create_body( tdata->pool, is_typing, NULL, NULL, -1); /* Add additional headers etc. */ pjsua_process_msg_data(tdata, msg_data); /* Add route set */ pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set); /* Create data to reauthenticate */ im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data); im_data->acc_id = acc_id; /* Send request (statefully) */ status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, im_data, &typing_callback); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send request", status); return status; } return PJ_SUCCESS; }
/* It does what it says.. */ static void subscribe_buddy_presence(unsigned index) { pj_pool_t *tmp_pool = NULL; pjsua_buddy *buddy; int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_tx_data *tdata; pj_status_t status; buddy = &pjsua_var.buddy[index]; acc_id = pjsua_acc_find_for_outgoing(&buddy->uri); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription", acc_id, index)); /* Generate suitable Contact header unless one is already set in * the account */ if (acc->contact.slen) { contact = acc->contact; } else { tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256); status = pjsua_acc_create_uac_contact(tmp_pool, &contact, acc_id, &buddy->uri); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pj_pool_release(tmp_pool); return; } } /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &acc->cfg.id, &contact, &buddy->uri, NULL, &buddy->dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create dialog", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } /* Increment the dialog's lock otherwise when presence session creation * fails the dialog will be destroyed prematurely. */ pjsip_dlg_inc_lock(buddy->dlg); status = pjsip_pres_create_uac( buddy->dlg, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub); if (status != PJ_SUCCESS) { pjsua_var.buddy[index].sub = NULL; pjsua_perror(THIS_FILE, "Unable to create presence client", status); /* This should destroy the dialog since there's no session * referencing it */ pjsip_dlg_dec_lock(buddy->dlg); if (tmp_pool) pj_pool_release(tmp_pool); return; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(buddy->dlg, &tp_sel); } /* Set route-set */ if (!pj_list_empty(&acc->route_set)) { pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set); } /* Set credentials */ if (acc->cred_cnt) { pjsip_auth_clt_set_credentials( &buddy->dlg->auth_sess, acc->cred_cnt, acc->cred); } /* Set authentication preference */ pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref); pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy); status = pjsip_pres_initiate(buddy->sub, -1, &tdata); if (status != PJ_SUCCESS) { pjsip_dlg_dec_lock(buddy->dlg); if (buddy->sub) { pjsip_pres_terminate(buddy->sub, PJ_FALSE); } buddy->sub = NULL; pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } pjsua_process_msg_data(tdata, NULL); status = pjsip_pres_send_request(buddy->sub, tdata); if (status != PJ_SUCCESS) { pjsip_dlg_dec_lock(buddy->dlg); if (buddy->sub) { pjsip_pres_terminate(buddy->sub, PJ_FALSE); } buddy->sub = NULL; pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } pjsip_dlg_dec_lock(buddy->dlg); if (tmp_pool) pj_pool_release(tmp_pool); }
/* * Send instant messaging outside dialog, using the specified account for * route set and authentication. */ PJ_DEF(pj_status_t) pjsua_im_send( pjsua_acc_id acc_id, const pj_str_t *to, const pj_str_t *mime_type, const pj_str_t *content, const pjsua_msg_data *msg_data, void *user_data) { pjsip_tx_data *tdata; const pj_str_t mime_text_plain = pj_str("text/plain"); const pj_str_t STR_CONTACT = { "Contact", 7 }; pjsip_media_type media_type; pjsua_im_data *im_data; pj_str_t contact; pj_status_t status; /* To and message body must be specified. */ PJ_ASSERT_RETURN(to && content, PJ_EINVAL); /* Create request. */ status = pjsip_endpt_create_request(pjsua_var.endpt, &pjsip_message_method, to, &pjsua_var.acc[acc_id].cfg.id, to, NULL, NULL, -1, NULL, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create request", status); return status; } /* If account is locked to specific transport, then set transport to * the request. */ if (pjsua_var.acc[acc_id].cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(pjsua_var.acc[acc_id].cfg.transport_id, &tp_sel); pjsip_tx_data_set_transport(tdata, &tp_sel); } /* Add accept header. */ pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)pjsua_im_create_accept(tdata->pool)); /* Add contact. */ status = pjsua_acc_create_uac_contact(tdata->pool, &contact, acc_id, to); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pjsip_tx_data_dec_ref(tdata); return status; } pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*) pjsip_generic_string_hdr_create(tdata->pool, &STR_CONTACT, &contact)); /* Create IM data to keep message details and give it back to * application on the callback */ im_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsua_im_data); im_data->acc_id = acc_id; im_data->call_id = PJSUA_INVALID_ID; pj_strdup_with_null(tdata->pool, &im_data->to, to); pj_strdup_with_null(tdata->pool, &im_data->body, content); im_data->user_data = user_data; /* Set default media type if none is specified */ if (mime_type == NULL) { mime_type = &mime_text_plain; } /* Parse MIME type */ pjsua_parse_media_type(tdata->pool, mime_type, &media_type); /* Add message body */ tdata->msg->body = pjsip_msg_body_create( tdata->pool, &media_type.type, &media_type.subtype, &im_data->body); if (tdata->msg->body == NULL) { pjsua_perror(THIS_FILE, "Unable to create msg body", PJ_ENOMEM); pjsip_tx_data_dec_ref(tdata); return PJ_ENOMEM; } /* Add additional headers etc. */ pjsua_process_msg_data(tdata, msg_data); /* Add route set */ pjsua_set_msg_route_set(tdata, &pjsua_var.acc[acc_id].route_set); /* Send request (statefully) */ status = pjsip_endpt_send_request( pjsua_var.endpt, tdata, -1, im_data, &im_callback); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send request", status); return status; } return PJ_SUCCESS; }