1 /******************************************************************
2 * common protocols' file management
3 ******************************************************************/
4 /*
5 * $Id: protfm.c,v 1.18 2005/08/22 17:16:05 mitry Exp $
6 *
7 * $Log: protfm.c,v $
8 * Revision 1.18 2005/08/22 17:16:05 mitry
9 * Removed useless static function
10 *
11 * Revision 1.17 2005/08/16 14:49:01 mitry
12 * Replaced strncpy() with xstrcpy()
13 *
14 * Revision 1.16 2005/08/12 15:36:19 mitry
15 * Changed gmtoff()
16 *
17 * Revision 1.15 2005/05/17 18:17:42 mitry
18 * Removed system basename() usage.
19 * Added qbasename() implementation.
20 *
21 * Revision 1.14 2005/05/16 20:32:42 mitry
22 * Changed code a bit
23 *
24 * Revision 1.13 2005/05/06 20:37:38 mitry
25 * Fixed dangerous syntax BUG :)
26 *
27 * Revision 1.12 2005/05/05 19:20:09 mitry
28 * Changed rxopen() and rxclose() a bit
29 *
30 * Revision 1.11 2005/04/08 18:12:31 mitry
31 * check_cps() sets tty_gothup to HUP_CPS
32 *
33 * Revision 1.10 2005/04/07 13:05:11 mitry
34 * Added check of nullable tosend arg
35 *
36 * Revision 1.9 2005/03/31 19:40:38 mitry
37 * Update function prototypes and it's duplication
38 *
39 * Revision 1.8 2005/03/28 17:02:52 mitry
40 * Pre non-blocking i/o update. Mostly non working.
41 *
42 * Revision 1.7 2005/02/23 21:47:47 mitry
43 * tty_online and tty_gothup logic
44 *
45 * Revision 1.6 2005/02/22 13:56:53 mitry
46 * Removed warning about difference in signedness
47 *
48 * Revision 1.5 2005/02/21 16:33:42 mitry
49 * Changed tty_hangedup to tty_online
50 *
51 */
52
53 #include "headers.h"
54
55 #ifdef HAVE_UTIME_H
56 #include <utime.h>
57 #endif
58
59 #include <fnmatch.h>
60 #include "hydra.h"
61 #include "ls_zmodem.h"
62 #include "binkp.h"
63 #include "qipc.h"
64 #include "tty.h"
65
66 /* Common protocols' vars */
67 FILE *txfd=NULL, *rxfd=NULL;
68 volatile long txpos, rxpos;
69 word txblklen, rxblklen;
70 byte *txbuf, *rxbuf;
71 /*
72 word txretries, rxretries;
73 long txsyncid, rxsyncid;
74 dword txoptions, rxoptions;
75 */
76 unsigned effbaud=DEFAULT_SPEED;
77 byte *rxbufptr;
78 int txstate, rxstate;
79 byte *rxbufmax;
80 long txstart; /*, rxstart; */
81 word txmaxblklen;
82 word timeout;
83 byte txlastc;
84
85 #define CHAT_BUF 16384
86 static unsigned char qrcv_buf[MSG_BUFFER]={0};
87 static unsigned char qsnd_buf[CHAT_BUF]={0};
88 static unsigned char ubuf[CHAT_BUF];
89 static char hellostr[MAX_STRING];
90 static unsigned short qsndbuflen=0;
91
92 static char weskipstr[]="recd: %s, 0 bytes, 0 cps [%sskipped]";
93 static char wesusstr[]="recd: %s, 0 bytes, 0 cps [%ssuspended]";
94
sifname(char * s)95 static int sifname(char *s)
96 {
97 static char ALLOWED_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz";
98 static int CHARS = sizeof(ALLOWED_CHARS) / sizeof(char);
99 int i;
100 for(i = 0; i < CHARS; i++) if(*s < ALLOWED_CHARS[i]) { *s = ALLOWED_CHARS[i]; break; }
101 if(i == CHARS) return 1;
102 return 0;
103 }
104
estimatedtime(off_t size,int cps,unsigned long baud)105 static char *estimatedtime(off_t size, int cps, unsigned long baud)
106 {
107 static char et[16];
108 int h,m,s;
109 if (cps < 1) cps = baud / 10;
110 if (!cps) cps = 1;
111 s = size / cps;
112 if (s < 1) s = 1;
113 h = s / 3600; s %= 3600;
114 m = s / 60; s %= 60;
115 snprintf(et,16,"%02d:%02d:%02d",h,m,s);
116 return et;
117 }
118
rxopen(char * name,time_t rtime,off_t rsize,FILE ** f)119 int rxopen(char *name, time_t rtime, off_t rsize, FILE **f)
120 {
121 struct stat sb;
122 slist_t *i;
123 char p[MAX_PATH + 5], bn[MAX_PATH + 5];
124 int prevcps = (recvf.start&&(time(NULL)-recvf.start>2))?recvf.cps:effbaud/10,rc;
125
126 if(!name || !*name) return FOP_ERROR;
127 xstrcpy(bn, qbasename(name), MAX_PATH);
128 mapname((char*)bn, cfgs(CFG_MAPIN), MAX_PATH);
129 recvf.start=time(NULL);
130 xfree(recvf.fname);
131 recvf.fname=xstrdup(bn);
132 recvf.mtime=rtime-gmtoff(recvf.start);
133 recvf.ftot=rsize;
134 if(recvf.toff+rsize > recvf.ttot) recvf.ttot+=rsize;
135 recvf.nf++;if(recvf.nf>recvf.allf) recvf.allf++;
136 IFPerl(if((rc=perl_on_recv())!=FOP_OK)return rc);
137 if(whattype(name)==IS_PKT&&(rsize==60||!rsize)&&cfgi(CFG_KILLBADPKT))return FOP_SKIP;
138 rc=skipiftic;skipiftic=0;
139 if(rc&&istic(bn)&&cfgi(CFG_AUTOTICSKIP)) {
140 write_log(rc==FOP_SKIP?weskipstr:wesusstr,recvf.fname,"auto");
141 return rc;
142 }
143 for(i=cfgsl(CFG_AUTOSKIP);i;i=i->next)
144 if(!xfnmatch(i->str, bn, FNM_PATHNAME)) {
145 write_log(weskipstr,recvf.fname,"");
146 skipiftic=FOP_SKIP;
147 return FOP_SKIP;
148 }
149 for(i=cfgsl(CFG_AUTOSUSPEND);i;i=i->next)
150 if(!xfnmatch(i->str, bn, FNM_PATHNAME)) {
151 write_log(wesusstr,recvf.fname,"");
152 skipiftic=FOP_SUSPEND;
153 return FOP_SUSPEND;
154 }
155
156 snprintf(p, MAX_PATH, "%s/tmp/", cfgs(CFG_INBOUND));
157 if(stat(p, &sb))
158 if(mkdirs(p) && errno!=EEXIST) {
159 write_log("can't make directory %s: %s", p, strerror(errno));
160 write_log(wesusstr,recvf.fname,"");
161 skipiftic=FOP_SUSPEND;
162 return FOP_SUSPEND;
163 }
164 snprintf(p, MAX_PATH, "%s/%s", ccs, bn);
165
166 if(!stat(p, &sb) && sb.st_size==rsize) {
167 write_log(weskipstr,recvf.fname,"");
168 skipiftic=FOP_SKIP;
169 return FOP_SKIP;
170 }
171
172 snprintf(p, MAX_PATH, "%s/tmp/%s", ccs, bn);
173
174 if(!stat(p, &sb)) {
175 if(sb.st_size<rsize && sb.st_mtime==recvf.mtime) {
176 *f=fopen(p, "ab");
177 if(!*f) {
178 write_log("can't open file %s for writing: %s", p,strerror(errno));
179 write_log(wesusstr,recvf.fname,"");
180 skipiftic=FOP_SUSPEND;
181 return FOP_SUSPEND;
182 }
183 recvf.foff = recvf.soff = ftello( *f );
184 if(cfgi(CFG_ESTIMATEDTIME)) {
185 write_log("start recv: %s, %lu bytes (from %lu), estimated time %s",
186 recvf.fname, (long) rsize, (long) recvf.soff, estimatedtime(rsize-recvf.soff,prevcps,effbaud));
187 }
188 return FOP_CONT;
189 }
190 }
191
192 *f=fopen(p, "wb");
193 if(!*f) {
194 write_log("can't open file %s for writing: %s", p,strerror(errno));
195 write_log(wesusstr,recvf.fname,"");
196 skipiftic=FOP_SUSPEND;
197 return FOP_SUSPEND;
198 }
199 recvf.foff=recvf.soff=0;
200 if(cfgi(CFG_ESTIMATEDTIME)) {
201 write_log("start recv: %s, %lu bytes, estimated time %s",
202 recvf.fname, (long) rsize, estimatedtime(rsize,prevcps,effbaud));
203 }
204 return FOP_OK;
205 }
206
rxclose(FILE ** f,int what)207 int rxclose(FILE **f, int what)
208 {
209 long cps=time(NULL)-recvf.start;
210 int rc,overwrite;
211 char *ss, p[MAX_PATH+5], p2[MAX_PATH+5];
212 struct utimbuf ut;struct stat sb;
213 slist_t *i;
214
215 if(!f || !*f) return FOP_ERROR;
216 recvf.toff+=recvf.foff;recvf.stot+=recvf.soff;
217 *p2=0;
218 if(!cps) cps=1;cps=(recvf.foff-recvf.soff)/cps;
219 IFPerl(if((ss=perl_end_recv(what))) {
220 if(!*ss)what=FOP_SKIP;
221 else xstrcpy(p2,ss,MAX_PATH);});
222 switch(what) {
223 case FOP_SUSPEND: ss="suspended";break;
224 case FOP_SKIP: ss="skipped";break;
225 case FOP_ERROR: ss="error";break;
226 case FOP_OK: ss="ok";break;
227 default: ss="";
228 }
229 if(recvf.soff)
230 write_log("rcvd: %s, %lu bytes (from %lu), %ld cps [%s]",
231 recvf.fname, (long) recvf.foff, (long) recvf.soff, cps, ss);
232 else
233 write_log("rcvd: %s, %lu bytes, %ld cps [%s]",
234 recvf.fname, (long) recvf.foff, cps, ss);
235 fclose(*f);*f=NULL;
236 snprintf(p, MAX_PATH, "%s/tmp/%s", cfgs(CFG_INBOUND), recvf.fname);
237 if(*p2) {
238 if(*p2!='/'&&*p2=='.') {
239 ss=xstrdup(p2);
240 snprintf(p2,MAX_PATH,"%s/%s",cfgs(CFG_INBOUND),ss);
241 xfree(ss);
242 }
243 } else snprintf(p2, MAX_PATH, "%s/%s", cfgs(CFG_INBOUND), recvf.fname);
244 ut.actime=ut.modtime=recvf.mtime;
245 recvf.foff=0;
246 switch(what) {
247 case FOP_SKIP:
248 lunlink(p);
249 break;
250 case FOP_SUSPEND:
251 case FOP_ERROR:
252 if(whattype(p)==IS_PKT&&cfgi(CFG_KILLBADPKT))lunlink(p);
253 else utime(p,&ut);
254 break;
255 case FOP_OK:
256 rc=receive_callback?receive_callback(p):0;
257 if(rc) lunlink(p);
258 else {
259 ss=p2+strlen(p2)-1;overwrite=0;
260 for(i=cfgsl(CFG_ALWAYSOVERWRITE);i;i=i->next)
261 if(!xfnmatch(i->str,recvf.fname,FNM_PATHNAME))
262 overwrite=1;
263 while(!overwrite&&!stat(p2, &sb)&&p2[0]) {
264 if(sifname(ss)) {
265 ss--;
266 while('.' == *ss && ss >= p2) ss--;
267 if(ss < p2) {
268 write_log("can't find suitable name for %s: leaving in temporary directory",p);
269 p2[0] = '\x00';
270 }
271 }
272 }
273 if(p2[0]) {
274 if(overwrite)lunlink(p2);
275 if(rename(p, p2)) {
276 write_log("can't rename %s to %s: %s",p,p2,strerror(errno));
277 } else {
278 utime(p2,&ut);chmod(p2,cfgi(CFG_DEFPERM));
279 }
280 }
281 }
282 break;
283 }
284 if(what==FOP_SKIP||what==FOP_SUSPEND)skipiftic=what;
285 recvf.start=0;recvf.ftot=0;
286 rxstatus=0;
287 return what;
288 }
289
txopen(char * tosend,char * sendas)290 FILE *txopen(char *tosend, char *sendas)
291 {
292 FILE *f;
293 struct stat sb;
294 int prevcps = (sendf.start&&(time(NULL)-sendf.start>2))?sendf.cps:effbaud/10;
295
296 if ( !tosend )
297 return NULL;
298
299 if(stat(tosend, &sb)) {
300 write_log("can't find file %s", tosend);
301 return NULL;
302 }
303 if(whattype(sendas)==IS_PKT&&sb.st_size==60)return NULL;
304 xfree(sendf.fname);
305 sendf.fname=xstrdup(sendas);
306 sendf.ftot=sb.st_size;
307 sendf.foff=sendf.soff=0;
308 sendf.start=time(NULL);
309 sendf.mtime=sb.st_mtime+gmtoff(sendf.start);
310 if(sendf.toff+sb.st_size > sendf.ttot) sendf.ttot+=sb.st_size;
311 sendf.nf++;if(sendf.nf>sendf.allf) sendf.allf++;
312 IFPerl({char *p=perl_on_send(tosend);if(p&&!*p)return NULL;
313 if(p){xfree(sendf.fname);sendf.fname=xstrdup(p);}});
314 f=fopen(tosend, "rb");
315 if(!f) {
316 write_log("can't open file %s for reading: %s", tosend,strerror(errno));
317 return NULL;
318 }
319 if(cfgi(CFG_ESTIMATEDTIME)) {
320 write_log("start send: %s, %lu bytes, estimated time %s",
321 sendf.fname, (long) sendf.ftot, estimatedtime(sendf.ftot,prevcps,effbaud));
322 }
323 return f;
324 }
325
txclose(FILE ** f,int what)326 int txclose(FILE **f, int what)
327 {
328 long cps=time(NULL)-sendf.start;
329 char *ss;
330
331 if(!f || !*f) return FOP_ERROR;
332 sendf.toff+=sendf.foff;sendf.stot+=sendf.soff;
333
334 if(!cps) cps=1;cps=(sendf.foff-sendf.soff)/cps;
335 IFPerl(perl_end_send(what));
336 switch(what) {
337 case FOP_SUSPEND: ss="suspended";break;
338 case FOP_SKIP: ss="skipped";break;
339 case FOP_ERROR: ss="error";break;
340 case FOP_OK: ss="ok";break;
341 default: ss="";
342 }
343 if(sendf.soff)write_log("sent: %s, %lu bytes (from %lu), %ld cps [%s]",
344 sendf.fname, (long) sendf.foff, (long) sendf.soff, cps, ss);
345 else write_log("sent: %s, %lu bytes, %ld cps [%s]",
346 sendf.fname, (long) sendf.foff, cps, ss);
347 sendf.foff=0;sendf.ftot=0;
348 sendf.start=0;
349 fclose(*f);*f=NULL;
350 return what;
351 }
352
chatinit(int prot)353 void chatinit(int prot)
354 {
355 xstrcpy(hellostr,"\05\05\05",MAX_STRING);
356 strtr(cfgs(CFG_CHATHALLOSTR),'|','\n');strtr(ccs,'$','\a');
357 snprintf(hellostr+3,MAX_STRING-7,ccs,rnode->sysop);
358 recode_to_remote(hellostr);
359 xstrcat(hellostr,"\05\05\05",MAX_STRING);
360 chattimer=0;
361 chatlg=0;
362 qsndbuflen=0;
363 *qsnd_buf=0;
364 switch(prot) {
365 case P_ZEDZAP:
366 case P_DIRZAP:
367 case P_ZMODEM:
368 chatprot=P_ZMODEM;
369 break;
370 case P_HYDRA:
371 #ifdef HYDRA8K16K
372 case P_HYDRA4:
373 case P_HYDRA8:
374 case P_HYDRA16:
375 #endif/*HYDRA8K16K*/
376 chatprot=P_HYDRA;
377 break;
378 case P_JANUS:
379 chatprot=P_JANUS;
380 break;
381 #ifdef WITH_BINKP
382 case 0:
383 if(bink)chatprot=P_BINKP;
384 #endif
385 }
386 }
387
c_devfree(void)388 int c_devfree(void)
389 {
390 int rc=0;
391 switch(chatprot) {
392 case P_ZMODEM:
393 rc=z_devfree();
394 break;
395 case P_HYDRA:
396 rc=hydra_devfree();
397 break;
398 #ifdef WITH_BINKP
399 case P_BINKP:
400 rc=binkp_devfree();
401 #endif
402 }
403 return rc;
404 }
405
c_devsend(unsigned char * str,unsigned len)406 int c_devsend(unsigned char *str,unsigned len)
407 {
408 int rc=0;
409 switch(chatprot) {
410 case P_ZMODEM:
411 rc=z_devsend(str,len-1);
412 break;
413 case P_HYDRA:
414 rc=hydra_devsend("CON",str,len);
415 break;
416 #ifdef WITH_BINKP
417 case P_BINKP:
418 rc=binkp_devsend(str,len);
419 #endif
420 }
421 return rc;
422 }
423
chatsend(unsigned char * str)424 int chatsend(unsigned char *str)
425 {
426 if(!str||!*str)return 0;
427 if(!c_devfree())return 1;
428 if(chattimer<2) {
429 c_devsend((unsigned char*)hellostr,strlen(hellostr)+1);
430 chatlg=chatlog_init(rnode->sysop,&rnode->addrs->addr,0);
431 qchat("");
432 } else if(*str!=5) {
433 xstrcpy( (char*) ubuf, (char*) str, CHAT_BUF);
434 recode_to_remote((char*)ubuf);
435 if(!c_devsend(ubuf,strlen((char*)ubuf)))return 1;
436 if(chatlg)chatlog_write((char*)str,0);
437 } else write_log("Chat already opened!");
438 chattimer=time(NULL)+TIM_CHAT;
439 return 0;
440 }
441
c_devrecv(unsigned char * data,unsigned len)442 void c_devrecv(unsigned char *data,unsigned len)
443 {
444 int i;
445 if(!data||!*data||!len)return;
446 data[len]=0;
447 if(chattimer<2) {
448 char *p;
449 if(len>5&&data[1]!=5&&(p=strstr((char*)data," * "))&&(strstr(p+3,"lose")||strstr(p+3,"has chat")))return;
450 c_devsend((unsigned char*)hellostr,strlen(hellostr));
451 chatlg=chatlog_init(rnode->sysop,&rnode->addrs->addr,1);
452 }
453 recode_to_local((char*)data);
454 if(data[strlen((char*)data)-1]==5)data[strlen((char*)data)-1]='\n';
455 for(len=i=0;len<=strlen((char*)data);len++)if(data[len]!=5)data[i++]=data[len];
456 chattimer=time(NULL)+TIM_CHAT;
457 if(chatlg)chatlog_write((char*)data,1);
458 qchat((char*)data);
459 }
460
getevt(void)461 void getevt(void)
462 {
463 int i;
464 while(qrecvpkt((char*)qrcv_buf)) {
465 switch(qrcv_buf[2]) {
466 case QR_SKIP:
467 rxstatus=RX_SKIP;
468 break;
469 case QR_REFUSE:
470 rxstatus=RX_SUSPEND;
471 break;
472 case QR_HANGUP:
473 tty_gothup = HUP_OPERATOR;
474 break;
475 case QR_CHAT:
476 if(qrcv_buf[3]) {
477 xstrcpy((char*)(qsnd_buf+qsndbuflen),(char*)(qrcv_buf+3),CHAT_BUF-qsndbuflen);
478 qsndbuflen+=strlen((char*)(qrcv_buf+3));
479 if(qsndbuflen>CHAT_BUF-128)qsndbuflen=CHAT_BUF-128;
480 } else {
481 i=chatprot;chatprot=-1;
482 chatsend(qsnd_buf);
483 if(chatlg)chatlog_done();
484 chatlg=0;chatprot=i;
485 xstrcat((char*)qsnd_buf,"\n * Chat closed\n",CHAT_BUF);
486 chatsend(qsnd_buf);
487 if(chattimer>1)qlcerase();
488 qsndbuflen=0;
489 chattimer=1;
490 }
491 break;
492 }
493 qsnd_buf[qsndbuflen]=0;
494 }
495 if(qsndbuflen>0)if(!chatsend(qsnd_buf))qsndbuflen=0;
496 }
497
check_cps(void)498 void check_cps(void)
499 {
500 int cpsdelay=cfgi(CFG_MINCPSDELAY),ncps=rnode->realspeed/1000,r=cfgi(CFG_REALMINCPS);
501 if(!(sendf.cps=time(NULL)-sendf.start))sendf.cps=1;
502 else sendf.cps=(sendf.foff-sendf.soff)/sendf.cps;
503 if(!(recvf.cps=time(NULL)-recvf.start))recvf.cps=1;
504 else recvf.cps=(recvf.foff-recvf.soff)/recvf.cps;
505 if(sendf.start&&cfgi(CFG_MINCPSOUT)>0&&(time(NULL)-sendf.start)>cpsdelay&&sendf.cps<(r?cci:cci*ncps)) {
506 write_log("mincpsout=%d reached, aborting session",r?cci:cci*ncps);
507 tty_gothup = HUP_CPS;
508 }
509 if(recvf.start&&cfgi(CFG_MINCPSIN)>0&&(time(NULL)-recvf.start)>cpsdelay&&recvf.cps<(r?cci:cci*ncps)) {
510 write_log("mincpsin=%d reached, aborting session",r?cci:cci*ncps);
511 tty_gothup = HUP_CPS;
512 }
513 getevt();
514 }
515