/*
(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);
int tuveChanList(myConnections_t *userConnection) {
char data[1024];
tuveChanList_t *tmpChan = 0x0;
sprintf(data,"LIST:Channel:users:Topic\n");
sSendData(userConnection,data);
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);
}
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(); */
/*
* 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 < MAX_BANS;i++) {
if (tmpChan->bans[i] == userConnection->userInfo.uid) {
sprintf(output,"MSG:TUveD:%s:You are banned from %s\n",channel,channel);
sSendData(userConnection,output);
return(0x1);
}
}
}
if (tuveAddChan(channel,userConnection) != 0x0) return(0x1);
/* Send JOIN to all users in the channel */
sprintf(output,"JOIN:%s:%s\n",channel,userConnection->userInfo.username);
tuveSendAllInChan(channel,userConnection,output);
tmpChan = findChan(channel);
assert(tmpChan);
sprintf(output,"CURPOS:%i:%s:%s:%i:%i\n",tmpChan->songTime - (tmpChan->videoEnd - (time(NULL) + VIDE_PAD_TIME)),tmpChan->videoFile,tmpChan->videoTitle,tmpChan->songTime,tmpChan->vid);
sSendData(userConnection,output);
min = tmpChan->songTime / 60;
sec = tmpChan->songTime % 60;
sprintf(output,"MSG:TUveD:%s:Playing %s (%i:%.2i)\n",channel,tmpChan->videoChanTitle,min,sec);
sSendData(userConnection,output);
/* 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 tuveAddChan(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 *tmpUsers = 0x0;
int deltaTime, day, hour, min, sec;
char output[1024];
//mji char topicTime[1024];
tmpChannel = findChan(channel);
// tmpChannel is okay to be null here
if (tmpChannel == 0x0) {
writeLog(2,"Channel %s does not exist adding to list\n",channel);
tmpChannel = addChan(channel);
}
for (tmpUsers = tmpChannel->users;tmpUsers != 0x0;tmpUsers = tmpUsers->next) {
if (!strcasecmp(tmpUsers->user->userInfo.username,userConnection->userInfo.username)) {
writeLog(2,"User: %s already in channel %s\n",userConnection->userInfo.username,channel);
return(0x0);
}
}
tmpUsers = (tuveUserList_t *)calloc(1,sizeof(tuveUserList_t));
tmpUsers->user = userConnection;
tmpUsers->prev = 0x0;
pthread_mutex_lock(&chanMutex);
if (tmpChannel->users == 0x0) {
tmpUsers->next = 0x0;
tmpChannel->users = tmpUsers;
}
else {
tmpUsers->next = tmpChannel->users;
tmpChannel->users->prev = tmpUsers;
tmpChannel->users = tmpUsers;
}
if (tmpChannel->nextUser == 0x0) {
tmpChannel->nextUser = tmpUsers;
tmpChannel->count = 0x0;
}
tmpChannel->userCount++;
memset(output,0x0,256);
//sprintf(output,"JOIN:%s:@TUveBOT",tmpChannel->channel);
/* Send the new user the channel list */
for (tmpUsers = tmpChannel->users;tmpUsers != 0x0;tmpUsers = tmpUsers->next) {
if (strlen(output) > 0)
sprintf(output,"%s:%s",output,tmpUsers->user->userInfo.username);
else
sprintf(output,"JOIN:%s:%s",tmpChannel->channel,tmpUsers->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(char *by,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 = findNick(nick);
if (userConnection == 0x0) {
writeLog(1,"findNick Failed: Kick\n");
return(0x1);
}
sprintf(output,"KICK:%s:%s:%s\n",chan,by,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,by,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(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);
sSendData(userConnection,"BAN\n");
if (userConnection == 0x0) {
writeLog(1,"nick Filed: Ban\n");
return(0x1);
}
for (i = 0x0;i < MAX_BANS;i++) {
if (tmpChannel->bans[i] == 0x0) {
tmpChannel->bans[i] = userConnection->userInfo.uid;
break;
}
}
sprintf(output,"MSG:TUveD:%s:%s has been banned\n",channel,userConnection->userInfo.username);
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 < MAX_BANS;i++) {
if (tmpChannel->bans[i] == userConnection->userInfo.uid) {
tmpChannel->bans[i] = 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 < MAX_BANS;i++) {
if (tmpChannel->bans[i] == userConnection->userInfo.uid) {
return(0x1);
}
}
return(0x0);
}