/* Pop up a message, end the transfer. */ void ft_complete(const char *errmsg) { /* Close the local file. */ if (fts.local_file != NULL && fclose(fts.local_file) < 0) { popup_an_errno(errno, "close(%s)", ftc->local_filename); } fts.local_file = NULL; /* Clean up the state. */ ft_state = FT_NONE; if (ft_start_id != NULL_IOID) { RemoveTimeOut(ft_start_id); ft_start_id = NULL_IOID; } /* Get the idle timeout going again. */ idle_ft_complete(); /* Pop down the in-progress shell. */ ft_gui_progress_popdown(); /* Pop up the text. */ if (errmsg != NULL) { char *msg_copy = NewString(errmsg); /* Make sure the error message will fit on the pop-up. */ ft_gui_errmsg_prepare(msg_copy); /* Clear out the progress display. */ ft_gui_clear_progress(); /* Pop up the error. */ popup_an_error("%s", msg_copy); Free(msg_copy); } else { struct timeval t1; double bytes_sec; char *buf; (void) gettimeofday(&t1, NULL); bytes_sec = (double)fts.length / ((double)(t1.tv_sec - t0.tv_sec) + (double)(t1.tv_usec - t0.tv_usec) / 1.0e6); buf = xs_buffer(get_message("ftComplete"), fts.length, display_scale(bytes_sec), fts.is_cut ? "CUT" : "DFT"); ft_gui_clear_progress(); ft_gui_complete_popup(buf); Free(buf); } /* I hope I can do this unconditionally. */ sms_continue(); }
/* Check for a trace file rollover event. */ void trace_rollover_check(void) { if (tracef == NULL || tracef_max == 0) return; /* See if we've reached a rollover point. */ if (tracef_size >= tracef_max) { char *alt_filename; char *new_header; #if defined(_WIN32) /*[*/ char *period; #endif /*]*/ /* Close up this file. */ wtrace("Trace rolled over\n"); fclose(tracef); tracef = NULL; /* Unlink and rename the alternate file. */ #if defined(_WIN32) /*[*/ period = strrchr(tracefile_name, '.'); if (period != CN) alt_filename = xs_buffer("%.*s-%s", period - tracefile_name, tracefile_name, period); else #endif /*]*/ alt_filename = xs_buffer("%s-", tracefile_name); (void) unlink(alt_filename); (void) rename(tracefile_name, alt_filename); Free(alt_filename); alt_filename = CN; tracef = fopen(tracefile_name, "w"); if (tracef == (FILE *)NULL) { popup_an_errno(errno, "%s", tracefile_name); return; } /* Initialize it. */ tracef_size = 0L; (void) SETLINEBUF(tracef); new_header = create_tracefile_header("rolled over"); do_ts = True; wtrace(new_header); Free(new_header); } }
/* * Start up a window to monitor the trace file. * * @param[in] path Trace file path. On Unix, this can be NULL to indicate * that the trace is just being piped. * @param[in] pipefd Array of pipe file descriptors. */ static void start_trace_window(const char *path, int pipefd[]) { switch (tracewindow_pid = fork_child()) { case 0: /* child process */ (void) execlp("xterm", "xterm", "-title", path? path: "trace", "-sb", "-e", "/bin/sh", "-c", xs_buffer("cat <&%d", pipefd[0]), NULL); (void) perror("exec(xterm) failed"); _exit(1); break; default: /* parent */ (void) close(pipefd[0]); ++children; break; case -1: /* error */ popup_an_errno(errno, "fork() failed"); break; } }
/* Callback for "OK" button on trace popup */ static void tracefile_callback(Widget w, XtPointer client_data, XtPointer call_data _is_unused) { char *tfn = CN; int devfd = -1; #if defined(X3270_DISPLAY) /*[*/ int pipefd[2]; Boolean just_piped = False; #endif /*]*/ char *buf; #if defined(X3270_DISPLAY) /*[*/ if (w) tfn = XawDialogGetValueString((Widget)client_data); else #endif /*]*/ tfn = (char *)client_data; tfn = do_subst(tfn, DS_VARS | DS_TILDE | DS_UNIQUE); if (strchr(tfn, '\'') || ((int)strlen(tfn) > 0 && tfn[strlen(tfn)-1] == '\\')) { popup_an_error("Illegal file name: %s", tfn); Free(tfn); goto done; } tracef_max = 0; if (!strcmp(tfn, "stdout")) { tracef = stdout; } else { #if defined(X3270_DISPLAY) /*[*/ FILE *pipefile = NULL; if (!strcmp(tfn, "none") || !tfn[0]) { just_piped = True; if (!appres.trace_monitor) { popup_an_error("Must specify a trace file " "name"); free(tfn); goto done; } } if (appres.trace_monitor) { if (pipe(pipefd) < 0) { popup_an_errno(errno, "pipe() failed"); Free(tfn); goto done; } pipefile = fdopen(pipefd[1], "w"); if (pipefile == NULL) { popup_an_errno(errno, "fdopen() failed"); (void) close(pipefd[0]); (void) close(pipefd[1]); Free(tfn); goto done; } (void) SETLINEBUF(pipefile); (void) fcntl(pipefd[1], F_SETFD, 1); } if (just_piped) { tracef = pipefile; } else #endif /*]*/ { Boolean append = False; #if defined(X3270_DISPLAY) /*[*/ tracef_pipe = pipefile; #endif /*]*/ /* Get the trace file maximum. */ get_tracef_max(); /* Open and configure the file. */ if ((devfd = get_devfd(tfn)) >= 0) tracef = fdopen(dup(devfd), "a"); else if (!strncmp(tfn, ">>", 2)) { append = True; tracef = fopen(tfn + 2, "a"); } else tracef = fopen(tfn, "w"); if (tracef == (FILE *)NULL) { popup_an_errno(errno, "%s", tfn); #if defined(X3270_DISPLAY) /*[*/ fclose(tracef_pipe); (void) close(pipefd[0]); (void) close(pipefd[1]); #endif /*]*/ Free(tfn); goto done; } tracef_size = ftello(tracef); Replace(tracefile_name, NewString(append? tfn + 2: tfn)); (void) SETLINEBUF(tracef); #if !defined(_WIN32) /*[*/ (void) fcntl(fileno(tracef), F_SETFD, 1); #endif /*]*/ } } #if defined(X3270_DISPLAY) /*[*/ /* Start the monitor window */ if (tracef != stdout && appres.trace_monitor) { switch (tracewindow_pid = fork_child()) { case 0: /* child process */ { char cmd[64]; (void) snprintf(cmd, sizeof(cmd), "cat <&%d", pipefd[0]); (void) execlp("xterm", "xterm", "-title", just_piped? "trace": tfn, "-sb", "-e", "/bin/sh", "-c", cmd, CN); } (void) perror("exec(xterm) failed"); _exit(1); default: /* parent */ (void) close(pipefd[0]); ++children; break; case -1: /* error */ popup_an_errno(errno, "fork() failed"); break; } } #endif /*]*/ #if defined(_WIN32) && defined(C3270) /*[*/ /* Start the monitor window. */ if (tracef != stdout && appres.trace_monitor && is_installed) { STARTUPINFO startupinfo; PROCESS_INFORMATION process_information; char *path; char *args; (void) memset(&startupinfo, '\0', sizeof(STARTUPINFO)); startupinfo.cb = sizeof(STARTUPINFO); startupinfo.lpTitle = tfn; (void) memset(&process_information, '\0', sizeof(PROCESS_INFORMATION)); path = xs_buffer("%scatf.exe", instdir); args = xs_buffer("\"%scatf.exe\" \"%s\"", instdir, tfn); if (CreateProcess( path, args, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupinfo, &process_information) == 0) { popup_an_error("CreateProcess(%s) failed: %s", path, win32_strerror(GetLastError())); Free(path); Free(args); } else { Free(path); Free(args); tracewindow_handle = process_information.hProcess; CloseHandle(process_information.hThread); } } #endif /*]*/ Free(tfn); /* We're really tracing, turn the flag on. */ appres.toggle[trace_reason].value = True; appres.toggle[trace_reason].changed = True; menubar_retoggle(&appres.toggle[trace_reason], trace_reason); /* Display current status. */ buf = create_tracefile_header("started"); do_ts = False; wtrace("%s", buf); Free(buf); done: #if defined(X3270_DISPLAY) /*[*/ if (w) XtPopdown(trace_shell); #endif /*]*/ return; }
/* * Write to the trace file, varargs style. * This is the only function that actually does output to the trace file -- * all others are wrappers around this function. */ static void vwtrace(const char *fmt, va_list args) { if (tracef_bufptr != CN) { tracef_bufptr += vsprintf(tracef_bufptr, fmt, args); /* XXX */ } else if (tracef != NULL) { int n2w, nw; char buf[16384]; struct timeval tv; time_t t; struct tm *tm; /* Start with a timestamp. */ if (do_ts) { (void) gettimeofday(&tv, NULL); t = tv.tv_sec; tm = localtime(&t); n2w = snprintf(buf, sizeof(buf), "%d%02d%02d.%02d%02d%02d.%03d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000L)); (void) fwrite(buf, n2w, 1, tracef); fflush(tracef); if (tracef_pipe != NULL) { (void) fwrite(buf, n2w, 1, tracef_pipe); fflush(tracef); } do_ts = False; } (void) vsnprintf(buf, sizeof(buf), fmt, args); n2w = strlen(buf); if (n2w > 0 && buf[n2w - 1] == '\n') do_ts = True; nw = fwrite(buf, n2w, 1, tracef); if (nw == 1) { fflush(tracef); } else { if (errno != EPIPE #if defined(EILSEQ) /*[*/ && errno != EILSEQ #endif /*]*/ ) popup_an_errno(errno, "Write to trace file failed"); #if defined(EILSEQ) /*[*/ if (errno != EILSEQ) #endif /*]*/ { stop_tracing(); return; } } tracef_size = ftello(tracef); if (tracef_pipe != NULL) { nw = fwrite(buf, n2w, 1, tracef_pipe); if (nw != 1) { (void) fclose(tracef_pipe); tracef_pipe = NULL; } else { fflush(tracef_pipe); } } } }
/* Start tracing, using the specified file. */ void tracefile_ok(const char *tfn) { int devfd = -1; #if !defined(_WIN32) /*[*/ int pipefd[2]; bool just_piped = false; #endif /*]*/ char *buf; char *stfn; stfn = do_subst(tfn, DS_VARS | DS_TILDE | DS_UNIQUE); if (strchr(stfn, '\'') || ((int)strlen(stfn) > 0 && stfn[strlen(stfn)-1] == '\\')) { popup_an_error("Illegal file name: %s", tfn); Free(stfn); goto done; } tracef_max = 0; if (!strcmp(stfn, "stdout")) { tracef = stdout; } else { #if !defined(_WIN32) /*[*/ FILE *pipefile = NULL; if (!strcmp(stfn, "none") || !stfn[0]) { just_piped = true; if (!appres.trace_monitor) { popup_an_error("Must specify a trace file name"); free(stfn); goto done; } } if (appres.trace_monitor) { if (pipe(pipefd) < 0) { popup_an_errno(errno, "pipe() failed"); Free(stfn); goto done; } pipefile = fdopen(pipefd[1], "w"); if (pipefile == NULL) { popup_an_errno(errno, "fdopen() failed"); (void) close(pipefd[0]); (void) close(pipefd[1]); Free(stfn); goto done; } (void) SETLINEBUF(pipefile); (void) fcntl(pipefd[1], F_SETFD, 1); } if (just_piped) { tracef = pipefile; } else #endif /*]*/ { bool append = false; #if !defined(_WIN32) /*[*/ tracef_pipe = pipefile; #endif /*]*/ /* Get the trace file maximum. */ get_tracef_max(); /* Open and configure the file. */ if ((devfd = get_devfd(stfn)) >= 0) tracef = fdopen(dup(devfd), "a"); else if (!strncmp(stfn, ">>", 2)) { append = true; tracef = fopen(stfn + 2, "a"); } else { tracef = fopen(stfn, "w"); } if (tracef == NULL) { popup_an_errno(errno, "%s", stfn); #if !defined(_WIN32) /*[*/ fclose(tracef_pipe); (void) close(pipefd[0]); (void) close(pipefd[1]); #endif /*]*/ Free(stfn); goto done; } tracef_size = ftello(tracef); Replace(tracefile_name, NewString(append? stfn + 2: stfn)); (void) SETLINEBUF(tracef); #if !defined(_WIN32) /*[*/ (void) fcntl(fileno(tracef), F_SETFD, 1); #endif /*]*/ } } /* Start the monitor window. */ if (tracef != stdout && appres.trace_monitor && product_has_display()) { #if !defined(_WIN32) /*[*/ start_trace_window(just_piped? NULL: stfn, pipefd); #else /*][*/ if (windirs_flags && GD_CATF) { start_trace_window(stfn); } #endif /*]*/ } Free(stfn); /* We're really tracing, turn the flag on. */ set_toggle(trace_reason, true); menubar_retoggle(trace_reason); /* Display current status. */ buf = create_tracefile_header("started"); wtrace(false, "%s", buf); Free(buf); done: return; }
/* * Write to the trace file, varargs style. * This is the only function that actually does output to the trace file -- * all others are wrappers around this function. */ static void vwtrace(bool do_ts, const char *fmt, va_list args) { size_t n2w_left, n2w, nw; char *ts; char *buf = NULL; char *bp; /* Ugly hack to write into a memory buffer. */ if (tracef_bufptr != NULL) { if (do_ts) { tracef_bufptr += sprintf(tracef_bufptr, "%s", gen_ts()); } tracef_bufptr += vsprintf(tracef_bufptr, fmt, args); return; } if (tracef == NULL) { return; } ts = NULL; buf = xs_vbuffer(fmt, args); n2w_left = strlen(buf); bp = buf; while (n2w_left > 0) { char *nl; bool wrote_nl = false; if (do_ts && !wrote_ts) { if (ts == NULL) { ts = gen_ts(); } (void) fwrite(ts, strlen(ts), 1, tracef); fflush(tracef); if (tracef_pipe != NULL) { (void) fwrite(ts, strlen(ts), 1, tracef_pipe); fflush(tracef); } wrote_ts = true; } nl = strchr(bp, '\n'); if (nl != NULL) { wrote_nl = true; n2w = nl - bp + 1; } else { n2w = n2w_left; } nw = fwrite(bp, n2w, 1, tracef); if (nw == 1) { fflush(tracef); } else { if (errno != EPIPE && !IS_EILSEQ(errno)) { popup_an_errno(errno, "Write to trace file failed"); } if (!IS_EILSEQ(errno)) { stop_tracing(); goto done; } } if (tracef_pipe != NULL) { nw = fwrite(bp, n2w, 1, tracef_pipe); if (nw != 1) { (void) fclose(tracef_pipe); tracef_pipe = NULL; } else { fflush(tracef_pipe); } } if (wrote_nl) { wrote_ts = false; } bp += n2w; n2w_left -= n2w; } tracef_size = ftello(tracef); done: if (buf != NULL) { Free(buf); } return; }
/* * Screen tracing callback. * Returns true for success, false for failure. */ static bool screentrace_cb(tss_t how, ptype_t ptype, char *tfn) { char *xtfn = NULL; int srv; if (how == TSS_FILE) { xtfn = do_subst(tfn, DS_VARS | DS_TILDE | DS_UNIQUE); screentracef = fopen(xtfn, "a"); } else { /* Printer. */ #if !defined(_WIN32) /*[*/ screentracef = popen(tfn, "w"); #else /*][*/ int fd; fd = win_mkstemp(&screentrace_tmpfn, ptype); if (fd < 0) { popup_an_errno(errno, "%s", "(temporary file)"); Free(tfn); return false; } screentracef = fdopen(fd, (ptype == P_GDI)? "wb+": "w"); #endif /*]*/ } if (screentracef == NULL) { if (how == TSS_FILE) popup_an_errno(errno, "%s", xtfn); else #if !defined(_WIN32) /*[*/ popup_an_errno(errno, "%s", tfn); #else /*][*/ popup_an_errno(errno, "%s", "(temporary file)"); #endif /*]*/ Free(xtfn); #if defined(_WIN32) /*[*/ Free(screentrace_tmpfn); screentrace_tmpfn = NULL; #endif /*]*/ return false; } if (how == TSS_FILE) Replace(screentrace_name, NewString(xtfn)); else Replace(screentrace_name, NewString(tfn)); Free(tfn); (void) SETLINEBUF(screentracef); #if !defined(_WIN32) /*[*/ (void) fcntl(fileno(screentracef), F_SETFD, 1); #endif /*]*/ srv = fprint_screen_start(screentracef, ptype, (how == TSS_PRINTER)? FPS_FF_SEP: 0, default_caption(), screentrace_name, &screentrace_fps); if (FPS_IS_ERROR(srv)) { if (srv == FPS_STATUS_ERROR) { popup_an_error("Screen trace start failed."); } else if (srv == FPS_STATUS_CANCEL) { popup_an_error("Screen trace canceled."); } fclose(screentracef); return false; } /* We're really tracing, turn the flag on. */ set_toggle(SCREEN_TRACE, true); menubar_retoggle(SCREEN_TRACE); return true; }
/* * Start a file transfer, based on the contents of an ft_state structure. * * This function will fail if the file exists and the overwrite flag is not * set. * * Returns the local file pointer, or NULL if the transfer could not start. * If an error is detected, it will call popup_an_error() with an appropriate * message. */ FILE * ft_go(ft_conf_t *p) { FILE *f; varbuf_t r; unsigned flen; /* Adjust the DFT buffer size. */ p->dft_buffersize = set_dft_buffersize(p->dft_buffersize); /* See if the local file can be overwritten. */ if (p->receive_flag && !p->append_flag && !p->allow_overwrite) { f = fopen(p->local_filename, p->ascii_flag? "r": "rb"); if (f != NULL) { (void) fclose(f); popup_an_error("Transfer: File exists"); return NULL; } } /* Open the local file. */ f = fopen(p->local_filename, ft_local_fflag(p)); if (f == NULL) { popup_an_errno(errno, "Local file '%s'", p->local_filename); return NULL; } /* Build the ind$file command */ vb_init(&r); vb_appendf(&r, "IND\\e005BFILE %s %s %s", p->receive_flag? "GET": "PUT", p->host_filename, (p->host_type != HT_TSO)? "(": ""); if (p->ascii_flag) { vb_appends(&r, "ASCII"); } else if (p->host_type == HT_CICS) { vb_appends(&r, "BINARY"); } if (p->ascii_flag && p->cr_flag) { vb_appends(&r, " CRLF"); } else if (p->host_type == HT_CICS) { vb_appends(&r, " NOCRLF"); } if (p->append_flag && !p->receive_flag) { vb_appends(&r, " APPEND"); } if (!p->receive_flag) { if (p->host_type == HT_TSO) { if (p->recfm != DEFAULT_RECFM) { /* RECFM Entered, process */ vb_appends(&r, " RECFM("); switch (p->recfm) { case RECFM_FIXED: vb_appends(&r, "F"); break; case RECFM_VARIABLE: vb_appends(&r, "V"); break; case RECFM_UNDEFINED: vb_appends(&r, "U"); break; default: break; }; vb_appends(&r, ")"); if (p->lrecl) { vb_appendf(&r, " LRECL(%d)", p->lrecl); } if (p->blksize) { vb_appendf(&r, " BLKSIZE(%d)", p->blksize); } } if (p->units != DEFAULT_UNITS) { /* Space Entered, processs it */ vb_appendf(&r, " SPACE(%d", p->primary_space); if (p->secondary_space) { vb_appendf(&r, ",%d", p->secondary_space); } vb_appends(&r, ")"); switch (p->units) { case TRACKS: vb_appends(&r, " TRACKS"); break; case CYLINDERS: vb_appends(&r, " CYLINDERS"); break; case AVBLOCK: vb_appendf(&r, " AVBLOCK(%d)", p->avblock); break; default: break; } } } else if (p->host_type == HT_VM) { if (p->recfm != DEFAULT_RECFM) { vb_appends(&r, " RECFM "); switch (p->recfm) { case RECFM_FIXED: vb_appends(&r, "F"); break; case RECFM_VARIABLE: vb_appends(&r, "V"); break; default: break; }; if (p->lrecl) { vb_appendf(&r, " LRECL %d", p->lrecl); } } } } vb_appends(&r, "\\n"); /* Erase the line and enter the command. */ flen = kybd_prime(); if (!flen || flen < vb_len(&r) - 1) { vb_free(&r); if (f != NULL) { fclose(f); if (p->receive_flag && !p->append_flag) { unlink(p->local_filename); } } popup_an_error("%s", get_message("ftUnable")); return NULL; } (void) emulate_input(vb_buf(&r), vb_len(&r), false); vb_free(&r); /* Now proceed with this context. */ ftc = p; /* Finish common initialization. */ fts.last_cr = false; fts.is_cut = false; fts.last_dbcs = false; fts.dbcs_state = FT_DBCS_NONE; ft_state = FT_AWAIT_ACK; idle_ft_start(); return f; }