/* (c) 2007 Christopher Olsen $Id: channel.c,v 1.65 2009/02/18 19:37:34 reddawg Exp $ */ #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <limits.h> #include <assert.h> #include "tuved.h" tuveChanList_t *channels = 0x0; tuveChanList_t *addChan(const char *channel); /* * This function will send the current channel list to the user specified w/ userConnection * Information provided to that user is channel,user count,current song * * We traverse the channel list however there is no need to lock it because the other * thread just reads this list and does not modify it. * */ int tuveChanList(myConnections_t *userConnection) { char data[512]; tuveChanList_t *tmpChan = 0x0; /* The first line is header information for the data set */ sSendData(userConnection,"LIST:Channel:users:Topic"); for (tmpChan = channels;tmpChan != 0x0;tmpChan = tmpChan->next) { sprintf(data,"LIST:%s:%i:%s:%s",tmpChan->channel,tmpChan->userCount,tmpChan->topic,tmpChan->videoTitle); sSendData(userConnection,data); } return(0x0); } /* End tuveChanList */ int tuveChanPart(const char *channel,myConnections_t *userConnection) { char output[512]; short inChan = 0x0; if (tuveRemoveFromChanList(channel,userConnection) == 0x1) { writeLog(0,"ERROR: Can not remove %s from %s\n",userConnection->userInfo.username,channel); inChan = 1; } if (tuveDelChan(channel,userConnection) == 0x1) { writeLog(0,"ERROR: Can not remove %s from %s's List\n",channel,userConnection->userInfo.username); inChan = 1; } if (inChan == 0x0) { sprintf(output,"MSG:TUveD:%s:%s Part (Left Channel)",channel,userConnection->userInfo.username); tuveSendAllInChan(channel,0x0,output); sprintf(output,"PART:%s:%s",channel,userConnection->userInfo.username); tuveSendAllInChan(channel,0x0,output); return(0x0); } return(0x1); } /* End tuveChanPart(); */ int tuveChanLive(const char *channel,const char *stream,const char *location) { tuveChanList_t *tmpChan = 0x0; char output[256]; if (stream == 0x0) return(0x1); /* Find The Channel */ tmpChan = findChan(channel); if (tmpChan == 0x0) return(0x1); strcpy(tmpChan->liveStream,stream); tmpChan->modes[CHAN_LIVE] = 0x1; //sprintf(output,"CURPOS:%s:-1:%s:Live Stream:0:0",tmpChan->channel,stream); sprintf(output,"LIVE:%s:%s",location,stream); tuveSendAllInChan(channel,0x0,output); return(0x0); } /* End int tuveChanLive(channel,stream) */ int tuveChanResume(const char *channel) { char output[256]; tuveChanList_t *tmpChan = 0x0; tmpChan = findChan(channel); if (tmpChan == 0x0) return(0x1); tmpChan->modes[CHAN_LIVE] = 0x0; sprintf(output,"CURPOS:%s:%li:%s:%s:%i:%i",tmpChan->channel,tmpChan->videoTime - (tmpChan->videoEnd - (time(NULL) + VIDE_PAD_TIME)),tmpChan->videoFile,tmpChan->videoTitle,tmpChan->videoTime,tmpChan->vid); tuveSendAllInChan(channel,0x0,output); return(0x0); } /* * Joins A User To A Channel */ int tuveChanJoin(const char *channel,myConnections_t *userConnection) { char output[256]; tuveChanList_t *tmpChan = 0x0; int min, sec; int i = 0x0; tmpChan = findChan(channel); if (tmpChan != 0x0) { for (i = 0x0;i < CHAN_MAX_BANS;i++) { if (tmpChan->bans[i][0] == userConnection->userInfo.uid) { sprintf(output,"MSG:TUveD:%s:You are banned from %s",channel,channel); sSendData(userConnection,output); return(0x1); } } } if (tuveAddChanToUser(channel,userConnection) != 0x0) return(0x1); /* Send JOIN to all users in the channel */ sprintf(output,"JOIN:%s:%s:%lld",channel,userConnection->userInfo.username,userConnection->userInfo.uid); tuveSendAllInChan(channel,userConnection,output); tmpChan = findChan(channel); assert(tmpChan); if (tmpChan->modes[CHAN_LIVE] == 1) { //sSendData(userConnection,"CURPOS:%s:-1:%s:Live Stream:0:0",tmpChan->channel,tmpChan->liveStream); sSendData(userConnection,"LIVE:1:%s\n",tmpChan->liveStream); } else { sSendData(userConnection,"CURPOS:%s:%i:%s:%s:%i:%i",tmpChan->channel,tmpChan->videoTime - (tmpChan->videoEnd - (time(NULL) + VIDE_PAD_TIME)),tmpChan->videoFile,tmpChan->videoTitle,tmpChan->videoTime,tmpChan->vid); min = tmpChan->videoTime / 60; sec = tmpChan->videoTime % 60; sSendData(userConnection,"MSG:TUveD:%s:Playing %s (%i:%.2i)",channel,tmpChan->videoChanTitle,min,sec); } /* Notify people in the channel that someone has joined */ sprintf(output,"MSG:TUveD:%s:%s (%s) has joined the channel.",channel,userConnection->userInfo.username,userConnection->host); tuveSendAllInChan(channel,userConnection,output); return(0x0); } int tuveDelUserChans(myConnections_t *userConnection,char *msg) { tuveUserChans_t *tmpChan = 0x0; tuveUserChans_t *tmpChan2 = 0x0; tmpChan = userConnection->userInfo.chans; tmpChan2 = tmpChan; for (;tmpChan != 0x0;tmpChan = tmpChan->next) { tuveSendAllInChan(tmpChan->channel,userConnection,"MSG:TUveD:%s:%s Quit (%s)",tmpChan->channel,userConnection->userInfo.username,msg); tuveSendAllInChan(tmpChan->channel,userConnection,"PART:%s:%s",tmpChan->channel,userConnection->userInfo.username); tuveRemoveFromChanList(tmpChan->channel,userConnection); free(tmpChan2); tmpChan2 = tmpChan->next; } if (tmpChan2 != 0x0) { free(tmpChan2); } return(0x0); } int tuveAddChanToUser(const char *channel,myConnections_t *userConnection) { tuveUserChans_t *tmpChan = 0x0; if (userConnection->userInfo.chans == 0x0) { userConnection->userInfo.chans = (tuveUserChans_t *)calloc(1,sizeof(tuveUserChans_t)); userConnection->userInfo.chans->prev = 0x0; userConnection->userInfo.chans->next = 0x0; sprintf(userConnection->userInfo.chans->channel, "%s", channel); } else { tmpChan = (tuveUserChans_t *)calloc(1,sizeof(tuveUserChans_t)); tmpChan->prev = 0x0; sprintf(tmpChan->channel, "%s", channel); tmpChan->next = userConnection->userInfo.chans; userConnection->userInfo.chans->prev = tmpChan; userConnection->userInfo.chans = tmpChan; } tuveAddToChanList(channel,userConnection); return(0x0); } int tuveDelChan(const char *channel,myConnections_t *userConnection) { tuveUserChans_t *tmpChan = 0x0; if (channel == 0x0) return(0x1); for (tmpChan = userConnection->userInfo.chans;tmpChan != 0x0;tmpChan = tmpChan->next) { if (!strcasecmp(tmpChan->channel,channel)) { writeLog(2,"Found %s On %s And Removed\n",tmpChan->channel,userConnection->userInfo.username); if (tmpChan->prev != 0x0) tmpChan->prev->next = tmpChan->next; else userConnection->userInfo.chans = tmpChan->next; if (tmpChan->next != 0x0) tmpChan->next->prev = tmpChan->prev; free(tmpChan); return(0x0); } } return(0x1); } int tuveRemoveFromChanList(const char *channel,myConnections_t *userConnection) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUsers = 0x0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) { writeLog(1,"tuveRemoveFromChanList: findChan failed!\n"); return(0x1); } tmpUsers = tmpChannel->users; writeLog(2,"Freeing User From Chan: %s\n",channel); pthread_mutex_lock(&chanMutex); for (;tmpUsers != 0x0;tmpUsers = tmpUsers->next) { if (!strcasecmp(tmpUsers->user->userInfo.username,userConnection->userInfo.username)) { writeLog(3,"Found and removed user: %s\n",tmpUsers->user->userInfo.username); if (tmpUsers->prev != 0x0) tmpUsers->prev->next = tmpUsers->next; else tmpChannel->users = tmpUsers->next; if (tmpUsers->next != 0x0) tmpUsers->next->prev = tmpUsers->prev; /* Undo Live if (tmpChannel->modes[CHAN_LIVE] != 0) && (tmpChannel->d */ if (tmpChannel->nextUser == tmpUsers) { if (tmpChannel->modes[CHAN_SCHEDULED] == 1) tmpChannel->modes[CHAN_SCHEDULED] = 0; if (tmpUsers->next != 0x0) tmpChannel->nextUser = tmpUsers->next; else if (tmpChannel->users != 0x0) tmpChannel->nextUser = tmpChannel->users; else tmpChannel->nextUser = 0x0; } tmpChannel->count = 0x0; tmpChannel->userCount--; free(tmpUsers); writeLog(3,"User Freed\n"); if (tmpChannel->users == 0x0) { writeLog(3,"Channel %s Has No More Users Freeing.\n",tmpChannel->channel); if (tmpChannel->prev != 0x0) tmpChannel->prev->next = tmpChannel->next; else channels = tmpChannel->next; if (tmpChannel->next != 0x0) tmpChannel->next->prev = tmpChannel->prev; channelCount--; free(tmpChannel); writeLog(3,"Channel Freed.\n"); } pthread_mutex_unlock(&chanMutex); return(0x0); } } pthread_mutex_unlock(&chanMutex); return(0x1); } int tuveAddToChanList(const char *channel,myConnections_t *userConnection) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUser = 0x0; char output[1024]; char nick[MAX_USER_LEN + 1]; int len = 0; tmpChannel = findChan(channel); // tmpChannel is okay to be null here if (tmpChannel == 0x0) { writeLog(2,"Channel %s does not exist creating now.\n",channel); tmpChannel = addChan(channel); } for (tmpUser = tmpChannel->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (!strcasecmp(tmpUser->user->userInfo.username,userConnection->userInfo.username)) { writeLog(2,"User: %s already in channel %s\n",userConnection->userInfo.username,channel); return(0x0); } } tmpUser = (tuveUserList_t *)calloc(1,sizeof(tuveUserList_t)); tmpUser->user = userConnection; tmpUser->prev = 0x0; pthread_mutex_lock(&chanMutex); if (tmpChannel->users == 0x0) { tmpUser->next = 0x0; tmpUser->chanLevel = 0x1; tmpChannel->users = tmpUser; } else { tmpUser->next = tmpChannel->users; tmpUser->chanLevel = 0x0; tmpChannel->users->prev = tmpUser; tmpChannel->users = tmpUser; } if (tmpChannel->nextUser == 0x0) { tmpChannel->nextUser = tmpUser; tmpChannel->count = 0x0; } tmpChannel->userCount++; memset(output,0x0,256); /* Send the new user the channel list */ for (tmpUser = tmpChannel->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (tmpUser->chanLevel == 0) strcpy(nick,tmpUser->user->userInfo.username); else sprintf(nick,"&%s",tmpUser->user->userInfo.username); if (strlen(output) > 0) sprintf(output,"%s:%s:%lld",output,nick,tmpUser->user->userInfo.uid); //tmpUser->user->userInfo.username); else sprintf(output,"JOIN:%s:%s:%lld",tmpChannel->channel,nick,tmpUser->user->userInfo.uid); //tmpUser->user->userInfo.username); } if (strlen(output) > 0) { sprintf(output,"%s",output); sSendData(userConnection,output); } sprintf(output,"TOPIC:%s:%s",tmpChannel->channel,tmpChannel->topic); sSendData(userConnection,output); sSendData(userConnection,"MSG:TUveD:%s:Topic for %s: %s",tmpChannel->channel,tmpChannel->channel,tmpChannel->topic); len = sprintf(output,"MSG:TUveD:%s:Topic was set by %s on %s",tmpChannel->channel,tmpChannel->topicSetBy, ctime(&tmpChannel->topicSet)); output[len-1] = '\0'; sSendData(userConnection,output); if (tmpChannel->modes[CHAN_TIME] == 1) { sSendData(userConnection,"MSG:TUveD:%s:This channel has a time limit of %i seconds for media.",tmpChannel->channel,tmpChannel->maxTime); sSendData(userConnection,"MODE:%s:T:1:%i",tmpChannel->channel,tmpChannel->maxTime); } else { sprintf(output,"MODE:%s:T:0",tmpChannel->channel); sSendData(userConnection,output); } if (tmpChannel->modes[CHAN_QUEUE] == 1) sprintf(output,"MODE:%s:Q:1",tmpChannel->channel); else sprintf(output,"MODE:%s:Q:0",tmpChannel->channel); sSendData(userConnection,output); if (tmpChannel->modes[CHAN_RANDOM] == 1) sprintf(output,"MODE:%s:R:1",tmpChannel->channel); else sprintf(output,"MODE:%s:R:0",tmpChannel->channel); sSendData(userConnection,output); sprintf(output,"MODE:%s:A:%i",tmpChannel->channel,tmpChannel->modes[CHAN_RATING]); sSendData(userConnection,output); sprintf(output,"MODE:%s:C:%i",tmpChannel->channel,tmpChannel->modes[CHAN_CLASS]); sSendData(userConnection,output); if (tmpChannel->modes[CHAN_EXCLUSIVE] != 0) sprintf(output,"MODE:%s:E:%i",tmpChannel->channel,tmpChannel->oid); else sprintf(output,"MODE:%s:E:0",tmpChannel->channel); sSendData(userConnection,output); writeLog(2,"Added user: %s to Channel: %s\n",userConnection->userInfo.username,channel); pthread_mutex_unlock(&chanMutex); return(0x0); } tuveChanList_t *findChan(const char *channel) { tuveChanList_t *tmpChannel = 0x0; assert(channel); pthread_mutex_lock(&chanMutex); for (tmpChannel = channels;tmpChannel != 0x0;tmpChannel = tmpChannel->next) { if (!strcasecmp(tmpChannel->channel,channel)) { pthread_mutex_unlock(&chanMutex); return(tmpChannel); } } pthread_mutex_unlock(&chanMutex); return(0x0); } /* * Add A Channel To The Global Channel List */ tuveChanList_t *addChan(const char *channel) { tuveChanList_t *tmpChannel = 0x0; pthread_mutex_lock(&chanMutex); channelCount++; if (channels == 0x0) { channels = (tuveChanList_t *)calloc(1,sizeof(tuveChanList_t)); channels->next = 0x0; channels->prev = 0x0; channels->users = 0x0; channels->modes[CHAN_QUEUE] = 0x1; channels->modes[CHAN_RATING] = 0x2; channels->modes[CHAN_CLASS] = 0x1; sprintf(channels->channel, "%s", channel); sprintf(channels->topic,"No Topic Set"); sprintf(channels->topicSetBy,"TUveD"); channels->topicSet = time(NULL); sprintf(channels->videoChanTitle,"No Video"); sprintf(channels->videoFile,"NA"); channels->videoEnd = 0x0; channels->comDelay = COM_DELAY; writeLog(2,"ADDED CHAN1\n"); tmpChannel = channels; } else { tmpChannel = (tuveChanList_t *)calloc(1,sizeof(tuveChanList_t)); sprintf(tmpChannel->channel, "%s", channel); sprintf(tmpChannel->topic,"No Topic Set"); sprintf(tmpChannel->topicSetBy,"TUveD"); tmpChannel->topicSet = time(NULL); sprintf(tmpChannel->videoChanTitle,"NoVideo"); sprintf(tmpChannel->videoFile,"NA"); tmpChannel->videoEnd = 0x0; tmpChannel->next = channels; tmpChannel->prev = 0x0; tmpChannel->users = 0x0; tmpChannel->modes[CHAN_QUEUE] = 0x1; tmpChannel->modes[CHAN_RATING] = 0x2; tmpChannel->modes[CHAN_CLASS] = 0x1; tmpChannel->comDelay = COM_DELAY; channels->prev = tmpChannel; channels = tmpChannel; writeLog(2,"ADDED CHAN2\n"); } pthread_mutex_unlock(&chanMutex); return(tmpChannel); } int tuveSendAllInUsersChans(myConnections_t *userConnection,char *output) { tuveUserChans_t *tmpChans = userConnection->userInfo.chans; for (;tmpChans != 0x0;tmpChans = tmpChans->next) { tuveSendAllInChan(tmpChans->channel,0x0,output); } return(0x0); } int tuveSendAllInChan(const char *channel,myConnections_t *userConnection,char const * __restrict fmt, ...) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUsers = 0x0; char data[2048]; va_list ap; int len = 0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) { writeLog(1,"findChan Failed!\n"); return(0x1); } //Dont see why i need a thread lock here tmpUsers = tmpChannel->users; va_start(ap,fmt); len = vsnprintf(data,2046,fmt,ap); va_end(ap); // data[len++] = '\r'; data[len++] = '\n'; //THIS IS A TEMP SOLUTION I HATE IT! for (;tmpUsers != 0x0;tmpUsers = tmpUsers->next) { if (userConnection == 0x0) send(tmpUsers->user->fd,data,len,MSG_NOSIGNAL);//sSendData(tmpUsers->user,data); else if (strcasecmp(tmpUsers->user->userInfo.username,userConnection->userInfo.username)) send(tmpUsers->user->fd,data,len,MSG_NOSIGNAL);//sSendData(tmpUsers->user,data); } return(0x0); } int tuveSetTopic(myConnections_t *userConnection,char *chan,char *topic) { char output[1024]; tuveChanList_t *tmpChannel = 0x0; tmpChannel = findChan(chan); if (tmpChannel == 0x0) { writeLog(1,"findChan Failed: SetTopic\n"); return(0x1); } strncpy(tmpChannel->topic,topic,128); sprintf(output,"TOPIC:%s:%s",chan,tmpChannel->topic); tuveSendAllInChan(chan,0x0,output); sprintf(output,"MSG:TUveD:%s:%s has set the topic to: %s",chan,userConnection->userInfo.username,tmpChannel->topic); tuveSendAllInChan(chan,0x0,output); tmpChannel->topicSet = time(NULL); sprintf(tmpChannel->topicSetBy, "%s", userConnection->userInfo.username); return(0x0); } int tuveKick(myConnections_t *byConnection,char *chan,char *nick,char *msg) { tuveChanList_t *tmpChannel = 0x0; myConnections_t *userConnection = 0x0; char output[1024]; tmpChannel = findChan(chan); if (tmpChannel == 0x0) { writeLog(1,"findchan Failed: Kick\n"); return(0x1); } userConnection = findNickOnChan(nick,chan); if (userConnection == 0x0) { sSendData(byConnection,"MSG:TUveD:STATUS:%s Not On %s",nick,chan); return(0x1); } sSendData(userConnection,"KICK:%s:%s:%s",chan,byConnection->userInfo.username,msg); nick = userConnection->userInfo.username; if (tuveRemoveFromChanList(chan,userConnection) == 0x1) writeLog(0,"ERROR: Can not remove %s from %s\n",userConnection->userInfo.username,chan); if (tuveDelChan(chan,userConnection) == 0x1) writeLog(0,"ERROR: Can not remove %s from %s's List\n",chan,userConnection->userInfo.username); sprintf(output,"MSG:TUveD:%s:%s has been kicked by %s, Reason: %s",chan,nick,byConnection->userInfo.username,msg); tuveSendAllInChan(chan,0x0,output); sprintf(output,"PART:%s:%s",chan,nick); tuveSendAllInChan(chan,0x0,output); writeLog(0,"Kicked %s\n",output); tuveChanJoin("#doghouse",userConnection); return(0x0); } int tuveBan(myConnections_t *byConnection,const char *channel,const char *nick,int length) { char output[1024]; tuveChanList_t *tmpChannel = 0x0; myConnections_t *userConnection = 0x0; int i = 0x0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) { writeLog(1,"findChan Failed: Ban\n"); return(0x1); } if (tuveFindChanLevel(channel,byConnection,0) < 1) { sSendData(byConnection,"MSG:TUveD:STATUS:You do not have permission to ban."); return(0x0); } userConnection = findNick(nick); if (userConnection == 0x0) { writeLog(1,"nick Filed: Ban\n"); return(0x1); } sSendData(userConnection,"BAN"); for (i = 0x0;i < CHAN_MAX_BANS;i++) { if (tmpChannel->bans[i][0] == 0x0) { tmpChannel->bans[i][0] = userConnection->userInfo.uid; tmpChannel->bans[i][1] = length + time(NULL); break; } } sprintf(output,"MSG:TUveD:%s:%s has been banned for %i seconds",channel,userConnection->userInfo.username,length); tuveSendAllInChan(channel,0x0,output); return(0x0); } int tuveUnBan(const char *channel,const char *nick) { char output[1024]; tuveChanList_t *tmpChannel = 0x0; myConnections_t *userConnection = 0x0; int i = 0x0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) { writeLog(1,"findchan Failed: Ban\n"); return(0x1); } userConnection = findNick(nick); if (userConnection == 0x0) { writeLog(1,"nick Filed: Ban\n"); return(0x1); } for (i = 0x0;i < CHAN_MAX_BANS;i++) { if (tmpChannel->bans[i][0] == userConnection->userInfo.uid) { tmpChannel->bans[i][0] = 0x0; break; } } sprintf(output,"MSG:TUveD:%s:%s has been unbanned",channel,userConnection->userInfo.username); tuveSendAllInChan(channel,0x0,output); return(0x0); } int tuveVerifyBan(const char *channel,const char *nick) { tuveChanList_t *tmpChannel = 0x0; myConnections_t *userConnection = 0x0; int i = 0x0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) { writeLog(1,"findchan Failed: Ban\n"); return(0x1); } userConnection = findNick(nick); if (userConnection == 0x0) { writeLog(1,"nick Filed: Ban\n"); return(0x1); } for (i = 0x0;i < CHAN_MAX_BANS;i++) { if (tmpChannel->bans[i][0] == userConnection->userInfo.uid) { return(0x1); } } return(0x0); } myConnections_t *findNickOnChan(const char *nick,const char *channel) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUser = 0x0; tmpChannel = findChan(channel); if (tmpChannel == 0x0) return(0x0); for (tmpUser = tmpChannel->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (!strcasecmp(tmpUser->user->userInfo.username,nick)) return(tmpUser->user); } return(0x0); } int tuveFindChanLevel(const char *channel,myConnections_t *userConnection,int eo) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUser = 0x0; if ((userConnection->userInfo.modes[USER_OVERLORD] == 1) && (eo != 1)) return(0x1); tmpChannel = findChan(channel); if (tmpChannel == 0x0) return(0x0); for (tmpUser = tmpChannel->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (tmpUser->user == userConnection) return(tmpUser->chanLevel); } return(-1); } int tuveChanOp(const char *channel,const char *nick,int level) { tuveChanList_t *tmpChannel = 0x0; tuveUserList_t *tmpUser = 0x0; char output[512]; tmpChannel = findChan(channel); if (tmpChannel == 0x0) return(0x1); writeLog(3,"Looking for %s on %s\n",nick,channel); for (tmpUser = tmpChannel->users;tmpUser != 0x0;tmpUser = tmpUser->next) { if (!strcasecmp(tmpUser->user->userInfo.username,nick)) { tmpUser->chanLevel = level; sprintf(output,"MODE:%s:O:%i:%s",tmpChannel->channel,level,tmpUser->user->userInfo.username); tuveSendAllInChan(channel,0x0,output); return(0x0); } } return(0x1); }