/* * request.c * (C) Peter Salanki 2004 * This program is copyright, and covered by the Gnu Public License. * The Natasha bot. * sorcer@linux.se */ #include #include #include #include #include #include #include #include #include #include #include #include "../../settings.h" #include "../../globals.h" #include "../../bottypes.h" #include "settings.h" #define NAME "Request" #define VERSION 1.00 #define END_LINE 0x0A /* \n */ void parseline(char *line); void onchan(struct arm *a); void response(int code); void handlerequest(char *chan, char *nick, char *arm); void handleaccept(char *chan, char *nick, char *arm, int uid); void handledecline(char *chan, char *nick, char *arm, int uid); void spewchan(void); int read_line(char *line_to_return); void *listener(void* ptr); int checksip(struct sockaddr_in *cliAddr); int putsocket(char *text, int fd); void cleanup(void); MODULE_INIT _module_init(MODULE m); MODULE_DESTROY _module_destroy(MODULE m); int nextspew; char glarm[NICKLEN]; char glrequester[NICKLEN]; int linkfd = 0; int listenfd = 0; short destroylistener = 0; pthread_t listenerthread; MODULE_INIT _module_init(MODULE m) { strncpy(m->name, NAME, 20); strncpy(m->compiledate, __DATE__ " " __TIME__, 30); m->version = VERSION; if(findarmbytype(BOT_CHECK) == NULL) { printf("Error: There is no checker service added to database. The Request module loading is aborted.\n"); return; } if(findchannel(PUBCHAN) == NULL) { printf("Error: The service is not in PUBCHAN. The Request module loading is aborted.\n"); return; } cleanup(); /* Create listener thread */ if(pthread_create(&listenerthread, NULL, listener, NULL)) printf("Error creating thread for request listener.\n"); pthread_detach(listenerthread); /* Detach thread */ } MODULE_DESTROY _module_destroy(MODULE m) { destroylistener = 1; close(linkfd); close(listenfd); } void cleanup (void) { /* This function will clean up all channels that the check service may have left in the channels db */ char query[MAX_QUERY]; snprintf(query, MAX_QUERY, "DELETE FROM `channels` WHERE `arm` = %i", findarmbytype(BOT_CHECK)->id); dbquery(query); EndDbQuery(); } /* Network functions */ int putsocket (char *text, int fd) { int l, j; l = strlen (text); j = write (fd, text, l); #ifdef DEBUG write (1, text, l); #endif if (j != l) { perror ("write:"); return 0; } return 1; } void *listener(void* ptr) { int cliLen; struct sockaddr_in cliAddr, servAddr; char line[MAX_NETDATA]; /* create the socket */ listenfd = socket(AF_INET, SOCK_STREAM, 0); if(listenfd<0) { perror("Error: listener cannot open socket "); return NULL; } /* bind our socket to server port */ servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = htonl(INADDR_ANY); servAddr.sin_port = htons(REQUEST_PORT); if(bind(listenfd, (struct sockaddr *) &servAddr, sizeof(servAddr))<0) { perror("Error: request-listener cannot bind port "); return NULL; } listen(listenfd, 5); printf("Request is waiting for connections on %u\n", REQUEST_PORT); while(1) { cliLen = sizeof(cliAddr); linkfd = accept(listenfd, (struct sockaddr *) &cliAddr, &cliLen); if(checksip(&cliAddr)) { if(linkfd < 0) { /* an error occured */ perror("Error: listener cannot accept connection "); return NULL; } /* init line */ memset(line,0x0,MAX_NETDATA); /* receive segments */ while(read_line(line)!=1) { #ifdef DEBUG printf("Request-Received: %s\n", line); #endif parseline(line); /* Parse the data */ memset(line,0x0,MAX_NETDATA); /* init line */ } } else { putsocket("You are not allowed to connect from this host.\n", linkfd); close(linkfd); sprintf(line, "%c4Warning:%c Request-Unauthorized connection from: %c%s%c", COLORS, COLORS, BOLD, inet_ntoa(cliAddr.sin_addr), BOLD); privmsg(HOMECHAN, line); } if(destroylistener) return NULL; } } int read_line(char *line_to_return) { static int rcv_ptr=0; static char rcv_msg[MAX_NETDATA]; static int n; int offset; offset=0; while(1) { if(rcv_ptr==0) { /* read data from socket */ memset(rcv_msg,0x0,MAX_NETDATA); /* init buffer */ n = recv(linkfd, rcv_msg, MAX_NETDATA, 0); /* wait for data */ if (n<0) { /* error! */ return 1; } else if (n==0) { /* the connection was closed */ close(linkfd); return 1; } } /* if new data read on socket */ /* OR */ /* if another line is still in buffer */ /* copy line into 'line_to_return' */ while(*(rcv_msg+rcv_ptr)!=END_LINE && rcv_ptr return line */ if(rcv_ptr==n-1) { /* set last byte to END_LINE */ *(line_to_return+offset)=END_LINE; rcv_ptr=0; return ++offset; } /* end of line but still some data in buffer => return line */ if(rcv_ptr */ /* wait for more data to arrive on socket */ if(rcv_ptr == n) { rcv_ptr = 0; } } /* end while */ } int checksip(struct sockaddr_in *cliAddr) { return 1; } /* Request functions */ void parseline(char *line) { char chan[CHANNELLEN]; char nick[NICKLEN]; char arm[NICKLEN]; char command[30]; int uid; sscanf(line, "%s", command); if(strcmp(command, "REQUEST") == 0) { sscanf(line, "%s %s %s %s", command, chan, nick, arm); Lock(); /* Lock Natasha */ handlerequest(chan, nick, arm); Unlock(); /* Unlock Natasha */ return; } else if(strcmp(command, "HANDLE") == 0) { sscanf(line, "%s %s %s %s %i", command, chan, nick, arm, &uid); Lock(); /* Lock Natasha */ handleaccept(chan, nick, arm, uid); Unlock(); /* Unlock Natasha */ return; } else if(strcmp(command, "DECLINE") == 0) { sscanf(line, "%s %s %s %s %i", command, chan, nick, arm, &uid); Lock(); /* Lock Natasha */ handledecline(chan, nick, arm, uid); Unlock(); /* Unlock Natasha */ return; } else if(strcmp(command, "RELOAD") == 0) { sscanf(line, "%*s %i", &uid); Lock(); /* Lock Natasha */ ReloadChannel(findchannelbyid(uid)); Unlock(); /* Unlock Natasha */ return; } } void handlerequest(char *chan, char *nick, char *arm) { // Return codes: 0 = banned 1 = Not on chan/no op 2 = No L, placed in queue 3 = Auto accepted 4 = Not auth'd 5 = No such user 6 = Internal error 7 = Not requestok 8 = Not enough users 9 = Not enough users with unique hosts struct activeuser *u; printf("Handleing request for %s to %s nick: %s\n", arm, chan, nick); if(findarmbytype(BOT_CHECK)->status == 0 || findchannel(chan) != NULL || strcasecmp(chan, HOMECHAN) == 0) { printf("Warning: Internal error in request.\n"); response(6); return; } if((u = findauser(nick)) == NULL) { response(5); return; } else if(u->auth == UNAUTHED) { add(u); response(4); return; } else if(u->requestok == 0) { response(7); return; } u->requestok = 0; strncpy(glarm, arm, NICKLEN); strncpy(glrequester, nick, NICKLEN); c_join(chan, findarmbytype(BOT_CHECK)); } void spewchan(void) { int i; char queuen, queuea[4]; char msg[512]; if(time(NULL) >= nextspew) { i = ItemsInQueue(); if(i > 1 || i == 0) { strcpy(queuea, "are"); queuen = 's'; } else { strcpy(queuea, "is"); queuen = ' '; } snprintf(msg, 512, "There %s %c%i%c item%c in queue.", queuea, BOLD, i, BOLD, queuen); privmsg(PUBCHAN, msg); nextspew = time(NULL) + QUEUEREPEAT; } } void response(int code) { char msg[MAX_NETDATA]; sprintf(msg, "%i\n", code); putsocket(msg, linkfd); close(linkfd); } void onchan(struct arm *a) { #ifdef AUTOACCEPT char msg[512]; #endif char query[MAX_QUERY]; char hosts[MINUNIQUE][HOSTLEN]; char *channel; char service = ' '; int tmp, chost, i, clone; struct activechanuser *acu; struct activeuser *mu; struct channel *c; char *estopic, *esnick; // SYNTAX: chan nick bot socket // Return codes: 0 = banned 1 = Not on chan/no op 2 = No L, placed in queue 3 = Auto accepted 4 = Not auth'd 5 = No such user 8 = Not enough users 9 = Not enough users with unique hosts channel = a->parsevars->args[1]; c = findchannel(channel); mu = findauser(glrequester); acu = firstacu; tmp = 0; /* Some inits */ for(chost = 0; chost < MINUNIQUE; ++chost) strncpy(hosts[chost], "", HOSTLEN); chost = 0; while (acu != NULL) { if(acu->channel == c && strcasecmp(a->nick, acu->user->nick) != 0) { /* Clonescan */ clone = 0; if(chost < MINUNIQUE) { for(i = 0; i <= chost; ++i) if(strcasecmp(acu->user->hostname, hosts[i]) == 0) clone = 1; if(clone == 0) { ++chost; strncpy(hosts[chost], acu->user->hostname, HOSTLEN); } } ++tmp; } acu = acu->next; } #ifdef Q #ifdef L if(findachanuser(findauser(L_NICK), c) != NULL) service = 'L'; #endif if(findachanuser(findauser(Q_NICK), c) != NULL) service = 'Q'; #endif acu = findachanuser(mu, c); if(acu == NULL || acu->op == 0) { response(1); estopic = escapequery(c->topic); esnick = escapequery(mu->nick); snprintf(query, MAX_QUERY, "INSERT INTO `request` (`channel`, `users`, `topic`, `uid`, `nick`, `time`, `type`, `status`, `huid`, `reason`, `htime`, `bot`) VALUES ('%s', '%i', '%s', '%i', '%s', UNIX_TIMESTAMP(), '0', '2', '0', 'Requester doesen\\'t have op', UNIX_TIMESTAMP(), '%s')", channel, tmp, estopic, mu->userid, esnick, glarm); free(estopic); free(esnick); dbquery(query); EndDbQuery(); c_part(channel, "Request declined - Requester is not on channel/is not op"); return; } if(tmp < MINUSERS) { response(8); estopic = escapequery(c->topic); esnick = escapequery(mu->nick); snprintf(query, MAX_QUERY, "INSERT INTO `request` (`channel`, `users`, `topic`, `uid`, `nick`, `time`, `type`, `status`, `huid`, `reason`, `htime`, `bot`) VALUES ('%s', '%i', '%s', '%i', '%s', UNIX_TIMESTAMP(), '0', '2', '0', 'Not enough users on channel', UNIX_TIMESTAMP(), '%s')", channel, tmp, estopic, mu->userid, esnick, glarm); free(estopic); free(esnick); dbquery(query); EndDbQuery(); c_part(channel, "Request declined - Not enough users on channel"); return; } if(chost < MINUNIQUE) { response(9); estopic = escapequery(c->topic); esnick = escapequery(mu->nick); snprintf(query, MAX_QUERY, "INSERT INTO `request` (`channel`, `users`, `topic`, `uid`, `nick`, `time`, `type`, `status`, `huid`, `reason`, `htime`, `bot`) VALUES ('%s', '%i', '%s', '%i', '%s', UNIX_TIMESTAMP(), '0', '2', '0', 'Not enough unique users on channel', UNIX_TIMESTAMP(), '%s')", channel, tmp, estopic, mu->userid, esnick, glarm); free(estopic); free(esnick); dbquery(query); EndDbQuery(); c_part(channel, "Request declined - Not enough unique users on channel"); return; } #ifdef AUTOACCEPT if(findachanuser(L_NICK, channel) == NULL && findachanuser(Q_NICK, channel) == NULL) { #endif // Put in queue response(2); estopic = escapequery(c->topic); esnick = escapequery(mu->nick); snprintf(query, MAX_QUERY, "INSERT INTO `request` (`channel`, `users`, `topic`, `uid`, `nick`, `time`, `type`, `status`, `service`, `bot`) VALUES ('%s', '%i', '%s', '%i', '%s', UNIX_TIMESTAMP(), '0', '0', '%c', '%s')", channel, tmp, estopic, mu->userid, esnick, service, glarm); free(estopic); free(esnick); dbquery(query); EndDbQuery(); c_part(channel, "Request placed in queue"); snprintf(query, MAX_QUERY, "There is a new request in queue for channel: %c%s%c", BOLD, channel, BOLD); privmsg(HOMECHAN, query); return; #ifdef AUTOACCEPT } response(3); c_part(channel, "Request accepted"); estopic = escapequery(c->topic); esnick = escapequery(mu->nick); snprintf(query, MAX_QUERY, "INSERT INTO `request` (`channel`, `users`, `topic`, `uid`, `nick`, `time`, `type`, `status`, `huid`, `htime`, `service`, `bot`) VALUES ('%s', '%i', '%s', '%i', '%s', UNIX_TIMESTAMP(), '0', '1', '0', UNIX_TIMESTAMP(), '%c', '%s')", channel, tmp, estopic, mu->userid, esnick, service, glarm); free(estopic); free(esnick); dbquery(query); EndDbQuery(); sprintf(msg, "Auto accept: %c%s%c requested by: %c%s%c", BOLD, channel, BOLD, BOLD, glrequester, BOLD); privmsg(HOMECHAN, msg); // join arm and that crap handleaccept(channel, glrequester, glarm, mu->userid); return; #endif } void handleaccept(char *chan, char *nick, char *arm, int uid) { char msg[512]; struct arm *a; if((a = findarm(arm)) == NULL) return; c_join(chan, a); c_setlev(uid, chan, CHAN_OWNER); snprintf(msg, MAX_QUERY, "Request is accepted. If you have any channel service, you need to set me to +ao. I.e /msg L chanlev %s %s +ao More information and manuals can be found at: %c%s%c The channel owner is: %c%s%c.", chan, arm, BOLD, HELPSITE, BOLD, BOLD, nick, BOLD); privmsg(chan, msg); response(1); /* Return 1 on success */ } void handledecline(char *chan, char *nick, char *arm, int uid) { char msg[512]; struct arm *a = findarmbytype(BOT_CHECK); snprintf(msg, 512, "JOIN %s\n\r", chan); putserver(msg, a); snprintf(msg, 512, "PRIVMSG %s :Your request has been declined. Please check our homepage for more information.\n\r", chan); putserver(msg, a); snprintf(msg, 512, "PART %s :Request declined\n\r", chan); putserver(msg, a); snprintf(msg, 512, "Your request for %c%s%c has been declined. Please check your E-Mail or go to our homepage for more information.", BOLD, chan, BOLD); privmsg(nick, msg); }