Skip to content

Commit c1b69d4

Browse files
callerid.c: Parse previously ignored Caller ID parameters.
Commit f2f397c previously made it possible to send Caller ID parameters to FXS stations which, prior to that, could not be sent. This change is complementary in that we now handle receiving all these parameters on FXO lines and provide these up to the dialplan, via chan_dahdi. In particular: * If a redirecting reason is provided, the channel's redirecting reason is set. No redirecting number is set, since there is no parameter for this in the Caller ID protocol, but the reason can be checked to determine if and why a call was forwarded. * If the Call Qualifier parameter is received, the Call Qualifier variable is set. * Some comments have been added to explain why some of the code is the way it is, to assist other people looking at it. With this change, Asterisk's Caller ID implementation is now reasonably complete for both FXS and FXO operation. Resolves: #681
1 parent 57ce1fe commit c1b69d4

File tree

4 files changed

+144
-17
lines changed

4 files changed

+144
-17
lines changed

channels/chan_dahdi.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,7 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
14361436
int res;
14371437
unsigned char buf[256];
14381438
int flags;
1439+
int redirecting;
14391440

14401441
poller.fd = p->subs[SUB_REAL].dfd;
14411442
poller.events = POLLPRI | POLLIN;
@@ -1482,15 +1483,15 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
14821483
}
14831484

14841485
if (res == 1) {
1485-
callerid_get(p->cs, &name, &num, &flags);
1486+
struct ast_channel *chan = analog_p->ss_astchan;
1487+
callerid_get_with_redirecting(p->cs, &name, &num, &flags, &redirecting);
14861488
if (name)
14871489
ast_copy_string(namebuf, name, ANALOG_MAX_CID);
14881490
if (num)
14891491
ast_copy_string(numbuf, num, ANALOG_MAX_CID);
14901492

14911493
if (flags & (CID_PRIVATE_NUMBER | CID_UNKNOWN_NUMBER)) {
14921494
/* If we got a presentation, we must set it on the channel */
1493-
struct ast_channel *chan = analog_p->ss_astchan;
14941495
struct ast_party_caller caller;
14951496

14961497
ast_party_caller_set_init(&caller, ast_channel_caller(chan));
@@ -1499,8 +1500,19 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
14991500
ast_party_caller_set(ast_channel_caller(chan), &caller, NULL);
15001501
ast_party_caller_free(&caller);
15011502
}
1503+
if (redirecting) {
1504+
/* There is a redirecting reason available in the Caller*ID received.
1505+
* No idea what the redirecting number is, since the Caller*ID protocol
1506+
* has no parameter for that, but at least we know WHY it was redirected. */
1507+
ast_channel_redirecting(chan)->reason.code = redirecting;
1508+
}
1509+
1510+
if (flags & CID_QUALIFIER) {
1511+
/* This is the inverse of how the qualifier is set in sig_analog */
1512+
pbx_builtin_setvar_helper(chan, "CALL_QUALIFIER", "1");
1513+
}
15021514

1503-
ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", num, name, flags);
1515+
ast_debug(1, "CallerID number: %s, name: %s, flags=%d, redirecting=%s\n", num, name, flags, ast_redirecting_reason_name(&ast_channel_redirecting(chan)->reason));
15041516
return 0;
15051517
}
15061518
}

funcs/func_callerid.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@
192192
You are responsible for setting it if/when needed.</para>
193193
<para>Supporting Caller ID units will display the LDC
194194
(Long Distance Call) indicator when they receive this parameter.</para>
195+
<para>For incoming calls on FXO ports, if the Call Qualifier parameter is received,
196+
this variable will also be set to 1.</para>
195197
<para>This option must be used with a channel driver
196198
that allows Asterisk to generate the Caller ID spill,
197199
which currently only includes <literal>chan_dahdi</literal>.</para>

include/asterisk/callerid.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,29 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int sample
190190
* \param cid Callerid state machine to act upon
191191
* \param number Pass the address of a pointer-to-char (will contain the phone number)
192192
* \param name Pass the address of a pointer-to-char (will contain the name)
193-
* \param flags Pass the address of an int variable(will contain the various callerid flags)
193+
* \param flags Pass the address of an int variable (will contain the various callerid flags - presentation flags and call qualifier)
194194
*
195195
* \details
196196
* This function extracts a callerid string out of a callerid_state state machine.
197197
* If no number is found, *number will be set to NULL. Likewise for the name.
198-
* Flags can contain any of the following:
198+
* Flags can contain any of the following: CID_PRIVATE_NAME, CID_PRIVATE_NUMBER, CID_UNKNOWN_NAME, CID_UNKNOWN_NUMBER, CID_MSGWAITING, CID_NOMSGWAITING, CID_QUALIFIER
199199
*/
200200
void callerid_get(struct callerid_state *cid, char **number, char **name, int *flags);
201201

