Newer
Older
tuved / src / botthread.c
#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() */