#include <stdio.h> #include <stdlib.h> #include <limits.h> #include "tuved.h" int playCnt = 0; int nextSong(); int chanMaint(); int tuveCMD_CMD(myConnections_t *userConnection,char *chan,char *data) { char output[512]; char dMS[2] = {'-','+'}; char *cmd = 0x0; char *cmdData = 0x0; char *modeString = 0x0; char *tmp = 0x0; char *tmp2 = 0x0; char *tok_last = 0x0; tuveChanList_t *tmpChan = 0x0; tuveUserList_t *tmpUser = 0x0; MYSQL_RES *res = 0x0; MYSQL_ROW row; short dM = 0x0; unsigned int i = 0x0; if (data == 0x0) return(0x1); cmd = strtok_r(data," ",&tok_last); cmdData = strtok_r(NULL,"\n",&tok_last); if (cmd == 0x0) return(0x1); if (strcasecmp(cmd,"login") == 0x0) { tok_last = 0x0; tmp = strtok_r(cmdData," ",&tok_last); tmp2 = strtok_r(NULL,"\n",&tok_last); if ((tmp != 0x0) & (tmp2 != 0x0)) { sprintf(output,"SELECT username,gid,uid FROM users WHERE username = '%s' AND password = '%s'",tmp,tmp2); res = dbQuery(output,1); if (res == 0x0) { sSendData(userConnection,"MSG:TUveD:STATUS:Sorry I'm Having MySQL Troubles."); } else if (mysql_num_rows(res) == 1) { sSendData(userConnection,"MSG:TUveD:%s:You have successfully logged in.",chan); row = mysql_fetch_row(res); sprintf(output,"INSERT INTO active (gid,uid,userid) VALUES(%s,%s,%lld)",row[1],row[2],userConnection->userInfo.uid); dbQuery(output,0); sSendData(findNick("TUveBOT"),"LOGIN:%s:%lld",userConnection->userInfo.username,userConnection->userInfo.uid); if (atoi(row[1]) == 1) { sprintf(output,"EMOTE:%s:STATUS:Is now an Evil Overlord!",userConnection->userInfo.username); tuveSendAllInUsersChans(userConnection,output); userConnection->userInfo.modes[USER_OVERLORD] = 1; } userConnection->userInfo.ident = 2; } else { sSendData(userConnection,"MSG:TUveD:%s:You have failed login.",chan); } if (res != 0x0) mysql_free_result(res); } } /* End login */ else if (tuveFindChanLevel(chan,userConnection,0) == 0) { sSendData(userConnection,"MSG:TUveD:STATUS:You do not have permission to set channel mode."); return(0x0); } /* Commands Stop Here If You Channel Level Isn't >= 1 */ else if (strcasecmp(cmd,"pause") == 0x0) { tuveSendAllInChan(chan,0x0,"PAUSE"); } else if (strcasecmp(cmd,"resume") == 0x0) { tuveSendAllInChan(chan,0x0,"RESUME\n"); } else if (strcasecmp(cmd,"skip") == 0x0) { if (cmdData != 0x0) tmpChan = findChan(cmdData); else tmpChan = findChan(chan); if (tmpChan != 0x0) { if (tmpChan->vidClass != 7) { tmpChan->videoEnd = 0x0; tmpChan->count = MAX_COUNT; } } } else if (strcasecmp(cmd,"mode") == 0x0) { tmpChan = findChan(chan); if (cmdData != 0x0) { tok_last = 0x0; modeString = strtok_r(cmdData," ",&tok_last); if (modeString[0] == '-') dM = 0; else if (modeString[0] == '+') dM = 1; else { sSendData(userConnection,"MSG:TUveD:STATUS:Invalid Mode String."); return(0x0); } for (i = 1;i < strlen(modeString);i++) { switch(modeString[i]) { case '-': dM = 0; break; case '+': dM = 1; break; case 'o': case 'O': tmp = strtok_r(NULL," ",&tok_last); if (tmp != 0x0) { if (tuveChanOp(chan,tmp,dM) == 0x0) { sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cO %s",chan,userConnection->userInfo.username,dMS[dM],tmp); tuveSendAllInChan(chan,0x0,output); } } else { sSendData(userConnection,"MSG:TUveD:STATUS:Missing +O Opperators"); } break; case 'a': case 'A': tmp = strtok_r(NULL," ",&tok_last); if (tmp != 0x0) { tmpChan->modes[CHAN_RATING] = atoi(tmp); sprintf(output,"MODE:%s:A:%i",tmpChan->channel,tmpChan->modes[CHAN_RATING]); tuveSendAllInChan(chan,0x0,output); } break; case 'c': case 'C': tmp = strtok_r(NULL," ",&tok_last); if (tmp != 0x0) { tmpChan->modes[CHAN_CLASS] = atoi(tmp); sprintf(output,"MODE:%s:C:%i",tmpChan->channel,tmpChan->modes[CHAN_CLASS]); tuveSendAllInChan(chan,0x0,output); } break; case 'e': case 'E': if (dM == 0) { tmpChan->modes[CHAN_EXCLUSIVE] = 0; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cExclusive",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); } else { sprintf(output,"SELECT oid FROM channels WHERE channel LIKE '%s'",tmpChan->channel); res = dbQuery(output,1); if (res == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry I'm having SQL troubles today.",tmpChan->channel); tuveSendAllInChan(tmpChan->channel,0x0,output); } else if (mysql_num_rows(res) == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry this channel is not registered.",tmpChan->channel); tuveSendAllInChan(tmpChan->channel,0x0,output); } else { row = mysql_fetch_row(res); tmpChan->modes[CHAN_EXCLUSIVE] = 1; tmpChan->oid = atoi(row[0]); sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cExclusive",chan,userConnection->userInfo.username,dMS[1]); tuveSendAllInChan(chan,0x0,output); } if (res != 0x0) mysql_free_result(res); } sprintf(output,"MODE:%s:E:%i",tmpChan->channel,tmpChan->modes[CHAN_EXCLUSIVE]); tuveSendAllInChan(chan,0x0,output); break; case 'r': case 'R': tmpChan->modes[CHAN_RANDOM] = dM; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cRandom",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:R:%i",tmpChan->channel,dM); tuveSendAllInChan(chan,0x0,output); break; case 'q': case 'Q': tmpChan->modes[CHAN_QUEUE] = dM; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cQueue",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:Q:%i",tmpChan->channel,dM); tuveSendAllInChan(chan,0x0,output); break; case 'X': tmpChan->modes[CHAN_NOADS] = dM; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cNo Advertisements",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:X:%i",tmpChan->channel,dM); tuveSendAllInChan(chan,0x0,output); break; case 't': case 'T': if (dM == 1) { tmp = strtok_r(NULL," ",&tok_last); if (tmp != 0x0) { tmpChan->modes[CHAN_TIME] = dM; tmpChan->maxTime = atoi(tmp); sprintf(output,"MSG:TUveD:%s:%s Sets Mode +Time Limit %s",chan,userConnection->userInfo.username,tmp); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:T:%i:%s",tmpChan->channel,dM,tmp); tuveSendAllInChan(chan,0x0,output); } } else { tmpChan->modes[CHAN_TIME] = dM; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cTime Limit",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:T:%i",tmpChan->channel,dM); tuveSendAllInChan(chan,0x0,output); } break; case 'S': if (dM == 0x1) { for (tmpUser = tmpChan->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (tmpUser->user == userConnection) { tmpChan->nextUser = tmpUser; } } } else tmpChan->nextUser = tmpChan->users; tmpChan->modes[CHAN_SCHEDULED] = dM; sprintf(output,"MSG:TUveD:%s:%s Sets Mode %cScheduled",chan,userConnection->userInfo.username,dMS[dM]); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MODE:%s:S:%i",tmpChan->channel,dM); tuveSendAllInChan(chan,0x0,output); break; default: sSendData(userConnection,"MSG:TUveD:STATUS:Invalid Channel Mode"); break; } } } } else if (strcasecmp(cmd,"queue") == 0x0) { tmpChan = findChan(chan); if (tmpChan == 0x0) return(0x0); sprintf(output,"MSG:TUveD:%s:Queue Order - ",userConnection->userInfo.username); for (tmpUser = tmpChan->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (tmpUser == tmpChan->nextUser) sprintf(output,"%s(%s),",output,tmpUser->user->userInfo.username); else if (tmpUser == tmpChan->nextUser->next) sprintf(output,"%s[%s],",output,tmpUser->user->userInfo.username); else sprintf(output,"%s%s,",output,tmpUser->user->userInfo.username); } sSendData(userConnection,output); } else if (strcasecmp(cmd,"random") == 0x0) { tmpChan = findChan(chan); if (tmpChan == 0x0) return(0x0); if ((tmpChan->modes[CHAN_LIVE] == 0x1) || (tmpChan->vidClass == 7)) return(0x0); sprintf(output,"SELECT artist,title,file,length,vid,classification,rating FROM videos WHERE status = 0 AND rating <= %i",tmpChan->modes[CHAN_RATING]); if (tmpChan->modes[CHAN_EXCLUSIVE]) sprintf(output,"%s AND oid = %i",output,tmpChan->modes[CHAN_EXCLUSIVE]); if (tmpChan->modes[CHAN_CLASS]) sprintf(output,"%s AND classification = %i",output,tmpChan->modes[CHAN_CLASS]); res = dbQuery(output,1); if (res == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry I'm Have SQL Troubles Today.",chan); tuveSendAllInChan(chan,0x0,output); } else if (mysql_num_rows(res) == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry There Are No Videos Available At The Current Channel Settings.",chan); tuveSendAllInChan(chan,0x0,output); } else { mysql_data_seek(res,(random() % mysql_num_rows(res))); row = mysql_fetch_row(res); //sprintf(output,"UPDATE videos SET count = %i WHERE vid = %s",atoi(row[7])+1,row[4]); //dbQuery(output,0); tuveBotSetSong(chan,userConnection->userInfo.username,row[0],row[1],atoi(row[3]),row[2],atoi(row[5]),atoi(row[6]),atoi(row[4])); } if (res != 0x0) mysql_free_result(res); } else if (strcasecmp(cmd,"rotatelog") == 0x0) { writeLog(0,"Rotating Log File"); fclose(logFile); sprintf(logFileName,"./logs/tuved.%li.log", time(NULL)); logFile = fopen(logFileName,"a"); writeLog(0,"Log Rotated"); } else if (strcasecmp(cmd,"nextuser") == 0x0) { sprintf(output,"MSG:TUveD:%s:The Next User is %s",chan,tmpChan->nextUser->user->userInfo.username); tuveSendAllInChan(chan,0x0,output); } return(0x0); } void *tuveCMD_Thread(void *threadid) { int tid; MYSQL_RES *res = 0x0; MYSQL_ROW row; tid = (int)threadid; writeLog(0,"Starting Bot Thread: [%d]\n", tid); res = dbQuery("SELECT count FROM videos ORDER BY count ASC LIMIT 1",1); row = mysql_fetch_row(res); if (row) playCnt = atoi(row[0]); mysql_free_result(res); while (1) { sleep(5); nextSong(); chanMaint(); } pthread_exit(NULL); } /* End tuveCMD_Thread() */ int chanMaint() { tuveChanList_t *tmpChans; time_t curTime = time(NULL); int i = 0x0; pthread_mutex_lock(&chanMutex); for (tmpChans = channels;tmpChans != 0x0;tmpChans = tmpChans->next) { for (i = 0;i < CHAN_MAX_BANS;i++) { if ((tmpChans->bans[i][0] != 0x0) && (tmpChans->bans[i][1] < curTime)) tmpChans->bans[i][0] = 0x0; } } pthread_mutex_unlock(&chanMutex); return(0x0); } int tuveBotSetVideo(char *chan,char *nick,int vid) { MYSQL_RES *res = 0x0; MYSQL_ROW row; char output[256]; sprintf(output,"SELECT artist,title,file,length,classification,rating,count FROM videos WHERE vid = %i",vid); res = dbQuery(output,1); if ((res == 0x0) || (mysql_num_rows(res) == 0x0)) { sprintf(output,"MSG:TUveD:%s:Sorry I'm Have SQL Troubles Today.",chan); tuveSendAllInChan(chan,0x0,output); } else { row = mysql_fetch_row(res); sprintf(output,"UPDATE videos SET count = %i WHERE vid = %i",atoi(row[6])+1,vid); dbQuery(output,0); tuveBotSetSong(chan,nick,row[0],row[1],atoi(row[3]),row[2],atoi(row[4]),atoi(row[5]),vid); } if (res != 0x0) mysql_free_result(res); return(0x0); } int tuveBotSetSong(char *channel,char *nick,char *artist,char *title,int length,char *file,int class,int rating,int vid) { tuveChanList_t *tmpChan; char output[1024]; int min, sec; songCount++; playCount += length; tmpChan = findChan(channel); if (tmpChan->modes[CHAN_SCHEDULED] == 0x1) goto jmpAhd; if (tmpChan->modes[CHAN_TIME] == 0x1) { if (length > tmpChan->maxTime) { return(0x0); } } if (tmpChan->modes[CHAN_RATING] < rating) return(0x0); if ((tmpChan->modes[CHAN_CLASS] != class) && (tmpChan->modes[CHAN_CLASS] != 0x0) && (class != 7)) return(0x0); jmpAhd: tmpChan->comDelay -= length; tmpChan->vidClass = class; min = length / 60; sec = length % 60; tmpChan->videoTime = length; tmpChan->videoEnd = length + time(NULL) + VIDE_PAD_TIME; tmpChan->vid = vid; sprintf(tmpChan->videoFile,"%s", file); if (nick[strlen(nick)-1] == 's') sprintf(tmpChan->videoChanTitle,"%s' Pick -> <A HREF=\"event:%i\"><FONT COLOR=\"#8080FF\">[%s - %s]</FONT></A>",nick,vid,artist,title); else sprintf(tmpChan->videoChanTitle,"%s's Pick -> <A HREF=\"event:%i\"><FONT COLOR=\"#8080FF\">[%s - %s]</FONT></A>",nick,vid,artist,title); sprintf(tmpChan->videoTitle,"%s - %s",artist,title); sprintf(output,"CURPOS:%s:0:%s:%s:%i:%i",tmpChan->channel,file,tmpChan->videoTitle,length,vid); writeLog(0,"[%s][%s]\n",output,channel); tuveSendAllInChan(channel,0x0,output); sprintf(output,"MSG:TUveD:%s:Playing %s (%d:%.2d)",channel,tmpChan->videoChanTitle,min,sec); tuveSendAllInChan(channel,0x0,output); /* if (tmpChan->count != -1) { if (tmpChan->nextUser != 0x0) tmpChan->nextUser = tmpChan->nextUser->next; if (tmpChan->nextUser == 0x0) tmpChan->nextUser = tmpChan->users; } */ tmpChan->count = MAX_COUNT; return(0x0); } // tuveBotSetSong() int nextSong() { char output[1024]; tuveChanList_t *tmpChans; MYSQL_RES *res = 0x0; MYSQL_ROW row; time_t curTime; short lC; curTime = time(NULL); pthread_mutex_lock(&chanMutex); for (tmpChans = channels;tmpChans != 0x0;tmpChans = tmpChans->next) { if ((tmpChans->modes[CHAN_LIVE] == 0x0) && (tmpChans->videoEnd < curTime)) { /* Set point to starting user */ findUser: if (tmpChans->modes[CHAN_SCHEDULED] == 0x1) goto gotUser; if ((tmpChans->modes[CHAN_NOADS] == 0) && (tmpChans->comDelay <= 0)) goto getCommercial; //if (tmpChans->modes[CHAN_QUEUE] == 0x0) /* If Channel Has Queues Disabled Jump Right To Random */ // goto getRandom; if (tmpChans->count == MAX_COUNT) { lC = 0; while (lC <= tmpChans->userCount) { /* Reset Chan Counter */ tmpChans->count = 0x0; if (tmpChans->nextUser == 0x0) goto getRandom; tmpChans->nextUser = tmpChans->nextUser->next; /* Make sure we didn't go beyond the list */ if (tmpChans->nextUser == 0x0) tmpChans->nextUser = tmpChans->users; if (tmpChans->nextUser == 0x0) goto sE; if (((tmpChans->modes[CHAN_QUEUE] == 0x0) && (tmpChans->nextUser->chanLevel >= 1)) || (tmpChans->modes[CHAN_QUEUE] == 0x1)) if (tmpChans->nextUser->user->userInfo.queue == 0x1) goto gotUser; lC++; } } else if (tmpChans->nextUser != 0x0) goto gotUser; /* Find A Random Song */ getRandom: if (tmpChans->modes[CHAN_RANDOM] == 0x1) { sprintf(output,"SELECT artist,title,file,length,vid,classification,rating,count,random_count FROM videos WHERE status = 0 AND rating <= %i",tmpChans->modes[CHAN_RATING]); if (tmpChans->modes[CHAN_EXCLUSIVE]) sprintf(output,"%s AND oid = %i",output,tmpChans->oid); //tmpChans->modes[CHAN_EXCLUSIVE]); if (tmpChans->modes[CHAN_CLASS]) sprintf(output,"%s AND classification = %i",output,tmpChans->modes[CHAN_CLASS]); sprintf(output,"%s ORDER BY random_count ASC, RAND() LIMIT 1", output); res = dbQuery(output,1); if (res == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry I'm Having SQL Troubles Today.",tmpChans->channel); tuveSendAllInChan(tmpChans->channel,0x0,output); } else if (mysql_num_rows(res) == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry Videos Matching The Channels Settings.",tmpChans->channel); tuveSendAllInChan(tmpChans->channel,0x0,output); } else { //mysql_data_seek(res,(random() % mysql_num_rows(res))); row = mysql_fetch_row(res); sprintf(output,"UPDATE videos SET random_count = %i WHERE vid = %s\n",atoi(row[8])+1,row[4]); dbQuery(output,0); tmpChans->count = MAX_COUNT; tuveBotSetSong(tmpChans->channel,"TUveD",row[0],row[1],atoi(row[3]),row[2],atoi(row[5]),atoi(row[6]),atoi(row[4])); } if (res != 0x0) mysql_free_result(res); } goto sE; getCommercial: tmpChans->comDelay = COM_DELAY; getComAgain: sprintf(output,"SELECT artist,title,file,length,vid,classification,rating,count FROM videos WHERE rating <= %i AND classification = 7 AND count <= %i",tmpChans->modes[CHAN_RATING],playCnt); res = dbQuery(output,1); if (res == 0x0) { sprintf(output,"MSG:TUveD:%s:Sorry I'm Having SQL Troubles Today.",tmpChans->channel); tuveSendAllInChan(tmpChans->channel,0x0,output); } else if (mysql_num_rows(res) == 0x0) { playCnt++; mysql_free_result(res); // XXX MrOlsen: This is a race condition if there are no commercials, bypassing temporarily // goto getComAgain; goto getRandom; } else { mysql_data_seek(res,(random() % mysql_num_rows(res))); row = mysql_fetch_row(res); sprintf(output,"UPDATE videos SET count = %i WHERE vid = %s\n",atoi(row[7])+1,row[4]); dbQuery(output,0); tmpChans->count = MAX_COUNT; tuveBotSetSong(tmpChans->channel,"TUveD",row[0],row[1],atoi(row[3]),row[2],atoi(row[5]),atoi(row[6]),atoi(row[4])); } if (res != 0x0) mysql_free_result(res); goto sE; gotUser: if (tmpChans->nextUser->user->userInfo.queue == 0x1) { if (((tmpChans->modes[CHAN_QUEUE] == 0x0) && (tmpChans->nextUser->chanLevel >= 1)) || (tmpChans->modes[CHAN_QUEUE] == 0x1)) { sSendData(tmpChans->nextUser->user,"GETVIDEO"); writeLog(0,"Need To Find Next Song For: %s, From User: %s\n",tmpChans->channel,tmpChans->nextUser->user->userInfo.username); tmpChans->count++; } else if (tmpChans->modes[CHAN_SCHEDULED] == 0) { tmpChans->count = MAX_COUNT; goto findUser; } } else if (tmpChans->modes[CHAN_SCHEDULED] == 0) { tmpChans->count = MAX_COUNT; goto findUser; } sE: asm("nop"); } } pthread_mutex_unlock(&chanMutex); return(0x0); } /* End nextSong() */