202+
/*! \brief Extract info out of callerID state machine. Flags are listed above
203+
* \param cid Callerid state machine to act upon
204+
* \param[out] number Pass the address of a pointer-to-char (will contain the phone number)
205+
* \param[out] name Pass the address of a pointer-to-char (will contain the name)
206+
* \param[out] flags Pass the address of an int variable (will contain the various callerid flags)
207+
* \param[out] redirecting Pass the address of an int variable (will contain the redirecting reason, if received - presentation flags and call qualifier)
208+
*
209+
* \details
210+
* This function extracts a callerid string out of a callerid_state state machine.
211+
* If no number is found, *number will be set to NULL. Likewise for the name.
212+
* Flags can contain any of the following: CID_PRIVATE_NAME, CID_PRIVATE_NUMBER, CID_UNKNOWN_NAME, CID_UNKNOWN_NUMBER, CID_MSGWAITING, CID_NOMSGWAITING, CID_QUALIFIER
213+
*/
214+
void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting);
215+
202216
/*!
203217
* \brief Get and parse DTMF-based callerid
204218
* \param cidstring The actual transmitted string.

main/callerid.c

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct callerid_state {
5353
char name[64];
5454
char number[64];
5555
int flags;
56+
int redirecting;
5657
int sawflag;
5758
int len;
5859

@@ -185,17 +186,26 @@ struct callerid_state *callerid_new(int cid_signalling)
185186
return cid;
186187
}
187188

188-
void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
189+
void callerid_get_with_redirecting(struct callerid_state *cid, char **name, char **number, int *flags, int *redirecting)
189190
{
190191
*flags = cid->flags;
191-
if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME))
192+
if (cid->flags & (CID_UNKNOWN_NAME | CID_PRIVATE_NAME)) {
192193
*name = NULL;
193-
else
194+
} else {
194195
*name = cid->name;
195-
if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER))
196+
}
197+
if (cid->flags & (CID_UNKNOWN_NUMBER | CID_PRIVATE_NUMBER)) {
196198
*number = NULL;
197-
else
199+
} else {
198200
*number = cid->number;
201+
}
202+
*redirecting = cid->redirecting;
203+
}
204+
205+
void callerid_get(struct callerid_state *cid, char **name, char **number, int *flags)
206+
{
207+
int redirecting;
208+
return callerid_get_with_redirecting(cid, name, number, flags, &redirecting);
199209
}
200210

201211
void callerid_get_dtmf(char *cidstring, char *number, int *flags)
@@ -541,6 +551,21 @@ int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, s
541551
return 0;
542552
}
543553

554+
static const char *mdmf_param_name(int param)
555+
{
556+
switch (param) {
557+
case 0x1: return "Date/Time";
558+
case 0x2: return "Caller Number";
559+
case 0x3: return "DNIS";
560+
case 0x4: return "Reason For Absence of Number";
561+
case 0x5: return "Reason For Redirection";
562+
case 0x6: return "Call Qualifier";
563+
case 0x7: return "Name";
564+
case 0x8: return "Reason For Absence of Name";
565+
case 0xB: return "Message Waiting";
566+
default: return "Unknown";
567+
}
568+
}
544569

545570
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, struct ast_format *codec)
546571
{
@@ -631,18 +656,41 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
631656
cid->name[0] = '\0';
632657
/* Update flags */
633658
cid->flags = 0;
659+
cid->redirecting = 0;
634660
/* If we get this far we're fine. */
635661
if ((cid->type == 0x80) || (cid->type == 0x82)) {
636662
/* MDMF */
663+
ast_debug(6, "%s Caller*ID spill received\n", cid->type == 0x80 ? "MDMF" : "MDMF Message Waiting");
637664
/* Go through each element and process */
638665
for (x = 0; x < cid->pos;) {
639-
switch (cid->rawdata[x++]) {
666+
int param = cid->rawdata[x++];
667+
ast_debug(7, "Caller*ID parameter %d (%s), length %d\n", param, mdmf_param_name(param), cid->rawdata[x]);
668+
switch (param) {
640669
case 1:
641-
/* Date */
670+
/* Date/Time... in theory we could synchronize our time according to the Caller*ID,
671+
* but it would be silly for a telephone switch to do that. */
642672
break;
673+
/* For MDMF spills, we would expect to get an "O" or a "P"
674+
* for paramter 4 (or 8) as opposed to 2 (or 7) to indicate
675+
* a blocked or out of area presentation.
676+
* However, for SDMF, which doesn't have parameters,
677+
* there is no differentiation, which is why the logic below
678+
* just checks the number and name field and here, we use the same
679+
* parsing logic for both parameters. Technically, it would be wrong
680+
* to receive an 'O' or 'P' for parameters 2 or 7 and treat it as
681+
* the reason for absence fields, but that is not likely to happen,
682+
* and if it did, could possibly be buggy Caller ID generation we would
683+
* want to treat the same way, anyways.
684+
*
685+
* The "Dialable Directory Number" is how the number would be called back.
686+
* Asterisk doesn't really have a corresponding thing for this,
687+
* so log it if we get it for debugging, but treat the same otherwise.
688+
*/
689+
case 3: /* Dialable Directory Number / Number (for Zebble) */
690+
ast_debug(3, "Caller*ID Dialable Directory Number: '%.*s'\n", cid->rawdata[x], cid->rawdata + x + 1);
691+
/* Fall through */
643692
case 2: /* Number */
644-
case 3: /* Number (for Zebble) */
645-
case 4: /* Number */
693+
case 4: /* Reason for Absence of Number. */
646694
res = cid->rawdata[x];
647695
if (res > 32) {
648696
ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]);
@@ -654,10 +702,43 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
654702
cid->number[res] = '\0';
655703
}
656704
break;
705+
case 5: /* Reason for Redirection */
706+
res = cid->rawdata[x];
707+
if (res != 1) {
708+
ast_log(LOG_WARNING, "Redirecting parameter length is %d?\n", res);
709+
break;
710+
}
711+
switch (*(cid->rawdata + x + 1)) {
712+
case 0x1:
713+
cid->redirecting = AST_REDIRECTING_REASON_USER_BUSY;
714+
break;
715+
case 0x2:
716+
cid->redirecting = AST_REDIRECTING_REASON_NO_ANSWER;
717+
break;
718+
case 0x3:
719+
cid->redirecting = AST_REDIRECTING_REASON_UNCONDITIONAL;
720+
break;
721+
case 0x4:
722+
cid->redirecting = AST_REDIRECTING_REASON_CALL_FWD_DTE;
723+
break;
724+
case 0x5:
725+
cid->redirecting = AST_REDIRECTING_REASON_DEFLECTION;
726+
break;
727+
default:
728+
ast_log(LOG_WARNING, "Redirecting reason is %02x?\n", *(cid->rawdata + x + 1));
729+
break;
730+
}
731+
break;
657732
case 6: /* Stentor Call Qualifier (ie. Long Distance call) */
733+
res = cid->rawdata[x];
734+
if (res == 1 && *(cid->rawdata + x + 1) == 'L') {
735+
cid->flags |= CID_QUALIFIER;
736+
} else if (res >= 1) {
737+
ast_debug(2, "Invalid value (len %d) received for Call Qualifier: '%c'\n", res, *(cid->rawdata + x + 1));
738+
}
658739
break;
659740
case 7: /* Name */
660-
case 8: /* Name */
741+
case 8: /* Reason for Absence of Name */
661742
res = cid->rawdata[x];
662743
if (res > 32) {
663744
ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]);
@@ -692,28 +773,46 @@ int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, stru
692773
}
693774
} else if (cid->type == 0x6) {
694775
/* VMWI SDMF */
776+
ast_debug(6, "VMWI SDMF Caller*ID spill received\n");
695777
if (cid->rawdata[2] == 0x42) {
696778
cid->flags |= CID_MSGWAITING;
697779
} else if (cid->rawdata[2] == 0x6f) {
698780
cid->flags |= CID_NOMSGWAITING;
699781
}
700782
} else {
701783
/* SDMF */
784+
ast_debug(6, "SDMF Caller*ID spill received\n");
702785
ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number));
703786
}
704787
if (!strcmp(cid->number, "P")) {
788+
ast_debug(6, "Caller*ID number is private\n");
705789
strcpy(cid->number, "");
706790
cid->flags |= CID_PRIVATE_NUMBER;
707-
} else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) {
791+
} else if (!strcmp(cid->number, "O")) {
792+
ast_debug(6, "Caller*ID number is out of area\n");
708793
strcpy(cid->number, "");
709794
cid->flags |= CID_UNKNOWN_NUMBER;
795+
} else if (ast_strlen_zero(cid->number)) {
796+
ast_debug(6, "No Caller*ID number provided, and no reason provided for its absence\n");
797+
strcpy(cid->number, "");
798+
cid->flags |= CID_UNKNOWN_NUMBER;
799+
} else {
800+
ast_debug(6, "Caller*ID number is '%s'\n", cid->number);
710801
}
711802
if (!strcmp(cid->name, "P")) {
803+
ast_debug(6, "Caller*ID name is private\n");
712804
strcpy(cid->name, "");
713805
cid->flags |= CID_PRIVATE_NAME;
714-
} else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) {
806+
} else if (!strcmp(cid->name, "O")) {
807+
ast_debug(6, "Caller*ID name is out of area\n");
715808
strcpy(cid->name, "");
716809
cid->flags |= CID_UNKNOWN_NAME;
810+
} else if (ast_strlen_zero(cid->name)) {
811+
ast_debug(6, "No Caller*ID name provided, and no reason provided for its absence\n");
812+
strcpy(cid->name, "");
813+
cid->flags |= CID_UNKNOWN_NAME;
814+
} else {
815+
ast_debug(6, "Caller*ID name is '%s'\n", cid->name);
717816
}
718817
return 1;
719818
break;

0 commit comments

Comments
 (0)