/*
(c) 2007 Christopher Olsen
$Id$
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.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\n");
for (tmpChan = channels;tmpChan != 0x0;tmpChan = tmpChan->next) {
sprintf(data,"LIST:%s:%i:%s:%s\n",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)\n",channel,userConnection->userInfo.username);
tuveSendAllInChan(channel,0x0,output);
sprintf(output,"PART:%s:%s\n",channel,userConnection->userInfo.username);
tuveSendAllInChan(channel,0x0,output);
return(0x0);
}
return(0x1);
} /* End tuveChanPart(); */
int tuveChanLive(const char *channel,const char *stream) {
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:-1:%s:Live Stream:0:0\n",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:%i:%s:%s:%i:%i\n",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\n",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\n",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:-1:%s:Live Stream:0:0\n",tmpChan->liveStream);
}
else {
sSendData(userConnection,"CURPOS:%i:%s:%s:%i:%i\n",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)\n",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.\n",channel,userConnection->userInfo.username,userConnection->host);
tuveSendAllInChan(channel,userConnection,output);
return(0x0);
}
int tuveDelUserChans(myConnections_t *userConnection,char *msg) {
char output[256];
tuveUserChans_t *tmpChan = 0x0;
tuveUserChans_t *tmpChan2 = 0x0;
tmpChan = userConnection->userInfo.chans;
tmpChan2 = tmpChan;
for (;tmpChan != 0x0;tmpChan = tmpChan->next) {
sprintf(output,"MSG:TUveD:%s:%s Quit (%s)\n",tmpChan->channel,userConnection->userInfo.username,msg);
tuveSendAllInChan(tmpChan->channel,userConnection,output);
sprintf(output,"PART:%s:%s\n",tmpChan->channel,userConnection->userInfo.username);
tuveSendAllInChan(tmpChan->channel,userConnection,output);
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,channel);
}
else {
tmpChan = (tuveUserChans_t *)calloc(1,sizeof(tuveUserChans_t));
tmpChan->prev = 0x0;
sprintf(tmpChan->channel,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;
if (tmpChannel->nextUser == tmpUsers) {
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");
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;
int deltaTime, day, hour, min, sec;
char output[1024];
char nick[MAX_USER_LEN + 1];
//mji char topicTime[1024];
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\n",output);
sSendData(userConnection,output);
}
sprintf(output,"TOPIC:%s:%s\n",tmpChannel->channel,tmpChannel->topic);
sSendData(userConnection,output);
sprintf(output,"MSG:TUveD:%s:Topic for %s: %s\n",tmpChannel->channel,tmpChannel->channel,tmpChannel->topic);
sSendData(userConnection,output);
deltaTime = time(NULL) - tmpChannel->topicSet;
day = deltaTime / 86400;
deltaTime -= (86400 * day);
hour = deltaTime / 3600;
deltaTime -= (3600 * hour);
min = deltaTime / 60;
deltaTime -= (60 * min);
sec = deltaTime;
sprintf(output,"MSG:TUveD:%s:Topic was set by %s %i seconds ago.\n",tmpChannel->channel,tmpChannel->topicSetBy,time(NULL) - tmpChannel->topicSet);
sSendData(userConnection,output);
if (tmpChannel->modes[CHAN_TIME] == 1) {
sprintf(output,"MSG:TUveD:%s:This channel has a time limit of %i seconds for songs.\n",tmpChannel->channel,tmpChannel->maxTime);
sSendData(userConnection,output);
sprintf(output,"MODE:%s:T:1:%i\n",tmpChannel->channel,tmpChannel->maxTime);
sSendData(userConnection,output);
}
else {
sprintf(output,"MODE:%s:T:0\n",tmpChannel->channel);
sSendData(userConnection,output);
}
if (tmpChannel->modes[CHAN_QUEUE] == 1)
sprintf(output,"MODE:%s:Q:1\n",tmpChannel->channel);
else
sprintf(output,"MODE:%s:Q:0\n",tmpChannel->channel);
sSendData(userConnection,output);
if (tmpChannel->modes[CHAN_RANDOM] == 1)
sprintf(output,"MODE:%s:R:1\n",tmpChannel->channel);
else
sprintf(output,"MODE:%s:R:0\n",tmpChannel->channel);
sSendData(userConnection,output);
sprintf(output,"MODE:%s:A:%i\n",tmpChannel->channel,tmpChannel->modes[CHAN_RATING]);
sSendData(userConnection,output);
sprintf(output,"MODE:%s:C:%i\n",tmpChannel->channel,tmpChannel->modes[CHAN_CLASS]);
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,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;
writeLog(2,"ADDED CHAN1\n");
tmpChannel = channels;
}
else {
tmpChannel = (tuveChanList_t *)calloc(1,sizeof(tuveChanList_t));
sprintf(tmpChannel->channel,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;
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 *output) {
tuveChanList_t *tmpChannel = 0x0;
tuveUserList_t *tmpUsers = 0x0;
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;
for (;tmpUsers != 0x0;tmpUsers = tmpUsers->next) {
if (userConnection == 0x0)
sSendData(tmpUsers->user,output);
else if (strcasecmp(tmpUsers->user->userInfo.username,userConnection->userInfo.username))
sSendData(tmpUsers->user,output);
}
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\n",chan,tmpChannel->topic);
tuveSendAllInChan(chan,0x0,output);
sprintf(output,"MSG:TUveD:%s:%s has set the topic to: %s\n",chan,userConnection->userInfo.username,tmpChannel->topic);
tuveSendAllInChan(chan,0x0,output);
tmpChannel->topicSet = time(NULL);
sprintf(tmpChannel->topicSetBy,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\n",nick,chan);
return(0x1);
}
sprintf(output,"KICK:%s:%s:%s\n",chan,byConnection->userInfo.username,msg);
sSendData(userConnection,output);
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\n",chan,nick,byConnection->userInfo.username,msg);
tuveSendAllInChan(chan,0x0,output);
sprintf(output,"PART:%s:%s\n",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.\n");
return(0x0);
}
userConnection = findNick(nick);
if (userConnection == 0x0) {
writeLog(1,"nick Filed: Ban\n");
return(0x1);
}
sSendData(userConnection,"BAN\n");
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\n",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\n",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\n",tmpChannel->channel,level,tmpUser->user->userInfo.username);
tuveSendAllInChan(channel,0x0,output);
return(0x0);
}
}
return(0x1);
}