blob: 25ce6dcf43d4b42932287e63324f2ba6f32fb4d3 [file] [log] [blame]
Benny Prijono5dcb38d2005-11-21 01:55:47 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
Benny Prijono268ca612006-02-07 12:34:11 +000019#include "pjsua.h"
Benny Prijono38998232006-02-08 22:44:25 +000020#include <stdlib.h>
Benny Prijonoccf95622006-02-07 18:48:01 +000021
Benny Prijono5dcb38d2005-11-21 01:55:47 +000022
Benny Prijono268ca612006-02-07 12:34:11 +000023#define THIS_FILE "main.c"
Benny Prijono5dcb38d2005-11-21 01:55:47 +000024
Benny Prijono834aee32006-02-19 01:38:06 +000025/* Current dialog */
Benny Prijonoa91a0032006-02-26 21:23:45 +000026static int current_acc;
27static int current_call = -1;
28
29
30/*
31 * Find next call.
32 */
33static pj_bool_t find_next_call(void)
34{
35 int i;
36
37 for (i=current_call+1; i<(int)pjsua.max_calls; ++i) {
38 if (pjsua.calls[i].inv != NULL) {
39 current_call = i;
40 return PJ_TRUE;
41 }
42 }
43
44 for (i=0; i<current_call; ++i) {
45 if (pjsua.calls[i].inv != NULL) {
46 current_call = i;
47 return PJ_TRUE;
48 }
49 }
50
51 current_call = -1;
52 return PJ_FALSE;
53}
54
55
56/*
57 * Find previous call.
58 */
59static pj_bool_t find_prev_call(void)
60{
61 int i;
62
63 for (i=current_call-1; i>=0; --i) {
64 if (pjsua.calls[i].inv != NULL) {
65 current_call = i;
66 return PJ_TRUE;
67 }
68 }
69
70 for (i=pjsua.max_calls-1; i>current_call; --i) {
71 if (pjsua.calls[i].inv != NULL) {
72 current_call = i;
73 return PJ_TRUE;
74 }
75 }
76
77 current_call = -1;
78 return PJ_FALSE;
79}
80
81
Benny Prijono5dcb38d2005-11-21 01:55:47 +000082
83/*
Benny Prijono268ca612006-02-07 12:34:11 +000084 * Notify UI when invite state has changed.
Benny Prijono5dcb38d2005-11-21 01:55:47 +000085 */
Benny Prijonoa91a0032006-02-26 21:23:45 +000086void pjsua_ui_inv_on_state_changed(int call_index, pjsip_event *e)
Benny Prijono5dcb38d2005-11-21 01:55:47 +000087{
Benny Prijonoa91a0032006-02-26 21:23:45 +000088 pjsua_call *call = &pjsua.calls[call_index];
89
Benny Prijono268ca612006-02-07 12:34:11 +000090 PJ_UNUSED_ARG(e);
Benny Prijono5dcb38d2005-11-21 01:55:47 +000091
Benny Prijonoa91a0032006-02-26 21:23:45 +000092 PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s",
93 call_index,
94 pjsua_inv_state_names[call->inv->state]));
Benny Prijono5dcb38d2005-11-21 01:55:47 +000095
Benny Prijonoa91a0032006-02-26 21:23:45 +000096 if (call->inv->state == PJSIP_INV_STATE_DISCONNECTED) {
97 call->inv = NULL;
98 if ((int)call->index == current_call) {
99 find_next_call();
Benny Prijono834aee32006-02-19 01:38:06 +0000100 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000101
Benny Prijono268ca612006-02-07 12:34:11 +0000102 } else {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000103
Benny Prijonoa91a0032006-02-26 21:23:45 +0000104 if (call && current_call==-1)
105 current_call = call->index;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000106
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000107 }
108}
109
Benny Prijonof3195072006-02-14 21:15:30 +0000110/**
111 * Notify UI when registration status has changed.
Benny Prijono632ce712006-02-09 14:01:40 +0000112 */
Benny Prijonof3195072006-02-14 21:15:30 +0000113void pjsua_ui_regc_on_state_changed(int code)
Benny Prijono632ce712006-02-09 14:01:40 +0000114{
Benny Prijonof3195072006-02-14 21:15:30 +0000115 PJ_UNUSED_ARG(code);
Benny Prijono632ce712006-02-09 14:01:40 +0000116
Benny Prijonof3195072006-02-14 21:15:30 +0000117 // Log already written.
Benny Prijono632ce712006-02-09 14:01:40 +0000118}
119
120
Benny Prijono834aee32006-02-19 01:38:06 +0000121/*
122 * Print buddy list.
123 */
124static void print_buddy_list(void)
125{
Benny Prijonoa91a0032006-02-26 21:23:45 +0000126 int i;
Benny Prijono834aee32006-02-19 01:38:06 +0000127
128 puts("Buddy list:");
Benny Prijonoa91a0032006-02-26 21:23:45 +0000129
Benny Prijono834aee32006-02-19 01:38:06 +0000130 if (pjsua.buddy_cnt == 0)
131 puts(" -none-");
132 else {
133 for (i=0; i<pjsua.buddy_cnt; ++i) {
134 const char *status;
135
136 if (pjsua.buddies[i].sub == NULL ||
137 pjsua.buddies[i].status.info_cnt==0)
138 {
139 status = " ? ";
140 }
141 else if (pjsua.buddies[i].status.info[0].basic_open)
142 status = " Online";
143 else
144 status = "Offline";
145
146 printf(" [%2d] <%s> %s\n",
147 i+1, status, pjsua.buddies[i].uri.ptr);
148 }
149 }
150 puts("");
151}
Benny Prijonof3195072006-02-14 21:15:30 +0000152
Benny Prijonoa91a0032006-02-26 21:23:45 +0000153
Benny Prijono632ce712006-02-09 14:01:40 +0000154/*
Benny Prijonoa91a0032006-02-26 21:23:45 +0000155 * Print account status.
Benny Prijono632ce712006-02-09 14:01:40 +0000156 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000157static void print_acc_status(int acc_index)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000158{
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000159 char reg_status[128];
Benny Prijono834aee32006-02-19 01:38:06 +0000160
Benny Prijonoa91a0032006-02-26 21:23:45 +0000161 if (pjsua.acc[acc_index].regc == NULL) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000162 pj_ansi_strcpy(reg_status, " -not registered to server-");
Benny Prijonoa91a0032006-02-26 21:23:45 +0000163
164 } else if (pjsua.acc[acc_index].reg_last_err != PJ_SUCCESS) {
165 pj_strerror(pjsua.acc[acc_index].reg_last_err, reg_status, sizeof(reg_status));
166
167 } else if (pjsua.acc[acc_index].reg_last_code>=200 &&
168 pjsua.acc[acc_index].reg_last_code<=699) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000169
170 pjsip_regc_info info;
171
Benny Prijonoa91a0032006-02-26 21:23:45 +0000172 pjsip_regc_get_info(pjsua.acc[acc_index].regc, &info);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000173
174 pj_snprintf(reg_status, sizeof(reg_status),
175 "%s (%.*s;expires=%d)",
Benny Prijonoa91a0032006-02-26 21:23:45 +0000176 pjsip_get_status_text(pjsua.acc[acc_index].reg_last_code)->ptr,
Benny Prijono26ff9062006-02-21 23:47:00 +0000177 (int)info.client_uri.slen,
178 info.client_uri.ptr,
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000179 info.next_reg);
180
181 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000182 pj_sprintf(reg_status, "in progress (%d)",
183 pjsua.acc[acc_index].reg_last_code);
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000184 }
185
Benny Prijonoa91a0032006-02-26 21:23:45 +0000186 printf("[%2d] Registration status: %s\n", acc_index, reg_status);
187 printf(" Online status: %s\n",
188 (pjsua.acc[acc_index].online_status ? "Online" : "Invisible"));
189}
190
191/*
192 * Show a bit of help.
193 */
194static void keystroke_help(void)
195{
196 int i;
197
198 printf(">>>>\n");
199
200 for (i=0; i<pjsua.acc_cnt; ++i)
201 print_acc_status(i);
202
Benny Prijono834aee32006-02-19 01:38:06 +0000203 print_buddy_list();
204
205 //puts("Commands:");
206 puts("+=============================================================================+");
207 puts("| Call Commands: | IM & Presence: | Misc: |");
208 puts("| | | |");
209 puts("| m Make new call | i Send IM | o Send OPTIONS |");
Benny Prijono26ff9062006-02-21 23:47:00 +0000210 puts("| a Answer call | s Subscribe presence | rr (Re-)register |");
211 puts("| h Hangup call | u Unsubscribe presence | ru Unregister |");
212 puts("| ] Select next dialog | t ToGgle Online status | d Dump status |");
Benny Prijonoa91a0032006-02-26 21:23:45 +0000213 puts("| [ Select previous dialog | | dc Dump config |");
Benny Prijono26ff9062006-02-21 23:47:00 +0000214 puts("| +--------------------------+-------------------+");
215 puts("| H Hold call | Conference Command | |");
216 puts("| v re-inVite (release hold) | cl List ports | |");
217 puts("| x Xfer call | cc Connect port | |");
Benny Prijono06c70942006-02-22 12:06:39 +0000218 puts("| # Send DTMF string | cd Disconnect port | |");
Benny Prijono26ff9062006-02-21 23:47:00 +0000219 puts("+------------------------------+--------------------------+-------------------+");
Benny Prijono834aee32006-02-19 01:38:06 +0000220 puts("| q QUIT |");
221 puts("+=============================================================================+");
222 printf(">>> ");
223
224
Benny Prijono1a01ad32006-02-07 21:13:28 +0000225 fflush(stdout);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000226}
227
Benny Prijono834aee32006-02-19 01:38:06 +0000228
229/*
230 * Input simple string
231 */
232static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len)
Benny Prijono38998232006-02-08 22:44:25 +0000233{
234 char *p;
235
236 printf("%s (empty to cancel): ", title); fflush(stdout);
237 fgets(buf, len, stdin);
238
239 /* Remove trailing newlines. */
240 for (p=buf; ; ++p) {
241 if (*p=='\r' || *p=='\n') *p='\0';
242 else if (!*p) break;
243 }
244
245 if (!*buf)
246 return PJ_FALSE;
247
248 return PJ_TRUE;
249}
250
Benny Prijono834aee32006-02-19 01:38:06 +0000251
252#define NO_NB -2
253struct input_result
254{
255 int nb_result;
256 char *uri_result;
257};
258
259
260/*
261 * Input URL.
262 */
263static void ui_input_url(const char *title, char *buf, int len,
264 struct input_result *result)
265{
266 result->nb_result = NO_NB;
267 result->uri_result = NULL;
268
269 print_buddy_list();
270
271 printf("Choices:\n"
272 " 0 For current dialog.\n"
273 " -1 All %d buddies in buddy list\n"
274 " [1 -%2d] Select from buddy list\n"
275 " URL An URL\n"
276 " <Enter> Empty input (or 'q') to cancel\n"
277 , pjsua.buddy_cnt, pjsua.buddy_cnt);
278 printf("%s: ", title);
279
280 fflush(stdout);
281 fgets(buf, len, stdin);
282 len = strlen(buf);
283
284 /* Left trim */
285 while (isspace(*buf)) {
286 ++buf;
287 --len;
288 }
289
290 /* Remove trailing newlines */
291 while (len && (buf[len-1] == '\r' || buf[len-1] == '\n'))
292 buf[--len] = '\0';
293
294 if (len == 0 || buf[0]=='q')
295 return;
296
297 if (isdigit(*buf) || *buf=='-') {
298
299 int i;
300
301 if (*buf=='-')
302 i = 1;
303 else
304 i = 0;
305
306 for (; i<len; ++i) {
307 if (!isdigit(buf[i])) {
308 puts("Invalid input");
309 return;
310 }
311 }
312
313 result->nb_result = atoi(buf);
314
315 if (result->nb_result > 0 && result->nb_result <= (int)pjsua.buddy_cnt) {
316 --result->nb_result;
317 return;
318 }
319 if (result->nb_result == -1)
320 return;
321
322 puts("Invalid input");
323 result->nb_result = NO_NB;
324 return;
325
326 } else {
327 pj_status_t status;
328
329 if ((status=pjsua_verify_sip_url(buf)) != PJ_SUCCESS) {
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000330 pjsua_perror(THIS_FILE, "Invalid URL", status);
Benny Prijono834aee32006-02-19 01:38:06 +0000331 return;
332 }
333
334 result->uri_result = buf;
335 }
336}
337
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000338static void conf_list(void)
339{
Benny Prijono39879152006-02-23 02:09:10 +0000340 unsigned i, count;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000341 pjmedia_conf_port_info info[PJSUA_MAX_CALLS];
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000342
343 printf("Conference ports:\n");
344
Benny Prijono39879152006-02-23 02:09:10 +0000345 count = PJ_ARRAY_SIZE(info);
346 pjmedia_conf_get_ports_info(pjsua.mconf, &count, info);
347 for (i=0; i<count; ++i) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000348 char txlist[PJSUA_MAX_CALLS*4+10];
349 int j;
Benny Prijono39879152006-02-23 02:09:10 +0000350 pjmedia_conf_port_info *port_info = &info[i];
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000351
Benny Prijono39879152006-02-23 02:09:10 +0000352 txlist[0] = '\0';
Benny Prijonoa91a0032006-02-26 21:23:45 +0000353 for (j=0; j<pjsua.max_calls+PJSUA_CONF_MORE_PORTS; ++j) {
Benny Prijono39879152006-02-23 02:09:10 +0000354 char s[10];
355 if (port_info->listener[j]) {
356 pj_sprintf(s, "#%d ", j);
357 pj_ansi_strcat(txlist, s);
358 }
359 }
Benny Prijono2f8992b2006-02-25 21:16:36 +0000360 printf("Port #%02d %20.*s transmitting to: %s\n",
Benny Prijono39879152006-02-23 02:09:10 +0000361 port_info->slot,
362 (int)port_info->name.slen,
363 port_info->name.ptr,
364 txlist);
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000365
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000366 }
Benny Prijono39879152006-02-23 02:09:10 +0000367 puts("");
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000368}
369
370
Benny Prijono268ca612006-02-07 12:34:11 +0000371static void ui_console_main(void)
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000372{
Benny Prijono834aee32006-02-19 01:38:06 +0000373 char menuin[10];
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000374 char buf[128];
Benny Prijono834aee32006-02-19 01:38:06 +0000375 struct input_result result;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000376
Benny Prijono834aee32006-02-19 01:38:06 +0000377 //keystroke_help();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000378
Benny Prijono268ca612006-02-07 12:34:11 +0000379 for (;;) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000380
Benny Prijono834aee32006-02-19 01:38:06 +0000381 keystroke_help();
382 fgets(menuin, sizeof(menuin), stdin);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000383
Benny Prijono834aee32006-02-19 01:38:06 +0000384 switch (menuin[0]) {
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000385
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000386 case 'm':
Benny Prijono268ca612006-02-07 12:34:11 +0000387 /* Make call! : */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000388 printf("(You currently have %d calls)\n", pjsua.call_cnt);
Benny Prijono834aee32006-02-19 01:38:06 +0000389
390 ui_input_url("Make call", buf, sizeof(buf), &result);
391 if (result.nb_result != NO_NB) {
392 if (result.nb_result == -1)
393 puts("You can't do that with make call!");
394 else
Benny Prijonoa91a0032006-02-26 21:23:45 +0000395 pjsua_make_call( current_acc,
396 pjsua.buddies[result.nb_result].uri.ptr,
397 NULL);
Benny Prijono834aee32006-02-19 01:38:06 +0000398 } else if (result.uri_result)
Benny Prijonoa91a0032006-02-26 21:23:45 +0000399 pjsua_make_call( current_acc, result.uri_result, NULL);
Benny Prijono834aee32006-02-19 01:38:06 +0000400
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000401 break;
Benny Prijono268ca612006-02-07 12:34:11 +0000402
403
Benny Prijono38998232006-02-08 22:44:25 +0000404 case 'a':
405
Benny Prijonoa91a0032006-02-26 21:23:45 +0000406 if (current_call == -1 ||
407 pjsua.calls[current_call].inv->role != PJSIP_ROLE_UAS ||
408 pjsua.calls[current_call].inv->state >= PJSIP_INV_STATE_CONNECTING)
Benny Prijono38998232006-02-08 22:44:25 +0000409 {
410 puts("No pending incoming call");
411 fflush(stdout);
412 continue;
413
414 } else {
415 pj_status_t status;
416 pjsip_tx_data *tdata;
417
Benny Prijono834aee32006-02-19 01:38:06 +0000418 if (!simple_input("Answer with code (100-699)", buf, sizeof(buf)))
Benny Prijono38998232006-02-08 22:44:25 +0000419 continue;
420
Benny Prijonof3195072006-02-14 21:15:30 +0000421 if (atoi(buf) < 100)
422 continue;
423
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000424 /*
425 * Must check again!
426 * Call may have been disconnected while we're waiting for
427 * keyboard input.
428 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000429 if (current_call == -1) {
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000430 puts("Call has been disconnected");
431 fflush(stdout);
432 continue;
433 }
434
Benny Prijonoa91a0032006-02-26 21:23:45 +0000435 status = pjsip_inv_answer(pjsua.calls[current_call].inv,
436 atoi(buf),
Benny Prijono834aee32006-02-19 01:38:06 +0000437 NULL, NULL, &tdata);
Benny Prijono38998232006-02-08 22:44:25 +0000438 if (status == PJ_SUCCESS)
Benny Prijonoa91a0032006-02-26 21:23:45 +0000439 status = pjsip_inv_send_msg(pjsua.calls[current_call].inv,
440 tdata, NULL);
Benny Prijono38998232006-02-08 22:44:25 +0000441
442 if (status != PJ_SUCCESS)
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000443 pjsua_perror(THIS_FILE, "Unable to create/send response",
444 status);
Benny Prijono38998232006-02-08 22:44:25 +0000445 }
446
447 break;
448
Benny Prijono834aee32006-02-19 01:38:06 +0000449
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000450 case 'h':
Benny Prijono268ca612006-02-07 12:34:11 +0000451
Benny Prijonoa91a0032006-02-26 21:23:45 +0000452 if (current_call == -1) {
Benny Prijono268ca612006-02-07 12:34:11 +0000453 puts("No current call");
Benny Prijono1a01ad32006-02-07 21:13:28 +0000454 fflush(stdout);
Benny Prijono268ca612006-02-07 12:34:11 +0000455 continue;
456
457 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000458 pjsua_call_hangup(current_call, PJSIP_SC_DECLINE);
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000459 }
Benny Prijono834aee32006-02-19 01:38:06 +0000460 break;
Benny Prijono268ca612006-02-07 12:34:11 +0000461
Benny Prijono834aee32006-02-19 01:38:06 +0000462 case ']':
Benny Prijono26ff9062006-02-21 23:47:00 +0000463 case '[':
464 /*
465 * Cycle next/prev dialog.
466 */
467 if (menuin[0] == ']') {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000468 find_next_call();
Benny Prijono26ff9062006-02-21 23:47:00 +0000469
470 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000471 find_prev_call();
Benny Prijono26ff9062006-02-21 23:47:00 +0000472 }
473
Benny Prijonoa91a0032006-02-26 21:23:45 +0000474 if (current_call != -1) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000475 char url[PJSIP_MAX_URL_SIZE];
476 int len;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000477 const pjsip_uri *u;
Benny Prijono26ff9062006-02-21 23:47:00 +0000478
Benny Prijonoa91a0032006-02-26 21:23:45 +0000479 u = pjsua.calls[current_call].inv->dlg->remote.info->uri;
480 len = pjsip_uri_print(0, u, url, sizeof(url)-1);
Benny Prijono26ff9062006-02-21 23:47:00 +0000481 if (len < 1) {
482 pj_ansi_strcpy(url, "<uri is too long>");
483 } else {
484 url[len] = '\0';
485 }
486
487 PJ_LOG(3,(THIS_FILE,"Current dialog: %s", url));
488
489 } else {
490 PJ_LOG(3,(THIS_FILE,"No current dialog"));
491 }
Benny Prijono834aee32006-02-19 01:38:06 +0000492 break;
493
Benny Prijono26ff9062006-02-21 23:47:00 +0000494 case 'H':
495 /*
496 * Hold call.
497 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000498 if (current_call != -1) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000499
Benny Prijonoa91a0032006-02-26 21:23:45 +0000500 pjsua_call_set_hold(current_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000501
502 } else {
503 PJ_LOG(3,(THIS_FILE, "No current call"));
504 }
505 break;
506
507 case 'v':
508 /*
509 * Send re-INVITE (to release hold, etc).
510 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000511 if (current_call != -1) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000512
Benny Prijonoa91a0032006-02-26 21:23:45 +0000513 pjsua_call_reinvite(current_call);
Benny Prijono26ff9062006-02-21 23:47:00 +0000514
515 } else {
516 PJ_LOG(3,(THIS_FILE, "No current call"));
517 }
518 break;
519
520 case 'x':
521 /*
522 * Transfer call.
523 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000524 if (current_call == -1) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000525
526 PJ_LOG(3,(THIS_FILE, "No current call"));
527
528 } else {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000529 int call = current_call;
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000530
Benny Prijono26ff9062006-02-21 23:47:00 +0000531 ui_input_url("Transfer to URL", buf, sizeof(buf), &result);
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000532
533 /* Check if call is still there. */
534
Benny Prijonoa91a0032006-02-26 21:23:45 +0000535 if (call != current_call) {
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000536 puts("Call has been disconnected");
537 continue;
538 }
539
Benny Prijono26ff9062006-02-21 23:47:00 +0000540 if (result.nb_result != NO_NB) {
541 if (result.nb_result == -1)
542 puts("You can't do that with transfer call!");
543 else
Benny Prijonoa91a0032006-02-26 21:23:45 +0000544 pjsua_call_xfer( current_call,
545 pjsua.buddies[result.nb_result].uri.ptr);
Benny Prijono26ff9062006-02-21 23:47:00 +0000546
547 } else if (result.uri_result) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000548 pjsua_call_xfer( current_call, result.uri_result);
Benny Prijono26ff9062006-02-21 23:47:00 +0000549 }
550 }
Benny Prijono834aee32006-02-19 01:38:06 +0000551 break;
552
Benny Prijono06c70942006-02-22 12:06:39 +0000553 case '#':
554 /*
555 * Send DTMF strings.
556 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000557 if (current_call == -1) {
Benny Prijono06c70942006-02-22 12:06:39 +0000558
559 PJ_LOG(3,(THIS_FILE, "No current call"));
560
Benny Prijonoa91a0032006-02-26 21:23:45 +0000561 } else if (pjsua.calls[current_call].session == NULL) {
Benny Prijono06c70942006-02-22 12:06:39 +0000562
563 PJ_LOG(3,(THIS_FILE, "Media is not established yet!"));
564
565 } else {
566 pj_str_t digits;
Benny Prijonoa91a0032006-02-26 21:23:45 +0000567 int call = current_call;
Benny Prijono06c70942006-02-22 12:06:39 +0000568 pj_status_t status;
569
570 if (!simple_input("DTMF strings to send (0-9*#A-B)", buf,
571 sizeof(buf)))
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000572 {
Benny Prijono06c70942006-02-22 12:06:39 +0000573 break;
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000574 }
575
Benny Prijonoa91a0032006-02-26 21:23:45 +0000576 if (call != current_call) {
Benny Prijonoe16f86c2006-02-23 18:03:29 +0000577 puts("Call has been disconnected");
578 continue;
579 }
Benny Prijono06c70942006-02-22 12:06:39 +0000580
581 digits = pj_str(buf);
Benny Prijonoa91a0032006-02-26 21:23:45 +0000582 status = pjmedia_session_dial_dtmf(pjsua.calls[current_call].session, 0,
Benny Prijono06c70942006-02-22 12:06:39 +0000583 &digits);
584 if (status != PJ_SUCCESS) {
585 pjsua_perror(THIS_FILE, "Unable to send DTMF", status);
586 } else {
587 puts("DTMF digits enqueued for transmission");
588 }
589 }
590 break;
591
Benny Prijono834aee32006-02-19 01:38:06 +0000592 case 's':
593 case 'u':
Benny Prijono26ff9062006-02-21 23:47:00 +0000594 /*
595 * Subscribe/unsubscribe presence.
596 */
597 ui_input_url("(un)Subscribe presence of", buf, sizeof(buf), &result);
Benny Prijono834aee32006-02-19 01:38:06 +0000598 if (result.nb_result != NO_NB) {
599 if (result.nb_result == -1) {
Benny Prijonoa91a0032006-02-26 21:23:45 +0000600 int i;
Benny Prijono834aee32006-02-19 01:38:06 +0000601 for (i=0; i<pjsua.buddy_cnt; ++i)
602 pjsua.buddies[i].monitor = (menuin[0]=='s');
603 } else {
604 pjsua.buddies[result.nb_result].monitor = (menuin[0]=='s');
605 }
606
Benny Prijonoa91a0032006-02-26 21:23:45 +0000607 pjsua_pres_refresh(current_acc);
Benny Prijono834aee32006-02-19 01:38:06 +0000608
609 } else if (result.uri_result) {
Benny Prijono26ff9062006-02-21 23:47:00 +0000610 puts("Sorry, can only subscribe to buddy's presence, "
611 "not arbitrary URL (for now)");
Benny Prijono834aee32006-02-19 01:38:06 +0000612 }
613
614 break;
615
Benny Prijono26ff9062006-02-21 23:47:00 +0000616 case 'r':
617 switch (menuin[1]) {
618 case 'r':
619 /*
620 * Re-Register.
621 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000622 pjsua_regc_update(current_acc, PJ_TRUE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000623 break;
624 case 'u':
625 /*
626 * Unregister
627 */
Benny Prijonoa91a0032006-02-26 21:23:45 +0000628 pjsua_regc_update(current_acc, PJ_FALSE);
Benny Prijono26ff9062006-02-21 23:47:00 +0000629 break;
630 }
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000631 break;
632
Benny Prijono834aee32006-02-19 01:38:06 +0000633 case 't':
Benny Prijonoa91a0032006-02-26 21:23:45 +0000634 pjsua.acc[current_acc].online_status =
635 !pjsua.acc[current_acc].online_status;
636 pjsua_pres_refresh(current_acc);
Benny Prijono834aee32006-02-19 01:38:06 +0000637 break;
638
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000639 case 'c':
640 switch (menuin[1]) {
641 case 'l':
642 conf_list();
643 break;
644 case 'c':
645 case 'd':
646 {
647 char src_port[10], dst_port[10];
648 pj_status_t status;
Benny Prijono26ff9062006-02-21 23:47:00 +0000649 const char *src_title, *dst_title;
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000650
Benny Prijono26ff9062006-02-21 23:47:00 +0000651 conf_list();
652
653 src_title = (menuin[1]=='c'?
654 "Connect src port #":
655 "Disconnect src port #");
656 dst_title = (menuin[1]=='c'?
657 "To dst port #":
658 "From dst port #");
659
660 if (!simple_input(src_title, src_port, sizeof(src_port)))
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000661 break;
Benny Prijono26ff9062006-02-21 23:47:00 +0000662
663 if (!simple_input(dst_title, dst_port, sizeof(dst_port)))
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000664 break;
665
666 if (menuin[1]=='c') {
Benny Prijono26ff9062006-02-21 23:47:00 +0000667 status = pjmedia_conf_connect_port(pjsua.mconf,
668 atoi(src_port),
669 atoi(dst_port));
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000670 } else {
Benny Prijono26ff9062006-02-21 23:47:00 +0000671 status = pjmedia_conf_disconnect_port(pjsua.mconf,
672 atoi(src_port),
673 atoi(dst_port));
Benny Prijonof04ffdd2006-02-21 00:11:18 +0000674 }
675 if (status == PJ_SUCCESS) {
676 puts("Success");
677 } else {
678 puts("ERROR!!");
679 }
680 }
681 break;
682 }
683 break;
684
Benny Prijono834aee32006-02-19 01:38:06 +0000685 case 'd':
Benny Prijonoa91a0032006-02-26 21:23:45 +0000686 if (menuin[1] == 'c') {
687 char settings[2000];
688 int len;
689
690 len = pjsua_dump_settings(settings, sizeof(settings));
691 if (len < 1)
692 PJ_LOG(3,(THIS_FILE, "Error: not enough buffer"));
693 else
694 PJ_LOG(3,(THIS_FILE,
695 "Dumping configuration (%d bytes):\n%s\n",
696 len, settings));
697 } else {
698 pjsua_dump();
699 }
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000700 break;
Benny Prijono268ca612006-02-07 12:34:11 +0000701
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000702 case 'q':
703 goto on_exit;
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000704 }
705 }
706
707on_exit:
Benny Prijono268ca612006-02-07 12:34:11 +0000708 ;
709}
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000710
Benny Prijonoccf95622006-02-07 18:48:01 +0000711
712/*****************************************************************************
713 * This is a very simple PJSIP module, whose sole purpose is to display
714 * incoming and outgoing messages to log. This module will have priority
715 * higher than transport layer, which means:
716 *
717 * - incoming messages will come to this module first before reaching
718 * transaction layer.
719 *
720 * - outgoing messages will come to this module last, after the message
721 * has been 'printed' to contiguous buffer by transport layer and
722 * appropriate transport instance has been decided for this message.
723 *
724 */
725
726/* Notification on incoming messages */
Benny Prijono268ca612006-02-07 12:34:11 +0000727static pj_bool_t console_on_rx_msg(pjsip_rx_data *rdata)
728{
729 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n"
730 "%s\n"
731 "--end msg--",
732 rdata->msg_info.len,
733 pjsip_rx_data_get_info(rdata),
734 rdata->pkt_info.src_name,
735 rdata->pkt_info.src_port,
736 rdata->msg_info.msg_buf));
737
Benny Prijonoccf95622006-02-07 18:48:01 +0000738 /* Always return false, otherwise messages will not get processed! */
Benny Prijono268ca612006-02-07 12:34:11 +0000739 return PJ_FALSE;
740}
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000741
Benny Prijonoccf95622006-02-07 18:48:01 +0000742/* Notification on outgoing messages */
Benny Prijono268ca612006-02-07 12:34:11 +0000743static pj_status_t console_on_tx_msg(pjsip_tx_data *tdata)
744{
Benny Prijonoccf95622006-02-07 18:48:01 +0000745
746 /* Important note:
747 * tp_info field is only valid after outgoing messages has passed
748 * transport layer. So don't try to access tp_info when the module
749 * has lower priority than transport layer.
750 */
751
Benny Prijono268ca612006-02-07 12:34:11 +0000752 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n"
753 "%s\n"
754 "--end msg--",
755 (tdata->buf.cur - tdata->buf.start),
756 pjsip_tx_data_get_info(tdata),
757 tdata->tp_info.dst_name,
758 tdata->tp_info.dst_port,
759 tdata->buf.start));
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000760
Benny Prijonoccf95622006-02-07 18:48:01 +0000761 /* Always return success, otherwise message will not get sent! */
Benny Prijono268ca612006-02-07 12:34:11 +0000762 return PJ_SUCCESS;
763}
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000764
Benny Prijonoccf95622006-02-07 18:48:01 +0000765/* The module instance. */
Benny Prijono268ca612006-02-07 12:34:11 +0000766static pjsip_module console_msg_logger =
767{
768 NULL, NULL, /* prev, next. */
Benny Prijono834aee32006-02-19 01:38:06 +0000769 { "mod-pjsua-log", 13 }, /* Name. */
Benny Prijono268ca612006-02-07 12:34:11 +0000770 -1, /* Id */
771 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
Benny Prijono268ca612006-02-07 12:34:11 +0000772 NULL, /* load() */
773 NULL, /* start() */
774 NULL, /* stop() */
775 NULL, /* unload() */
776 &console_on_rx_msg, /* on_rx_request() */
777 &console_on_rx_msg, /* on_rx_response() */
778 &console_on_tx_msg, /* on_tx_request. */
779 &console_on_tx_msg, /* on_tx_response() */
780 NULL, /* on_tsx_state() */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000781
Benny Prijono268ca612006-02-07 12:34:11 +0000782};
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000783
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000784
Benny Prijonoccf95622006-02-07 18:48:01 +0000785
786/*****************************************************************************
787 * Console application custom logging:
788 */
789
790
791static FILE *log_file;
792
793
794static void app_log_writer(int level, const char *buffer, int len)
795{
796 /* Write to both stdout and file. */
797
798 if (level <= pjsua.app_log_level)
799 pj_log_write(level, buffer, len);
800
801 if (log_file) {
802 fwrite(buffer, len, 1, log_file);
803 fflush(log_file);
804 }
805}
806
807
808void app_logging_init(void)
809{
810 /* Redirect log function to ours */
811
812 pj_log_set_log_func( &app_log_writer );
813
814 /* If output log file is desired, create the file: */
815
816 if (pjsua.log_filename)
817 log_file = fopen(pjsua.log_filename, "wt");
818}
819
820
821void app_logging_shutdown(void)
822{
823 /* Close logging file, if any: */
824
825 if (log_file) {
826 fclose(log_file);
827 log_file = NULL;
828 }
829}
830
831/*****************************************************************************
Benny Prijonof3195072006-02-14 21:15:30 +0000832 * Error display:
Benny Prijonoccf95622006-02-07 18:48:01 +0000833 */
834
Benny Prijonoccf95622006-02-07 18:48:01 +0000835/*
Benny Prijonof3195072006-02-14 21:15:30 +0000836 * Display error message for the specified error code.
Benny Prijonoccf95622006-02-07 18:48:01 +0000837 */
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000838void pjsua_perror(const char *sender, const char *title,
839 pj_status_t status)
Benny Prijonoccf95622006-02-07 18:48:01 +0000840{
Benny Prijonof3195072006-02-14 21:15:30 +0000841 char errmsg[PJ_ERR_MSG_SIZE];
Benny Prijonoccf95622006-02-07 18:48:01 +0000842
Benny Prijonof3195072006-02-14 21:15:30 +0000843 pj_strerror(status, errmsg, sizeof(errmsg));
Benny Prijonoccf95622006-02-07 18:48:01 +0000844
Benny Prijonobcaed6c2006-02-19 15:37:19 +0000845 PJ_LOG(1,(sender, "%s: %s [code=%d]", title, errmsg, status));
Benny Prijonoccf95622006-02-07 18:48:01 +0000846}
847
848
Benny Prijonoccf95622006-02-07 18:48:01 +0000849
850
851/*****************************************************************************
852 * main():
853 */
854int main(int argc, char *argv[])
Benny Prijono268ca612006-02-07 12:34:11 +0000855{
Benny Prijono2f8992b2006-02-25 21:16:36 +0000856
Benny Prijono268ca612006-02-07 12:34:11 +0000857 /* Init default settings. */
Benny Prijono268ca612006-02-07 12:34:11 +0000858 pjsua_default();
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000859
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000860
Benny Prijonoccf95622006-02-07 18:48:01 +0000861 /* Initialize pjsua (to create pool etc).
Benny Prijono268ca612006-02-07 12:34:11 +0000862 */
Benny Prijono268ca612006-02-07 12:34:11 +0000863 if (pjsua_init() != PJ_SUCCESS)
864 return 1;
865
Benny Prijonoccf95622006-02-07 18:48:01 +0000866
867 /* Parse command line arguments: */
Benny Prijonof3195072006-02-14 21:15:30 +0000868 if (pjsua_parse_args(argc, argv) != PJ_SUCCESS)
Benny Prijonoccf95622006-02-07 18:48:01 +0000869 return 1;
870
871
872 /* Init logging: */
Benny Prijonoccf95622006-02-07 18:48:01 +0000873 app_logging_init();
874
875
Benny Prijono268ca612006-02-07 12:34:11 +0000876 /* Register message logger to print incoming and outgoing
877 * messages.
878 */
Benny Prijono268ca612006-02-07 12:34:11 +0000879 pjsip_endpt_register_module(pjsua.endpt, &console_msg_logger);
880
881
Benny Prijonoccf95622006-02-07 18:48:01 +0000882 /* Start pjsua! */
Benny Prijonoccf95622006-02-07 18:48:01 +0000883 if (pjsua_start() != PJ_SUCCESS) {
884
885 pjsua_destroy();
886 return 1;
887 }
888
889
Benny Prijono268ca612006-02-07 12:34:11 +0000890 /* Sleep for a while, let any messages get printed to console: */
Benny Prijono268ca612006-02-07 12:34:11 +0000891 pj_thread_sleep(500);
892
893
894 /* Start UI console main loop: */
Benny Prijono268ca612006-02-07 12:34:11 +0000895 ui_console_main();
896
897
898 /* Destroy pjsua: */
Benny Prijono268ca612006-02-07 12:34:11 +0000899 pjsua_destroy();
900
Benny Prijonoccf95622006-02-07 18:48:01 +0000901
902 /* Close logging: */
Benny Prijonoccf95622006-02-07 18:48:01 +0000903 app_logging_shutdown();
904
905
Benny Prijono268ca612006-02-07 12:34:11 +0000906 /* Exit... */
Benny Prijono5dcb38d2005-11-21 01:55:47 +0000907
908 return 0;
909}
910