int tdd_feed(struct tdd_state *tdd, unsigned char *ubuf, int len) { int mylen = len; int olen; int b = 'X'; int res; int c,x; short *buf = ast_calloc(1, 2 * len + tdd->oldlen); short *obuf = buf; if (!buf) { ast_log(LOG_WARNING, "Out of memory\n"); return -1; } memcpy(buf, tdd->oldstuff, tdd->oldlen); mylen += tdd->oldlen / 2; for (x = 0; x < len; x++) buf[x + tdd->oldlen / 2] = AST_MULAW(ubuf[x]); c = res = 0; while (mylen >= 1320) { /* has to have enough to work on */ olen = mylen; res = fsk_serial(&tdd->fskd, buf, &mylen, &b); if (mylen < 0) { ast_log(LOG_ERROR, "fsk_serial made mylen < 0 (%d) (olen was %d)\n", mylen, olen); ast_free(obuf); return -1; } buf += (olen - mylen); if (res < 0) { ast_log(LOG_NOTICE, "fsk_serial failed\n"); ast_free(obuf); return -1; } if (res == 1) { /* Ignore invalid bytes */ if (b > 0x7f) continue; c = tdd_decode_baudot(tdd, b); if ((c < 1) || (c > 126)) continue; /* if not valid */ break; } } if (mylen) { memcpy(tdd->oldstuff, buf, mylen * 2); tdd->oldlen = mylen * 2; } else tdd->oldlen = 0; ast_free(obuf); if (res) { tdd->mode = 2; /* put it in mode where it reliably puts teleprinter in correct shift mode */ return(c); } return 0; }
int callerid_feed(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec) { int mylen = len; int olen; int b = 'X'; int res; int x; short *buf; buf = ast_alloca(2 * len + cid->oldlen); memcpy(buf, cid->oldstuff, cid->oldlen); mylen += cid->oldlen/2; for (x = 0; x < len; x++) buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]); while (mylen >= 160) { olen = mylen; res = fsk_serial(&cid->fskd, buf, &mylen, &b); if (mylen < 0) { ast_log(LOG_ERROR, "No start bit found in fsk data.\n"); return -1; } buf += (olen - mylen); if (res < 0) { ast_log(LOG_NOTICE, "fsk_serial failed\n"); return -1; } if (res == 1) { if (b > 0xff) { if (cid->sawflag != 5) { /* Ignore invalid bytes */ continue; } /* * We can tollerate an error on the checksum character since the * checksum character is the last character in the message and * it validates the message. * * Remove character error flags. * Bit 8 : Parity error * Bit 9 : Framing error */ b &= 0xff; } switch (cid->sawflag) { case 0: /* Look for flag */ if (b == 'U') cid->sawflag = 2; break; case 2: /* Get lead-in */ if ((b == 0x04) || (b == 0x80) || (b == 0x06) || (b == 0x82)) { cid->type = b; cid->sawflag = 3; cid->cksum = b; } break; case 3: /* Get length */ /* Not a lead in. We're ready */ cid->sawflag = 4; cid->len = b; cid->pos = 0; cid->cksum += b; break; case 4: /* Retrieve message */ if (cid->pos >= 128) { ast_log(LOG_WARNING, "Caller ID too long???\n"); return -1; } cid->rawdata[cid->pos++] = b; cid->len--; cid->cksum += b; if (!cid->len) { cid->rawdata[cid->pos] = '\0'; cid->sawflag = 5; } break; case 5: /* Check checksum */ if ((b + cid->cksum) & 0xff) { ast_log(LOG_NOTICE, "Caller*ID failed checksum\n"); /* Try again */ cid->sawflag = 0; break; } cid->number[0] = '\0'; cid->name[0] = '\0'; /* Update flags */ cid->flags = 0; /* If we get this far we're fine. */ if ((cid->type == 0x80) || (cid->type == 0x82)) { /* MDMF */ /* Go through each element and process */ for (x = 0; x < cid->pos;) { switch (cid->rawdata[x++]) { case 1: /* Date */ break; case 2: /* Number */ case 3: /* Number (for Zebble) */ case 4: /* Number */ res = cid->rawdata[x]; if (res > 32) { ast_log(LOG_NOTICE, "Truncating long caller ID number from %d bytes to 32\n", cid->rawdata[x]); res = 32; } if (ast_strlen_zero(cid->number)) { memcpy(cid->number, cid->rawdata + x + 1, res); /* Null terminate */ cid->number[res] = '\0'; } break; case 6: /* Stentor Call Qualifier (ie. Long Distance call) */ break; case 7: /* Name */ case 8: /* Name */ res = cid->rawdata[x]; if (res > 32) { ast_log(LOG_NOTICE, "Truncating long caller ID name from %d bytes to 32\n", cid->rawdata[x]); res = 32; } memcpy(cid->name, cid->rawdata + x + 1, res); cid->name[res] = '\0'; break; case 11: /* Message Waiting */ res = cid->rawdata[x + 1]; if (res) cid->flags |= CID_MSGWAITING; else cid->flags |= CID_NOMSGWAITING; break; case 17: /* UK: Call type, 1=Voice Call, 2=Ringback when free, 129=Message waiting */ case 19: /* UK: Network message system status (Number of messages waiting) */ case 22: /* Something French */ break; default: ast_log(LOG_NOTICE, "Unknown IE %d\n", cid->rawdata[x - 1]); } res = cid->rawdata[x]; if (0 > res){ /* Negative offset in the CID Spill */ ast_log(LOG_NOTICE, "IE %d has bad field length of %d at offset %d\n", cid->rawdata[x-1], cid->rawdata[x], x); /* Try again */ cid->sawflag = 0; break; /* Exit the loop */ } x += cid->rawdata[x]; x++; } } else if (cid->type == 0x6) { /* VMWI SDMF */ if (cid->rawdata[2] == 0x42) { cid->flags |= CID_MSGWAITING; } else if (cid->rawdata[2] == 0x6f) { cid->flags |= CID_NOMSGWAITING; } } else { /* SDMF */ ast_copy_string(cid->number, cid->rawdata + 8, sizeof(cid->number)); } if (!strcmp(cid->number, "P")) { strcpy(cid->number, ""); cid->flags |= CID_PRIVATE_NUMBER; } else if (!strcmp(cid->number, "O") || ast_strlen_zero(cid->number)) { strcpy(cid->number, ""); cid->flags |= CID_UNKNOWN_NUMBER; } if (!strcmp(cid->name, "P")) { strcpy(cid->name, ""); cid->flags |= CID_PRIVATE_NAME; } else if (!strcmp(cid->name, "O") || ast_strlen_zero(cid->name)) { strcpy(cid->name, ""); cid->flags |= CID_UNKNOWN_NAME; } return 1; break; default: ast_log(LOG_ERROR, "Dunno what to do with a digit in sawflag %d\n", cid->sawflag); } } } if (mylen) { memcpy(cid->oldstuff, buf, mylen * 2); cid->oldlen = mylen * 2; } else cid->oldlen = 0; return 0; }
int callerid_feed_jp(struct callerid_state *cid, unsigned char *ubuf, int len, format_t codec) { int mylen = len; int olen; int b = 'X'; int b2; int res; int x; short *buf; buf = ast_alloca(2 * len + cid->oldlen); memcpy(buf, cid->oldstuff, cid->oldlen); mylen += cid->oldlen / 2; for (x = 0; x < len; x++) buf[x+cid->oldlen/2] = AST_XLAW(ubuf[x]); while (mylen >= 160) { b = b2 = 0; olen = mylen; res = fsk_serial(&cid->fskd, buf, &mylen, &b); if (mylen < 0) { ast_log(LOG_ERROR, "No start bit found in fsk data.\n"); return -1; } buf += (olen - mylen); if (res < 0) { ast_log(LOG_NOTICE, "fsk_serial failed\n"); return -1; } if (res == 1) { b2 = b; b &= 0x7f; /* crc checksum calculation */ if (cid->sawflag > 1) cid->crc = calc_crc(cid->crc, (unsigned char) b2); /* Ignore invalid bytes */ if (b > 0xff) continue; /* skip DLE if needed */ if (cid->sawflag > 0) { if (cid->sawflag != 5 && cid->skipflag == 0 && b == 0x10) { cid->skipflag = 1 ; continue ; } } if (cid->skipflag == 1) cid->skipflag = 0 ; /* caller id retrieval */ switch (cid->sawflag) { case 0: /* DLE */ if (b == 0x10) { cid->sawflag = 1; cid->skipflag = 0; cid->crc = 0; } break; case 1: /* SOH */ if (b == 0x01) cid->sawflag = 2; break ; case 2: /* HEADER */ if (b == 0x07) cid->sawflag = 3; break; case 3: /* STX */ if (b == 0x02) cid->sawflag = 4; break; case 4: /* SERVICE TYPE */ if (b == 0x40) cid->sawflag = 5; break; case 5: /* Frame Length */ cid->sawflag = 6; break; case 6: /* NUMBER TYPE */ cid->sawflag = 7; cid->pos = 0; cid->rawdata[cid->pos++] = b; break; case 7: /* NUMBER LENGTH */ cid->sawflag = 8; cid->len = b; if ((cid->len+2) >= sizeof(cid->rawdata)) { ast_log(LOG_WARNING, "too long caller id string\n") ; return -1; } cid->rawdata[cid->pos++] = b; break; case 8: /* Retrieve message */ cid->rawdata[cid->pos++] = b; cid->len--; if (cid->len<=0) { cid->rawdata[cid->pos] = '\0'; cid->sawflag = 9; } break; case 9: /* ETX */ cid->sawflag = 10; break; case 10: /* CRC Checksum 1 */ cid->sawflag = 11; break; case 11: /* CRC Checksum 2 */ cid->sawflag = 12; if (cid->crc != 0) { ast_log(LOG_WARNING, "crc checksum error\n") ; return -1; } /* extract caller id data */ for (x = 0; x < cid->pos;) { switch (cid->rawdata[x++]) { case 0x02: /* caller id number */ cid->number[0] = '\0'; cid->name[0] = '\0'; cid->flags = 0; res = cid->rawdata[x++]; ast_copy_string(cid->number, &cid->rawdata[x], res+1); x += res; break; case 0x21: /* additional information */ /* length */ x++; /* number type */ switch (cid->rawdata[x]) { case 0x00: /* unknown */ case 0x01: /* international number */ case 0x02: /* domestic number */ case 0x03: /* network */ case 0x04: /* local call */ case 0x06: /* short dial number */ case 0x07: /* reserved */ default: /* reserved */ ast_debug(2, "cid info:#1=%X\n", (unsigned)cid->rawdata[x]); break ; } x++; /* numbering plan octed 4 */ x++; /* numbering plan octed 5 */ switch (cid->rawdata[x]) { case 0x00: /* unknown */ case 0x01: /* recommendation E.164 ISDN */ case 0x03: /* recommendation X.121 */ case 0x04: /* telex dial plan */ case 0x08: /* domestic dial plan */ case 0x09: /* private dial plan */ case 0x05: /* reserved */ default: /* reserved */ ast_debug(2, "cid info:#2=%X\n", (unsigned)cid->rawdata[x]); break ; } x++; break ; case 0x04: /* no callerid reason */ /* length */ x++; /* no callerid reason code */ switch (cid->rawdata[x]) { case 'P': /* caller id denied by user */ case 'O': /* service not available */ case 'C': /* pay phone */ case 'S': /* service congested */ cid->flags |= CID_UNKNOWN_NUMBER; ast_debug(2, "no cid reason:%c\n", cid->rawdata[x]); break ; } x++; break ; case 0x09: /* dialed number */ /* length */ res = cid->rawdata[x++]; /* dialed number */ x += res; break ; case 0x22: /* dialed number additional information */ /* length */ x++; /* number type */ switch (cid->rawdata[x]) { case 0x00: /* unknown */ case 0x01: /* international number */ case 0x02: /* domestic number */ case 0x03: /* network */ case 0x04: /* local call */ case 0x06: /* short dial number */ case 0x07: /* reserved */ default: /* reserved */ if (option_debug > 1) ast_log(LOG_NOTICE, "did info:#1=%X\n", (unsigned)cid->rawdata[x]); break ; } x++; /* numbering plan octed 4 */ x++; /* numbering plan octed 5 */ switch (cid->rawdata[x]) { case 0x00: /* unknown */ case 0x01: /* recommendation E.164 ISDN */ case 0x03: /* recommendation X.121 */ case 0x04: /* telex dial plan */ case 0x08: /* domestic dial plan */ case 0x09: /* private dial plan */ case 0x05: /* reserved */ default: /* reserved */ ast_debug(2, "did info:#2=%X\n", (unsigned)cid->rawdata[x]); break ; } x++; break ; } } return 1; break; default: ast_log(LOG_ERROR, "invalid value in sawflag %d\n", cid->sawflag); } } } if (mylen) { memcpy(cid->oldstuff, buf, mylen * 2); cid->oldlen = mylen * 2; } else cid->oldlen = 0; return 0; }