/* * Receive files with Zmodem, Ymodem or Xmodem. * This receiver will figure out what to do, you should * be able to send anything. */ int zmrcvfiles(int want1k, int wantg) { int rc; Syslog('+', "%s: start receive", protname()); get_frame_buffer(); Rxtimeout = 10; if (secbuf == NULL) secbuf = malloc(MAXBLOCK+1); tryzhdrtype = ZRINIT; if ((rc = tryz()) < 0) { Syslog('+', "%s: could not initiate receive, rc=%d", protname(), rc); } else { if (rc == 0) { if (protocol == ZM_ZMODEM) { Syslog('+', "%s: switching to Ymodem", protname()); protocol = ZM_YMODEM; } rc = ymrcvfiles(want1k, wantg); goto fubar; } /* * Zmodem receiver */ switch (rc) { case ZCOMPL: rc = 0; break; case ZFILE: rc = rzfiles(); break; } } fubar: if (fout) { if (closeit(0)) { WriteError("%s: Error closing file", protname); } } if (secbuf) free(secbuf); secbuf = NULL; io_mode(0, 1); /* Normal raw mode */ /* * Some programs send some garbage after the transfer, eat these. * This also introduces a pause after the transfer, some clients * need this. */ purgeline(200); Syslog('+', "%s: end receive rc=%d", protname(), rc); return abs(rc); }
/* send cancel string to get the other end to shut up */ void canit(int fd, int *func_write(int, char *, int)) { static char canistr[] = { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0 }; purgeline(0); (*func_write) (fd, canistr, strlen(canistr)); }
static int wctx(struct zm_fileinfo *zi) { register size_t thisblklen; register int sectnum, attempts, firstch; firstsec = TRUE; thisblklen = blklen; while ((firstch = READLINE_PF(Rxtimeout)) != NAK && firstch != WANTCRC && firstch != WANTG && firstch != TIMEOUT && firstch != CAN); if (firstch == CAN) { return ERROR; } if (firstch == WANTCRC) Crcflg = TRUE; if (firstch == WANTG) Crcflg = TRUE; sectnum = 0; for (;;) { if (zi->bytes_total <= (zi->bytes_sent + 896L)) thisblklen = 128; if (!filbuf(txbuf, thisblklen)) break; if (wcputsec(txbuf, ++sectnum, thisblklen) == ERROR) return ERROR; zi->bytes_sent += thisblklen; } fclose(input_f); attempts = 0; do { purgeline(io_mode_fd); sendline(EOT); flushmo(); ++attempts; } while ((firstch = (READLINE_PF(Rxtimeout)) != ACK) && attempts < RETRYMAX); if (attempts == RETRYMAX) { return ERROR; } else return OK; }
/* * Ack a ZFIN packet, let byegones be byegones */ static void ackbibi(void) { int n; vfile("ackbibi:"); Readnum = 1; stohdr(0L); for (n = 3; --n >= 0;) { purgeline(); zshhdr(ZFIN, Txhdr); switch (readline(100)) { case 'O': readline(1); /* Discard 2nd 'O' */ vfile("ackbibi complete"); return; case RCDO: return; case TIMEOUT: default: break; } } }
int bbs_zsendfile(char *filename, char *remote) { struct stat f; if (stat(filename, &f) != 0) return ERROR; Totalleft = f.st_size; Filesleft = 1; calc_blklen(Totalleft); protocol = ZM_ZMODEM; io_mode_fd = 1; blklen = start_blklen = 1024; if (setjmp(zmodemjmp) == 0) { zsendline_init(); io_mode(io_mode_fd, 1); readline_setup(io_mode_fd, 128, 256); raw_write(0, "rz\r", 3); /* TODO : throw away received input */ purgeline(io_mode_fd); stohdr(0L); zshhdr(ZRQINIT, Txhdr); zrqinits_sent++; oflush(); Crcflg = FALSE; firstsec = TRUE; bytcnt = (size_t) - 1; Totsecs = 0; if (wcs(filename, remote) == ERROR) { readline_clean(); return ERROR; } if (zmodem_requested) saybibi(); else if (protocol != ZM_XMODEM) { struct zm_fileinfo zi; char *pa; pa = (char *)malloc(PATH_MAX + 1); *pa = '\0'; zi.fname = pa; zi.modtime = 0; zi.mode = 0; zi.bytes_total = 0; zi.bytes_sent = 0; zi.bytes_received = 0; zi.bytes_skipped = 0; wctxpn(&zi); free(pa); } oflush(); /* here needs a oflush */ /* eat avalible input */ /* better to eat some input here */ io_mode(io_mode_fd, 0); readline_clean(); } else { oflush(); signal(SIGALRM, SIG_IGN); alarm(0); return ERROR; } return OK; }
/* * Download files to the user. * Returns: * 0 - All seems well * 1 - No transfer protocol selected * 2 - No files to download. */ int download(down_list *download_list) { down_list *tmpf; int err, maxrc = 0, Count = 0; char *temp, *symTo, *symFrom; unsigned int Size = 0; struct dirent *dp; DIR *dirp; struct timeval starttime, endtime; struct timezone tz; Syslog('b', "download()"); for (tmpf = download_list; tmpf; tmpf = tmpf->next) { Syslog('b', "%s,%s,%ld,%ld,%ld,%s,%s,%s", tmpf->local, tmpf->remote, tmpf->cps, tmpf->area, tmpf->size, tmpf->kfs ?"KFS":"KEEP", tmpf->sent ?"SENT":"N/A", tmpf->failed ?"FAILED":"N/A"); } /* * If user has no default protocol, make sure he has one. */ if (!ForceProtocol()) { return 1; } symTo = calloc(PATH_MAX, sizeof(char)); symFrom = calloc(PATH_MAX, sizeof(char)); temp = calloc(PATH_MAX, sizeof(char)); /* * Build symlinks into the users tag directory. */ chdir("./tag"); for (tmpf = download_list; tmpf; tmpf = tmpf->next) { if (!tmpf->sent && !tmpf->failed) { snprintf(symFrom, PATH_MAX, "%s/%s/tag/%s", CFG.bbs_usersdir, exitinfo.Name, tmpf->remote); Syslog('b', "test \"%s\" \"%s\"", symFrom, tmpf->local); if (strcmp(symFrom, tmpf->local)) { Syslog('b', "different, need a symlink"); unlink(tmpf->remote); snprintf(symFrom, PATH_MAX, "%s", tmpf->remote); snprintf(symTo, PATH_MAX, "%s", tmpf->local); if (symlink(symTo, symFrom)) { WriteError("$Can't create symlink %s %s %d", symTo, symFrom, errno); tmpf->failed = TRUE; } else { Syslog('b', "Created symlink %s -> %s", symFrom, symTo); } tmpf->kfs = FALSE; } else { Syslog('b', "the same, file is in tag directory"); } /* * Check if file or symlink is really there. */ snprintf(symFrom, PATH_MAX, "%s", tmpf->remote); if ((access(symFrom, F_OK)) != 0) { WriteError("File or symlink %s check failed, unmarking download", symFrom); tmpf->failed = TRUE; } else { Count++; Size += tmpf->size; } } } Home(); if (!Count) { /* * Nothing to download */ free(temp); free(symTo); free(symFrom); return 2; } clear(); /* File(s) : */ pout(YELLOW, BLACK, (char *) Language(349)); snprintf(temp, PATH_MAX, "%d", Count); PUTSTR(temp); Enter(1); /* Size : */ pout( CYAN, BLACK, (char *) Language(350)); snprintf(temp, PATH_MAX, "%u", Size); PUTSTR(temp); Enter(1); /* Protocol : */ pout( CYAN, BLACK, (char *) Language(351)); snprintf(temp, PATH_MAX, "%s", sProtName); PUTSTR(temp); Enter(1); Syslog('+', "Download files start, protocol: %s", sProtName); PUTSTR(sProtAdvice); Enter(2); /* * Wait a while before download */ sleep(2); if (uProtInternal) { snprintf(temp, PATH_MAX, "%s/%s/tag", CFG.bbs_usersdir, exitinfo.Name); chdir(temp); if (strncasecmp(sProtName, "zmodem-8k", 9) == 0) { maxrc = zmsndfiles(download_list, TRUE); Home(); } else if (strncasecmp(sProtName, "zmodem", 6) == 0) { maxrc = zmsndfiles(download_list, FALSE); Home(); } else if ((strncasecmp(sProtName, "xmodem", 6) == 0) || (strncasecmp(sProtName, "ymodem", 6) == 0)) { if (strncasecmp(sProtName, "xmodem", 6) == 0) protocol = ZM_XMODEM; else protocol = ZM_YMODEM; if (strstr(sProtName, "1K") || strstr(sProtName, "1k")) maxrc = ymsndfiles(download_list, TRUE); else maxrc = ymsndfiles(download_list, FALSE); Home(); } else { Syslog('!', "Warning internal protocol %s not supported", sProtName); maxrc = 1; } } else { gettimeofday(&starttime, &tz); /* * Transfer the files. Set the Client/Server time at the maximum * time the user has plus 10 minutes. The overall timer 10 seconds * less. Not a nice but working solution. */ alarm_set(((exitinfo.iTimeLeft + 10) * 60) - 10); Altime((exitinfo.iTimeLeft + 10) * 60); snprintf(temp, PATH_MAX, "%s/%s/tag", CFG.bbs_usersdir, exitinfo.Name); if ((dirp = opendir(temp)) == NULL) { WriteError("$Download: Can't open dir: %s", temp); free(temp); } else { chdir(temp); free(temp); temp = NULL; while ((dp = readdir(dirp)) != NULL ) { if (*(dp->d_name) != '.') { if (temp != NULL) { temp = xstrcat(temp, (char *)" "); temp = xstrcat(temp, dp->d_name); } else { temp = xstrcpy(dp->d_name); } } } if (temp != NULL) { if ((err = execute_str(sProtDn, temp, NULL, NULL, NULL, NULL))) { WriteError("$Download error %d, prot: %s", err, sProtDn); } /* * Restore rawport */ rawport(); free(temp); } else { WriteError("No filebatch created"); } closedir(dirp); } purgeline(200); /* Wait a while, some Wintendo programs ignore input for a few seconds */ Altime(0); alarm_off(); alarm_on(); Home(); gettimeofday(&endtime, &tz); /* * Checking the successfull sent files, they are missing from * the ./tag directory. Failed files are still there. */ Count = Size = 0; for (tmpf = download_list; tmpf && (maxrc < 2); tmpf = tmpf->next) { if (!tmpf->sent && !tmpf->failed) { snprintf(symTo, PATH_MAX, "./tag/%s", tmpf->remote); /* * If symlink is gone the file is sent. */ if ((access(symTo, R_OK)) != 0) { Syslog('+', "File %s from area %d sent ok", tmpf->remote, tmpf->area); tmpf->sent = TRUE; Size += tmpf->size; Count++; } else { Syslog('+', "Failed to sent %s from area %d", Tag.LFile, Tag.Area); } } } /* * Work out transfer rate in seconds by dividing the * Size of the File by the amount of time it took to download * the file. */ Syslog('+', "Download %s in %d file(s)", transfertime(starttime, endtime, (unsigned int)Size, TRUE), Count); } free(symTo); free(symFrom); for (tmpf = download_list; tmpf; tmpf = tmpf->next) { Syslog('b', "%s,%s,%ld,%ld,%ld,%s,%s,%s", tmpf->local, tmpf->remote, tmpf->cps, tmpf->area, tmpf->size, tmpf->kfs ?"KFS":"KEEP", tmpf->sent ?"SENT":"N/A", tmpf->failed ?"FAILED":"N/A"); } Syslog('b', "download() rc=%d", maxrc); return maxrc; }