static int txfax_exec(struct ast_channel *chan, void *data) { int res = 0; char source_file[256]; char *x; char *s; char *t; char *v; int option; int len; t30_state_t fax; int calling_party; int verbose; int samples; struct localuser *u; struct ast_frame *inf = NULL; struct ast_frame outf; int original_read_fmt; int original_write_fmt; uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET]; uint8_t *buf = __buf + AST_FRIENDLY_OFFSET; if (chan == NULL) { ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n"); return -1; } span_set_message_handler(span_message); /* The next few lines of code parse out the filename and header from the input string */ if (data == NULL) { /* No data implies no filename or anything is present */ ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n"); return -1; } calling_party = FALSE; verbose = FALSE; source_file[0] = '\0'; for (option = 0, v = s = data; v; option++, s++) { t = s; v = strchr(s, '|'); s = (v) ? v : s + strlen(s); strncpy((char *) buf, t, s - t); buf[s - t] = '\0'; if (option == 0) { /* The first option is always the file name */ len = s - t; if (len > 255) len = 255; strncpy(source_file, t, len); source_file[len] = '\0'; } else if (strncmp("caller", t, s - t) == 0) { calling_party = TRUE; } else if (strncmp("debug", t, s - t) == 0) { verbose = TRUE; } } /* Done parsing */ LOCAL_USER_ADD(u); if (chan->_state != AST_STATE_UP) { /* Shouldn't need this, but checking to see if channel is already answered * Theoretically asterisk should already have answered before running the app */ res = ast_answer(chan); } if (!res) { original_read_fmt = chan->readformat; if (original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n"); return -1; } } original_write_fmt = chan->writeformat; if (original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); if (res < 0) { ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n"); res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); return -1; } } fax_init(&fax, calling_party, NULL); if (verbose) fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"); if (x && x[0]) t30_set_local_ident(&fax, x); x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"); if (x && x[0]) t30_set_header_info(&fax, x); t30_set_tx_file(&fax, source_file, -1, -1); //t30_set_phase_b_handler(&fax, phase_b_handler, chan); //t30_set_phase_d_handler(&fax, phase_d_handler, chan); t30_set_phase_e_handler(&fax, phase_e_handler, chan); while (ast_waitfor(chan, -1) > -1) { inf = ast_read(chan); if (inf == NULL) { res = -1; break; } if (inf->frametype == AST_FRAME_VOICE) { if (fax_rx(&fax, inf->data, inf->samples)) break; samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples); if (len) { memset(&outf, 0, sizeof(outf)); outf.frametype = AST_FRAME_VOICE; outf.subclass = AST_FORMAT_SLINEAR; outf.datalen = len*sizeof(int16_t); outf.samples = len; outf.data = &buf[AST_FRIENDLY_OFFSET]; outf.offset = AST_FRIENDLY_OFFSET; if (ast_write(chan, &outf) < 0) { ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno)); break; } } } ast_frfree(inf); } if (inf == NULL) { ast_log(LOG_DEBUG, "Got hangup\n"); res = -1; } if (original_read_fmt && original_read_fmt != AST_FORMAT_SLINEAR) { res = ast_set_read_format(chan, original_read_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name); } if (original_write_fmt && original_write_fmt != AST_FORMAT_SLINEAR) { res = ast_set_write_format(chan, original_write_fmt); if (res) ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name); } fax_release(&fax); } else { ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name); } LOCAL_USER_REMOVE(u); return res; }
void client_run(int client_socket, char *local_ip, int local_port, char *remote_ip, int remote_port) { char sendbuf[RCVBUFSIZE], recvbuf[RCVBUFSIZE], infobuf[RCVBUFSIZE]; struct sockaddr_in addr = {0}, sendaddr = {0}; int read_bytes; int usock; int reuse_addr = 1; fax_state_t fax; char tmp[512], fn[512], *file_name = "/tmp/test.tiff"; int send_fax = FALSE; int g711 = 0; int pcmu = 0; snprintf(sendbuf, sizeof(sendbuf), "connect\n\n"); send(client_socket, sendbuf, strlen(sendbuf), 0); if ((read_bytes = recv(client_socket, infobuf, sizeof(infobuf), 0)) < 0) { die("recv() failed"); } #if SOCKET2ME_DEBUG printf("READ [%s]\n", infobuf); #endif if (cheezy_get_var(infobuf, "Channel-Read-Codec-Name", tmp, sizeof(tmp))) { if (!strcasecmp(tmp, "pcmu")) { g711 = 1; pcmu = 1; } else if (!strcasecmp(tmp, "pcma")) { g711 = 1; } } snprintf(sendbuf, sizeof(sendbuf), "sendmsg\n" "call-command: unicast\n" "local-ip: %s\n" "local-port: %d\n" "remote-ip: %s\n" "remote-port: %d\n" "transport: udp\n" "%s" "\n", local_ip, local_port, remote_ip, remote_port, g711 ? "flags: native\n" : "" ); if (cheezy_get_var(infobuf, "variable_fax_file_name", fn, sizeof(fn))) { file_name = fn; } if (cheezy_get_var(infobuf, "variable_fax_mode", tmp, sizeof(tmp))) { if (!strcasecmp(tmp, "send")) { send_fax = TRUE; } } if (cheezy_get_var(infobuf, "variable_fax_preexec", tmp, sizeof(tmp))) { set_vars(infobuf); system(tmp); } #if SOCKET2ME_DEBUG printf("SEND: [%s]\n", sendbuf); #endif send(client_socket, sendbuf, strlen(sendbuf), 0); memset(recvbuf, 0, sizeof(recvbuf)); if ((read_bytes = recv(client_socket, recvbuf, sizeof(recvbuf), 0)) < 0) { die("recv() failed"); } #if SOCKET2ME_DEBUG printf("READ [%s]\n", recvbuf); #endif if ((usock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { die("socket() failed"); } setsockopt(usock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); /*addr.sin_addr.s_addr = inet_addr(remote_ip);*/ addr.sin_port = htons(remote_port); sendaddr.sin_family = AF_INET; sendaddr.sin_addr.s_addr = inet_addr(local_ip); sendaddr.sin_port = htons(local_port); if (bind(usock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { die("bind() failed"); } printf("%s Fax filename: [%s] from %s:%d -> %s:%d\n", send_fax ? "Sending" : "Receiving", file_name, local_ip, local_port, remote_ip, remote_port); fax_init(&fax, send_fax); t30_set_local_ident(&fax.t30_state, "Socket 2 ME"); t30_set_header_info(&fax.t30_state, "Socket 2 ME"); if (send_fax) { t30_set_tx_file(&fax.t30_state, file_name, -1, -1); } else { t30_set_rx_file(&fax.t30_state, file_name, -1); } t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, NULL); t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, NULL); t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, NULL); t30_set_document_handler(&fax.t30_state, document_handler, NULL); t30_set_ecm_capability(&fax.t30_state, TRUE); t30_set_supported_compressions(&fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); t30_set_supported_image_sizes(&fax.t30_state, T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH | T30_SUPPORT_215MM_WIDTH | T30_SUPPORT_255MM_WIDTH | T30_SUPPORT_303MM_WIDTH); t30_set_supported_resolutions(&fax.t30_state, T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION | T30_SUPPORT_R8_RESOLUTION | T30_SUPPORT_R16_RESOLUTION); for (;;) { struct sockaddr_in local_addr = {0}; size_t cliAddrLen = sizeof(local_addr); unsigned char audiobuf[1024], rawbuf[1024], outbuf[1024]; short *usebuf = NULL; int tx, tx_bytes, bigger, sample_count; fd_set ready; FD_ZERO(&ready); FD_SET(usock, &ready); FD_SET(client_socket, &ready); bigger = usock > client_socket ? usock : client_socket; select(++bigger, &ready, NULL, NULL, NULL); if (FD_ISSET(client_socket, &ready)) { memset(recvbuf, 0, sizeof(recvbuf)); if ((read_bytes = recv(client_socket, recvbuf, sizeof(recvbuf), 0)) < 0) { die("recv() failed"); } if (read_bytes == 0) { break; } #if SOCKET2ME_DEBUG printf("READ [%s]\n", recvbuf); #endif } if (!FD_ISSET(usock, &ready)) { continue; } if ((read_bytes = recvfrom(usock, audiobuf, sizeof(audiobuf), 0, (struct sockaddr *) &local_addr, &cliAddrLen)) < 0) { die("recvfrom() failed"); } if (g711) { int i; short *rp = (short *) rawbuf; for (i = 0; i < read_bytes; i++) { if (pcmu) { rp[i] = ulaw_to_linear(audiobuf[i]); } else { rp[i] = alaw_to_linear(audiobuf[i]); } } usebuf = rp; sample_count = read_bytes; } else { usebuf = (short *) audiobuf; sample_count = read_bytes / 2; } fax_rx(&fax, usebuf, sample_count); #if SOCKET2ME_DEBUG printf("Handling client %s:%d %d bytes\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port), read_bytes); #endif if ((tx = fax_tx(&fax, (short *)outbuf, sample_count)) < 0) { printf("Fax Error\n"); break; } else if (!tx) { continue; } if (g711) { int i; short *bp = (short *) outbuf; for (i = 0; i < tx; i++) { if (pcmu) { rawbuf[i] = linear_to_ulaw(bp[i]); } else { rawbuf[i] = linear_to_alaw(bp[i]); } } usebuf = (short *) rawbuf; tx_bytes = tx; } else { usebuf = (short *)outbuf; tx_bytes = tx * 2; } cliAddrLen = sizeof(sendaddr); if (sendto(usock, usebuf, tx_bytes, 0, (struct sockaddr *) &sendaddr, sizeof(sendaddr)) != tx_bytes) { die("sendto() sent a different number of bytes than expected"); } } close(client_socket); close(usock); t30_terminate(&fax.t30_state); fax_release(&fax); if (cheezy_get_var(infobuf, "variable_fax_postexec", tmp, sizeof(tmp))) { set_vars(infobuf); system(tmp); } printf("Done\n"); snprintf(sendbuf, sizeof(sendbuf), "hangup\n\n"); send(client_socket, sendbuf, strlen(sendbuf), 0); }