You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1560 lines
38 KiB
C
1560 lines
38 KiB
C
/*
|
|
* binkleyforce -- unix FTN mailer project
|
|
*
|
|
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
#include "includes.h"
|
|
#include "confread.h"
|
|
#include "logger.h"
|
|
#include "io.h"
|
|
#include "util.h"
|
|
#include "session.h"
|
|
#include "prot_common.h"
|
|
#include "outbound.h"
|
|
#include "freq.h"
|
|
|
|
const char *Protocols[] =
|
|
{
|
|
"Unknown", "Xmodem", "Zmodem", "ZedZap", "DirZap",
|
|
"Janus", "Hydra", "Tcp", "BinkP"
|
|
};
|
|
|
|
/*****************************************************************************
|
|
* Get first file from files queue not marked as sent. Extract files in the
|
|
* order: netmail, arcmail, other files, file request. Files of equal type
|
|
* extract in the order of flavor descending
|
|
*
|
|
* Arguments:
|
|
* dest pointer to the pointer to put file information to
|
|
* pi pointer to the protocol information structure
|
|
* q pointer to the files queue
|
|
*
|
|
* Return value:
|
|
* Zero value on success and non-zero if nothing to send
|
|
*/
|
|
static int prot_get_next_file(s_filelist **dest, s_protinfo *pi, s_fsqueue *q)
|
|
{
|
|
s_filelist *ptrl = NULL;
|
|
s_filelist *best = NULL;
|
|
|
|
*dest = NULL;
|
|
|
|
for( ptrl = q->fslist; ptrl; ptrl = ptrl->next )
|
|
if( ptrl->status == STATUS_WILLSEND )
|
|
{
|
|
if( pi->reqs_only )
|
|
{
|
|
if( (ptrl->type & TYPE_REQUEST) )
|
|
{
|
|
*dest = ptrl;
|
|
return 0;
|
|
}
|
|
}
|
|
else if( best )
|
|
{
|
|
if( (ptrl->type & TYPE_NETMAIL) )
|
|
{
|
|
if( (best->type & TYPE_NETMAIL) )
|
|
{
|
|
if( ptrl->flavor > best->flavor )
|
|
best = ptrl;
|
|
} else
|
|
best = ptrl;
|
|
}
|
|
else if( (ptrl->type & TYPE_ARCMAIL) )
|
|
{
|
|
if( (best->type & TYPE_ARCMAIL) && (ptrl->flavor > best->flavor) )
|
|
best = ptrl;
|
|
else if( !(best->type & TYPE_NETMAIL)
|
|
&& !(best->type & TYPE_ARCMAIL) )
|
|
best = ptrl;
|
|
}
|
|
else if( !(ptrl->type & TYPE_REQUEST) && (best->type & TYPE_REQUEST) )
|
|
best = ptrl;
|
|
}
|
|
else
|
|
best = ptrl;
|
|
}
|
|
|
|
if( best )
|
|
{
|
|
*dest = best;
|
|
return 0;
|
|
}
|
|
|
|
for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next )
|
|
if( ptrl->status == STATUS_WILLSEND )
|
|
{
|
|
*dest = ptrl;
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Calculate total files number and size we are going to send. It will be
|
|
* used by some protocols that supports reporting of total traffic to the
|
|
* remote side (e.g. Zmodem protocols could)
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
* q pointer to the files queue
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
/*
|
|
void prot_update_traffic(s_protinfo *pi, const s_fsqueue *q)
|
|
{
|
|
s_filelist *ptrl = NULL;
|
|
|
|
pi->send_bytesleft = 0;
|
|
pi->send_filesleft = 0;
|
|
|
|
if( !state.sopts.holdall )
|
|
{
|
|
for( ptrl = q->fslist; ptrl; ptrl = ptrl->next )
|
|
if( ptrl->status == STATUS_WILLSEND )
|
|
{
|
|
pi->send_filesleft += 1;
|
|
pi->send_bytesleft += ptrl->size;
|
|
}
|
|
|
|
for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next )
|
|
if( ptrl->status == STATUS_WILLSEND )
|
|
{
|
|
pi->send_filesleft += 1;
|
|
pi->send_bytesleft += ptrl->size;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* Open next file for sending. Set all necessary information. And do all
|
|
* necessary checks.
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* Zero value on success and non-zero if have nothing to send
|
|
*/
|
|
int p_tx_fopen(s_protinfo *pi)
|
|
{
|
|
FILE *fp;
|
|
struct stat st;
|
|
s_filelist *ptrl = NULL;
|
|
|
|
if( state.sopts.holdall )
|
|
return 1;
|
|
|
|
get_next_file:
|
|
if( prot_get_next_file(&ptrl, pi, &state.queue) || !ptrl )
|
|
return 1;
|
|
|
|
/* Mark this file as "processed" */
|
|
ptrl->status = STATUS_SENDING;
|
|
|
|
pi->send_left_num -= 1;
|
|
pi->send_left_size -= ptrl->size;
|
|
|
|
if( pi->send_left_size < 0 )
|
|
pi->send_left_size = 0;
|
|
if( pi->send_left_num < 0 )
|
|
pi->send_left_num = 0;
|
|
|
|
/* Reset MinCPS time counter */
|
|
pi->tx_low_cps_time = 0;
|
|
|
|
DEB((D_PROT, "p_tx_fopen: now opening \"%s\"", ptrl->fname));
|
|
|
|
if( stat(ptrl->fname, &st) )
|
|
{
|
|
logerr("send: cannot stat file \"%s\"", ptrl->fname);
|
|
goto get_next_file;
|
|
}
|
|
|
|
if( (fp = file_open(ptrl->fname, "r")) == NULL )
|
|
{
|
|
logerr("send: cannot open file \"%s\"", ptrl->fname);
|
|
goto get_next_file;
|
|
}
|
|
|
|
/*
|
|
* Add new entry to the send files queue
|
|
*/
|
|
if( pi->sentfiles && pi->n_sentfiles > 0 )
|
|
{
|
|
pi->sentfiles = (s_finfo *)xrealloc(pi->sentfiles, sizeof(s_finfo)*(pi->n_sentfiles+1));
|
|
memset(&pi->sentfiles[pi->n_sentfiles], '\0', sizeof(s_finfo));
|
|
pi->send = &pi->sentfiles[pi->n_sentfiles++];
|
|
}
|
|
else
|
|
{
|
|
pi->sentfiles = (s_finfo *)xmalloc(sizeof(s_finfo));
|
|
memset(pi->sentfiles, '\0', sizeof(s_finfo));
|
|
pi->send = pi->sentfiles;
|
|
pi->n_sentfiles = 1;
|
|
}
|
|
|
|
/*
|
|
* Set file information
|
|
*/
|
|
pi->send->fp = fp;
|
|
pi->send->local_name = (char*)xstrcpy(file_getname(ptrl->fname));
|
|
pi->send->net_name = recode_file_out(p_convfilename(pi->send->local_name, ptrl->type));
|
|
pi->send->fname = (char*)xstrcpy(ptrl->fname);
|
|
pi->send->mod_time = (ptrl->type & TYPE_REQUEST) ? time(NULL) : st.st_mtime;
|
|
pi->send->mod_time = localtogmt(pi->send->mod_time);
|
|
pi->send->mod_time += pi->send->mod_time%2;
|
|
pi->send->mode = st.st_mode;
|
|
pi->send->bytes_total = st.st_size;
|
|
pi->send->start_time = time(NULL);
|
|
pi->send->eofseen = FALSE;
|
|
pi->send->status = FSTAT_PROCESS;
|
|
pi->send->type = ptrl->type;
|
|
pi->send->action = ptrl->action;
|
|
pi->send->flodsc = ptrl->flodsc;
|
|
|
|
if( strcmp(pi->send->local_name, pi->send->net_name) == 0 )
|
|
{
|
|
log("send: \"%s\" %d bytes",
|
|
pi->send->local_name,
|
|
pi->send->bytes_total);
|
|
}
|
|
else
|
|
{
|
|
log("send: \"%s\" %d bytes -> \"%s\"",
|
|
pi->send->local_name,
|
|
pi->send->bytes_total,
|
|
pi->send->net_name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void prot_traffic_update(s_traffic *traf, size_t size, int xtime, int type)
|
|
{
|
|
if( type & TYPE_REQANSW )
|
|
{
|
|
traf->freqed_size += size;
|
|
traf->freqed_time += xtime;
|
|
traf->freqed_num++;
|
|
}
|
|
else if( type & TYPE_NETMAIL )
|
|
{
|
|
traf->netmail_size += size;
|
|
traf->netmail_time += xtime;
|
|
traf->netmail_num++;
|
|
}
|
|
else if( type & TYPE_ARCMAIL )
|
|
{
|
|
traf->arcmail_size += size;
|
|
traf->arcmail_time += xtime;
|
|
traf->arcmail_num++;
|
|
}
|
|
else
|
|
{
|
|
traf->files_size += size;
|
|
traf->files_time += xtime;
|
|
traf->files_num++;
|
|
}
|
|
}
|
|
|
|
size_t prot_traffic_total_size(const s_traffic *traff)
|
|
{
|
|
return traff->netmail_size + traff->arcmail_size
|
|
+ traff->files_size + traff->freqed_size;
|
|
}
|
|
|
|
int prot_traffic_total_num(const s_traffic *traff)
|
|
{
|
|
return traff->netmail_num + traff->arcmail_num
|
|
+ traff->files_num + traff->freqed_num;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Close sending file. If file was sent successfully than make appropriate
|
|
* actions (e.g. unlink/truncate file)
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* Zero value on success and non-zero to indicate error
|
|
*/
|
|
int p_tx_fclose(s_protinfo *pi)
|
|
{
|
|
long trans_time = 0;
|
|
long cps = 0;
|
|
|
|
if( pi->send->fp )
|
|
{
|
|
(void)file_close(pi->send->fp);
|
|
pi->send->fp = NULL;
|
|
}
|
|
|
|
/*
|
|
* Calculate send time, CPS, etc
|
|
*/
|
|
trans_time = (long)time(NULL) - (long)pi->send->start_time;
|
|
|
|
if( trans_time > 0 )
|
|
cps = (long)((pi->send->bytes_sent - pi->send->bytes_skipped) / trans_time);
|
|
|
|
log("sent: \"%s\" %ld [%s]: %ld seconds, %ld CPS",
|
|
pi->send->net_name,
|
|
(long)(pi->send->bytes_sent - pi->send->bytes_skipped),
|
|
(pi->send->status == FSTAT_SKIPPED) ? "skipped" :
|
|
(pi->send->status == FSTAT_REFUSED) ? "refused" :
|
|
(pi->send->status == FSTAT_SUCCESS) ? "ok" : "error",
|
|
(long)(trans_time > 0) ? trans_time : 0,
|
|
(long)(cps > 0) ? cps : 0);
|
|
|
|
/*
|
|
* Update outgoing traffic structure
|
|
*/
|
|
prot_traffic_update(&pi->traffic_sent,
|
|
pi->send->bytes_sent - pi->send->bytes_skipped,
|
|
trans_time, pi->send->type);
|
|
|
|
/*
|
|
* Calculate time of sending FREQ'ed files
|
|
*/
|
|
if( (pi->send->type & TYPE_REQANSW) == TYPE_REQANSW )
|
|
pi->send_freqtime += trans_time;
|
|
|
|
/*
|
|
* Do necessary actions
|
|
*/
|
|
if( pi->send->status == FSTAT_SUCCESS || pi->send->status == FSTAT_SKIPPED )
|
|
{
|
|
FILE *tfp;
|
|
|
|
if( (pi->send->type & TYPE_FROMFLO) )
|
|
out_flo_marksent(pi->send->fname,
|
|
state.queue.flotab[pi->send->flodsc].fname);
|
|
|
|
switch(pi->send->action) {
|
|
case ACTION_NOTHING:
|
|
DEB((D_PROT, "p_tx_fclose: do nothing with file \"%s\"", pi->send->fname));
|
|
break;
|
|
|
|
case ACTION_UNLINK:
|
|
case ACTION_FORCEUNLINK:
|
|
DEB((D_PROT, "p_tx_fclose: unlinking file \"%s\"", pi->send->fname));
|
|
if( unlink(pi->send->fname) && errno != ENOENT )
|
|
logerr("send: cannot unlink file \"%s\"", pi->send->fname);
|
|
break;
|
|
|
|
case ACTION_TRUNCATE:
|
|
DEB((D_PROT, "p_tx_fclose: truncating file \"%s\"", pi->send->fname));
|
|
if( (tfp = fopen(pi->send->fname, "w")) )
|
|
fclose(tfp);
|
|
else if( errno != ENOENT )
|
|
logerr("send: cannot truncate file \"%s\"", pi->send->fname);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Read next part of file to the buffer. User by transmitter.
|
|
*
|
|
* Arguments:
|
|
* buffer pointer to the buffer
|
|
* buflen buffer size
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* >= 0 - number of bytes read
|
|
* -1 - error reading file (must try to send file later)
|
|
* -2 - file must be skipped (send never)
|
|
*/
|
|
int p_tx_readfile(char *buffer, size_t buflen, s_protinfo *pi)
|
|
{
|
|
int n;
|
|
struct stat st;
|
|
long ftell_pos = ftell(pi->send->fp);
|
|
|
|
pi->send->eofseen = FALSE; /* clear EOF flag */
|
|
|
|
/*
|
|
* Sanity check: sync our transmitter position
|
|
* with the position returned by the ftell()
|
|
*/
|
|
if( ftell_pos < 0 )
|
|
{
|
|
log("Error: ftell() return %ld for the file \"%s\"",
|
|
ftell_pos, pi->send->fname);
|
|
pi->send->status = FSTAT_REFUSED;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Try receive file later, if such error occurs
|
|
*/
|
|
if( pi->send->bytes_sent != ftell_pos )
|
|
{
|
|
log("internal error: invalid transmitting offset");
|
|
log("pi->send->bytes_sent = %ld, ftell() = %ld",
|
|
(long)pi->send->bytes_sent, ftell_pos);
|
|
pi->send->bytes_received = ftell_pos;
|
|
return -1;
|
|
}
|
|
|
|
if( stat(pi->send->fname, &st) == -1 && errno == ENOENT )
|
|
{
|
|
log("send: file not found! do you want to skip it?");
|
|
pi->send->status = FSTAT_SKIPPED;
|
|
return -2;
|
|
}
|
|
else if( (n = fread(buffer, 1, buflen, pi->send->fp)) < buflen )
|
|
{
|
|
if( feof(pi->send->fp) )
|
|
pi->send->eofseen = TRUE;
|
|
else
|
|
{
|
|
log("send: error reading file from disk (ferror = %d)",
|
|
ferror(pi->send->fp));
|
|
pi->send->status = FSTAT_REFUSED;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Write buffer to the file. Used by receiver.
|
|
*
|
|
* Arguments:
|
|
* buffer pointer to the buffer
|
|
* buflen number of bytes in buffer
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* 0 - successfully written
|
|
* -1 - error writing file (receive later)
|
|
* -2 - file must be skipped (receive never)
|
|
*/
|
|
int p_rx_writefile(const char *buffer, size_t buflen, s_protinfo *pi)
|
|
{
|
|
struct stat st;
|
|
long ftell_pos = ftell(pi->recv->fp);
|
|
|
|
/*
|
|
* Sanity check: sync our receiver position
|
|
* with the position returned by the ftell()
|
|
*/
|
|
if( ftell_pos < 0 )
|
|
{
|
|
log("Error: ftell() return %ld for the file \"%s\"",
|
|
ftell_pos, pi->recv->fname);
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Try receive file later, if such error occurs
|
|
*/
|
|
if( pi->recv->bytes_received != ftell_pos )
|
|
{
|
|
log("internal error: invalid receiving offset");
|
|
log("pi->recv->bytes_received = %ld, ftell() = %ld",
|
|
(long)pi->recv->bytes_received, ftell_pos);
|
|
pi->recv->bytes_received = ftell_pos;
|
|
return -1;
|
|
}
|
|
|
|
if( stat(pi->recv->fname, &st) == -1 )
|
|
{
|
|
fflush(pi->recv->fp);
|
|
if( stat(pi->recv->fname, &st) == -1 && errno == ENOENT )
|
|
{
|
|
log("recv: skip file \"%s\" (file not found)", pi->recv->fname);
|
|
pi->recv->status = FSTAT_SKIPPED;
|
|
return -2;
|
|
}
|
|
}
|
|
|
|
if( buflen > 0 && fwrite(buffer, buflen, 1, pi->recv->fp) != 1 )
|
|
{
|
|
log("recv: error writing file \"%s\" to disk (ferror = %d)",
|
|
pi->recv->fname, ferror(pi->recv->fp));
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Move file from temporary inbound to main
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* 0 - successfully processed file
|
|
* 1 - error occured (mailer must refuse this file (receive later))
|
|
*/
|
|
static int p_move2inbound(s_protinfo *pi)
|
|
{
|
|
int rc = 0;
|
|
char *realname = NULL;
|
|
char *uniqname = NULL;
|
|
char *destname = NULL;
|
|
|
|
if( state.inbound && pi->recv->local_name )
|
|
{
|
|
realname = (char *)xstrcpy(state.inbound);
|
|
realname = (char *)xstrcat(realname, pi->recv->local_name);
|
|
} else
|
|
return 1;
|
|
|
|
if( access(realname, F_OK) == -1 )
|
|
{
|
|
destname = realname;
|
|
}
|
|
else
|
|
{
|
|
if( (uniqname = prot_unique_name(state.inbound,
|
|
pi->recv->local_name, pi->recv->type)) == NULL )
|
|
{
|
|
log("recv: cannot get unique name for \"%s\"",
|
|
pi->recv->local_name);
|
|
free(realname);
|
|
return 1;
|
|
}
|
|
|
|
if( !strcmp(realname, uniqname) )
|
|
{
|
|
log("recv: overwriting \"%s\"",
|
|
file_getname(uniqname));
|
|
}
|
|
else
|
|
{
|
|
log("recv: rename \"%s\" -> \"%s\"",
|
|
pi->recv->local_name, file_getname(uniqname));
|
|
}
|
|
|
|
destname = uniqname;
|
|
}
|
|
|
|
if( (rc = rename(pi->recv->fname, destname)) == -1 )
|
|
{
|
|
logerr("recv: cannot rename \"%s\" -> \"%s\"",
|
|
pi->recv->fname, destname);
|
|
}
|
|
else
|
|
{
|
|
mode_t fmode = 0;
|
|
|
|
/*
|
|
* Change new file permissions
|
|
*/
|
|
if( (pi->recv->type & TYPE_NETMAIL) == TYPE_NETMAIL )
|
|
fmode = conf_filemode(cf_mode_netmail);
|
|
else if( (pi->recv->type & TYPE_ARCMAIL) == TYPE_ARCMAIL )
|
|
fmode = conf_filemode(cf_mode_arcmail);
|
|
else if( (pi->recv->type & TYPE_REQUEST) == TYPE_REQUEST )
|
|
fmode = conf_filemode(cf_mode_request);
|
|
else if( (pi->recv->type & TYPE_TICFILE) == TYPE_TICFILE )
|
|
fmode = conf_filemode(cf_mode_ticfile);
|
|
|
|
if( fmode == 0 )
|
|
fmode = conf_filemode(cf_mode_default);
|
|
|
|
if( chmod(destname, fmode ? fmode : (S_IRUSR|S_IWUSR)) == -1 )
|
|
logerr("recv: cannot set permissions for file \"%s\"",
|
|
destname);
|
|
}
|
|
|
|
if( realname )
|
|
free(realname);
|
|
if( uniqname )
|
|
free(uniqname);
|
|
|
|
return rc ? 1 : 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Compare the two file informations. One specified by file information
|
|
* structure (s_finfo) and another specified by other variables.
|
|
*
|
|
* Arguments:
|
|
* finf pointer to the file information
|
|
* fn file name
|
|
* sz file size
|
|
* tm file modification time
|
|
*
|
|
* Return value:
|
|
* Zero value if two files with such parameters seems to be the same
|
|
* file, and non-zero if it is different files
|
|
*/
|
|
int p_compfinfo(s_finfo *finf, const char *fn, size_t sz, time_t tm)
|
|
{
|
|
return ( sz == finf->bytes_total && tm == finf->mod_time
|
|
&& strcmp(fn, finf->net_name) == 0 ) ? 0 : 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Open file for receiving. If file with such name allready exist:
|
|
* 1) if timestamp and size identical to existing one, then skip;
|
|
* 2) if only timestamp is equal and size of existing file is shorter then
|
|
* it possible was an unfinished transfer - try to recover;
|
|
* 3) in all other cases rename receiving file.
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
* fn file name |
|
|
* sz file size | \ as it was reported by
|
|
* tm file last modification time | / remote side (need checks)
|
|
* mode file permissions |
|
|
*
|
|
* Return value:
|
|
* 0 - successful call
|
|
* 1 - refuse this file (receive later)
|
|
* 2 - skip this file (never receive it)
|
|
*/
|
|
int p_rx_fopen(s_protinfo *pi, char *fn, size_t sz, time_t tm, mode_t mode)
|
|
{
|
|
const char *openmode = "w"; /* Set open mode to overwrite */
|
|
struct stat st;
|
|
const char *p_skiplist = NULL;
|
|
const char *p_delaylist = NULL;
|
|
size_t minfree = 0;
|
|
size_t needed_bytes_total = 0;
|
|
|
|
/*
|
|
* Check. May be we are receiving this file allready
|
|
*/
|
|
if( pi->recv && p_compfinfo(pi->recv, fn, sz, tm) == 0 )
|
|
{
|
|
log("recv: got duplicated file information");
|
|
|
|
if( pi->recv->fp )
|
|
return 0;
|
|
else if( pi->recv->status == FSTAT_SKIPPED )
|
|
return 2;
|
|
else if( pi->recv->status == FSTAT_REFUSED )
|
|
return 1;
|
|
}
|
|
|
|
/* Reset mincps time counter */
|
|
pi->rx_low_cps_time = 0;
|
|
|
|
/*
|
|
* Add new entry to the receive files queue
|
|
*/
|
|
if( pi->rcvdfiles && pi->n_rcvdfiles > 0 )
|
|
{
|
|
pi->rcvdfiles = (s_finfo *)xrealloc(pi->rcvdfiles, sizeof(s_finfo)*(pi->n_rcvdfiles+1));
|
|
memset(&pi->rcvdfiles[pi->n_rcvdfiles], '\0', sizeof(s_finfo));
|
|
pi->recv = &pi->rcvdfiles[pi->n_rcvdfiles++];
|
|
}
|
|
else
|
|
{
|
|
pi->rcvdfiles = (s_finfo *)xmalloc(sizeof(s_finfo));
|
|
memset(pi->rcvdfiles, '\0', sizeof(s_finfo));
|
|
pi->recv = pi->rcvdfiles;
|
|
pi->n_rcvdfiles = 1;
|
|
}
|
|
|
|
/*
|
|
* Set file information
|
|
*/
|
|
pi->recv->net_name = (char*)xstrcpy(fn);
|
|
pi->recv->local_name = xstrcpy(file_getname(fn));
|
|
pi->recv->bytes_total = sz;
|
|
pi->recv->mod_time = tm;
|
|
pi->recv->mode = mode;
|
|
pi->recv->start_time = time(NULL);
|
|
pi->recv->eofseen = FALSE;
|
|
pi->recv->status = FSTAT_PROCESS;
|
|
pi->recv->type = out_filetype(pi->recv->net_name);
|
|
pi->recv->action = ACTION_NOTHING;
|
|
pi->recv->flodsc = 0;
|
|
|
|
/*
|
|
* Convert file name to local charset
|
|
*/
|
|
recode_file_in(pi->recv->local_name);
|
|
|
|
/*
|
|
* Remove undesirable characters from file name
|
|
*/
|
|
file_name_makesafe(pi->recv->local_name);
|
|
|
|
/*
|
|
* Upper case file names convert to lower case.
|
|
*/
|
|
if( string_isupper(pi->recv->local_name) )
|
|
string_tolower(pi->recv->local_name);
|
|
|
|
if( strcmp(pi->recv->local_name, pi->recv->net_name) )
|
|
{
|
|
log("recv: \"%s\" %d bytes -> \"%s\"",
|
|
string_printable(pi->recv->net_name),
|
|
pi->recv->bytes_total,
|
|
string_printable(pi->recv->local_name));
|
|
}
|
|
else
|
|
{
|
|
log("recv: \"%s\" %d bytes",
|
|
string_printable(pi->recv->local_name),
|
|
pi->recv->bytes_total);
|
|
}
|
|
|
|
/*
|
|
* Get `DelayFilesIn', `Skipfiles' and `MinFree' values
|
|
*/
|
|
p_skiplist = conf_string(cf_skip_files_recv);
|
|
p_delaylist = conf_string(cf_delay_files_recv);
|
|
minfree = conf_number(cf_min_free_space);
|
|
|
|
/*
|
|
* Should we delay(refuse) this file NOW?
|
|
*/
|
|
if( p_delaylist && !checkmasks(p_delaylist, pi->recv->net_name) )
|
|
{
|
|
log("recv: file from delaylist -> refuse");
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
return(1);
|
|
}
|
|
|
|
/*
|
|
* Should we skip this file NOW?
|
|
*/
|
|
if( p_skiplist && !checkmasks(p_skiplist, pi->recv->net_name) )
|
|
{
|
|
log("recv: file from skiplist -> skip");
|
|
pi->recv->status = FSTAT_SKIPPED;
|
|
return(2);
|
|
}
|
|
|
|
/*
|
|
* Check. May be we allready have this file
|
|
*/
|
|
if( (pi->recv->type & TYPE_REQUEST) || (pi->recv->type & TYPE_NETMAIL) )
|
|
{
|
|
pi->recv->fname = p_gettmpname(state.tinbound, pi->recv->local_name,
|
|
state.node.addr, pi->recv->bytes_total,
|
|
pi->recv->mod_time);
|
|
}
|
|
else /* It is not netmail or filerequest */
|
|
{
|
|
char *fname;
|
|
fname = (char *)xstrcpy(state.inbound);
|
|
fname = (char *)xstrcat(fname, pi->recv->local_name);
|
|
|
|
if( stat(fname, &st ) == 0 )
|
|
{
|
|
/* Skip file if we allready have it's copy */
|
|
if( pi->recv->mod_time == localtogmt(st.st_mtime)
|
|
&& pi->recv->bytes_total == st.st_size )
|
|
{
|
|
log("recv: allready have \"%s\"", fname);
|
|
pi->recv->status = FSTAT_SKIPPED;
|
|
}
|
|
}
|
|
|
|
free(fname); fname = NULL;
|
|
|
|
if( pi->recv->status == FSTAT_SKIPPED )
|
|
return 2;
|
|
|
|
pi->recv->fname = p_gettmpname(state.tinbound, pi->recv->local_name,
|
|
state.node.addr, pi->recv->bytes_total,
|
|
pi->recv->mod_time);
|
|
|
|
/* Now make same check for temporary inbound */
|
|
if( stat(pi->recv->fname, &st) == 0 )
|
|
{
|
|
/* Skip if it is the same file */
|
|
if( pi->recv->mod_time == localtogmt(st.st_mtime)
|
|
&& pi->recv->bytes_total == st.st_size )
|
|
{
|
|
/*
|
|
* We will skip it and try to move it into inbound
|
|
* directory, do you know who could left it here ? :)
|
|
*/
|
|
|
|
log("recv: allready have \"%s\"", pi->recv->fname);
|
|
|
|
if( p_move2inbound(pi) == 0 )
|
|
pi->recv->status = FSTAT_SKIPPED;
|
|
else
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
|
|
free(pi->recv->fname);
|
|
pi->recv->fname = NULL;
|
|
|
|
return pi->recv->status == FSTAT_SKIPPED ? 2 : 1;
|
|
}
|
|
else if( pi->recv->mod_time == localtogmt(st.st_mtime)
|
|
&& pi->recv->bytes_total >= st.st_size )
|
|
{
|
|
pi->recv->bytes_skipped = st.st_size;
|
|
pi->recv->bytes_received = pi->recv->bytes_skipped;
|
|
|
|
log("recv: receiving \"%s\" from offset %ld",
|
|
pi->recv->fname, (long)pi->recv->bytes_skipped);
|
|
|
|
openmode = "a";
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check, there is enough space in our inbound
|
|
*/
|
|
if (openmode == "a") needed_bytes_total = minfree + pi->recv->bytes_total - pi->recv->bytes_skipped;
|
|
else needed_bytes_total = minfree + pi->recv->bytes_total;
|
|
|
|
if( minfree > 0 && getfreespace(state.inbound) < needed_bytes_total )
|
|
{
|
|
log("recv: not enough free space in inbound -> refuse");
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
return(1);
|
|
}
|
|
|
|
DEB((D_PROT, "p_rx_fopen: call fopen(\"%s\", \"%s\")",
|
|
pi->recv->fname, openmode));
|
|
|
|
if( (pi->recv->fp = file_open(pi->recv->fname, openmode)) == NULL )
|
|
{
|
|
logerr("recv: cannot open \"%s\" -> refuse", pi->recv->fname);
|
|
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
free(pi->recv->fname);
|
|
pi->recv->fname = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
if( pi->buffer && pi->buflen > 0 )
|
|
{
|
|
#ifdef SETVBUF_REVERSED
|
|
setvbuf(pi->recv->fp, _IOFBF, pi->buffer, pi->buflen);
|
|
#else
|
|
setvbuf(pi->recv->fp, pi->buffer, _IOFBF, pi->buflen);
|
|
#endif
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Close receiving file. If it was completly received - move it to the main
|
|
* inbound directory.
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* 0 - successfull call
|
|
* 1 - error occured, refuse this file (receive later)
|
|
*/
|
|
int p_rx_fclose(s_protinfo *pi)
|
|
{
|
|
long trans_time = 0;
|
|
long cps = 0;
|
|
int rc = 0;
|
|
struct stat st;
|
|
|
|
DEB((D_PROT, "p_rx_fclose: close file \"%s\"", pi->recv->fname));
|
|
|
|
if( pi->recv->fp )
|
|
{
|
|
rc = file_close(pi->recv->fp); pi->recv->fp = NULL;
|
|
|
|
if( rc )
|
|
{
|
|
/*
|
|
* This may be any sort of errors, including
|
|
* random data corruptions. Return error.
|
|
*/
|
|
logerr("recv: cannot close file \"%s\"", pi->recv->fname);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if( pi->recv->status == FSTAT_SKIPPED )
|
|
{
|
|
/*
|
|
* Remove skipped file from temp. inbound
|
|
*/
|
|
if( unlink(pi->recv->fname) == -1 && errno != ENOENT )
|
|
logerr("recv: cannot remove skipped file \"%s\"", pi->recv->fname);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Set original file modification time
|
|
*/
|
|
if( pi->recv->mod_time )
|
|
{
|
|
struct utimbuf tvp;
|
|
|
|
tvp.actime = time(NULL);
|
|
tvp.modtime = gmttolocal(pi->recv->mod_time);
|
|
utime(pi->recv->fname, &tvp);
|
|
}
|
|
|
|
/*
|
|
* Set default file permission to 0600
|
|
*/
|
|
if( chmod(pi->recv->fname, (S_IRUSR | S_IWUSR)) == -1 )
|
|
logerr("recv: cannot change mode for file \"%s\"", pi->recv->fname);
|
|
}
|
|
|
|
/*
|
|
* Update incoming traffic structure
|
|
*/
|
|
prot_traffic_update(&pi->traffic_rcvd,
|
|
pi->recv->bytes_received - pi->recv->bytes_skipped,
|
|
trans_time, pi->recv->type);
|
|
|
|
/*
|
|
* If file was received successfuly
|
|
*/
|
|
if( pi->recv->status == FSTAT_SUCCESS )
|
|
{
|
|
/*
|
|
* Sanity check. Compare real file length with the
|
|
* expected length (reported by the remote side)
|
|
*/
|
|
if( stat(pi->recv->fname, &st) == -1 )
|
|
{
|
|
log("cannot stat received file \"%s\"", pi->recv->fname);
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
}
|
|
else if( st.st_size != pi->recv->bytes_total )
|
|
{
|
|
log("received file has invalid size %ld (%ld expected)",
|
|
(long)st.st_size, (long)pi->recv->bytes_total);
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
}
|
|
else if( state.reqstat == REQS_ALLOW
|
|
&& (pi->recv->type & TYPE_REQUEST) )
|
|
{
|
|
/* Run our freq processor */
|
|
req_proc(pi->recv->fname, &pi->filelist);
|
|
unlink(pi->recv->fname);
|
|
}
|
|
else if( p_move2inbound(pi) )
|
|
{
|
|
log("recv: can't move file into main inbound -> refuse");
|
|
pi->recv->status = FSTAT_REFUSED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Calculate receive time, CPS, etc
|
|
*/
|
|
trans_time = (long)time(NULL) - (long)pi->recv->start_time;
|
|
|
|
if( trans_time > 0 )
|
|
cps = (long)((pi->recv->bytes_received - pi->recv->bytes_skipped) / trans_time);
|
|
|
|
log("rcvd: \"%s\" %ld [%s]: %ld seconds, %ld CPS",
|
|
pi->recv->local_name,
|
|
(long)(pi->recv->bytes_received - pi->recv->bytes_skipped),
|
|
(pi->recv->status == FSTAT_SKIPPED) ? "skipped" :
|
|
(pi->recv->status == FSTAT_REFUSED) ? "refused" :
|
|
(pi->recv->status == FSTAT_SUCCESS) ? "ok" : "error",
|
|
(long)(trans_time > 0) ? trans_time : 0,
|
|
(long)(cps > 0) ? cps : 0);
|
|
|
|
return pi->recv->status == FSTAT_SUCCESS ? 0 : 1;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Check current receiving/sending speeds (CPS), check time limits.
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
* bidir if hydra, check only one CPS value
|
|
*
|
|
* Return value:
|
|
* PRC_NOERROR - all ok
|
|
* PRC_STOPTIME - abort session due to time limits
|
|
* PRC_CPSTOOLOW - abort session due low speed
|
|
*/
|
|
int p_info(s_protinfo *pi, int bidir)
|
|
{
|
|
int rc = 0, rx_cps_low = 0, tx_cps_low = 0;
|
|
time_t tx_now, rx_now, now;
|
|
|
|
now = time(NULL);
|
|
|
|
if( pi->send && pi->send->status == FSTAT_PROCESS )
|
|
{
|
|
tx_now = (long)time(NULL) - (long)pi->send->start_time;
|
|
pi->tx_cps = (pi->send->bytes_sent - pi->send->bytes_skipped) / (tx_now ? tx_now : 1);
|
|
|
|
/* Is it FREQ answer? */
|
|
if( pi->freq_timelimit > 0 && (pi->send->type & TYPE_REQANSW) )
|
|
{
|
|
/*
|
|
* Check FREQ time limit not reached?
|
|
*/
|
|
if( pi->send_freqtime + tx_now > pi->freq_timelimit )
|
|
{
|
|
log("reached FREQ time limit %d second(s)", pi->freq_timelimit);
|
|
rc = PRC_STOPTIME;
|
|
}
|
|
}
|
|
|
|
/* Check is transmiting CPS to low */
|
|
if( pi->min_tx_cps )
|
|
{
|
|
if( pi->tx_low_cps_time )
|
|
{
|
|
if( pi->tx_cps < pi->min_tx_cps )
|
|
{
|
|
if( now - pi->tx_low_cps_time >= pi->min_cps_time )
|
|
{
|
|
tx_cps_low = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pi->tx_low_cps_time = 0;
|
|
}
|
|
}
|
|
else if( pi->tx_cps < pi->min_tx_cps )
|
|
{
|
|
pi->tx_low_cps_time = now;
|
|
}
|
|
}
|
|
} /* end of if( txi ) */
|
|
|
|
if( pi->recv && pi->recv->status == FSTAT_PROCESS )
|
|
{
|
|
rx_now = (long)time(NULL) - (long)pi->recv->start_time;
|
|
pi->rx_cps = (pi->recv->bytes_received - pi->recv->bytes_skipped) / (rx_now ? rx_now : 1);
|
|
|
|
/* Check is receiving CPS to low */
|
|
if( pi->min_rx_cps )
|
|
{
|
|
if( pi->rx_low_cps_time )
|
|
{
|
|
if( pi->rx_cps < pi->min_rx_cps )
|
|
{
|
|
if( now - pi->rx_low_cps_time >= pi->min_cps_time )
|
|
{
|
|
rx_cps_low = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pi->rx_low_cps_time = 0;
|
|
}
|
|
}
|
|
else if( pi->rx_cps < pi->min_rx_cps )
|
|
{
|
|
pi->rx_low_cps_time = now;
|
|
}
|
|
}
|
|
} /* end of if( rxi ) */
|
|
|
|
/* check maybe now is a good time to stop it ? =) */
|
|
if( pi->stop_time && now >= pi->stop_time )
|
|
{
|
|
log("reached stop time");
|
|
rc = PRC_STOPTIME;
|
|
}
|
|
|
|
if ( tx_cps_low )
|
|
{
|
|
if ( !bidir || rx_cps_low ) {
|
|
log("transmitting speed below %d cps", pi->min_tx_cps);
|
|
rc = PRC_CPSTOOLOW;
|
|
}
|
|
}
|
|
|
|
if ( rx_cps_low )
|
|
{
|
|
if ( !bidir || tx_cps_low ) {
|
|
log("receiving speed below %d cps", pi->min_rx_cps);
|
|
rc = PRC_CPSTOOLOW;
|
|
}
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Log short session statistic. Output overall Send/Received bytes, avreage
|
|
* CPS, on-line time
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void p_log_txrxstat(const s_protinfo *pi)
|
|
{
|
|
char abuf[BF_MAXADDRSTR+1];
|
|
s_faddr tmpaddr = state.node.addr;
|
|
int total_time = time_elapsed(pi->start_time);
|
|
int files_sent = prot_traffic_total_num(&pi->traffic_sent);
|
|
int files_rcvd = prot_traffic_total_num(&pi->traffic_rcvd);
|
|
size_t bytes_sent = prot_traffic_total_size(&pi->traffic_sent);
|
|
size_t bytes_rcvd = prot_traffic_total_size(&pi->traffic_rcvd);
|
|
size_t total_traff = bytes_sent + bytes_rcvd;
|
|
size_t total_cps = (total_traff / (total_time ? total_time : 1));
|
|
|
|
tmpaddr.domain[0] = '\0'; /* remove domain from address */
|
|
|
|
log("%s, S/R %ld/%ld, %ld/%ld bytes in %ld seconds, %ld CPS",
|
|
ftn_addrstr(abuf, tmpaddr),
|
|
files_sent, files_rcvd,
|
|
(long)bytes_sent, (long)bytes_rcvd,
|
|
(long)((total_time > 0) ? total_time : 0),
|
|
(long)((total_cps > 0) ? total_cps : 0));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Do session cleanup. Remove temporary files, remove useless file requests
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void p_session_cleanup(s_protinfo *pi, bool success)
|
|
{
|
|
int i;
|
|
s_filelist *ptrl;
|
|
|
|
if( success )
|
|
{
|
|
/*
|
|
* Remove sent file requests after successfull sessions
|
|
*/
|
|
for( i = 0; i < pi->n_sentfiles; i++ )
|
|
if( (pi->sentfiles[i].type & TYPE_REQUEST)
|
|
&& (pi->sentfiles[i].status == FSTAT_SUCCESS) )
|
|
{
|
|
if( unlink(pi->sentfiles[i].fname) == -1 && errno != ENOENT )
|
|
{
|
|
logerr("can't unlink '.req' file \"%s\"",
|
|
pi->sentfiles[i].fname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Delete files with action ACTION_FORCEUNLINK
|
|
*/
|
|
for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next )
|
|
{
|
|
/* It must be allready deleted if it is sent */
|
|
if( ptrl->action == ACTION_FORCEUNLINK && ptrl->status != STATUS_SENT )
|
|
{
|
|
if( unlink(ptrl->fname) && errno != ENOENT )
|
|
logerr("cannot unlink temporary file \"%s\"", ptrl->fname);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Do all necessary convertions and checks with file names before sending it
|
|
*
|
|
* Arguments:
|
|
* origname pointer to the original file name
|
|
* type file type (netmail, arcmail, etc.)
|
|
*
|
|
* Return value:
|
|
* Pointer to the new file name (must be freed)
|
|
*/
|
|
char *p_convfilename(const char *origname, int type)
|
|
{
|
|
const char *p;
|
|
char *dest = NULL;
|
|
long crc = 0L;
|
|
s_faddr addr;
|
|
|
|
if( (type & TYPE_NETMAIL) )
|
|
{
|
|
/*
|
|
* Generate random file name for netmail packets
|
|
*/
|
|
dest = (char*)xmalloc(32);
|
|
sprintf(dest, "%08lx.pkt", (long)rand());
|
|
}
|
|
else if( (type & TYPE_ASONAME) == TYPE_ASONAME
|
|
&& (type & TYPE_ARCMAIL) == TYPE_ARCMAIL )
|
|
{
|
|
/*
|
|
* Generate new file name for arcmail from AmigaDos style
|
|
* outbound, such files looks like "2.5020.1682.9.fr1".
|
|
*/
|
|
if( (p = strrchr(origname, '.')) )
|
|
crc = getcrc32ccitt(origname, p - origname - 1);
|
|
else
|
|
crc = getcrc32ccitt(origname, strlen(origname));
|
|
|
|
dest = (char*)xmalloc(32);
|
|
sprintf(dest, "%08lx%s", (long)crc, p?p:".fr0");
|
|
}
|
|
else if( (type & TYPE_ASONAME) == TYPE_ASONAME
|
|
&& (type & TYPE_REQUEST) == TYPE_REQUEST )
|
|
{
|
|
/*
|
|
* Generate new file name for file request from AmigaDos
|
|
* style outbound, such files looks like "2.5020.1682.0.req".
|
|
*/
|
|
dest = (char*)xmalloc(32);
|
|
if( out_parse_name_aso(&addr, origname) == 0 )
|
|
sprintf(dest, "%04x%04x.req", addr.net, addr.node);
|
|
else
|
|
sprintf(dest, "%08lx.req", (long)rand());
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* All other files send with their real name, but:
|
|
* 1) remove "nonprintable" characters
|
|
* 2) convert files to 8+3 format if remote has no long
|
|
* file names support (indicated by $state.sopts.fnc)
|
|
*/
|
|
if( state.sopts.fnc )
|
|
{
|
|
dest = (char*)xmalloc(13);
|
|
file_get_dos_name(dest, origname);
|
|
}
|
|
else
|
|
{
|
|
dest = (char*)xstrcpy(origname);
|
|
if( string_isupper(dest) )
|
|
string_tolower(dest);
|
|
}
|
|
}
|
|
|
|
return dest;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Get temporary file name with full path.
|
|
*
|
|
* Arguments:
|
|
* inbound path to temporary inbound directory
|
|
* filename file name
|
|
* addr remote address \
|
|
* sz file size > Used to generate unique file names
|
|
* tm file time /
|
|
*
|
|
* Return value:
|
|
* Pointer to the temporary file name (must be freed)
|
|
*/
|
|
char *p_gettmpname(const char *inbound, char *filename, s_faddr addr,
|
|
size_t sz, time_t tm)
|
|
{
|
|
char *dest;
|
|
char abuf[BF_MAXADDRSTR+1];
|
|
char bbuf[BF_MAXADDRSTR+30];
|
|
char cbuf[16];
|
|
|
|
sprintf(bbuf, "%s %lx %lx", ftn_addrstr(abuf, addr), (long)sz, (long)tm);
|
|
sprintf(cbuf, "%lx", (long)getcrc32ccitt(bbuf, strlen(bbuf)));
|
|
|
|
dest = xstrcpy(inbound);
|
|
dest = xstrcat(dest, filename);
|
|
dest = xstrcat(dest, ".");
|
|
dest = xstrcat(dest, cbuf);
|
|
|
|
return dest;
|
|
}
|
|
|
|
#define MAX_TRIES 1024
|
|
|
|
/*****************************************************************************
|
|
* Get new file name for received file. Use it when we allready have
|
|
* file with such name in inbound directory.
|
|
*
|
|
* Rename file with the next algorithm:
|
|
*
|
|
* - For file request. Overwrite existing file
|
|
*
|
|
* - For netmail or ticfile. Generate new unique
|
|
* file name. (1234abcde.pkt -> ab04d51f.pkt)
|
|
*
|
|
* - For arcmail. Rotate extension chars to make
|
|
* unique name. (057d63a6.su0 -> 057d63a6.su1)
|
|
*
|
|
* - For other files. Try to add a numeric value
|
|
* as additional extension ("net5020.ndl.1")
|
|
*
|
|
* Arguments:
|
|
* dirname pointer to the directory (inbound)
|
|
* fname pointer to the file name
|
|
* type file type (netmail, arcmail, etc.)
|
|
*
|
|
* Return value:
|
|
* Pointer to the new file name with path (must be freed), and
|
|
* NULL to indicate error
|
|
*/
|
|
char *prot_unique_name(char *dirname, char *fname, int type)
|
|
{
|
|
int try = 0;
|
|
int offs = 0;
|
|
char *result = NULL;
|
|
char *p;
|
|
|
|
if( (type & TYPE_REQUEST) )
|
|
{
|
|
result = (char *)xstrcpy(dirname);
|
|
result = (char *)xstrcat(result, fname);
|
|
}
|
|
else if( (type & TYPE_NETMAIL) || (type & TYPE_TICFILE) )
|
|
{
|
|
char *ext = (type & TYPE_NETMAIL) ? "pkt" : "tic";
|
|
|
|
offs = strlen(dirname);
|
|
result = (char *)xmalloc(offs + 36);
|
|
strncpy(result, dirname, offs + 35);
|
|
result[offs + 35] = '\0';
|
|
|
|
do
|
|
{
|
|
++try;
|
|
sprintf(result+offs, "%08lx.%s", (long)rand(), ext);
|
|
}
|
|
while( !access(result, F_OK) && try < MAX_TRIES );
|
|
}
|
|
else if( (type & TYPE_ARCMAIL) )
|
|
{
|
|
result = (char *)xstrcpy(dirname);
|
|
result = (char *)xstrcat(result, fname);
|
|
|
|
p = result + strlen(result) - 1;
|
|
|
|
do
|
|
{
|
|
++try;
|
|
|
|
if( (*p >= '0') && (*p <= '8') )
|
|
++*p;
|
|
else if( (*p >= 'A') && (*p <= 'Y') )
|
|
++*p;
|
|
else if( (*p >= 'a') && (*p <= 'y') )
|
|
++*p;
|
|
else if( (*p == '9') )
|
|
*p = 'a';
|
|
else if( (*p == 'z') )
|
|
*p = 'A';
|
|
else if( --p < result || *p == '.' || *p == '/' )
|
|
{
|
|
free(result);
|
|
result = NULL;
|
|
break;
|
|
}
|
|
}
|
|
while( !access(result, F_OK) && try < MAX_TRIES );
|
|
}
|
|
else
|
|
{
|
|
result = (char *)xstrcpy(dirname);
|
|
result = (char *)xstrcat(result, fname);
|
|
|
|
offs = strlen(result);
|
|
|
|
result = (char *)xrealloc(result, offs + 16);
|
|
|
|
if( result[offs-1] != '.' )
|
|
{
|
|
result[offs++] = '.';
|
|
result[offs ] = '\0';
|
|
}
|
|
|
|
do
|
|
{
|
|
++try;
|
|
sprintf(result+offs, "%d", try);
|
|
}
|
|
while( !access(result, F_OK) && try < MAX_TRIES );
|
|
}
|
|
|
|
if( try >= MAX_TRIES )
|
|
{
|
|
if( result )
|
|
free(result);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Release memory used by file information structure
|
|
*
|
|
* Arguments:
|
|
* fi pointer to the file information structure
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void deinit_finfo(s_finfo *fi)
|
|
{
|
|
if( fi->fp )
|
|
fclose(fi->fp);
|
|
|
|
if( fi->local_name )
|
|
free(fi->local_name);
|
|
if( fi->net_name )
|
|
free(fi->net_name);
|
|
if( fi->fname )
|
|
free(fi->fname);
|
|
|
|
memset(fi, '\0', sizeof(s_finfo));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Init protocol information structure. Set all necessary options, such as
|
|
* minimal CPSes, start/stop time, etc.
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
* caller are we caller?
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void init_protinfo(s_protinfo *pi, bool caller)
|
|
{
|
|
long tmp;
|
|
long sesslimit;
|
|
|
|
memset(pi, '\0', sizeof(s_protinfo));
|
|
|
|
pi->start_time = time(NULL);
|
|
|
|
if( (pi->buflen = conf_number(cf_recv_buffer_size)) > 0 )
|
|
pi->buflen = (pi->buflen / 2048) * 2048;
|
|
else
|
|
pi->buflen = 32768;
|
|
|
|
if( pi->buflen > 0 )
|
|
pi->buffer = (char*)xmalloc(pi->buflen);
|
|
|
|
if( (tmp = conf_number(cf_min_cps_time)) > 0 )
|
|
pi->min_cps_time = tmp;
|
|
else
|
|
pi->min_cps_time = 60;
|
|
|
|
/*
|
|
* Set abort time if session limit was specified
|
|
*/
|
|
if( caller )
|
|
sesslimit = conf_number(cf_session_limit_out);
|
|
else
|
|
sesslimit = conf_number(cf_session_limit_in);
|
|
|
|
if( sesslimit > 0 )
|
|
pi->stop_time = time(0) + sesslimit;
|
|
|
|
/*
|
|
* Set minimal transmit speed (CPS)
|
|
*/
|
|
if( (tmp = conf_number(cf_min_cps_send)) > 0 )
|
|
pi->min_tx_cps = tmp;
|
|
else
|
|
{
|
|
if( state.handshake->protocol == PROT_ZMODEM
|
|
|| state.handshake->protocol == PROT_ZEDZAP
|
|
|| state.handshake->protocol == PROT_DIRZAP )
|
|
tmp = conf_connlist(cf_zmodem_mincps_send, state.connspeed);
|
|
else if( state.handshake->protocol == PROT_HYDRA )
|
|
tmp = conf_connlist(cf_hydra_mincps_send, state.connspeed);
|
|
else
|
|
tmp = 0;
|
|
|
|
if( tmp > 0 )
|
|
pi->min_tx_cps = tmp;
|
|
}
|
|
|
|
/*
|
|
* Set minimal receive speed (CPS)
|
|
*/
|
|
if( (tmp = conf_number(cf_min_cps_recv)) > 0 )
|
|
pi->min_rx_cps = tmp;
|
|
else
|
|
{
|
|
if( state.handshake->protocol == PROT_ZMODEM
|
|
|| state.handshake->protocol == PROT_ZEDZAP
|
|
|| state.handshake->protocol == PROT_DIRZAP )
|
|
tmp = conf_connlist(cf_zmodem_mincps_recv, state.connspeed);
|
|
else if( state.handshake->protocol == PROT_HYDRA )
|
|
tmp = conf_connlist(cf_hydra_mincps_recv, state.connspeed);
|
|
else
|
|
tmp = 0;
|
|
|
|
if( tmp > 0 )
|
|
pi->min_rx_cps = tmp;
|
|
}
|
|
|
|
/*
|
|
* Report about selected limits
|
|
*/
|
|
if( sesslimit > 0 && (pi->min_tx_cps > 0 || pi->min_rx_cps > 0) )
|
|
log("use restrictions: %d/%d cps, %d seconds", pi->min_tx_cps, pi->min_rx_cps, sesslimit);
|
|
else if( pi->min_tx_cps > 0 || pi->min_rx_cps > 0 )
|
|
log("use restrictions: %d/%d cps", pi->min_tx_cps, pi->min_rx_cps);
|
|
else if( sesslimit > 0 )
|
|
log("use restrictions: %d seconds", sesslimit);
|
|
|
|
DEB((D_PROT, "protinfo_init: min_tx_cps = %ld, min_rx_cps = %ld",
|
|
(long)pi->min_tx_cps, (long)pi->min_rx_cps));
|
|
DEB((D_PROT, "protinfo_init: buffersize = %ld, stoptime = %ld",
|
|
(long)pi->min_tx_cps, (long)pi->min_rx_cps));
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* Release memory used by protocol information structure
|
|
*
|
|
* Arguments:
|
|
* pi pointer to the protocol information structure
|
|
*
|
|
* Return value:
|
|
* None
|
|
*/
|
|
void deinit_protinfo(s_protinfo *pi)
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < pi->n_sentfiles; i++ )
|
|
deinit_finfo(&pi->sentfiles[i]);
|
|
|
|
for( i = 0; i < pi->n_rcvdfiles; i++ )
|
|
deinit_finfo(&pi->rcvdfiles[i]);
|
|
|
|
if( pi->buffer )
|
|
free(pi->buffer);
|
|
if( pi->sentfiles )
|
|
free(pi->sentfiles);
|
|
if( pi->rcvdfiles )
|
|
free(pi->rcvdfiles);
|
|
|
|
memset(pi, '\0', sizeof(s_protinfo));
|
|
}
|