688 lines
15 KiB
C
688 lines
15 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: MBSE BBS Daemon
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2006
|
|
*
|
|
* Michiel Broek FIDO: 2:280/2802
|
|
* Beekmansbos 10
|
|
* 1971 BV IJmuiden
|
|
* the Netherlands
|
|
*
|
|
* This file is part of MBSE BBS.
|
|
*
|
|
* This BBS 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, or (at your option) any
|
|
* later version.
|
|
*
|
|
* MB BBS is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MB BBS; see the file COPYING. If not, write to the Free
|
|
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/mbselib.h"
|
|
#include "taskstat.h"
|
|
#include "taskregs.h"
|
|
#include "taskdisk.h"
|
|
#include "taskinfo.h"
|
|
#include "taskutil.h"
|
|
#include "taskchat.h"
|
|
#include "taskcomm.h"
|
|
#include "taskibc.h"
|
|
|
|
|
|
extern int oserr; /* Copy of Unix error */
|
|
extern int sock; /* Server socket */
|
|
extern struct sockaddr_un from; /* From socket address */
|
|
extern int fromlen; /* From address length */
|
|
extern int logtrans; /* Log transactions */
|
|
|
|
|
|
|
|
/************************************************************************
|
|
*
|
|
* Logging procedures.
|
|
*/
|
|
|
|
int userlog(char *);
|
|
int userlog(char *param)
|
|
{
|
|
char *prname, *prpid, *grade, *msg;
|
|
static char lfn[PATH_MAX], token[14];
|
|
int rc;
|
|
|
|
lfn[0] = '\0';
|
|
strncpy(token, strtok(param, ","), 14);
|
|
strncpy(token, strtok(NULL, ","), 14);
|
|
snprintf(lfn, PATH_MAX, "%s/log/%s", getenv("MBSE_ROOT"), token);
|
|
prname = strtok(NULL, ",");
|
|
prpid = strtok(NULL, ",");
|
|
grade = strtok(NULL, ",");
|
|
msg = xstrcpy(cldecode(strtok(NULL, ";")));
|
|
rc = ulog(lfn, grade, prname, prpid, msg);
|
|
free(msg);
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Process command received from the client.
|
|
*/
|
|
char *exe_cmd(char *);
|
|
char *exe_cmd(char *in)
|
|
{
|
|
static char obuf[SS_BUFSIZE];
|
|
static char ibuf[SS_BUFSIZE];
|
|
static char cmd[4];
|
|
static char token[SS_BUFSIZE];
|
|
static char ebuf[19];
|
|
static char *cnt, var1[16];
|
|
int result;
|
|
char *buf;
|
|
|
|
strncpy(ibuf, in, SS_BUFSIZE);
|
|
strncpy(cmd, ibuf, 4);
|
|
// token[0] = '\0';
|
|
strncpy(ebuf, "200:1,Syntax error;", 19);
|
|
|
|
/*
|
|
* Split the commandline after the colon so we can give the
|
|
* options directly to the actual functions. Also set a default
|
|
* and most used answer.
|
|
*/
|
|
strncpy(token, &ibuf[5], SS_BUFSIZE);
|
|
strncpy(obuf, "100:0;", SS_BUFSIZE);
|
|
|
|
|
|
/*
|
|
* The A(counting) commands.
|
|
*
|
|
* AINI:5,pid,tty,user,program,city;
|
|
* 100:1,linenr;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "AINI", 4) == 0) {
|
|
if ((result = reg_newcon(token)) != -1) {
|
|
snprintf(obuf, SS_BUFSIZE, "100:1,%d;", result);
|
|
return obuf;
|
|
} else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ACLO:1,pid;
|
|
* 107:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd ,"ACLO", 4) == 0) {
|
|
if (reg_closecon(token) == 0) {
|
|
strcpy(obuf, "107:0;");
|
|
return obuf;
|
|
} else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ADOI:2,pid,doing;
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "ADOI", 4) == 0) {
|
|
if (reg_doing(token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ATCP:1,pid;
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "ATCP", 4) == 0) {
|
|
if (reg_ip(token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ATTY:2,pid,tty;
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "ATTY", 4) == 0) {
|
|
if (reg_tty(token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ALOG:5,file,program,pid,grade,text;
|
|
* 100:0;
|
|
* 201:1,errno;
|
|
*/
|
|
if (strncmp(cmd, "ALOG", 4) == 0) {
|
|
if (userlog(token) != 0)
|
|
snprintf(obuf, SS_BUFSIZE, "201:1,%d;", oserr);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* AUSR:3,pid,user,city;
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "AUSR", 4) == 0) {
|
|
if (reg_user(token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ADIS:2,pid,flag; (set Do Not Disturb).
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "ADIS", 4) == 0) {
|
|
if (reg_silent(token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ATIM:2,pid,seconds;
|
|
* 100:0;
|
|
* 200:1,Syntax Error;
|
|
*/
|
|
if (strncmp(cmd, "ATIM", 4) == 0) {
|
|
if (reg_timer(TRUE, token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ADEF:1,pid;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "ADEF", 4) == 0) {
|
|
if (reg_timer(FALSE, token) == 0)
|
|
return obuf;
|
|
else {
|
|
stat_inc_serr();
|
|
return ebuf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for personal message
|
|
*
|
|
* CIPM:1,pid; (Is personal message present)
|
|
* 100:2,fromname,message;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "CIPM", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
reg_ipm_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* CSPM:3,fromuser,touser,text; (Send personal message).
|
|
* 100:1,n; n: 1=donotdisturb 2=buffer full 3=error
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "CSPM", 4) == 0) {
|
|
if ((result = reg_spm(token)))
|
|
snprintf(obuf, SS_BUFSIZE, "100:1,%d;", result);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* CSYS:2,pid,1; Sysop available for chat (from mbmon)
|
|
* CSYS:2,pid,0; Sysop goes away (from mbmon)
|
|
* 100:0; Allways Ok.
|
|
*/
|
|
if (strncmp(cmd, "CSYS", 4) == 0) {
|
|
reg_sysop(token);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* CPAG:2,pid,reason; Page sysop for a chat
|
|
* 100:1,n; 1=busy, 2=sysop not available, 3=error
|
|
* 100:0; Ok
|
|
*/
|
|
if (strncmp(cmd, "CPAG", 4) == 0) {
|
|
if ((result = reg_page(token))) {
|
|
snprintf(obuf, SS_BUFSIZE, "100:1,%d;", result);
|
|
}
|
|
Syslog('+', "%s", obuf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* CCAN:1,pid; Cancel sysop page
|
|
* 100:0; Always Ok
|
|
*/
|
|
if (strncmp(cmd, "CCAN", 4) == 0) {
|
|
reg_cancel(token);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Check for sysop page (from mbmon)
|
|
*
|
|
* CCKP:0;
|
|
* 100:3,pid,1,reason; Page is active
|
|
* 100:3,pid,0,reason; Page is canceled, but user still online
|
|
* 100:0; No page active
|
|
*/
|
|
if (strncmp(cmd, "CCKP", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
reg_checkpage_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Check for sysop in chatmode for forced sysop chat
|
|
*
|
|
* CISC:1,pid;
|
|
* 100:1,1; Yes (and drop into chatmode)
|
|
* 100:1,0; No
|
|
*/
|
|
if (strncmp(cmd, "CISC", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
chat_checksysop_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Connect to chatserver
|
|
*
|
|
* CCON:4,pid,username,unixname,n; Connect to chatserver with username, n=1 user is the sysop
|
|
* 100:1,error; If error
|
|
* 100:0; Ok
|
|
*/
|
|
if (strncmp(cmd, "CCON", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
chat_connect_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Close chat session
|
|
*
|
|
* CCLO:1,pid; Leave chatserver
|
|
* 100:1,error; Error
|
|
* 100:0; Ok
|
|
*/
|
|
if (strncmp(cmd, "CCLO", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
chat_close_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Put message on server
|
|
*
|
|
* CPUT:2,pid,message; Put message on server
|
|
* 100:2,0,error; Error, not fatal and continue chat
|
|
* 100:2,1,error; Error, fatal and disconnect
|
|
* 100:0; Ok
|
|
*/
|
|
if (strncmp(cmd, "CPUT", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
chat_put_r(token, buf);
|
|
strncpy(obuf, buf, SS_BUFSIZE);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* Get message from server
|
|
*
|
|
* CGET:1,pid; Get message from server
|
|
* 100:2,0,message; If message present
|
|
* 100:2,1,error; Error and disconnect
|
|
* 100:0; No message
|
|
*/
|
|
if (strncmp(cmd, "CGET", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
chat_get_r(token, buf);
|
|
strncpy(obuf, buf, SS_BUFSIZE);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* The D(isk) commands.
|
|
*/
|
|
|
|
/*
|
|
* DRES:0; Reset and reread disk tables.
|
|
* 100:0; Always Ok.
|
|
*/
|
|
if (strncmp(cmd, "DRES", 4) == 0) {
|
|
return disk_reset();
|
|
}
|
|
|
|
/*
|
|
* DSPC:1,n; Check free space in MBytes
|
|
* 100:2,0,n; No, n = lowest size in MBytes
|
|
* 100:2,1,n; Yes, n = lowest size in MBytes
|
|
* 100:1,2; Unknown
|
|
* 100:1,3; Error
|
|
*/
|
|
if (strncmp(cmd, "DSPC", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
disk_check_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* DGFS:0; Get filesystem status.
|
|
* 100:n,data1,..,data10;
|
|
*/
|
|
if (strncmp(cmd, "DGFS", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
disk_getfs_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* The G(lobal) commands.
|
|
*
|
|
* GNOP:1,pid;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd ,"GNOP", 4) == 0) {
|
|
reg_nop(token);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GPNG:n,data;
|
|
* 100:n,data;
|
|
*/
|
|
if (strncmp(cmd, "GPNG", 4) == 0) {
|
|
snprintf(obuf, SS_BUFSIZE, "100:%s", token);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GVER:0;
|
|
* 100:1,Version ...;
|
|
*/
|
|
if (strncmp(cmd, "GVER", 4) == 0) {
|
|
snprintf(obuf, SS_BUFSIZE, "100:1,Version %s;", VERSION);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GSTA:0;
|
|
* 100:19,start,laststart,daily,startups,clients,tot_clients,tot_peak,tot_syntax,tot_comerr,
|
|
* today_clients,today_peak,today_syntax,today_comerr,!BBSopen,ZMH,internet,Processing,Load,sequence;
|
|
* 201:1,16;
|
|
*/
|
|
if (strncmp(cmd, "GSTA", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
stat_status_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GMON:1,n; n=1 First time
|
|
* 100:7,pid,tty,user,program,city,isdoing,starttime;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "GMON", 4) == 0) {
|
|
cnt = strtok(token, ",");
|
|
strcpy(var1, strtok(NULL, ";"));
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
get_reginfo_r(atoi(var1), buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GDST:0; Obsolete!
|
|
* 100:n,data1,..,data10;
|
|
*/
|
|
// if (strncmp(cmd, "GDST", 4) == 0) {
|
|
// buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
// disk_getfs_r(buf);
|
|
// snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
// free(buf);
|
|
// return obuf;
|
|
// }
|
|
|
|
/*
|
|
* GSYS:0;
|
|
* 100:7,calls,pots_calls,isdn_calls,network_calls,local_calls,startdate,last_caller;
|
|
* 201:1,16;
|
|
*/
|
|
if (strncmp(cmd, "GSYS", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
get_sysinfo_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GLCC:0;
|
|
* 100:1,n;
|
|
*/
|
|
if (strncmp(cmd, "GLCC", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
get_lastcallercount_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* GLCR:1,recno;
|
|
* 100:9,user,location,level,device,time,mins,calls,speed,actions;
|
|
* 201:1,16;
|
|
*/
|
|
if (strncmp(cmd, "GLCR", 4) == 0) {
|
|
cnt = strtok(token, ",");
|
|
strcpy(var1, strtok(NULL, ";"));
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
get_lastcallerrec_r(atoi(var1), buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
|
|
/*
|
|
* The (S)tatus commands.
|
|
*
|
|
* SBBS:0;
|
|
* 100:2,n,status message;
|
|
*/
|
|
if (strncmp(cmd, "SBBS", 4) == 0) {
|
|
switch(stat_bbs_stat()) {
|
|
case 0: snprintf(obuf, SS_BUFSIZE, "100:2,0,The system is open for use;");
|
|
break;
|
|
case 1: snprintf(obuf, SS_BUFSIZE, "100:2,1,The system is closed right now!;");
|
|
break;
|
|
case 2: snprintf(obuf, SS_BUFSIZE, "100:2,2,The system is closed for Zone Mail Hour!;");
|
|
break;
|
|
}
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SOPE:0;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "SOPE", 4) == 0) {
|
|
stat_set_open(1);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SCLO:0;
|
|
* 100:0;
|
|
*/
|
|
if (strncmp(cmd, "SCLO", 4) == 0) {
|
|
stat_set_open(0);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SFRE:0;
|
|
* 100:1,Running utilities: n Active users: n;
|
|
* 100:0;
|
|
* 201:1,16;
|
|
*/
|
|
if (strncmp(cmd, "SFRE", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
reg_fre_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SSEQ:0;
|
|
* 100:1,number;
|
|
* 200:1,16;
|
|
*/
|
|
if (strncmp(cmd, "SSEQ", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
getseq_r(buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SEST:1,semafore; Get status of semafore
|
|
* 100:1,n; 1 = set, 0 = not set
|
|
* 200:1,16;
|
|
*/
|
|
if (strncmp(cmd, "SEST", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
sem_status_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SECR:1,semafore; Set semafore
|
|
* 100:0;
|
|
* 200:1,16;
|
|
*/
|
|
if (strncmp(cmd, "SECR", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
sem_create_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
/*
|
|
* SERM:1,semafore; Remove semafore
|
|
* 100:0;
|
|
* 200:1,16;
|
|
*/
|
|
if (strncmp(cmd, "SERM", 4) == 0) {
|
|
buf = calloc(SS_BUFSIZE, sizeof(char));
|
|
sem_remove_r(token, buf);
|
|
snprintf(obuf, SS_BUFSIZE, "%s", buf);
|
|
free(buf);
|
|
return obuf;
|
|
}
|
|
|
|
|
|
/*
|
|
* If we got this far, there must be an error.
|
|
*/
|
|
stat_inc_serr();
|
|
Syslog('!', "Comm systax error: \"%s:%s\"", cmd, printable(token, 0));
|
|
return ebuf;
|
|
}
|
|
|
|
|
|
|
|
void do_cmd(char *cmd)
|
|
{
|
|
char buf[SS_BUFSIZE];
|
|
int slen, tries = 0;
|
|
|
|
if (logtrans)
|
|
Syslog('-', "< %s", cmd);
|
|
snprintf(buf, SS_BUFSIZE, "%s", exe_cmd(cmd));
|
|
if (logtrans)
|
|
Syslog('-', "> %s", buf);
|
|
|
|
for (;;) {
|
|
slen = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&from, fromlen);
|
|
if (slen == -1)
|
|
Syslog('?', "$do_cmd(): sendto error %d %s", tries, from.sun_path);
|
|
else if (slen != strlen(buf))
|
|
Syslog('?', "do_cmd(): send %d of %d bytes, try=%d", slen, strlen(buf), tries);
|
|
else
|
|
return;
|
|
tries++;
|
|
if (tries == 3)
|
|
return;
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
|