Example #1
0
File: tdd.c Project: GGGO/asterisk
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;
}
Example #2
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;
}
Example #3
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;
}