├── TODO ├── README ├── Marefile ├── bounced.sln ├── config.h ├── src ├── timer.h ├── dmemory.h ├── quit.c ├── names.c ├── password.c ├── ping.c ├── admin.c ├── timer.c ├── list.h ├── topic.c ├── md5.h ├── hash.h ├── hashlist.h ├── privmsg.c ├── dmemory.c ├── nick.c ├── client.c ├── md5.c ├── motd.c ├── tools.c ├── bounced.c └── connection.c ├── bounced.vcxproj.filters ├── sample.motd ├── bounced.vcxproj └── LICENSE /TODO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craflin/bounced/master/TODO -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Bounced is an undocumented irc bouncer that I wrote 10 years ago. -------------------------------------------------------------------------------- /Marefile: -------------------------------------------------------------------------------- 1 | 2 | targets = { 3 | bounced = cApplication + { 4 | includePaths = { 5 | ".", "src" 6 | } 7 | root = "src" 8 | files = { 9 | "src/*.c" = cSource 10 | "src/*.h" 11 | "config.h" 12 | } 13 | if tool == "vcxproj" { 14 | libs = { "ws2_32" } 15 | } 16 | } 17 | } 18 | 19 | if tool == "vcxproj" { 20 | linkFlags += "/SUBSYSTEM:CONSOLE" 21 | } 22 | -------------------------------------------------------------------------------- /bounced.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bounced", "bounced.vcxproj", "{0A887EEB-4998-75E8-8864-0888B06F2191}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {0A887EEB-4998-75E8-8864-0888B06F2191}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {0A887EEB-4998-75E8-8864-0888B06F2191}.Debug|Win32.Build.0 = Debug|Win32 14 | {0A887EEB-4998-75E8-8864-0888B06F2191}.Release|Win32.ActiveCfg = Release|Win32 15 | {0A887EEB-4998-75E8-8864-0888B06F2191}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | /* config.h. Generated from config.h.in by configure. */ 2 | /* config.h.in. Generated from configure.in by autoheader. */ 3 | 4 | /* #undef FD_SETSIZE */ 5 | 6 | #define CONFIGFILE "config" 7 | #define LOGFILE "log" 8 | #define MOTDFILE "motd" 9 | #define PIDFILE "pid" 10 | #define USERSFILE "users" 11 | 12 | #define INBUFFER 515 13 | #define OUTBUFFER 643 14 | 15 | #define USE_UID "nobody" 16 | #define USE_GID "nobody" 17 | 18 | /* #undef DEBUG */ 19 | /* #undef DEBUG_MEMORY */ 20 | /* #undef DEBUG_PROTOCOL */ 21 | /* #undef DEBUG_SOCKET */ 22 | 23 | /* Name of package */ 24 | #define PACKAGE "bounced" 25 | 26 | /* Define to the address where bug reports for this package should be sent. */ 27 | #define PACKAGE_BUGREPORT "" 28 | 29 | /* Define to the full name of this package. */ 30 | #define PACKAGE_NAME "" 31 | 32 | /* Define to the full name and version of this package. */ 33 | #define PACKAGE_STRING "" 34 | 35 | /* Define to the one symbol short name of this package. */ 36 | #define PACKAGE_TARNAME "" 37 | 38 | /* Define to the version of this package. */ 39 | #define PACKAGE_VERSION "" 40 | 41 | /* Define to 1 if you have the ANSI C header files. */ 42 | #define STDC_HEADERS 1 43 | 44 | /* Version number of package */ 45 | #define VERSION "0.27-dev4" 46 | -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | file: timer.c 3 | desciption: timer 4 | begin: Mon Jan 29 17:35 CET 2002 5 | copyright: (C) 2002 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifndef _TIMER_H 15 | #define _TIMER_H 16 | 17 | #include 18 | 19 | typedef void (*PTIMERPROC) (void *); 20 | 21 | typedef struct tagTIMER 22 | { 23 | struct tagTIMER * pNext; 24 | PTIMERPROC pTimerProc; 25 | void* pParams; 26 | time_t timeNext; 27 | time_t timeInterval; 28 | int iEvents; 29 | } TIMER, *PTIMER; 30 | 31 | extern PTIMER TimerAdd(time_t timeNow, time_t timeInterval, int iEvents, PTIMERPROC pTimerProc, void* pParams); 32 | extern void TimerExec(time_t timeNow); 33 | extern time_t TimerNext(time_t timeNow, time_t timeDefault); 34 | extern void TimersFree(void); 35 | extern int TimerSetInterval(PTIMER pTimer, time_t timeInterval); 36 | extern int TimerReset(PTIMER pTimer, time_t timeNow, time_t timeInterval); 37 | extern int TimerFree(PTIMER pTimer); 38 | extern int TimerSet(PTIMER* ppTimer, time_t timeNow, time_t timeInterval, int iEvents, PTIMERPROC pTimerProc, void* pParams); 39 | 40 | #endif /* _TIMER_H */ 41 | -------------------------------------------------------------------------------- /bounced.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/dmemory.h: -------------------------------------------------------------------------------- 1 | /* 2 | file: debug.h 3 | desciption: malloc calloc realloc strdup free and "cast" debugging 4 | begin: 10/07/02 5 | copyright: (C) 2002 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifndef _DEBUG_H 15 | #define _DEBUG_H 16 | 17 | #ifdef DEBUG_MEMORY 18 | 19 | extern int DebugMemoryInit(void); 20 | extern int DebugMemoryCleanup(void); 21 | extern int DebugMemoryCheckBlocks(void); 22 | extern size_t DebugMemoryUsage(void); 23 | extern int DebugMemoryShowStats(void); 24 | extern void* DebugMemoryMalloc(const char* strType, const char* strFile, int iLine, size_t size); 25 | extern void* DebugMemoryCalloc(const char* strType, const char* strFile, int iLine, size_t sizeNum, size_t size); 26 | extern void* DebugMemoryRealloc(const char* strType, const char* strFile, int iLine, void* p, size_t size); 27 | extern char* DebugMemoryStrdup(const char* strType, const char* strFile, int iLine, const char* str); 28 | extern void DebugMemoryFree(const char* strType, const char* strFile, int iLine, void* p); 29 | extern void* DebugMemoryCast(const char* strType, const char* strFile, int iLine, void* p); 30 | 31 | #define MALLOC(type,size) ((type)DebugMemoryMalloc(#type,__FILE__,__LINE__,size)) 32 | #define CALLOC(type,num,size) ((type)DebugMemoryCalloc(#type,__FILE__,__LINE__,num,size)) 33 | #define REALLOC(type,memblock,size) ((type)DebugMemoryRealloc(#type,__FILE__,__LINE__,memblock,size)) 34 | #define STRDUP(type,str) ((type)DebugMemoryStrdup(#type,__FILE__,__LINE__,str)) 35 | #define FREE(type,memblock) {DebugMemoryFree(#type,__FILE__,__LINE__,memblock);(type)0;} 36 | 37 | #define CAST(type,memblock) ((type)DebugMemoryCast(#type,__FILE__,__LINE__,memblock)) 38 | 39 | #else 40 | 41 | #define DebugMemoryInit() 1 42 | #define DebugMemoryCleanup() 1 43 | #define DebugMemoryCheckBlocks() 1 44 | #define DebugMemoryUsage() 0 45 | #define DebugMemoryShowStats() 1 46 | 47 | #define MALLOC(type,size) ((type)malloc(size)) 48 | #define CALLOC(type,num,size) ((type)calloc(num,size)) 49 | #define REALLOC(type,memblock,size) ((type)realloc(memblock,size)) 50 | #define STRDUP(type,str) ((type)strdup(str)) 51 | #define FREE(type,memblock) free(memblock) 52 | 53 | #define CAST(type,memblock) ((type)memblock) 54 | 55 | #endif /* DEBUG_MEMORY */ 56 | 57 | #endif /* _DEBUG_H_ */ 58 | -------------------------------------------------------------------------------- /sample.motd: -------------------------------------------------------------------------------- 1 | # 2 | # sample.motd for bounced-0.27+ 3 | # 4 | # 12/02/06 addition 5 | # 6 | 7 | # this is a sample motd file for bounced-0.27+ 8 | # 9 | # these motd variables are supported: 10 | # 11 | # %C = current time 12 | # %c = total connection count 13 | # %I = the ip of the current user 14 | # %l = number of total logins 15 | # %B = bouncer name (BouncerName from config file) 16 | # %N = nick of current user 17 | # %U = name of the current user 18 | # %R = real name of current user 19 | # %E = email of current user 20 | # %S = system info string (ex. "Windows 2000", "Linux 2.4.7-10") 21 | # %u = number of users 22 | # %V = server version string 23 | # %W = bounced's uptime 24 | # %w = time when the server was started 25 | # %i = current incoming traffic (in kB/s) 26 | # %o = current outgoing traffic (in kB/s) 27 | # %t = current traffic (in kB/s) 28 | # %D = current connection count of the bounced 29 | # %U = current amount of server connections 30 | # %L = current amount of client connections 31 | # %J = total incoming bytes in MB 32 | # %O = total outgoing bytes in MB 33 | # %T = total bytes in MB 34 | # %% = % (the character) 35 | # 36 | # and these motd directive are supported: 37 | # 38 | # FormatTime (type: string, default: %A, %d of %B %Y %X) 39 | # description: Sets the format of %C and %w. (See "man strftime" for format info.) 40 | # 41 | # FormatUptime (type: string, default: %#D days, %#H hours, %#M minutes and %#S seconds) 42 | # description: Sets the format of %W. (%D = days, %H = hours, %M = minutes, %S = seconds, # = no leading zeros) 43 | # 44 | # Your motd can look like this: 45 | 46 | FormatTime "%A, %d of %B %Y %X" 47 | FormatUptime "%#D days, %#H hours, %#M minutes and %#S seconds" 48 | 49 | - _|_|_| _| 50 | - _| _| _| 51 | - _| _| _| 52 | - _|_|_| _|_| _| _| _| _|_| _|_| _|_| _|_|_| 53 | - _| _| _| _| _| _| _|_| _| _| _| _| _| _| 54 | - _| _| _| _| _| _| _| _| _| _|_|_| _| _| 55 | - _| _| _| _| _| _| _| _| _| _| _| _| 56 | - _|_|_| _|_| _|_| _| _| _|_| _|_| _|_| 57 | - 58 | - Welcome %N (%I), 59 | - 60 | - you are on a Bounced beta server. 61 | - This bouncer bounces %u users. 62 | - 63 | - Bouncer Version: %V on %S 64 | - Bouncer Uptime: %W 65 | - Current Time: %C 66 | - Current Traffic: %t kB/s (%i kB/s in, %o kB/s out) 67 | - Total Traffic: %T MB (%J MB in, %O MB out) 68 | - 69 | -------------------------------------------------------------------------------- /src/quit.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: quit.c 3 | desciption: handle quit messages 4 | begin: 02/06/04 5 | copyright: (C) 2004 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | 20 | #include "bounced.h" 21 | 22 | /* server handlers */ 23 | 24 | int ServerHandlerQuit(PSERVER pServer, char* strCommand, char* strParams) 25 | { 26 | char* strNick; 27 | 28 | if( SplitIRCPrefixNick(strCommand,&strNick) ) 29 | { 30 | PPROFILE pProfile = pServer->pProfile; 31 | PPROFILECHANNEL pProfileChannel; 32 | PPROFILECHANNELUSER pProfileChannelUser; 33 | 34 | pProfile->nLogID++; 35 | 36 | for(pProfileChannel = pProfile->hashlistProfileChannels.pFirst; pProfileChannel; pProfileChannel = pProfileChannel->hllProfile.pNext) 37 | { 38 | HASHLIST_LOOKUP(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,strNick,pProfileChannelUser); 39 | if(pProfileChannelUser) 40 | { 41 | ProfileLogMsgCreate(0,pProfileChannel,pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP); 42 | ProfileChannelUserClose(pProfileChannelUser,0); 43 | } 44 | } 45 | } 46 | 47 | /* try to reuse the prefered nick */ 48 | { 49 | char* strPreferedNick; 50 | if(!pServer->pProfile->listClients.pFirst && pServer->pProfile->c_strDetachNick && *pServer->pProfile->c_strDetachNick) 51 | strPreferedNick = pServer->pProfile->c_strDetachNick; 52 | else 53 | strPreferedNick = pServer->pProfile->c_strNick; 54 | if(!strcasecmp(strNick,strPreferedNick) && strcasecmp(pServer->strNick,strPreferedNick)) 55 | ConnectionSendFormat(pServer->pConnection,"NICK :%s\r\n",strPreferedNick); 56 | } 57 | 58 | return 0; 59 | strParams = 0; 60 | } 61 | 62 | /* client handlers */ 63 | 64 | int ClientHandlerQuit(PCLIENT pClient, char* strCommand, char* strParams) 65 | { 66 | char* strArg[1]; 67 | unsigned int nArgs; 68 | 69 | nArgs = SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1); 70 | 71 | ConnectionCloseAsync(pClient->pConnection); 72 | 73 | if(pClient->pProfile) 74 | { 75 | ProfileDetach(pClient->pProfile,pClient,nArgs > 0 ? strArg[0] : 0); 76 | ASSERT(pClient->pProfile == 0); 77 | } 78 | 79 | return 1; 80 | strCommand = 0; 81 | } 82 | -------------------------------------------------------------------------------- /src/names.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: names.c 3 | desciption: handle names replays 4 | begin: 02/06/04 5 | copyright: (C) 2004 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | 20 | #include "bounced.h" 21 | 22 | /* server handlers */ 23 | 24 | int ServerHandlerNumNamReply(PSERVER pServer, char* strCommand, char* strParams) 25 | { 26 | char* strArg[3]; 27 | 28 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 29 | { 30 | PPROFILECHANNEL pProfileChannel; 31 | PPROFILE pProfile; 32 | 33 | pProfile = pServer->pProfile; 34 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[1],pProfileChannel); 35 | if(pProfileChannel) 36 | { 37 | char* str,*strEnd; 38 | char cPrefix; 39 | 40 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_LISTITEM); 41 | 42 | if(!pServer->cInList) 43 | HASHLIST_REMOVE_ALL(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers); 44 | pServer->cInList++; 45 | 46 | str = strArg[2]; 47 | do 48 | { 49 | strEnd = strchr(str,' '); 50 | if(strEnd) 51 | *(strEnd++) = '\0'; 52 | if(*str) 53 | { 54 | if(IsIRCNickPrefix(*str,pProfile->strPrefix)) 55 | { 56 | cPrefix = *str; 57 | str++; 58 | } 59 | else 60 | cPrefix = 0; 61 | if(*str) 62 | ProfileChannelUserCreate(pProfileChannel,str,cPrefix,0); 63 | } 64 | str = strEnd; 65 | } while(str); 66 | } 67 | } 68 | 69 | return 0; 70 | strCommand = 0; 71 | } 72 | 73 | int ServerHandlerNumEndOfNames(PSERVER pServer, char* strCommand, char* strParams) 74 | { 75 | char* strArg[1]; 76 | 77 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) == sizeof(strArg)/sizeof(*strArg)) 78 | { 79 | PPROFILECHANNEL pProfileChannel; 80 | PPROFILE pProfile; 81 | 82 | pProfile = pServer->pProfile; 83 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 84 | if(pProfileChannel) 85 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 86 | } 87 | 88 | pServer->cInList = 0; 89 | 90 | return 0; 91 | strCommand = 0; 92 | } 93 | -------------------------------------------------------------------------------- /src/password.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: user.c 3 | desciption: load user file 4 | begin: 10/25/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | 21 | #include "bounced.h" 22 | 23 | #include "md5.h" 24 | 25 | int PasswordIsValid(const char* str) 26 | { 27 | ASSERT(str); 28 | if(!str) 29 | return 0; 30 | if(!*str || *str == ':' || strchr(str,' ')) 31 | return 0; 32 | return 1; 33 | } 34 | 35 | int PasswordCreate(const char* str, char* pcMD5) 36 | { 37 | struct md5_ctx md; 38 | ASSERT(str); 39 | ASSERT(pcMD5); 40 | if(!str || !pcMD5) 41 | return 0; 42 | md5_init_ctx (&md); 43 | md5_process_bytes(str,strlen(str),&md); 44 | md5_finish_ctx(&md,pcMD5); 45 | return 1; 46 | } 47 | 48 | int PasswordCompare(const char* pcMD5Pass, const char* pcMD5PassTest) 49 | { 50 | int i; 51 | ASSERT(pcMD5Pass); 52 | ASSERT(pcMD5PassTest); 53 | if(!pcMD5Pass || !pcMD5PassTest) 54 | return 0; 55 | for(i = 0; i < 16; i++) 56 | if(pcMD5Pass[i]) 57 | break; 58 | if(i >= 16) 59 | return 1; 60 | return !memcmp(pcMD5Pass,pcMD5PassTest,16); 61 | } 62 | 63 | int PasswordStrTo(char* str, char* pcMD5) 64 | { 65 | int i; 66 | ASSERT(str); 67 | ASSERT(pcMD5); 68 | if(!str || !pcMD5) 69 | return 0; 70 | for(i = 0; i < 16; i++) 71 | { 72 | *str = toupper(*str); 73 | if((*str < '0' || *str > '9') && (*str < 'A' || *str > 'F')) 74 | return 0; 75 | pcMD5[i] = ((*str >= 'A' ? (*str-'A'+10) : (*str-'0')) << 4); 76 | str++; 77 | *str = toupper(*str); 78 | if((*str < '0' || *str > '9') && (*str < 'A' || *str > 'F')) 79 | return 0; 80 | pcMD5[i] |= (*str >= 'A' ? (*str-'A'+10) : (*str-'0')); 81 | str++; 82 | } 83 | return i; 84 | } 85 | 86 | static char g_Hex[] = "0123456789ABCDEF"; 87 | int PasswordToStr(const char* pcMD5, char* strOut, unsigned int nOutSize) 88 | { 89 | int i; 90 | ASSERT(pcMD5); 91 | ASSERT(strOut); 92 | ASSERT(nOutSize >= 33); 93 | if(!pcMD5 || !strOut || nOutSize < 33) 94 | return 0; 95 | for (i = 16-1; i >= 0; i--) 96 | { 97 | strOut[2*i+1] = g_Hex[pcMD5[i] & 0xf]; 98 | strOut[2*i] = g_Hex[(pcMD5[i] >> 4) & 0xf]; 99 | } 100 | strOut[32] = '\0'; 101 | return 1; 102 | } 103 | 104 | /* client handlers */ 105 | 106 | int ClientHandlerPassword(PCLIENT pClient, char* strCommand, char* strParams) 107 | { 108 | char* strArg[2]; 109 | unsigned int nArgs; 110 | 111 | if(*strParams == ':') 112 | strParams++; 113 | 114 | ASSERT(pClient->pUser); 115 | 116 | nArgs = SplitLine(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0); 117 | if(nArgs > 0) 118 | { 119 | if(!strcasecmp(strArg[0],"set") ) 120 | { 121 | if(nArgs > 1) 122 | { 123 | char pcMD5Pass[16]; 124 | 125 | if(!PasswordIsValid(strArg[1]) || !PasswordCreate(strArg[1],pcMD5Pass)) 126 | { 127 | ClientMessage(pClient,"Invalid password"); 128 | return 1; 129 | } 130 | 131 | memcpy(pClient->pUser->pcMD5Pass,pcMD5Pass,16); 132 | 133 | ClientMessage(pClient,"Changed password"); 134 | return 1; 135 | } 136 | } 137 | } 138 | 139 | if( !ClientMessage(pClient,"Usage is /%s set ",strCommand) ) 140 | return 1; 141 | 142 | return 1; 143 | } 144 | -------------------------------------------------------------------------------- /src/ping.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: ping.c 3 | desciption: ping handlers 4 | begin: 11/09/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | 20 | #include "bounced.h" 21 | 22 | /* unregistered server handlers */ 23 | 24 | int ServerHandlerUnregisteredPing(PSERVER pServer, char* strCommand, char* strParams) 25 | { 26 | char* strArg[1]; 27 | 28 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg)) 29 | return 1; 30 | 31 | ConnectionSendFormat(pServer->pConnection,"PONG :%s\r\n",strArg[0]); 32 | return 1; 33 | strCommand = 0; 34 | } 35 | 36 | /* server handlers */ 37 | 38 | int ServerHandlerPing(PSERVER pServer, char* strCommand, char* strParams) 39 | { 40 | char* strArg[1]; 41 | PCLIENT pClient; 42 | 43 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg)) 44 | return 1; 45 | 46 | { 47 | PCLIENT pNextClient; 48 | for(pClient = pServer->pProfile->listClients.pFirst; pClient; pClient = pNextClient) 49 | { 50 | pNextClient = pClient->llProfile.pNext; 51 | if(pClient->bWantPong) 52 | { 53 | if(ConnectionSendFormat(pClient->pConnection,"ERROR :Closing Link: %s (Ping timeout)\r\n",iptoa(pClient->pConnection->nIP))) 54 | ConnectionCloseAsync(pClient->pConnection); 55 | ASSERT(pClient->pProfile == pServer->pProfile); 56 | ProfileDetach(pServer->pProfile,pClient,"Ping timeout"); 57 | } 58 | } 59 | } 60 | 61 | if(!ConnectionSendFormat(pServer->pConnection,"PONG :%s\r\n",strArg[0])) 62 | return 1; 63 | 64 | for(pClient = pServer->pProfile->listClients.pFirst; pClient; pClient = pClient->llProfile.pNext) 65 | { 66 | if(!ConnectionSendFormat(pClient->pConnection,"PING :%s\r\n",iptoa(pClient->pConnection->nIP))) 67 | continue; 68 | pClient->bWantPong = 1; 69 | } 70 | 71 | return 1; 72 | strCommand = 0; 73 | } 74 | 75 | /* client handlers */ 76 | 77 | int ClientHandlerPing(PCLIENT pClient, char* strCommand, char* strParams) 78 | { 79 | char* strArg[2]; 80 | unsigned int nArgc; 81 | PPROFILE pProfile; 82 | 83 | if((nArgc = SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0)) < 1) 84 | { 85 | ConnectionSendFormat(pClient->pConnection,":%s 409 %s :No origin specified\r\n",c_strBouncerName,pClient->strNick); 86 | return 1; 87 | } 88 | 89 | pProfile = pClient->pProfile; 90 | if( !pProfile || !pProfile->pServer || !pProfile->pServer->bRegistered) 91 | { 92 | if(nArgc > 1) 93 | ConnectionSendFormat(pClient->pConnection,"PONG %s :%s\r\n",strArg[0],strArg[1]); 94 | else 95 | ConnectionSendFormat(pClient->pConnection,"PONG :%s\r\n",strArg[0]); 96 | return 1; 97 | } 98 | 99 | return 0; 100 | strCommand = 0; 101 | } 102 | 103 | int ClientHandlerPong(PCLIENT pClient, char* strCommand, char* strParams) 104 | { 105 | char* strArg[1]; 106 | 107 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg)) 108 | { 109 | ConnectionSendFormat(pClient->pConnection,":%s 409 %s :No origin specified\r\n",c_strBouncerName,pClient->strNick); 110 | return 1; 111 | } 112 | 113 | if(!strcasecmp(strArg[0],iptoa(pClient->pConnection->nIP))) 114 | { 115 | pClient->bWantPong = 0; 116 | return 1; 117 | } 118 | 119 | return 0; 120 | strCommand = 0; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /src/admin.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: admin.c 3 | desciption: handle admin commands 4 | begin: 01/05/04 5 | copyright: (C) 2004 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | 20 | #include "bounced.h" 21 | 22 | /* client handlers */ 23 | 24 | int ClientHandlerAdmin(PCLIENT pClient, char* strCommand, char* strParams) 25 | { 26 | char* str; 27 | 28 | if(*strParams == ':') 29 | strParams++; 30 | str = NextArg(&strParams); 31 | 32 | if(*str) 33 | { 34 | if(!strcasecmp(str,"user") ) 35 | { 36 | str = strCommand+strlen(strCommand); 37 | *(str++) = ' '; 38 | strcpy(str,"user"); 39 | return ClientSubhandlerAdminUser(pClient,strCommand,strParams); 40 | } 41 | if(!strcasecmp(str,"config") ) 42 | { 43 | str = strCommand+strlen(strCommand); 44 | *(str++) = ' '; 45 | strcpy(str,"config"); 46 | return ClientSubhandlerAdminConfig(pClient,strCommand,strParams); 47 | } 48 | if(!strcasecmp(str,"privmsg") ) 49 | { 50 | str = strCommand+strlen(strCommand); 51 | *(str++) = ' '; 52 | strcpy(str,"privmsg"); 53 | return ClientSubhandlerAdminPrivmsg(pClient,strCommand,strParams); 54 | } 55 | if(!strcasecmp(str,"notice") ) 56 | { 57 | str = strCommand+strlen(strCommand); 58 | *(str++) = ' '; 59 | strcpy(str,"notice"); 60 | return ClientSubhandlerAdminNotice(pClient,strCommand,strParams); 61 | } 62 | if(!strcasecmp(str,"wallops") ) 63 | { 64 | str = strCommand+strlen(strCommand); 65 | *(str++) = ' '; 66 | strcpy(str,"wallops"); 67 | return ClientSubhandlerAdminWallops(pClient,strCommand,strParams); 68 | } 69 | } 70 | 71 | if( !ClientMessage(pClient,"Usage is /%s user",strCommand) || 72 | !ClientMessage(pClient," /%s config",strCommand) || 73 | !ClientMessage(pClient," /%s privmsg",strCommand) || 74 | !ClientMessage(pClient," /%s notice",strCommand) || 75 | !ClientMessage(pClient," /%s wallops",strCommand) ) 76 | return 1; 77 | 78 | return 1; 79 | } 80 | 81 | /* admin subhandlers */ 82 | 83 | int ClientSubhandlerAdminPrivmsg(PCLIENT pClient, char* strCommand, char* strParams) 84 | { 85 | char* strArg[1]; 86 | 87 | if(SplitLine(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 88 | { 89 | PCLIENT pCli; 90 | for(pCli = g_listClients.pFirst; pCli; pCli = pCli->ll.pNext) 91 | ConnectionSendFormat(pCli->pConnection,":%s PRIVMSG %s :%s\r\n",c_strBouncerName,pCli->strNick,strArg[0]); 92 | return 1; 93 | } 94 | 95 | if( !ClientMessage(pClient,"Usage is /%s ",strCommand) ) 96 | return 1; 97 | 98 | return 1; 99 | } 100 | 101 | int ClientSubhandlerAdminNotice(PCLIENT pClient, char* strCommand, char* strParams) 102 | { 103 | char* strArg[1]; 104 | 105 | if(SplitLine(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 106 | { 107 | PCLIENT pCli; 108 | for(pCli = g_listClients.pFirst; pCli; pCli = pCli->ll.pNext) 109 | ConnectionSendFormat(pCli->pConnection,":%s NOTICE %s :%s\r\n",c_strBouncerName,pCli->strNick,strArg[0]); 110 | return 1; 111 | } 112 | 113 | if( !ClientMessage(pClient,"Usage is /%s ",strCommand) ) 114 | return 1; 115 | 116 | return 1; 117 | } 118 | 119 | int ClientSubhandlerAdminWallops(PCLIENT pClient, char* strCommand, char* strParams) 120 | { 121 | char* strArg[1]; 122 | 123 | if(SplitLine(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 124 | { 125 | PCLIENT pCli; 126 | for(pCli = g_listClients.pFirst; pCli; pCli = pCli->ll.pNext) 127 | ConnectionSendFormat(pCli->pConnection,":%s WALLOPS :%s\r\n",c_strBouncerName,strArg[0]); 128 | return 1; 129 | } 130 | 131 | if( !ClientMessage(pClient,"Usage is /%s ",strCommand) ) 132 | return 1; 133 | 134 | return 1; 135 | } 136 | 137 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: timer.c 3 | desciption: timer 4 | begin: Mon Jan 29 17:35 CET 2002 5 | copyright: (C) 2002 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /*HAVE_CONFIG_H*/ 17 | 18 | #include 19 | 20 | #include "timer.h" 21 | 22 | extern void TimerSchedule(PTIMER pTimer); 23 | extern int TimerUnschedule(PTIMER pTimer); 24 | 25 | PTIMER g_pTimersPending = 0; 26 | 27 | void TimerSchedule(PTIMER pTimer) 28 | { 29 | PTIMER* ppSlot; 30 | 31 | if(!pTimer->iEvents) 32 | return; 33 | 34 | for(ppSlot = &g_pTimersPending; *ppSlot; ppSlot = &(*ppSlot)->pNext) 35 | { 36 | if(pTimer->timeNext < (*ppSlot)->timeNext) 37 | break; 38 | } 39 | pTimer->pNext = *ppSlot; 40 | *ppSlot = pTimer; 41 | } 42 | 43 | int TimerUnschedule(PTIMER pTimer) 44 | { 45 | PTIMER* ppSlot; 46 | 47 | for(ppSlot = &g_pTimersPending; *ppSlot; ppSlot = &(*ppSlot)->pNext) 48 | { 49 | if(pTimer == *ppSlot) 50 | { 51 | *ppSlot = pTimer->pNext; 52 | return 1; 53 | } 54 | } 55 | return 0; 56 | } 57 | 58 | PTIMER TimerAdd(time_t timeNow, time_t timeInterval, int iEvents, PTIMERPROC pTimerProc, void* pParams) 59 | { 60 | PTIMER pNew; 61 | 62 | if(!iEvents || !pTimerProc) 63 | return 0; 64 | 65 | if(!(pNew = malloc(sizeof(TIMER)))) 66 | return 0; 67 | pNew->iEvents = iEvents; 68 | pNew->pNext = 0; 69 | pNew->pParams = pParams; 70 | pNew->pTimerProc = pTimerProc; 71 | pNew->timeInterval = timeInterval; 72 | pNew->timeNext = timeNow+timeInterval; 73 | 74 | TimerSchedule(pNew); 75 | 76 | return pNew; 77 | } 78 | 79 | void TimerExec(time_t timeNow) 80 | { 81 | PTIMER pCurrent; 82 | 83 | while(g_pTimersPending && g_pTimersPending->timeNext <= timeNow) 84 | { 85 | pCurrent = g_pTimersPending; 86 | g_pTimersPending = pCurrent->pNext; 87 | if(pCurrent->iEvents == 1 || pCurrent->iEvents == 0) 88 | { 89 | pCurrent->pTimerProc(pCurrent->pParams); 90 | free(pCurrent); 91 | } 92 | else 93 | { 94 | if(pCurrent->iEvents > 0) 95 | pCurrent->iEvents--; 96 | pCurrent->timeNext += pCurrent->timeInterval; 97 | TimerSchedule(pCurrent); 98 | pCurrent->pTimerProc(pCurrent->pParams); /* do this here because otherwise thet timer proc can't delete this timer with TimerFree() */ 99 | } 100 | } 101 | } 102 | 103 | time_t TimerNext(time_t timeNow, time_t timeDefault) 104 | { 105 | if(g_pTimersPending) 106 | { 107 | if(g_pTimersPending->timeNext <= timeNow) 108 | { 109 | TimerExec(timeNow); 110 | return TimerNext(timeNow,timeDefault); 111 | } 112 | return g_pTimersPending->timeNext-timeNow; 113 | } 114 | return timeDefault; 115 | } 116 | 117 | void TimersFree(void) 118 | { 119 | PTIMER pTimer; 120 | while(g_pTimersPending) 121 | { 122 | pTimer = g_pTimersPending; 123 | g_pTimersPending = g_pTimersPending->pNext; 124 | free(pTimer); 125 | } 126 | } 127 | 128 | 129 | int TimerSetInterval(PTIMER pTimer, time_t timeInterval) 130 | { 131 | if(!pTimer) 132 | return 0; 133 | 134 | TimerUnschedule(pTimer); 135 | pTimer->timeNext = pTimer->timeNext-pTimer->timeInterval+timeInterval; 136 | pTimer->timeInterval = timeInterval; 137 | TimerSchedule(pTimer); 138 | 139 | return 1; 140 | } 141 | 142 | int TimerReset(PTIMER pTimer, time_t timeNow, time_t timeInterval) 143 | { 144 | if(!pTimer) 145 | return 0; 146 | 147 | TimerUnschedule(pTimer); 148 | pTimer->timeNext = timeNow+timeInterval; 149 | pTimer->timeInterval = timeInterval; 150 | TimerSchedule(pTimer); 151 | 152 | return 1; 153 | } 154 | 155 | int TimerFree(PTIMER pTimer) 156 | { 157 | if(!pTimer) 158 | return 0; 159 | if(!TimerUnschedule(pTimer)) 160 | return 0; 161 | free(pTimer); 162 | return 1; 163 | } 164 | 165 | int TimerSet(PTIMER* ppTimer, time_t timeNow, time_t timeInterval, int iEvents, PTIMERPROC pTimerProc, void* pParams) 166 | { 167 | if(!ppTimer || !iEvents || !pTimerProc) 168 | return 0; 169 | if(*ppTimer) 170 | { 171 | if(timeInterval) 172 | TimerSetInterval(*ppTimer,timeInterval); 173 | else 174 | { 175 | TimerFree(*ppTimer); 176 | *ppTimer = 0; 177 | } 178 | } 179 | else if(timeInterval && !(*ppTimer = TimerAdd(timeNow,timeInterval,iEvents,pTimerProc,pParams))) 180 | return 0; 181 | return 1; 182 | } 183 | -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | file: list.h 3 | desciption: double linked list macros 4 | begin: 01/19/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifndef _LIST_H 15 | #define _LIST_H 16 | 17 | #define LIST_INITTYPE(LISTINFO) struct tag##LISTINFO \ 18 | { \ 19 | LISTINFO##_ITEM* pFirst; \ 20 | unsigned int nCount; \ 21 | } 22 | 23 | #define LIST_SIZEOF(LISTINFO) (sizeof(struct tag##LISTINFO)) 24 | 25 | #define LIST(LISTINFO) struct tag##LISTINFO 26 | #define PLIST(LISTINFO) struct tag##LISTINFO* 27 | 28 | #define LISTLINK(LISTINFO) struct \ 29 | { \ 30 | LISTINFO##_ITEM** ppPreviousNext; \ 31 | LISTINFO##_ITEM* pNext; \ 32 | } LISTINFO##_LINK 33 | 34 | #define LIST_INIT(LISTINFO,listexName) \ 35 | { \ 36 | (listexName).nCount = 0; \ 37 | (listexName).pFirst = 0; \ 38 | } 39 | 40 | #define LIST_ADD(LISTINFO,listexName,pItem) \ 41 | { \ 42 | if(((pItem)->LISTINFO##_LINK.pNext = (listexName).pFirst)) \ 43 | (listexName).pFirst->LISTINFO##_LINK.ppPreviousNext = &(pItem)->LISTINFO##_LINK.pNext; \ 44 | (pItem)->LISTINFO##_LINK.ppPreviousNext = &(listexName).pFirst; \ 45 | (listexName).pFirst = (pItem); \ 46 | (listexName).nCount++; \ 47 | } 48 | 49 | #define LIST_INSERT_AFTER(LISTINFO,listexName,pItem,pNewItem) \ 50 | { \ 51 | if(((pNewItem)->LISTINFO##_LINK.pNext = (pItem)->LISTINFO##_LINK.pNext)) \ 52 | (pItem)->LISTINFO##_LINK.pNext->LISTINFO##_LINK.ppPreviousNext = &(pNewItem)->LISTINFO##_LINK.pNext; \ 53 | (pNewItem)->LISTINFO##_LINK.ppPreviousNext = &(pItem)->LISTINFO##_LINK.pNext; \ 54 | (pItem)->LISTINFO##_LINK.pNext = (pNewItem); \ 55 | (listexName).nCount++; \ 56 | } 57 | /* 58 | #define LIST_INSERT_BEFORE(LISTINFO,listexName,pItem,pNewItem) \ 59 | { \ 60 | (pNewItem)->LISTINFO##_LINK.pNext = (pItem); \ 61 | (pNewItem)->LISTINFO##_LINK.ppPreviousNext = (pItem)->LISTINFO##_LINK.ppPreviousNext; \ 62 | (pItem)->LISTINFO##_LINK.ppPreviousNext = &(pNewItem)->LISTINFO##_LINK.pNext; \ 63 | *(pNewItem)->LISTINFO##_LINK.ppPreviousNext = (pNewItem); 64 | (listexName).nCount++; \ 65 | } 66 | */ 67 | #define LIST_INSERT(LISTINFO,listexName,ppInsertPreviousNext,pNewItem) \ 68 | { \ 69 | if(((pNewItem)->LISTINFO##_LINK.pNext = *(ppInsertPreviousNext))) \ 70 | (pNewItem)->LISTINFO##_LINK.pNext->LISTINFO##_LINK.ppPreviousNext = &(pNewItem)->LISTINFO##_LINK.pNext; \ 71 | (pNewItem)->LISTINFO##_LINK.ppPreviousNext = (ppInsertPreviousNext); \ 72 | *(ppInsertPreviousNext) = (pNewItem); \ 73 | (listexName).nCount++; \ 74 | } 75 | 76 | #define LIST_SEARCH_ITEM(LISTINFO,listexName,pItem,pItemResult/*out*/) \ 77 | { \ 78 | for((pItemResult) = (listexName).pFirst; \ 79 | (pItemResult); (pItemResult) = (pItemResult)->LISTINFO##_LINK.pNext) \ 80 | if((pItemResult) == (pItem)) \ 81 | break; \ 82 | } 83 | 84 | #define LIST_REMOVE_ITEM(LISTINFO,listexName,pItem) \ 85 | { \ 86 | if((*(pItem)->LISTINFO##_LINK.ppPreviousNext = (pItem)->LISTINFO##_LINK.pNext)) \ 87 | (pItem)->LISTINFO##_LINK.pNext->LISTINFO##_LINK.ppPreviousNext = (pItem)->LISTINFO##_LINK.ppPreviousNext; \ 88 | (listexName).nCount--; \ 89 | LISTINFO##_FREEPROC((pItem)); \ 90 | } 91 | 92 | #define LIST_REMOVE_ITEM_NOFREE(LISTINFO,listexName,pItem) \ 93 | { \ 94 | if((*(pItem)->LISTINFO##_LINK.ppPreviousNext = (pItem)->LISTINFO##_LINK.pNext)) \ 95 | (pItem)->LISTINFO##_LINK.pNext->LISTINFO##_LINK.ppPreviousNext = (pItem)->LISTINFO##_LINK.ppPreviousNext; \ 96 | (listexName).nCount--; \ 97 | } 98 | 99 | #define LIST_REMOVE_FIRST(LISTINFO,listexName) \ 100 | LIST_REMOVE_ITEM(LISTINFO,listexName,(listexName).pFirst) 101 | 102 | #define LIST_REMOVE_FIRST_NOFREE(LISTINFO,listexName) \ 103 | LIST_REMOVE_ITEM_NOFREE(LISTINFO,listexName,(listexName).pFirst) 104 | 105 | #define LIST_REMOVE_NEXT(LISTINFO,listexName,pItem) \ 106 | LIST_REMOVE_ITEM(LISTINFO,listexName,(pItem)->LISTINFO##_LINK.pNext) 107 | 108 | #define LIST_REMOVE_NEXT_NOFREE(LISTINFO,listexName,pItem) \ 109 | LIST_REMOVE_ITEM_NOFREE(LISTINFO,listexName,(pItem)->LISTINFO##_LINK.pNext) 110 | 111 | #define LIST_REMOVE_ALL(LISTINFO,listexName) \ 112 | { \ 113 | LISTINFO##_ITEM* pItem; \ 114 | while((pItem = (listexName).pFirst)) \ 115 | { \ 116 | if(((listexName).pFirst = pItem->LISTINFO##_LINK.pNext)) \ 117 | (listexName).pFirst->LISTINFO##_LINK.ppPreviousNext = &(listexName).pFirst; \ 118 | (listexName).nCount--; \ 119 | LISTINFO##_FREEPROC(pItem); \ 120 | } \ 121 | } 122 | /* 123 | #define LIST_REMOVE_ALL_NOFREE(LISTINFO,listexName) \ 124 | { \ 125 | while((listexName).pFirst) \ 126 | { \ 127 | if(((listexName).pFirst = (listexName).pFirst->LISTINFO##_LINK.pNext)) \ 128 | (listexName).pFirst->LISTINFO##_LINK.ppPreviousNext = &(listexName).pFirst; \ 129 | (listexName).nCount--; \ 130 | } \ 131 | } 132 | */ 133 | #define LIST_REMOVE_ALL_NOFREE(LISTINFO,listexName) LIST_INIT(LISTINFO,listexName) 134 | 135 | #endif /* _LIST_H */ 136 | -------------------------------------------------------------------------------- /src/topic.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: topic.c 3 | desciption: handle topic replays 4 | begin: 02/06/04 5 | copyright: (C) 2004 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "bounced.h" 23 | 24 | /* server handlers */ 25 | 26 | int ServerHandlerTopic(PSERVER pServer, char* strCommand, char* strParams) 27 | { 28 | char* strArg[2]; 29 | unsigned int nArgs; 30 | 31 | if((nArgs = SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1)) >= 1) 32 | { 33 | PPROFILECHANNEL pProfileChannel; 34 | PPROFILE pProfile; 35 | 36 | pProfile = pServer->pProfile; 37 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 38 | if(pProfileChannel) 39 | { 40 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 41 | 42 | if(pProfileChannel->strTopic) 43 | { 44 | FREE(char*,pProfileChannel->strTopic); 45 | pProfileChannel->strTopic = 0; 46 | } 47 | if(pProfileChannel->strTopicSetBy) 48 | { 49 | FREE(char*,pProfileChannel->strTopicSetBy); 50 | pProfileChannel->strTopicSetBy = 0; 51 | } 52 | pProfileChannel->timeTopicSetTime = 0; 53 | 54 | if( nArgs > 1 && *strArg[1] && 55 | (pProfileChannel->strTopic = STRDUP(char*,strArg[1])) ) 56 | { 57 | char* str; 58 | 59 | if( SplitIRCPrefix(strCommand,&str) && 60 | (pProfileChannel->strTopicSetBy = STRDUP(char*,str)) ) 61 | pProfileChannel->timeTopicSetTime = g_timeNow; 62 | } 63 | } 64 | } 65 | 66 | return 0; 67 | } 68 | 69 | int ServerHandlerNumNoTopic(PSERVER pServer, char* strCommand, char* strParams) 70 | { 71 | char* strArg[1]; 72 | 73 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) == sizeof(strArg)/sizeof(*strArg)) 74 | { 75 | PPROFILECHANNEL pProfileChannel; 76 | PPROFILE pProfile; 77 | 78 | pProfile = pServer->pProfile; 79 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 80 | if(pProfileChannel) 81 | { 82 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 83 | 84 | if(pProfileChannel->strTopic) 85 | { 86 | FREE(char*,pProfileChannel->strTopic); 87 | pProfileChannel->strTopic = 0; 88 | } 89 | if(pProfileChannel->strTopicSetBy) 90 | { 91 | FREE(char*,pProfileChannel->strTopicSetBy); 92 | pProfileChannel->strTopicSetBy = 0; 93 | } 94 | pProfileChannel->timeTopicSetTime = 0; 95 | } 96 | } 97 | 98 | return 0; 99 | strCommand = 0; 100 | } 101 | 102 | int ServerHandlerNumTopic(PSERVER pServer, char* strCommand, char* strParams) 103 | { 104 | char* strArg[2]; 105 | 106 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 107 | { 108 | PPROFILECHANNEL pProfileChannel; 109 | PPROFILE pProfile; 110 | 111 | pProfile = pServer->pProfile; 112 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 113 | if(pProfileChannel) 114 | { 115 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 116 | 117 | if(pProfileChannel->strTopic) 118 | { 119 | FREE(char*,pProfileChannel->strTopic); 120 | pProfileChannel->strTopic = 0; 121 | } 122 | if(pProfileChannel->strTopicSetBy) 123 | { 124 | FREE(char*,pProfileChannel->strTopicSetBy); 125 | pProfileChannel->strTopicSetBy = 0; 126 | } 127 | pProfileChannel->timeTopicSetTime = 0; 128 | pProfileChannel->strTopic = STRDUP(char*,strArg[1]); 129 | } 130 | } 131 | 132 | return 0; 133 | strCommand = 0; 134 | } 135 | 136 | int ServerHandlerNumTopicSetBy(PSERVER pServer, char* strCommand, char* strParams) 137 | { 138 | char* strArg[3]; 139 | 140 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) == sizeof(strArg)/sizeof(*strArg)) 141 | { 142 | PPROFILECHANNEL pProfileChannel; 143 | PPROFILE pProfile; 144 | 145 | pProfile = pServer->pProfile; 146 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 147 | if(pProfileChannel) 148 | { 149 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 150 | 151 | if(pProfileChannel->strTopicSetBy) 152 | { 153 | FREE(char*,pProfileChannel->strTopicSetBy); 154 | pProfileChannel->strTopicSetBy = 0; 155 | } 156 | pProfileChannel->timeTopicSetTime = 0; 157 | 158 | if( (pProfileChannel->strTopicSetBy = STRDUP(char*,strArg[1])) ) 159 | pProfileChannel->timeTopicSetTime = atoul(strArg[2]); 160 | } 161 | } 162 | 163 | return 0; 164 | strCommand = 0; 165 | } 166 | -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | /* md5.h - Declaration of functions and data types used for MD5 sum 2 | computing library functions. 3 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. 4 | NOTE: The canonical source of this file is maintained with the GNU C 5 | Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the 9 | Free Software Foundation; either version 2, or (at your option) any 10 | later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software Foundation, 19 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 | 21 | #ifndef _MD5_H 22 | #define _MD5_H 1 23 | 24 | #include 25 | 26 | #if defined HAVE_LIMITS_H || _LIBC 27 | # include 28 | #endif 29 | 30 | /* The following contortions are an attempt to use the C preprocessor 31 | to determine an unsigned integral type that is 32 bits wide. An 32 | alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but 33 | doing that would require that the configure script compile and *run* 34 | the resulting executable. Locally running cross-compiled executables 35 | is usually not possible. */ 36 | 37 | #ifdef _LIBC 38 | # include 39 | typedef u_int32_t md5_uint32; 40 | #else 41 | # if defined __STDC__ && __STDC__ 42 | # define UINT_MAX_32_BITS 4294967295U 43 | # else 44 | # define UINT_MAX_32_BITS 0xFFFFFFFF 45 | # endif 46 | 47 | /* If UINT_MAX isn't defined, assume it's a 32-bit type. 48 | This should be valid for all systems GNU cares about because 49 | that doesn't include 16-bit systems, and only modern systems 50 | (that certainly have ) have 64+-bit integral types. */ 51 | 52 | # ifndef UINT_MAX 53 | # define UINT_MAX UINT_MAX_32_BITS 54 | # endif 55 | 56 | # if UINT_MAX == UINT_MAX_32_BITS 57 | typedef unsigned int md5_uint32; 58 | # else 59 | # if USHRT_MAX == UINT_MAX_32_BITS 60 | typedef unsigned short md5_uint32; 61 | # else 62 | # if ULONG_MAX == UINT_MAX_32_BITS 63 | typedef unsigned long md5_uint32; 64 | # else 65 | /* The following line is intended to evoke an error. 66 | Using #error is not portable enough. */ 67 | "Cannot determine unsigned 32-bit data type." 68 | # endif 69 | # endif 70 | # endif 71 | #endif 72 | 73 | #undef __P 74 | #if defined (__STDC__) && __STDC__ 75 | #define __P(x) x 76 | #else 77 | #define __P(x) () 78 | #endif 79 | 80 | /* Structure to save state of computation between the single steps. */ 81 | struct md5_ctx 82 | { 83 | md5_uint32 A; 84 | md5_uint32 B; 85 | md5_uint32 C; 86 | md5_uint32 D; 87 | 88 | md5_uint32 total[2]; 89 | md5_uint32 buflen; 90 | char buffer[128]; 91 | }; 92 | 93 | /* 94 | * The following three functions are build up the low level used in 95 | * the functions `md5_stream' and `md5_buffer'. 96 | */ 97 | 98 | /* Initialize structure containing state of computation. 99 | (RFC 1321, 3.3: Step 3) */ 100 | extern void md5_init_ctx __P ((struct md5_ctx *ctx)); 101 | 102 | /* Starting with the result of former calls of this function (or the 103 | initialization function update the context for the next LEN bytes 104 | starting at BUFFER. 105 | It is necessary that LEN is a multiple of 64!!! */ 106 | extern void md5_process_block __P ((const void *buffer, size_t len, 107 | struct md5_ctx *ctx)); 108 | 109 | /* Starting with the result of former calls of this function (or the 110 | initialization function update the context for the next LEN bytes 111 | starting at BUFFER. 112 | It is NOT required that LEN is a multiple of 64. */ 113 | extern void md5_process_bytes __P ((const void *buffer, size_t len, 114 | struct md5_ctx *ctx)); 115 | 116 | /* Process the remaining bytes in the buffer and put result from CTX 117 | in first 16 bytes following RESBUF. The result is always in little 118 | endian byte order, so that a byte-wise output yields to the wanted 119 | ASCII representation of the message digest. 120 | 121 | IMPORTANT: On some systems it is required that RESBUF is correctly 122 | aligned for a 32 bits value. */ 123 | extern void *md5_finish_ctx __P ((struct md5_ctx *ctx, void *resbuf)); 124 | 125 | 126 | /* Put result from CTX in first 16 bytes following RESBUF. The result is 127 | always in little endian byte order, so that a byte-wise output yields 128 | to the wanted ASCII representation of the message digest. 129 | 130 | IMPORTANT: On some systems it is required that RESBUF is correctly 131 | aligned for a 32 bits value. */ 132 | extern void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf)); 133 | 134 | 135 | /* Compute MD5 message digest for bytes read from STREAM. The 136 | resulting message digest number will be written into the 16 bytes 137 | beginning at RESBLOCK. */ 138 | extern int md5_stream __P ((FILE *stream, void *resblock)); 139 | 140 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The 141 | result is always in little endian byte order, so that a byte-wise 142 | output yields to the wanted ASCII representation of the message 143 | digest. */ 144 | extern void *md5_buffer __P ((const char *buffer, size_t len, void *resblock)); 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | file: _hash.h 3 | desciption: hash macros 4 | begin: 01/17/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifndef _HASH_H 15 | #define _HASH_H 16 | 17 | #define HASH_INITTYPE(HASHINFO,nSize) struct tag##HASHINFO \ 18 | { \ 19 | HASHINFO##_ITEM* ppHash[nSize]; \ 20 | unsigned int nCount; \ 21 | } 22 | 23 | #define HASH_SIZEOF(HASHINFO) (sizeof(struct tag##HASHINFO)) 24 | 25 | #define HASH(HASHINFO) struct tag##HASHINFO 26 | #define PHASH(HASHINFO) struct tag##HASHINFO* 27 | 28 | #define HASHLINK(HASHINFO) struct \ 29 | { \ 30 | HASHINFO##_ITEM* pNext; \ 31 | } HASHINFO##_LINK 32 | 33 | #define HASH_SIZE(HASHINFO,hashName) (sizeof((hashName).ppHash)/sizeof(*(hashName).ppHash)) 34 | 35 | #define HASH_INIT(HASHINFO,hashName) \ 36 | { \ 37 | (hashName).nCount = 0; \ 38 | memset((hashName).ppHash,0,sizeof((hashName).ppHash)); \ 39 | } 40 | 41 | #define HASH_ADD(HASHINFO,hashName,pItem) \ 42 | { \ 43 | HASHINFO##_ITEM** ppItem = \ 44 | &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((HASHINFO##_KEY((pItem))))) % HASH_SIZE(HASHINFO,hashName)]; \ 45 | (pItem)->HASHINFO##_LINK.pNext = *ppItem; \ 46 | *ppItem = (pItem); \ 47 | (hashName).nCount++; \ 48 | } 49 | 50 | #define HASH_SEARCH_ITEM(HASHINFO,hashName,pItem,pItemResult/*out*/) \ 51 | { \ 52 | for((pItemResult) = (hashName).ppHash[(HASHINFO##_CHECKSUMPROC((HASHINFO##_KEY((pItem))))) % HASH_SIZE(HASHINFO,hashName)]; \ 53 | (pItemResult); (pItemResult) = (pItemResult)->HASHINFO##_LINK.pNext) \ 54 | if((pItemResult) == (pItem)) \ 55 | break; \ 56 | } 57 | 58 | #define HASH_LOOKUP(HASHINFO,hashName,pKey,pItemResult/*out*/) \ 59 | { \ 60 | for((pItemResult) = (hashName).ppHash[(HASHINFO##_CHECKSUMPROC((pKey))) % HASH_SIZE(HASHINFO,hashName)]; \ 61 | (pItemResult); (pItemResult) = (pItemResult)->HASHINFO##_LINK.pNext) \ 62 | if(HASHINFO##_COMPAREPROC((pKey),(HASHINFO##_KEY((pItemResult))))) \ 63 | break; \ 64 | } 65 | 66 | #define HASH_LOOKUP_POINTER(HASHINFO,hashName,pKey,ppItemResult/*out*/) \ 67 | { \ 68 | for((ppItemResult) = &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((pKey))) % HASH_SIZE(HASHINFO,hashName)]; \ 69 | *(ppItemResult); (ppItemResult) = &(*(ppItemResult))->HASHINFO##_LINK.pNext) \ 70 | if(HASHINFO##_COMPAREPROC((pKey),(HASHINFO##_KEY((*(ppItemResult)))))) \ 71 | break; \ 72 | } 73 | 74 | #define HASH_REMOVE_ITEM(HASHINFO,hashName,pItem) \ 75 | { \ 76 | HASHINFO##_ITEM** ppItem; \ 77 | for(ppItem = &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((HASHINFO##_KEY((pItem))))) % HASH_SIZE(HASHINFO,hashName)]; \ 78 | *ppItem; ppItem = &(*ppItem)->HASHINFO##_LINK.pNext) \ 79 | if(*ppItem == (pItem)) \ 80 | { \ 81 | *ppItem = (pItem)->HASHINFO##_LINK.pNext; \ 82 | (hashName).nCount--; \ 83 | HASHINFO##_FREEPROC((pItem)); \ 84 | break; \ 85 | } \ 86 | } 87 | 88 | #define HASH_REMOVE_ITEM_NOFREE(HASHINFO,hashName,pItem) \ 89 | { \ 90 | HASHINFO##_ITEM** ppItem; \ 91 | for(ppItem = &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((HASHINFO##_KEY((pItem))))) % HASH_SIZE(HASHINFO,hashName)]; \ 92 | *ppItem; ppItem = &(*ppItem)->HASHINFO##_LINK.pNext) \ 93 | if(*ppItem == (pItem)) \ 94 | { \ 95 | *ppItem = (pItem)->HASHINFO##_LINK.pNext; \ 96 | (hashName).nCount--; \ 97 | break; \ 98 | } \ 99 | } 100 | 101 | #define HASH_REMOVE_ITEM_POINTER(HASHINFO,hashName,ppItem) \ 102 | { \ 103 | HASHINFO##_ITEM* pItem = (*ppItem); \ 104 | *(ppItem) = (*(ppItem))->HASHINFO##_LINK.pNext; \ 105 | (hashName).nCount--; \ 106 | HASHINFO##_FREEPROC(pItem); \ 107 | } 108 | 109 | #define HASH_REMOVE_ITEM_POINTER_NOFREE(HASHINFO,hashName,ppItem) \ 110 | { \ 111 | *(ppItem) = (*(ppItem))->HASHINFO##_LINK.pNext; \ 112 | (hashName).nCount--; \ 113 | } 114 | 115 | #define HASH_REMOVE(HASHINFO,hashName,pKey) \ 116 | { \ 117 | HASHINFO##_ITEM** ppItem; \ 118 | for(ppItem = &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((pKey))) % HASH_SIZE(HASHINFO,hashName)]; \ 119 | *ppItem; ppItem = &(*ppItem)->HASHINFO##_LINK.pNext) \ 120 | if(HASHINFO##_COMPAREPROC((pKey),(HASHINFO##_KEY((*ppItem))))) \ 121 | { \ 122 | HASHINFO##_ITEM* pItem = *ppItem; \ 123 | *ppItem = pItem->HASHINFO##_LINK.pNext; \ 124 | (hashName).nCount--; \ 125 | HASHINFO##_FREEPROC(pItem); \ 126 | break; \ 127 | } \ 128 | } 129 | 130 | #define HASH_REMOVE_NOFREE(HASHINFO,hashName,pKey) \ 131 | { \ 132 | HASHINFO##_ITEM** ppItem; \ 133 | for(ppItem = &(hashName).ppHash[(HASHINFO##_CHECKSUMPROC((pKey))) % HASH_SIZE(HASHINFO,hashName)]; \ 134 | *ppItem; ppItem = &(*ppItem)->HASHINFO##_LINK.pNext) \ 135 | if(HASHINFO##_COMPAREPROC((pKey),(HASHINFO##_KEY((*ppItem))))) \ 136 | { \ 137 | HASHINFO##_ITEM* pItem = *ppItem; \ 138 | *ppItem = pItem->HASHINFO##_LINK.pNext; \ 139 | (hashName).nCount--; \ 140 | break; \ 141 | } \ 142 | } 143 | 144 | #define HASH_REMOVE_ALL(HASHINFO,hashName) \ 145 | { \ 146 | HASHINFO##_ITEM **ppItem,*pItem,**ppItemEnd = &(hashName).ppHash[HASH_SIZE(HASHINFO,hashName)]; \ 147 | for(ppItem = (hashName).ppHash; ppItem < ppItemEnd; ppItem++) \ 148 | while((pItem = *ppItem)) \ 149 | { \ 150 | *ppItem = pItem->HASHINFO##_LINK.pNext; \ 151 | (hashName).nCount--; \ 152 | HASHINFO##_FREEPROC(pItem); \ 153 | } \ 154 | } 155 | /* 156 | #define HASH_REMOVE_ALL_NOFREE(HASHINFO,hashName) \ 157 | { \ 158 | HASHINFO##_ITEM **ppItem,*pItem,**ppItemEnd = &(hashName).ppHash[HASH_SIZE(HASHINFO,hashName)]; \ 159 | for(ppItem = (hashName).ppHash; ppItem < ppItemEnd; ppItem++) \ 160 | while((pItem = *ppItem)) \ 161 | { \ 162 | *ppItem = pItem->HASHINFO##_LINK.pNext; \ 163 | (hashName).nCount--; \ 164 | } \ 165 | } 166 | */ 167 | #define HASH_REMOVE_ALL_NOFREE(HASHINFO,hashName) HASH_INIT(HASHINFO,hashName) 168 | 169 | #endif /* _HASH_H */ 170 | -------------------------------------------------------------------------------- /src/hashlist.h: -------------------------------------------------------------------------------- 1 | /* 2 | file: _hashlist.h 3 | desciption: double linked hashlist macros 4 | begin: 01/20/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifndef _HASHLIST_H 15 | #define _HASHLIST_H 16 | 17 | #define HASHLIST_INITTYPE(HASHLISTINFO,nSize) struct tag##HASHLISTINFO \ 18 | { \ 19 | HASHLISTINFO##_ITEM* ppHash[nSize]; \ 20 | HASHLISTINFO##_ITEM* pFirst; \ 21 | unsigned int nCount; \ 22 | } 23 | 24 | #define HASHLIST_SIZEOF(HASHLISTINFO) (sizeof(struct tag##HASHLISTINFO)) 25 | 26 | #define HASHLIST(HASHLISTINFO) struct tag##HASHLISTINFO 27 | #define PHASHLIST(HASHLISTINFO) struct tag##HASHLISTINFO* 28 | 29 | #define HASHLISTLINK(HASHLISTINFO) struct \ 30 | { \ 31 | HASHLISTINFO##_ITEM** ppPreviousNext; \ 32 | HASHLISTINFO##_ITEM* pNext; \ 33 | HASHLISTINFO##_ITEM** ppRow; \ 34 | } HASHLISTINFO##_LINK 35 | 36 | #define HASHLIST_SIZE(HASHLISTINFO,hashlistName) (sizeof((hashlistName).ppHash)/sizeof(*(hashlistName).ppHash)) 37 | 38 | #define HASHLIST_INIT(HASHLISTINFO,hashlistName) \ 39 | { \ 40 | (hashlistName).pFirst = 0; \ 41 | (hashlistName).nCount = 0; \ 42 | memset((hashlistName).ppHash,0,sizeof((hashlistName).ppHash)); \ 43 | } 44 | 45 | #define HASHLIST_ADD(HASHLISTINFO,hashlistName,pItem) \ 46 | { \ 47 | (pItem)->HASHLISTINFO##_LINK.ppRow = \ 48 | &(hashlistName).ppHash[(HASHLISTINFO##_CHECKSUMPROC((HASHLISTINFO##_KEY((pItem))))) % HASHLIST_SIZE(HASHLISTINFO,hashlistName)]; \ 49 | if(((pItem)->HASHLISTINFO##_LINK.pNext = *(pItem)->HASHLISTINFO##_LINK.ppRow)) \ 50 | { \ 51 | (pItem)->HASHLISTINFO##_LINK.ppPreviousNext = (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext; \ 52 | *(pItem)->HASHLISTINFO##_LINK.ppPreviousNext = (pItem); \ 53 | (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext = &(pItem)->HASHLISTINFO##_LINK.pNext; \ 54 | } \ 55 | else \ 56 | { \ 57 | if(((pItem)->HASHLISTINFO##_LINK.pNext = (hashlistName).pFirst)) \ 58 | (hashlistName).pFirst->HASHLISTINFO##_LINK.ppPreviousNext = &(pItem)->HASHLISTINFO##_LINK.pNext; \ 59 | (hashlistName).pFirst = (pItem); \ 60 | (pItem)->HASHLISTINFO##_LINK.ppPreviousNext = &(hashlistName).pFirst; \ 61 | } \ 62 | *(pItem)->HASHLISTINFO##_LINK.ppRow = (pItem); \ 63 | (hashlistName).nCount++; \ 64 | } 65 | 66 | #define HASHLIST_SEARCH_ITEM(HASHLISTINFO,hashlistName,pItem,pItemResult/*out*/) \ 67 | { \ 68 | HASHLISTINFO##_ITEM** ppRow = \ 69 | &(hashlistName).ppHash[(HASHLISTINFO##_CHECKSUMPROC((HASHLISTINFO##_KEY((pItem))))) % HASHLIST_SIZE(HASHLISTINFO,hashlistName)]; \ 70 | for((pItemResult) = *ppRow; (pItemResult) && (pItemResult)->HASHLISTINFO##_LINK.ppRow == ppRow; (pItemResult) = (pItemResult)->HASHLISTINFO##_LINK.pNext) \ 71 | if((pItemResult) == (pItem)) \ 72 | break; \ 73 | if((pItemResult) && (pItemResult)->HASHLISTINFO##_LINK.ppRow != ppRow) \ 74 | (pItemResult) = 0; \ 75 | } 76 | 77 | #define HASHLIST_LOOKUP(HASHLISTINFO,hashlistName,pKey,pItemResult/*out*/) \ 78 | { \ 79 | HASHLISTINFO##_ITEM** ppRow = \ 80 | &(hashlistName).ppHash[(HASHLISTINFO##_CHECKSUMPROC((pKey))) % HASHLIST_SIZE(HASHLISTINFO,hashlistName)]; \ 81 | for((pItemResult) = *ppRow; (pItemResult) && (pItemResult)->HASHLISTINFO##_LINK.ppRow == ppRow; (pItemResult) = (pItemResult)->HASHLISTINFO##_LINK.pNext) \ 82 | if(HASHLISTINFO##_COMPAREPROC((pKey),(HASHLISTINFO##_KEY((pItemResult))))) \ 83 | break; \ 84 | if((pItemResult) && (pItemResult)->HASHLISTINFO##_LINK.ppRow != ppRow) \ 85 | (pItemResult) = 0; \ 86 | } 87 | 88 | #define HASHLIST_REMOVE_ITEM(HASHLISTINFO,hashlistName,pItem) \ 89 | { \ 90 | if((*(pItem)->HASHLISTINFO##_LINK.ppPreviousNext = (pItem)->HASHLISTINFO##_LINK.pNext)) \ 91 | { \ 92 | (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext = (pItem)->HASHLISTINFO##_LINK.ppPreviousNext; \ 93 | if(*(pItem)->HASHLISTINFO##_LINK.ppRow == (pItem)) \ 94 | *(pItem)->HASHLISTINFO##_LINK.ppRow = (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == (pItem)->HASHLISTINFO##_LINK.ppRow ? (pItem)->HASHLISTINFO##_LINK.pNext : 0; \ 95 | } \ 96 | else if(*(pItem)->HASHLISTINFO##_LINK.ppRow == (pItem)) \ 97 | *(pItem)->HASHLISTINFO##_LINK.ppRow = 0; \ 98 | (hashlistName).nCount--; \ 99 | HASHLISTINFO##_FREEPROC((pItem)); \ 100 | } 101 | 102 | #define HASHLIST_REMOVE_ITEM_NOFREE(HASHLISTINFO,hashlistName,pItem) \ 103 | { \ 104 | if((*(pItem)->HASHLISTINFO##_LINK.ppPreviousNext = (pItem)->HASHLISTINFO##_LINK.pNext)) \ 105 | { \ 106 | (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext = (pItem)->HASHLISTINFO##_LINK.ppPreviousNext; \ 107 | if(*(pItem)->HASHLISTINFO##_LINK.ppRow == (pItem)) \ 108 | *(pItem)->HASHLISTINFO##_LINK.ppRow = (pItem)->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == (pItem)->HASHLISTINFO##_LINK.ppRow ? (pItem)->HASHLISTINFO##_LINK.pNext : 0; \ 109 | } \ 110 | else if(*(pItem)->HASHLISTINFO##_LINK.ppRow == (pItem)) \ 111 | *(pItem)->HASHLISTINFO##_LINK.ppRow = 0; \ 112 | (hashlistName).nCount--; \ 113 | } 114 | 115 | #define HASHLIST_REMOVE(HASHLISTINFO,hashlistName,pKey) \ 116 | { \ 117 | HASHLISTINFO##_ITEM *pItem,**ppRow = \ 118 | &(hashlistName).ppHash[(HASHLISTINFO##_CHECKSUMPROC((pKey))) % HASHLIST_SIZE(HASHLISTINFO,hashlistName)]; \ 119 | for(pItem = *ppRow; pItem && pItem->HASHLISTINFO##_LINK.ppRow == ppRow; pItem = pItem->HASHLISTINFO##_LINK.pNext) \ 120 | if(HASHLISTINFO##_COMPAREPROC((pKey),(HASHLISTINFO##_KEY(pItem)))) \ 121 | { \ 122 | if((*pItem->HASHLISTINFO##_LINK.ppPreviousNext = pItem->HASHLISTINFO##_LINK.pNext)) \ 123 | { \ 124 | pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext = pItem->HASHLISTINFO##_LINK.ppPreviousNext; \ 125 | if(*ppRow == pItem) \ 126 | *ppRow = pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == ppRow ? pItem->HASHLISTINFO##_LINK.pNext : 0; \ 127 | } \ 128 | else if(*ppRow == pItem) \ 129 | *ppRow = 0; \ 130 | (hashlistName).nCount--; \ 131 | HASHLISTINFO##_FREEPROC(pItem); \ 132 | break; \ 133 | } \ 134 | } 135 | 136 | #define HASHLIST_REMOVE_NOFREE(HASHLISTINFO,hashlistName,pKey) \ 137 | { \ 138 | HASHLISTINFO##_ITEM *pItem,**ppRow = \ 139 | &(hashlistName).ppHash[(HASHLISTINFO##_CHECKSUMPROC((pKey))) % HASHLIST_SIZE(HASHLISTINFO,hashlistName)]; \ 140 | for(pItem = *ppRow; pItem && pItem->HASHLISTINFO##_LINK.ppRow == ppRow; pItem = pItem->HASHLISTINFO##_LINK.pNext) \ 141 | if(HASHLISTINFO##_COMPAREPROC((pKey),(HASHLISTINFO##_KEY(pItem)))) \ 142 | { \ 143 | if((*pItem->HASHLISTINFO##_LINK.ppPreviousNext = pItem->HASHLISTINFO##_LINK.pNext)) \ 144 | { \ 145 | pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppPreviousNext = pItem->HASHLISTINFO##_LINK.ppPreviousNext; \ 146 | if(*ppRow == pItem) \ 147 | *ppRow = pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == ppRow ? pItem->HASHLISTINFO##_LINK.pNext : 0; \ 148 | } \ 149 | else if(*ppRow == pItem) \ 150 | *ppRow = 0; \ 151 | (hashlistName).nCount--; \ 152 | break; \ 153 | } \ 154 | } 155 | 156 | #define HASHLIST_REMOVE_ALL(HASHLISTINFO,hashlistName) \ 157 | { \ 158 | HASHLISTINFO##_ITEM* pItem; \ 159 | while((pItem = (hashlistName).pFirst)) \ 160 | { \ 161 | if(((hashlistName).pFirst = pItem->HASHLISTINFO##_LINK.pNext)) \ 162 | { \ 163 | (hashlistName).pFirst->HASHLISTINFO##_LINK.ppPreviousNext = &(hashlistName).pFirst; \ 164 | if(*pItem->HASHLISTINFO##_LINK.ppRow == pItem) \ 165 | *pItem->HASHLISTINFO##_LINK.ppRow = pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == pItem->HASHLISTINFO##_LINK.ppRow ? pItem->HASHLISTINFO##_LINK.pNext : 0; \ 166 | } \ 167 | else if(*(pItem)->HASHLISTINFO##_LINK.ppRow == pItem) \ 168 | *(pItem)->HASHLISTINFO##_LINK.ppRow = 0; \ 169 | (hashlistName).nCount--; \ 170 | HASHLISTINFO##_FREEPROC(pItem); \ 171 | } \ 172 | } 173 | /* 174 | #define HASHLIST_REMOVE_ALL_NOFREE(HASHLISTINFO,hashlistName) \ 175 | { \ 176 | HASHLISTINFO##_ITEM* pItem; \ 177 | while((pItem = (hashlistName).pFirst)) \ 178 | { \ 179 | if(((hashlistName).pFirst = pItem->HASHLISTINFO##_LINK.pNext)) \ 180 | { \ 181 | (hashlistName).pFirst->HASHLISTINFO##_LINK.ppPreviousNext = &(hashlistName).pFirst; \ 182 | if(*pItem->HASHLISTINFO##_LINK.ppRow == pItem) \ 183 | *pItem->HASHLISTINFO##_LINK.ppRow = pItem->HASHLISTINFO##_LINK.pNext->HASHLISTINFO##_LINK.ppRow == pItem->HASHLISTINFO##_LINK.ppRow ? pItem->HASHLISTINFO##_LINK.pNext : 0; \ 184 | } \ 185 | else if(*(pItem)->HASHLISTINFO##_LINK.ppRow == pItem) \ 186 | *(pItem)->HASHLISTINFO##_LINK.ppRow = 0; \ 187 | (hashlistName).nCount--; \ 188 | } \ 189 | } 190 | */ 191 | #define HASHLIST_REMOVE_ALL_NOFREE(HASHLISTINFO,hashlistName) HASHLIST_INIT(HASHLISTINFO,hashlistName) 192 | 193 | #endif /* _HASHLIST_H */ 194 | -------------------------------------------------------------------------------- /src/privmsg.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: privmsg.c 3 | desciption: handle privmsgs and notices 4 | begin: 02/06/04 5 | copyright: (C) 2004 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "bounced.h" 23 | 24 | /* server handlers */ 25 | 26 | int ServerHandlerPrivmsg(PSERVER pServer, char* strCommand, char* strParams) 27 | { 28 | char* strArg[2]; 29 | 30 | if( SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 31 | { 32 | PPROFILE pProfile = pServer->pProfile; 33 | 34 | if(*strArg[1] == '\001' && strncmp(&strArg[1][1],"ACTION ",7) ) /* ctcp request */ 35 | { 36 | if(pProfile->listClients.pFirst) 37 | return 0; /* don't log ctcp requests */ 38 | 39 | /* handle ctcp request */ 40 | if(!strncmp(&strArg[1][1],"VERSION",7)) 41 | { 42 | char* strNick; 43 | if(SplitIRCPrefixNick(strCommand,&strNick)) 44 | ConnectionSendFormat(pServer->pConnection,"NOTICE %s :\001VERSION %s\001\r\n",strNick,g_strVersion); 45 | } 46 | else if(!strncmp(&strArg[1][1],"PING",4)) 47 | { 48 | char* strNick; 49 | 50 | char* strCtcpArg = &strArg[1][5]; 51 | char* str; 52 | if(*strCtcpArg == ' ') 53 | strCtcpArg++; 54 | str = strCtcpArg+strlen(strCtcpArg)-1; 55 | if(*str == '\001') 56 | *str = '\0'; 57 | 58 | if(SplitIRCPrefixNick(strCommand,&strNick)) 59 | ConnectionSendFormat(pServer->pConnection,"NOTICE %s :\001PING %s\001\r\n",strNick,strCtcpArg); 60 | } 61 | else if(!strncmp(&strArg[1][1],"CLIENTINFO",10)) 62 | { 63 | char* strNick; 64 | if(SplitIRCPrefixNick(strCommand,&strNick)) 65 | ConnectionSendFormat(pServer->pConnection,"NOTICE %s :\001CLIENTINFO VERSION PING CLIENTINFO\001\r\n",strNick); 66 | } 67 | 68 | return 1; 69 | } 70 | 71 | /* log message */ 72 | { 73 | PPROFILECHANNEL pProfileChannel; 74 | 75 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 76 | if(pProfileChannel) 77 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP|PLMF_ADJUSTNICKLEN); 78 | else if(!pProfile->listClients.pFirst) 79 | ProfileLogMsgCreate(pProfile,0,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP); 80 | } 81 | } 82 | 83 | return 0; 84 | strCommand = 0; 85 | } 86 | 87 | int ServerHandlerNotice(PSERVER pServer, char* strCommand, char* strParams) 88 | { 89 | char* strArg[2]; 90 | 91 | if( SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 92 | { 93 | PPROFILE pProfile = pServer->pProfile; 94 | 95 | if(*strArg[1] == '\001' ) /* ctcp answer */ 96 | return 0; /* don't log ctcp answer (forward them (when a client is online) or drop them) */ 97 | 98 | /* log message */ 99 | { 100 | PPROFILECHANNEL pProfileChannel; 101 | 102 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 103 | if(pProfileChannel) 104 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP|PLMF_ADJUSTNICKLEN); 105 | else if(!pProfile->listClients.pFirst) 106 | ProfileLogMsgCreate(pProfile,0,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP); 107 | } 108 | 109 | } 110 | 111 | return 0; 112 | strCommand = 0; 113 | } 114 | 115 | /* client handlers */ 116 | 117 | int ClientHandlerPrivmsg(PCLIENT pClient, char* strCommand, char* strParams) 118 | { 119 | if(CompareIRCAddressNick(strParams,c_strBouncerName)) 120 | { 121 | char *strAction,*str; 122 | 123 | pClient->cMessageMode = CMM_PRIVMSG; 124 | 125 | strAction = strParams+strlen(c_strBouncerName)+1; 126 | if(*strAction == ':') 127 | strAction++; 128 | 129 | str = strAction; 130 | do 131 | { 132 | if(*str == ' ') 133 | { 134 | *(str++) = '\0'; 135 | break; 136 | } 137 | else if(*str == '\r' || *str == '\n') 138 | { 139 | *str = '\0'; 140 | break; 141 | } 142 | *str = toupper(*str); 143 | ++str; 144 | } while(*str); 145 | 146 | { 147 | struct tagCLIENTHANDLER* pHandler; 148 | HASH_LOOKUP(CLIENTHANDLER_HASH,g_hashClientHandlers,strAction,pHandler); 149 | if(pHandler && ( 150 | !(pHandler->nFlags & CHF_BOUNCER) || 151 | (!(pHandler->nFlags & CHF_ADMIN) && (!pClient->pUser->strAllowedCommands || !ConfigFindVar(pClient->pUser->strAllowedCommands,pHandler->strAction))) || 152 | (pHandler->nFlags & CHF_ADMIN && !pClient->bAdmin) ) ) 153 | pHandler = 0; 154 | if(pHandler) 155 | { 156 | sprintf(strCommand,"msg %s %s",c_strBouncerName,pHandler->strAction); 157 | pHandler->pProc(pClient,strCommand,str); 158 | } 159 | else 160 | ClientMessage(pClient,"Unknown command \"%s\"\r\n",strAction); 161 | } 162 | 163 | pClient->cMessageMode = CMM_DEFAULT; 164 | return 1; 165 | } 166 | 167 | { 168 | char* strArg[2]; 169 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 170 | { 171 | if(pClient->pProfile) 172 | { 173 | PPROFILE pProfile = pClient->pProfile; 174 | PPROFILECHANNEL pProfileChannel; 175 | 176 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 177 | if(pProfileChannel) 178 | { 179 | PCLIENT pCurClient; 180 | unsigned short sLength; 181 | 182 | sLength = strformat(g_strOutBuffer,sizeof(g_strOutBuffer),":%s!~%s@%s PRIVMSG %s :%s\r\n",pClient->strNick,pClient->pUser->strName,iptoa(pClient->pConnection->nIP),strArg[0],strArg[1]); 183 | 184 | for(pCurClient = pProfile->listClients.pFirst; pCurClient; pCurClient = pCurClient->llProfile.pNext) 185 | if(pCurClient != pClient) 186 | ConnectionSend(pCurClient->pConnection,g_strOutBuffer,sLength); 187 | 188 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strOutBuffer,sLength,PLMF_TIMESTAMP|PLMF_ADJUSTNICKLEN); 189 | } 190 | } 191 | } 192 | } 193 | 194 | return 0; 195 | } 196 | 197 | int ClientHandlerNotice(PCLIENT pClient, char* strCommand, char* strParams) 198 | { 199 | if(CompareIRCAddressNick(strParams,c_strBouncerName)) 200 | { 201 | char *strAction,*str; 202 | 203 | pClient->cMessageMode = CMM_NOTICE; 204 | 205 | strAction = strParams+strlen(c_strBouncerName)+1; 206 | if(*strAction == ':') 207 | strAction++; 208 | 209 | str = strAction; 210 | do 211 | { 212 | if(*str == ' ') 213 | { 214 | *(str++) = '\0'; 215 | break; 216 | } 217 | else if(*str == '\r' || *str == '\n') 218 | { 219 | *str = '\0'; 220 | break; 221 | } 222 | *str = toupper(*str); 223 | ++str; 224 | } while(*str); 225 | 226 | { 227 | struct tagCLIENTHANDLER* pHandler; 228 | HASH_LOOKUP(CLIENTHANDLER_HASH,g_hashClientHandlers,strAction,pHandler); 229 | if(pHandler && ( 230 | !(pHandler->nFlags & CHF_BOUNCER) || 231 | (!(pHandler->nFlags & CHF_ADMIN) && (!pClient->pUser->strAllowedCommands || !ConfigFindVar(pClient->pUser->strAllowedCommands,pHandler->strAction))) || 232 | (pHandler->nFlags & CHF_ADMIN && !pClient->bAdmin) ) ) 233 | pHandler = 0; 234 | if(pHandler) 235 | { 236 | sprintf(strCommand,"notice %s %s",c_strBouncerName,pHandler->strAction); 237 | pHandler->pProc(pClient,strCommand,str); 238 | } 239 | else 240 | ClientMessage(pClient,"Unknown command \"%s\"\r\n",strAction); 241 | } 242 | 243 | pClient->cMessageMode = CMM_DEFAULT; 244 | return 1; 245 | } 246 | 247 | { 248 | char* strArg[2]; 249 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) == sizeof(strArg)/sizeof(*strArg)) 250 | { 251 | if(*strArg[1] == '\001' && strncmp(&strArg[1][1],"ACTION ",7) ) /* ctcp answer */ 252 | { 253 | if(!strncmp(&strArg[1][1],"VERSION",7) ) /* hook version answer */ 254 | { 255 | if(pClient->pProfile && pClient->pProfile->pServer && pClient->pProfile->pServer->bRegistered) 256 | { 257 | char* strCtcpArg = &strArg[1][8]; 258 | char* str; 259 | if(*strCtcpArg == ' ') 260 | strCtcpArg++; 261 | str = strCtcpArg+strlen(strCtcpArg)-1; 262 | if(*str == '\001') 263 | *str = '\0'; 264 | 265 | ConnectionSendFormat(pClient->pProfile->pServer->pConnection,"NOTICE %s :\001VERSION %s - %s\001\r\n",strArg[0],g_strVersion,strCtcpArg); 266 | } 267 | return 1; 268 | } 269 | 270 | return 0; /* don't log ctcp answers */ 271 | } 272 | 273 | if(pClient->pProfile) 274 | { 275 | PPROFILE pProfile = pClient->pProfile; 276 | PPROFILECHANNEL pProfileChannel; 277 | 278 | HASHLIST_LOOKUP(PROFILE_PROFILECHANNEL_HASHLIST,pProfile->hashlistProfileChannels,strArg[0],pProfileChannel); 279 | if(pProfileChannel) 280 | { 281 | PCLIENT pCurClient; 282 | 283 | ProfileLogMsgCreate(0,pProfileChannel,++pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,PLMF_TIMESTAMP|PLMF_ADJUSTNICKLEN); 284 | 285 | for(pCurClient = pProfile->listClients.pFirst; pCurClient; pCurClient = pCurClient->llProfile.pNext) 286 | if(pCurClient != pClient) 287 | ConnectionSendFormat(pCurClient->pConnection,":%s!~%s@%s NOTICE %s :%s\r\n",pClient->strNick,pClient->pUser->strName,iptoa(pClient->pConnection->nIP),strArg[0],strArg[1]); 288 | } 289 | } 290 | } 291 | } 292 | 293 | return 0; 294 | } 295 | 296 | -------------------------------------------------------------------------------- /bounced.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | bounced 15 | {0A887EEB-4998-75E8-8864-0888B06F2191} 16 | bounced 17 | 18 | 19 | 20 | Application 21 | false 22 | v120 23 | 24 | 25 | Application 26 | false 27 | v120 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | Debug\ 41 | Debug\ 42 | true 43 | Release\ 44 | Release\ 45 | bounced 46 | .exe 47 | bounced 48 | .exe 49 | 50 | 51 | 52 | .;src;%(AdditionalIncludeDirectories) 53 | 54 | 55 | 56 | 57 | false 58 | 59 | 60 | true 61 | Console 62 | ws2_32.lib;%(AdditionalDependencies) 63 | 64 | 65 | 66 | 67 | .;src;%(AdditionalIncludeDirectories) 68 | 69 | 70 | 71 | 72 | false 73 | 74 | 75 | true 76 | true 77 | Console 78 | ws2_32.lib;%(AdditionalDependencies) 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | Level3 108 | Disabled 109 | Level3 110 | MaxSpeed 111 | true 112 | 113 | 114 | Level3 115 | Disabled 116 | Level3 117 | MaxSpeed 118 | true 119 | 120 | 121 | Level3 122 | Disabled 123 | Level3 124 | MaxSpeed 125 | true 126 | 127 | 128 | Level3 129 | Disabled 130 | Level3 131 | MaxSpeed 132 | true 133 | 134 | 135 | Level3 136 | Disabled 137 | Level3 138 | MaxSpeed 139 | true 140 | 141 | 142 | Level3 143 | Disabled 144 | Level3 145 | MaxSpeed 146 | true 147 | 148 | 149 | Level3 150 | Disabled 151 | Level3 152 | MaxSpeed 153 | true 154 | 155 | 156 | Level3 157 | Disabled 158 | Level3 159 | MaxSpeed 160 | true 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /src/dmemory.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: debug.c 3 | desciption: malloc calloc realloc strdup free and "cast" debugging 4 | begin: 10/07/02 5 | copyright: (C) 2002 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /*HAVE_CONFIG_H*/ 17 | 18 | #ifdef DEBUG_MEMORY 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "dmemory.h" 26 | 27 | #include "bounced.h" /* 4 debug */ 28 | 29 | #define DEBUG_MEMORY_BLOCK_HASH_SIZE /*(1024*5+1)*/(1024+1) 30 | #define DEBUG_MEMORY_TYPE_INFO_HASH_SIZE 32 31 | #define DEBUG_MEMORY_MALLOCBYTE 0xcc 32 | #define DEBUG_MEMORY_FREEBYTE 0xff 33 | 34 | typedef struct tagDEBUGMEMORYBLOCK 35 | { 36 | const char* strType; 37 | const char* strFile; 38 | int iLine; 39 | size_t size; 40 | unsigned int nSum; 41 | struct tagDEBUGMEMORYBLOCK* pNext; 42 | } DEBUGMEMORYBLOCK, *PDEBUGMEMORYBLOCK; 43 | 44 | typedef struct tagDEBUGMEMORYTYPEINFO 45 | { 46 | const char* strType; 47 | size_t size; 48 | unsigned int nBlocks; 49 | struct tagDEBUGMEMORYTYPEINFO* pNext; 50 | } DEBUGMEMORYTYPEINFO, *PDEBUGMEMORYTYPEINFO; 51 | 52 | PDEBUGMEMORYBLOCK g_pDebugMemoryBlockHash[DEBUG_MEMORY_BLOCK_HASH_SIZE]; 53 | size_t g_sizeDebugMemoryUsed = 0; 54 | PDEBUGMEMORYTYPEINFO g_pDebugMemoryTypeInfoHash[DEBUG_MEMORY_TYPE_INFO_HASH_SIZE]; 55 | 56 | unsigned int DebugMemoryBlockSum(PDEBUGMEMORYBLOCK pBlock) 57 | { 58 | unsigned int sum/* = 0*/; 59 | sum = /*(sum<<4)+*/(unsigned int)pBlock->strType; 60 | sum = (sum<<4)+(unsigned int)pBlock->strFile; 61 | sum = (sum<<4)+(unsigned int)pBlock->iLine; 62 | sum = (sum<<4)+(unsigned int)pBlock->size; 63 | return sum; 64 | } 65 | 66 | int DebugMemoryInit(void) 67 | { 68 | if(g_sizeDebugMemoryUsed) 69 | return 0; 70 | memset(g_pDebugMemoryBlockHash,0,sizeof(g_pDebugMemoryBlockHash)); 71 | memset(g_pDebugMemoryTypeInfoHash,0,sizeof(g_pDebugMemoryTypeInfoHash)); 72 | printf("DebugMemory: Enabled!\n"); 73 | return 1; 74 | } 75 | 76 | int DebugMemoryCleanup(void) 77 | { 78 | unsigned int n; 79 | int iReturn = 1; 80 | PDEBUGMEMORYBLOCK pDMB, pNextDMB; 81 | for(n = 0; n < (sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); n++) 82 | for(pDMB = g_pDebugMemoryBlockHash[n]; pDMB; pDMB = pNextDMB) 83 | { 84 | pNextDMB = pDMB->pNext; 85 | printf("DebugMemory: Memory leak! %s(%d) Type %s Size %u Pointer 0x%08x\n",pDMB->strFile,pDMB->iLine,pDMB->strType,pDMB->size,(unsigned int)pDMB+sizeof(DEBUGMEMORYBLOCK)); 86 | free(pDMB); 87 | iReturn = 0; 88 | } 89 | if(!iReturn) 90 | assert(0); 91 | return iReturn; 92 | } 93 | 94 | int DebugMemoryCheckBlocks(void) 95 | { 96 | int iReturn = 1; 97 | PDEBUGMEMORYBLOCK *ppDMB,*ppEndDMB,pDMB; 98 | ppDMB = g_pDebugMemoryBlockHash; 99 | ppEndDMB = ppDMB+(sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); 100 | printf("DebugMemoery: Checking blocks...\n"); 101 | for(; ppDMB < ppEndDMB; ppDMB++) 102 | for(pDMB = *ppDMB; pDMB; pDMB = pDMB->pNext) 103 | if(pDMB->nSum != DebugMemoryBlockSum(pDMB)) 104 | { 105 | 106 | printf("DebugMemory: Brocken Memory detected! %s(%d) Type %s Size %u Pointer 0x%08x\n",pDMB->strFile,pDMB->iLine,pDMB->strType,pDMB->size,(unsigned int)pDMB+sizeof(DEBUGMEMORYBLOCK)); 107 | iReturn = 0; 108 | } 109 | 110 | if(g_DebugHasMotdCopied) 111 | { 112 | if(g_DebuglistMotd.pFirst != g_listMotd.pFirst || 113 | g_DebuglistMotd.nCount != g_listMotd.nCount || 114 | g_DebugMotdStrFirst.ll.pNext != g_listMotd.pFirst->ll.pNext || 115 | g_DebugMotdStrFirst.p != g_listMotd.pFirst->p || 116 | g_DebugMotdStrFirst.i != g_listMotd.pFirst->i ) 117 | { 118 | printf("OMG! the motd fucked up again!\n\n"); 119 | printf("OMG! the motd fucked up again!\n\n"); 120 | printf("OMG! the motd fucked up again!\n\n"); 121 | iReturn = 0; 122 | } 123 | } 124 | 125 | if(!iReturn) 126 | assert(0); 127 | return iReturn; 128 | } 129 | 130 | size_t DebugMemoryUsage(void) 131 | { 132 | return g_sizeDebugMemoryUsed; 133 | } 134 | 135 | int DebugMemoryShowStats(void) 136 | { 137 | unsigned int n; 138 | PDEBUGMEMORYTYPEINFO pDTI; 139 | for(n = 0; n < sizeof(g_pDebugMemoryTypeInfoHash)/sizeof(PDEBUGMEMORYTYPEINFO); n++) 140 | for(pDTI = g_pDebugMemoryTypeInfoHash[n]; pDTI; pDTI = pDTI->pNext) 141 | printf("DebugMemory: %s: %u Bytes (%u MB), %u Blocks\n",pDTI->strType,pDTI->size,pDTI->size/1024/1024,pDTI->nBlocks); 142 | return 1; 143 | } 144 | 145 | void* DebugMemoryMalloc(const char* strType, const char* strFile, int iLine, size_t size) 146 | { 147 | PDEBUGMEMORYBLOCK pDMB; 148 | PDEBUGMEMORYTYPEINFO* ppDTI; 149 | unsigned int nRow; 150 | if(!size) 151 | printf("DebugMemory: Warning: Allocating zero bytes! %s(%d) Type %s Size %u\n",strFile,iLine,strType,size); 152 | 153 | { 154 | const char* str = strType; 155 | for(nRow = *str; *str; str++) 156 | nRow += *str; 157 | } 158 | 159 | for(ppDTI = &g_pDebugMemoryTypeInfoHash[nRow % (sizeof(g_pDebugMemoryTypeInfoHash)/sizeof(PDEBUGMEMORYTYPEINFO))]; *ppDTI; ppDTI = &(*ppDTI)->pNext) 160 | if(!strcmp(strType,(*ppDTI)->strType)) 161 | break; 162 | if(!*ppDTI) 163 | { 164 | if(!(*ppDTI = malloc(sizeof(DEBUGMEMORYTYPEINFO)))) 165 | { 166 | printf("DebugMemory: Out of memory! %s(%d) Type %s Size %u\n",strFile,iLine,strType,size); 167 | assert(0); 168 | return 0; 169 | } 170 | (*ppDTI)->strType = strType; 171 | (*ppDTI)->size = 0; 172 | (*ppDTI)->nBlocks = 0; 173 | (*ppDTI)->pNext = 0; 174 | } 175 | 176 | 177 | if(!(pDMB = malloc(sizeof(DEBUGMEMORYBLOCK)+size))) 178 | { 179 | if(pDMB) 180 | free(pDMB); 181 | if(*ppDTI && !(*ppDTI)->nBlocks) 182 | { 183 | free(*ppDTI); 184 | *ppDTI = 0; 185 | } 186 | printf("DebugMemory: Out of memory! %s(%d) Type %s Size %u\n",strFile,iLine,strType,size); 187 | assert(0); 188 | return 0; 189 | } 190 | pDMB->strType = strType; 191 | pDMB->strFile = strFile; 192 | pDMB->iLine = iLine; 193 | pDMB->size = size; 194 | pDMB->nSum = DebugMemoryBlockSum(pDMB); 195 | g_sizeDebugMemoryUsed += size; 196 | nRow = ((unsigned int)pDMB) % (sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); 197 | pDMB->pNext = g_pDebugMemoryBlockHash[nRow]; 198 | g_pDebugMemoryBlockHash[nRow] = pDMB; 199 | (char*)pDMB += sizeof(DEBUGMEMORYBLOCK); 200 | memset(pDMB,DEBUG_MEMORY_MALLOCBYTE,size); 201 | 202 | (*ppDTI)->nBlocks++; 203 | (*ppDTI)->size += size; 204 | 205 | return pDMB; 206 | } 207 | 208 | void* DebugMemoryCalloc(const char* strType, const char* strFile, int iLine, size_t sizeNum, size_t size) 209 | { 210 | void* p; 211 | if(!(p = DebugMemoryMalloc(strType,strFile,iLine,sizeNum*size))) 212 | return 0; 213 | memset(p,0,sizeNum*size); 214 | return p; 215 | } 216 | 217 | void* DebugMemoryRealloc(const char* strType, const char* strFile, int iLine, void* p, size_t size) 218 | { 219 | (char*)p -= sizeof(DEBUGMEMORYBLOCK); 220 | { 221 | unsigned int nRow = ((unsigned int)p) % (sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); 222 | PDEBUGMEMORYBLOCK pDMB; 223 | for(pDMB = g_pDebugMemoryBlockHash[nRow]; pDMB; pDMB = pDMB->pNext) 224 | if(pDMB == p) 225 | { 226 | void* pNew; 227 | if(strcmp(pDMB->strType,strType)) 228 | { 229 | printf("DebugMemory: Tryed to realloc %s to %s! %s(%d) Size %u NewSize %u Pointer 0x%08x\n",pDMB->strType,strType,strFile,iLine,pDMB->size,size,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 230 | assert(0); 231 | } 232 | if(!p) 233 | printf("DebugMemory: Warning: Reallocating zero pointer! %s(%d) Type %s Size %u NewSize %u Pointer 0x%08x\n",strFile,iLine,strType,pDMB->size,size,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 234 | 235 | if(!(pNew = DebugMemoryMalloc(strType,strFile,iLine,size))) 236 | return 0; 237 | (char*)p += sizeof(DEBUGMEMORYBLOCK); 238 | memcpy(pNew,p,size < pDMB->size ? size : pDMB->size); 239 | DebugMemoryFree(strType,strFile,iLine,p); 240 | return pNew; 241 | } 242 | printf("DebugMemory: Tryed to realloc invalid pointer! %s(%d) Type %s NewSize %u Pointer 0x%08x\n",strFile,iLine,strType,size,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 243 | assert(0); 244 | } 245 | return 0; 246 | } 247 | 248 | char* DebugMemoryStrdup(const char* strType, const char* strFile, int iLine, const char* str) 249 | { 250 | char* p; 251 | size_t size = strlen(str)+1; 252 | if(!str) 253 | printf("DebugMemory: Warning: Strdup zero pointer! %s(%d) Type %s Size %u Pointer 0x%08x\n",strFile,iLine,strType,size,(unsigned int)str); 254 | if(!(p = DebugMemoryMalloc(strType,strFile,iLine,size))) 255 | return 0; 256 | memcpy(p,str,size); 257 | return p; 258 | } 259 | 260 | void DebugMemoryFree(const char* strType, const char* strFile, int iLine, void* p) 261 | { 262 | (char*)p -= sizeof(DEBUGMEMORYBLOCK); 263 | { 264 | unsigned int nRow = ((unsigned int)p) % (sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); 265 | PDEBUGMEMORYBLOCK* ppDMB; 266 | for(ppDMB = &g_pDebugMemoryBlockHash[nRow]; *ppDMB; ppDMB = &(*ppDMB)->pNext) 267 | if(*ppDMB == p) 268 | { 269 | PDEBUGMEMORYBLOCK pDMB = *ppDMB; 270 | 271 | { 272 | PDEBUGMEMORYTYPEINFO* ppDTI; 273 | const char* str = strType; 274 | for(nRow = *str; *str; str++) 275 | nRow += *str; 276 | for(ppDTI = &g_pDebugMemoryTypeInfoHash[nRow % (sizeof(g_pDebugMemoryTypeInfoHash)/sizeof(PDEBUGMEMORYTYPEINFO))]; *ppDTI; ppDTI = &(*ppDTI)->pNext) 277 | if(!strcmp(strType,(*ppDTI)->strType)) 278 | break; 279 | if(!*ppDTI) 280 | assert(0); /* strange error no type info for strType.... shouldn't happen */ 281 | else 282 | { 283 | (*ppDTI)->size -= pDMB->size; 284 | if(!--(*ppDTI)->nBlocks) 285 | { 286 | PDEBUGMEMORYTYPEINFO pDTI = *ppDTI;; 287 | *ppDTI = pDTI->pNext; 288 | free(pDTI); 289 | } 290 | } 291 | } 292 | 293 | *ppDMB = pDMB->pNext; 294 | if(strcmp(pDMB->strType,strType)) 295 | { 296 | printf("DebugMemory: Tryed to free %s as %s! %s(%d) Size %u Pointer 0x%08x\n",pDMB->strType,strType,strFile,iLine,pDMB->size,(unsigned int)p); 297 | assert(0); 298 | } 299 | g_sizeDebugMemoryUsed -= pDMB->size; 300 | memset((char*)p+sizeof(DEBUGMEMORYBLOCK),DEBUG_MEMORY_FREEBYTE,pDMB->size); 301 | free(pDMB); 302 | 303 | return; 304 | } 305 | printf("DebugMemory: Tryed to free invalid pointer! %s(%d) Type %s Pointer 0x%08x\n",strFile,iLine,strType,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 306 | assert(0); 307 | } 308 | } 309 | 310 | void* DebugMemoryCast(const char* strType, const char* strFile, int iLine, void* p) 311 | { 312 | if(p) 313 | { 314 | (char*)p -= sizeof(DEBUGMEMORYBLOCK); 315 | { 316 | unsigned int nRow = ((unsigned int)p) % (sizeof(g_pDebugMemoryBlockHash)/sizeof(PDEBUGMEMORYBLOCK)); 317 | PDEBUGMEMORYBLOCK pDMB; 318 | for(pDMB = g_pDebugMemoryBlockHash[nRow]; pDMB; pDMB = pDMB->pNext) 319 | if(pDMB == p) 320 | { 321 | if(strcmp(pDMB->strType,strType)) 322 | { 323 | printf("DebugMemory: Tryed to cast %s to %s! %s(%d) Size %u Pointer 0x%08x\n",pDMB->strType,strType,strFile,iLine,pDMB->size,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 324 | assert(0); 325 | } 326 | return (char*)p+sizeof(DEBUGMEMORYBLOCK); 327 | } 328 | printf("DebugMemory: Tryed to cast invalid point to %s! %s(%d) Pointer 0x%08x\n",strType,strFile,iLine,(unsigned int)p+sizeof(DEBUGMEMORYBLOCK)); 329 | assert(0); 330 | } 331 | } 332 | return (char*)p+sizeof(DEBUGMEMORYBLOCK); 333 | } 334 | 335 | #endif /* DEBUG_MEMORY */ 336 | 337 | -------------------------------------------------------------------------------- /src/nick.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: nick.c 3 | desciption: nick handlers 4 | begin: 11/09/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "bounced.h" 23 | 24 | /* helper functions */ 25 | 26 | int NickIsValid(char* strNick, unsigned int nMaxNicklen) 27 | { 28 | ASSERT(strNick); 29 | ASSERT(nMaxNicklen > 0); 30 | 31 | if(!strNick || nMaxNicklen == 0) 32 | return 0; 33 | 34 | /* old */ 35 | /* if( !*strNick || 36 | strchr("@%+#$&!:",*strNick) || 37 | strchr(strNick,',') ) 38 | return 0; 39 | */ 40 | /* new (see rfc2812) */ 41 | if( (*strNick < 'A' || *strNick > 'Z') && (*strNick < 'a' || *strNick > 'z') && 42 | (*strNick < 0x5B || *strNick > 0x60) && (*strNick < 0x7B || *strNick > 0x7D) ) 43 | return 0; 44 | { 45 | char* str; 46 | for(str = strNick+1; *str; str++) 47 | { 48 | if((unsigned int)(str-strNick) >= nMaxNicklen) 49 | { 50 | *str = '\0'; 51 | return 1; 52 | } 53 | if( (*str < 'A' || *str > 'Z') && (*str < 'a' || *str > 'z') && 54 | (*str < '0' || *str > '9') && 55 | (*str < 0x5B || *str > 0x60) && (*str < 0x7B || *str > 0x7D) && 56 | *str != '-' ) 57 | return 0; 58 | } 59 | } 60 | 61 | return 1; 62 | } 63 | 64 | /* unregistered server handlers */ 65 | 66 | int ServerHandlerUnregisteredNickError(PSERVER pServer, char* strCommand, char* strParams) 67 | { 68 | PPROFILE pProfile = pServer->pProfile; 69 | char* strAlternativeNick = 0; 70 | 71 | ASSERT(!pServer->bRegistered); 72 | 73 | ASSERT(pServer->strNick); 74 | if(!pServer->strNick) 75 | return 1; 76 | 77 | /* find alternative nick */ 78 | if((pProfile->c_strDetachNick && *pProfile->c_strDetachNick) && strcmp(pProfile->c_strDetachNick,pProfile->c_strNick) && !strcmp(pProfile->c_strDetachNick,pServer->strNick)) 79 | strAlternativeNick = pProfile->c_strNick; 80 | else if((pProfile->c_strAlternativeNick && *pProfile->c_strAlternativeNick) && strcmp(pProfile->c_strAlternativeNick,pProfile->c_strNick) && strcmp(pProfile->c_strAlternativeNick,pServer->strNick)) 81 | strAlternativeNick = pProfile->c_strAlternativeNick; 82 | 83 | /* use alternative nick */ 84 | if(strAlternativeNick) 85 | { 86 | if( !ConnectionSendFormat(pServer->pConnection,"NICK :%s\r\n",strAlternativeNick) ) 87 | return 1; 88 | 89 | if(!(strAlternativeNick = STRDUP(char*,strAlternativeNick))) 90 | { 91 | OUTOFMEMORY; 92 | ConnectionCloseAsync(pServer->pConnection); 93 | return 1; 94 | } 95 | 96 | FREE(char*,pServer->strNick); 97 | pServer->strNick = strAlternativeNick; 98 | return 1; 99 | } 100 | 101 | ConnectionCloseAsync(pServer->pConnection); 102 | 103 | return 0; /* 0, damit der client sieht, warum es nicht geklappt hat... */ 104 | strParams = 0; 105 | strCommand = 0; 106 | } 107 | 108 | /* server handlers */ 109 | 110 | int ServerHandlerNick(PSERVER pServer, char* strCommand, char* strParams) 111 | { 112 | char* strArg[1]; 113 | char* strNick; 114 | 115 | if( SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg) || 116 | !SplitIRCPrefixNick(strCommand,&strNick)) 117 | return 1; 118 | 119 | if(!strcmp(strNick,strArg[0]) || !NickIsValid(strArg[0],pServer->pProfile->nNickLen) ) 120 | return 1; 121 | 122 | /* is our nick change? */ 123 | if(!strcasecmp(strNick,pServer->strNick)) 124 | { 125 | PPROFILE pProfile = pServer->pProfile; 126 | PCLIENT pClient; 127 | char* strNewNick; 128 | 129 | ASSERT(pProfile); 130 | 131 | /* change nick in welcome message */ 132 | if(pServer->listServerWelcomeMsgs.pFirst && pServer->listServerWelcomeMsgs.pFirst->nCode == 1) 133 | { 134 | PSERVERWELCOMEMSG pServerWelcomeMsg = pServer->listServerWelcomeMsgs.pFirst; 135 | char* str; 136 | unsigned int nNick = strlen(pServer->strNick); 137 | str = strstr(pServerWelcomeMsg->strMsg,pServer->strNick); 138 | while(str) 139 | { 140 | if(isspace(str[nNick]) || str[nNick] == '!') 141 | { 142 | char* strCommand; 143 | unsigned int nNewNick = strlen(strArg[0]); 144 | unsigned int nMsg = strlen(pServerWelcomeMsg->strMsg); 145 | 146 | strCommand = MALLOC(char*,nMsg-nNick+nNewNick+1); 147 | if(!strCommand) 148 | { 149 | OUTOFMEMORY; 150 | ConnectionCloseAsync(pServer->pConnection); 151 | return 1; 152 | } 153 | 154 | memcpy(strCommand,pServerWelcomeMsg->strMsg,str-pServerWelcomeMsg->strMsg); 155 | memcpy(strCommand+(str-pServerWelcomeMsg->strMsg),strArg[0],nNewNick); 156 | memcpy(strCommand+(str-pServerWelcomeMsg->strMsg)+nNewNick,str+nNick,nMsg-nNick-(str-pServerWelcomeMsg->strMsg)+1); 157 | 158 | FREE(char*,pServerWelcomeMsg->strMsg); 159 | pServerWelcomeMsg->strMsg = strCommand; 160 | 161 | break; 162 | } 163 | str = strstr(str+1,pServer->strNick); 164 | } 165 | } 166 | 167 | /* change nick in SERVER struct */ 168 | if(!(strNewNick = STRDUP(char*,strArg[0]))) 169 | { 170 | OUTOFMEMORY; 171 | ConnectionCloseAsync(pServer->pConnection); 172 | return 1; 173 | } 174 | if(pServer->strNick) 175 | FREE(char*,pServer->strNick); 176 | pServer->strNick = strNewNick; 177 | 178 | /* change nick in PROFILE struct */ 179 | if(!(strNewNick = STRDUP(char*,strArg[0]))) 180 | { 181 | OUTOFMEMORY; 182 | ConnectionCloseAsync(pServer->pConnection); 183 | return 1; 184 | } 185 | if(pProfile->strNick) 186 | FREE(char*,pProfile->strNick); 187 | pProfile->strNick = strNewNick; 188 | 189 | /* change nicks in CLIENT structs */ 190 | for(pClient = pProfile->listClients.pFirst; pClient; pClient = pClient->llProfile.pNext) 191 | { 192 | if(!ConnectionSendFormat(pClient->pConnection,":%s!~%s@%s NICK :%s\r\n",pClient->strNick,pClient->strName,iptoa(pClient->pConnection->nIP),strArg[0])) 193 | continue; 194 | 195 | if(!(strNewNick = STRDUP(char*,strArg[0]))) 196 | { 197 | OUTOFMEMORY; 198 | ConnectionCloseAsync(pClient->pConnection); 199 | continue; 200 | } 201 | 202 | if(pClient->strNick) 203 | FREE(char*,pClient->strNick); 204 | pClient->strNick = strNewNick; 205 | } 206 | 207 | /* force adding nick command to channel logs (not only the channels where HASHLIST_LOOKUP is successful) */ 208 | { 209 | PPROFILE pProfile = pServer->pProfile; 210 | PPROFILECHANNEL pProfileChannel; 211 | PPROFILECHANNELUSER pProfileChannelUser; 212 | char* strNewNick; 213 | 214 | pProfile->nLogID++; 215 | 216 | for(pProfileChannel = pProfile->hashlistProfileChannels.pFirst; pProfileChannel; pProfileChannel = pProfileChannel->hllProfile.pNext) 217 | { 218 | ProfileLogMsgCreate(0,pProfileChannel,pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 219 | 220 | HASHLIST_LOOKUP(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,strNick,pProfileChannelUser); 221 | if(pProfileChannelUser) 222 | { 223 | strNewNick = STRDUP(char*,strArg[0]); 224 | if(strNewNick) 225 | { 226 | HASHLIST_REMOVE_ITEM_NOFREE(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,pProfileChannelUser); 227 | if(pProfileChannelUser->strNick) 228 | FREE(char*,pProfileChannelUser->strNick); 229 | pProfileChannelUser->strNick = strNewNick; 230 | HASHLIST_ADD(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,pProfileChannelUser); 231 | } 232 | } 233 | } 234 | } 235 | 236 | return 1; 237 | } 238 | else 239 | { 240 | /* add nick command to channel logs*/ 241 | { 242 | PPROFILE pProfile = pServer->pProfile; 243 | PPROFILECHANNEL pProfileChannel; 244 | PPROFILECHANNELUSER pProfileChannelUser; 245 | char* strNewNick; 246 | 247 | pProfile->nLogID++; 248 | 249 | for(pProfileChannel = pProfile->hashlistProfileChannels.pFirst; pProfileChannel; pProfileChannel = pProfileChannel->hllProfile.pNext) 250 | { 251 | HASHLIST_LOOKUP(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,strNick,pProfileChannelUser); 252 | if(pProfileChannelUser) 253 | { 254 | ProfileLogMsgCreate(0,pProfileChannel,pProfile->nLogID,g_strCurrentCommand,g_nCurrentCommandLength,0); 255 | 256 | strNewNick = STRDUP(char*,strArg[0]); 257 | if(strNewNick) 258 | { 259 | HASHLIST_REMOVE_ITEM_NOFREE(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,pProfileChannelUser); 260 | if(pProfileChannelUser->strNick) 261 | FREE(char*,pProfileChannelUser->strNick); 262 | pProfileChannelUser->strNick = strNewNick; 263 | HASHLIST_ADD(PROFILECHANNEL_PROFILECHANNELUSER_HASHLIST,pProfileChannel->hashlistProfileChannelUsers,pProfileChannelUser); 264 | } 265 | } 266 | } 267 | } 268 | } 269 | 270 | /* try to reuse the prefered nick */ 271 | { 272 | char* strPreferedNick; 273 | if(!pServer->pProfile->listClients.pFirst && pServer->pProfile->c_strDetachNick && *pServer->pProfile->c_strDetachNick) 274 | strPreferedNick = pServer->pProfile->c_strDetachNick; 275 | else 276 | strPreferedNick = pServer->pProfile->c_strNick; 277 | if(strPreferedNick && !strcasecmp(strNick,strPreferedNick) && strcasecmp(pServer->strNick,strPreferedNick)) 278 | ConnectionSendFormat(pServer->pConnection,"NICK :%s\r\n",strPreferedNick); 279 | } 280 | 281 | return 0; 282 | } 283 | 284 | /* client handlers */ 285 | 286 | int ClientHandlerNick(PCLIENT pClient, char* strCommand, char* strParams) 287 | { 288 | char* strArg[1]; 289 | 290 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg)) 291 | { 292 | ConnectionSendFormat(pClient->pConnection,":%s 431 %s :No nickname given\r\n",c_strBouncerName,pClient->strNick); 293 | return 1; 294 | } 295 | 296 | if(pClient->pProfile && pClient->pProfile->pServer && 297 | !strcmp(pClient->pProfile->pServer->strNick,strArg[0])) 298 | return 1; 299 | 300 | if(!NickIsValid(strArg[0],pClient->pProfile ? pClient->pProfile->nNickLen : DEFAULT_NICKLEN) ) 301 | { 302 | ConnectionSendFormat(pClient->pConnection,":%s 432 %s :Erroneus nickname\r\n",c_strBouncerName,pClient->strNick); 303 | return 1; 304 | } 305 | 306 | /* no profile.. just accept the new nick */ 307 | if(!pClient->pProfile) 308 | { 309 | char* strNewNick; 310 | 311 | if(!ConnectionSendFormat(pClient->pConnection,":%s!~%s@%s NICK :%s\r\n",pClient->strNick,pClient->strName,iptoa(pClient->pConnection->nIP),strArg[0])) 312 | return 1; 313 | 314 | if(!(strNewNick = STRDUP(char*,strArg[0]))) 315 | { 316 | OUTOFMEMORY; 317 | ConnectionCloseAsync(pClient->pConnection); 318 | return 1; 319 | } 320 | if(pClient->strNick) 321 | FREE(char*,pClient->strNick); 322 | pClient->strNick = strNewNick; 323 | 324 | return 1; 325 | } 326 | 327 | else 328 | { 329 | char* strNewNick; 330 | PPROFILE pProfile = pClient->pProfile; 331 | 332 | /* use nick as prefered nick */ 333 | if(ProfileConfigSetVar(1,pProfile,"Nick",strArg[0],0) <= 0) 334 | { 335 | ConnectionCloseAsync(pClient->pConnection); 336 | return 1; 337 | } 338 | 339 | /* if server connection, send nickchange to server */ 340 | if(pProfile->pServer && pProfile->pServer->bRegistered) 341 | { 342 | ConnectionSendFormat(pProfile->pServer->pConnection,"NICK :%s\r\n",strArg[0]); 343 | return 1; 344 | } 345 | else 346 | { 347 | /* attach nick to all profile clients */ 348 | PCLIENT pClient; 349 | for(pClient = pProfile->listClients.pFirst; pClient; pClient = pClient->llProfile.pNext) 350 | { 351 | if(!ConnectionSendFormat(pClient->pConnection,":%s!~%s@%s NICK :%s\r\n",pClient->strNick,pClient->strName,iptoa(pClient->pConnection->nIP),strArg[0])) 352 | continue; 353 | 354 | if(!(strNewNick = STRDUP(char*,strArg[0]))) 355 | { 356 | OUTOFMEMORY; 357 | ConnectionCloseAsync(pClient->pConnection); 358 | continue; 359 | } 360 | if(pClient->strNick) 361 | FREE(char*,pClient->strNick); 362 | pClient->strNick = strNewNick; 363 | } 364 | } 365 | } 366 | 367 | return 1; 368 | strCommand = 0; 369 | } 370 | -------------------------------------------------------------------------------- /src/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: client.c 3 | desciption: handle client commands 4 | begin: 11/25/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "bounced.h" 25 | 26 | size_t vstrformat(char* str, size_t maxsize, const char* format, va_list ap); 27 | 28 | 29 | CLIENTHANDLERUNREGISTERED_TABLE_START 30 | 31 | CLIENTHANDLER("PASS",ClientHandlerUnregisteredPass,CHF_NORMAL) 32 | CLIENTHANDLER("USER",ClientHandlerUnregisteredUser,CHF_NORMAL) 33 | CLIENTHANDLER("NICK",ClientHandlerUnregisteredNick,CHF_NORMAL) 34 | 35 | CLIENTHANDLER("DBACCESS",ClientHandlerUnregisteredDBAccess,CHF_NORMAL) 36 | 37 | CLIENTHANDLERUNREGISTERED_TABLE_END 38 | 39 | CLIENTHANDLER_TABLE_START 40 | 41 | CLIENTHANDLER("PASS" ,ClientHandlerPass , CHF_NORMAL) 42 | CLIENTHANDLER("USER" ,ClientHandlerUser , CHF_NORMAL) 43 | 44 | CLIENTHANDLER("NICK" ,ClientHandlerNick , CHF_NORMAL) /* nick.c */ 45 | CLIENTHANDLER("QUIT" ,ClientHandlerQuit , CHF_NORMAL) 46 | CLIENTHANDLER("PING" ,ClientHandlerPing , CHF_NORMAL) 47 | CLIENTHANDLER("PONG" ,ClientHandlerPong , CHF_NORMAL) /* ping.c */ 48 | CLIENTHANDLER("NOTICE" ,ClientHandlerNotice , CHF_NORMAL) /* privmsg.c */ 49 | CLIENTHANDLER("PRIVMSG" ,ClientHandlerPrivmsg , CHF_NORMAL) /* privmsg.c */ 50 | CLIENTHANDLER("JOIN" ,ClientHandlerJoin , CHF_NORMAL) /* channel.c */ 51 | CLIENTHANDLER("PART" ,ClientHandlerPart , CHF_NORMAL) /* channel.c */ 52 | CLIENTHANDLER("MODE" ,ClientHandlerMode , CHF_NORMAL) /* mode.c */ 53 | 54 | CLIENTHANDLER("PROFILE" ,ClientHandlerProfile , CHF_BOUNCER) 55 | CLIENTHANDLER("SERVER" ,ClientHandlerServer , CHF_BOUNCER) 56 | CLIENTHANDLER("PASSWORD",ClientHandlerPassword, CHF_BOUNCER) /* password.c */ 57 | CLIENTHANDLER("CONFIG" ,ClientHandlerConfig , CHF_BOUNCER) 58 | CLIENTHANDLER("HELP" ,ClientHandlerHelp , CHF_BOUNCER) 59 | 60 | CLIENTHANDLER("ADMIN" ,ClientHandlerAdmin , CHF_BOUNCER|CHF_ADMIN) 61 | 62 | CLIENTHANDLER_TABLE_END 63 | 64 | int ClientHandlersInit(void) 65 | { 66 | unsigned int i; 67 | 68 | HASH_INIT(CLIENTHANDLER_HASH,g_hashClientHandlers); 69 | for(i = 0; i < CLIENTHANDLER_COUNT; i++) 70 | HASH_ADD(CLIENTHANDLER_HASH,g_hashClientHandlers,&g_pClientHandlers[i]); 71 | 72 | HASH_INIT(CLIENTHANDLERUNREGISTERED_HASH,g_hashClientHandlersUnregistered); 73 | for(i = 0; i < CLIENTHANDLERUNREGISTERED_COUNT; i++) 74 | HASH_ADD(CLIENTHANDLERUNREGISTERED_HASH,g_hashClientHandlersUnregistered,&g_pClientHandlersUnregistered[i]); 75 | 76 | return 1; 77 | } 78 | 79 | PCLIENT ClientCreate(void) 80 | { 81 | PCLIENT pClient; 82 | 83 | if( !(pClient = CALLOC(PCLIENT,1,sizeof(CLIENT))) ) 84 | { 85 | OUTOFMEMORY; 86 | if(pClient) 87 | ClientFree(pClient); 88 | return 0; 89 | } 90 | 91 | LIST_ADD(CLIENT_LIST,g_listClients,pClient); 92 | 93 | return pClient; 94 | } 95 | 96 | void ClientFree(PCLIENT pClient) 97 | { 98 | if(pClient->pProfile) 99 | { 100 | ProfileDetach(pClient->pProfile,pClient,0); 101 | ASSERT(pClient->pProfile == 0); 102 | } 103 | 104 | if(pClient->pUser) 105 | { 106 | UserDetach(pClient->pUser,pClient); 107 | ASSERT(pClient->pUser == 0); 108 | } 109 | 110 | if(pClient->strName) 111 | FREE(char*,pClient->strName); 112 | if(pClient->strNick) 113 | FREE(char*,pClient->strNick); 114 | if(pClient->strRealName) 115 | FREE(char*,pClient->strRealName); 116 | if(pClient->strMode) 117 | FREE(char*,pClient->strMode); 118 | FREE(PCLIENT,pClient); 119 | } 120 | 121 | void ClientClose(PCLIENT pClient) 122 | { 123 | ASSERT(0); 124 | return; 125 | pClient = 0; 126 | } 127 | 128 | int ClientMessage(PCLIENT pClient, const char* format,...) 129 | { 130 | va_list ap; 131 | unsigned short sLength; 132 | 133 | if(pClient->pConnection->bClosing) 134 | return 0; 135 | 136 | if(pClient->cMessageMode == CMM_PRIVMSG) 137 | sLength = strformat(g_strOutBuffer,sizeof(g_strOutBuffer)-2,":%s PRIVMSG %s :",c_strBouncerName,pClient->strNick); 138 | else 139 | sLength = strformat(g_strOutBuffer,sizeof(g_strOutBuffer)-2,":%s NOTICE %s :",c_strBouncerName,pClient->strNick); 140 | 141 | va_start (ap, format); 142 | sLength += vstrformat(g_strOutBuffer+sLength,sizeof(g_strOutBuffer)-2-sLength,format, ap); 143 | va_end (ap); 144 | 145 | g_strOutBuffer[sLength++] = '\r'; 146 | g_strOutBuffer[sLength++] = '\n'; 147 | g_strOutBuffer[sLength] = '\0'; 148 | 149 | return ConnectionSend(pClient->pConnection,g_strOutBuffer,sLength); 150 | } 151 | 152 | int ClientRegister(PCLIENT pClient) 153 | { 154 | PUSER pUser; 155 | char bAdmin; 156 | 157 | ASSERT(pClient->strNick); 158 | ASSERT(pClient->strName); 159 | ASSERT(!pClient->bRegistered); 160 | 161 | HASHLIST_LOOKUP(USER_HASHLIST,g_hashlistUsers,pClient->strName,pUser); 162 | if(!pUser || !PasswordCompare(pUser->pcMD5Pass,pClient->pcMD5Pass) ) 163 | { 164 | Log("Invalid login from %s (%s)",iptoa(pClient->pConnection->nIP),pClient->strName); 165 | if(!ConnectionSendFormat(pClient->pConnection,":%s 464 %s :Password incorrect\r\n",c_strBouncerName,pClient->strNick)) 166 | return 0; 167 | ConnectionCloseAsync(pClient->pConnection); 168 | return 0; 169 | } 170 | 171 | bAdmin = pUser->strAllowedCommands && ConfigFindVar(pUser->strAllowedCommands,"ADMIN"); 172 | if( (!bAdmin && pUser->listClients.nCount >= c_nUserMaxClients) || 173 | (!bAdmin && UserHasFlag(pUser,'b')) ) 174 | { 175 | if(!ConnectionSendFormat(pClient->pConnection,":%s 464 %s :Password incorrect\r\n",c_strBouncerName,pClient->strNick)) 176 | return 0; 177 | ConnectionCloseAsync(pClient->pConnection); 178 | return 0; 179 | } 180 | 181 | g_dLogins++; 182 | 183 | pUser->timeLastSeen = g_timeNow; 184 | g_bUsersChanged = 1; 185 | pClient->bAdmin = bAdmin; 186 | pClient->bRegistered = 1; 187 | strcpy(pClient->strName,pUser->strName); /* maybe case is different */ 188 | 189 | if(!UserAttach(pUser,pClient)) 190 | return 0; 191 | 192 | return 1; 193 | } 194 | 195 | int ClientHandleCommand(PCLIENT pClient, char* strCommand, unsigned int nLength) 196 | { 197 | char *strAction,*strActionEnd = 0,*str; 198 | char cActionEnd = 0; 199 | 200 | if(*strCommand == ':') 201 | { 202 | strAction = strchr(strCommand,' '); 203 | if(!strAction) 204 | return 1; 205 | strAction++; 206 | } 207 | else 208 | strAction = strCommand; 209 | 210 | if(!*strAction) 211 | return 1; 212 | 213 | str = strAction; 214 | do 215 | { 216 | if(*str == ' ') 217 | { 218 | strActionEnd = str++; 219 | cActionEnd = *strActionEnd; 220 | *strActionEnd = '\0'; 221 | break; 222 | } 223 | else if(*str == '\r' || *str == '\n') 224 | { 225 | strActionEnd = str; 226 | cActionEnd = *strActionEnd; 227 | *strActionEnd = '\0'; 228 | break; 229 | } 230 | *str = toupper(*str); 231 | ++str; 232 | } while(*str); 233 | 234 | { 235 | struct tagCLIENTHANDLER* pHandler; 236 | if(pClient->bRegistered) 237 | { 238 | HASH_LOOKUP(CLIENTHANDLER_HASH,g_hashClientHandlers,strAction,pHandler); 239 | if(pHandler && ( 240 | (pHandler->nFlags & CHF_BOUNCER && !(pHandler->nFlags & CHF_ADMIN) && (!pClient->pUser->strAllowedCommands || !ConfigFindVar(pClient->pUser->strAllowedCommands,pHandler->strAction))) || 241 | (pHandler->nFlags & CHF_ADMIN && !pClient->bAdmin) ) ) 242 | pHandler = 0; 243 | } 244 | else 245 | HASH_LOOKUP(CLIENTHANDLERUNREGISTERED_HASH,g_hashClientHandlersUnregistered,strAction,pHandler) 246 | 247 | if(pHandler) 248 | { 249 | memcpy(g_strInBufferCopy,strCommand,nLength+1); 250 | 251 | if(strActionEnd) 252 | *strActionEnd = cActionEnd; 253 | 254 | g_strCurrentCommand = strCommand; 255 | g_nCurrentCommandLength = nLength; 256 | 257 | if( !pHandler->pProc(pClient,g_strInBufferCopy,g_strInBufferCopy+(str-strCommand)) && 258 | pClient->pProfile && pClient->pProfile->pServer && pClient->pProfile->pServer->bRegistered) 259 | return ConnectionSend(pClient->pProfile->pServer->pConnection,strCommand,nLength); 260 | } 261 | else 262 | { 263 | 264 | 265 | if(!pClient->bRegistered) 266 | return ConnectionSendFormat(pClient->pConnection,":%s 451 %s :You have not registered\r\n",c_strBouncerName,pClient->strNick ? pClient->strNick : "*"); 267 | 268 | if(pClient->pProfile && pClient->pProfile->pServer && pClient->pProfile->pServer->bRegistered) 269 | { 270 | if(strActionEnd) 271 | *strActionEnd = cActionEnd; 272 | return ConnectionSend(pClient->pProfile->pServer->pConnection,strCommand,nLength); 273 | } 274 | } 275 | } 276 | 277 | 278 | return 1; 279 | } 280 | 281 | /* unrigistered client handlers */ 282 | 283 | int ClientHandlerUnregisteredPass(PCLIENT pClient, char* strCommand, char* strParams) 284 | { 285 | char* strArg[1]; 286 | 287 | ASSERT(!pClient->bRegistered); 288 | 289 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) != sizeof(strArg)/sizeof(*strArg)) 290 | { 291 | ConnectionSendFormat(pClient->pConnection,":%s 461 %s PASS :Not enough parameters\r\n",c_strBouncerName,pClient->strNick ? pClient->strNick : "*"); 292 | return 1; 293 | } 294 | 295 | PasswordCreate(strArg[0],pClient->pcMD5Pass); 296 | return 1; 297 | strCommand = 0; 298 | } 299 | 300 | int ClientHandlerUnregisteredUser(PCLIENT pClient, char* strCommand, char* strParams) 301 | { 302 | char* strArg[4]; 303 | 304 | ASSERT(!pClient->bRegistered); 305 | 306 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),1) != sizeof(strArg)/sizeof(*strArg)) 307 | { 308 | ConnectionSendFormat(pClient->pConnection,":%s 461 %s USER :Not enough parameters\r\n",c_strBouncerName,pClient->strNick ? pClient->strNick : "*"); 309 | return 1; 310 | } 311 | 312 | if(!UserIsNameValid(strArg[0])) 313 | { 314 | ConnectionCloseAsync(pClient->pConnection); 315 | return 1; 316 | } 317 | 318 | if(pClient->strName) 319 | FREE(char*,pClient->strName); 320 | if(!(pClient->strName = STRDUP(char*,strArg[0]))) 321 | { 322 | OUTOFMEMORY; 323 | ConnectionCloseAsync(pClient->pConnection); 324 | return 1; 325 | } 326 | if(pClient->strRealName) 327 | FREE(char*,pClient->strRealName); 328 | if(!(pClient->strRealName = STRDUP(char*,strArg[3]))) 329 | { 330 | OUTOFMEMORY; 331 | ConnectionCloseAsync(pClient->pConnection); 332 | return 1; 333 | } 334 | 335 | if(pClient->strNick) 336 | { 337 | ClientRegister(pClient); 338 | return 1; 339 | } 340 | 341 | return 1; 342 | strCommand = 0; 343 | } 344 | 345 | int ClientHandlerUnregisteredNick(PCLIENT pClient, char* strCommand, char* strParams) 346 | { 347 | char* strArg[1]; 348 | 349 | ASSERT(!pClient->bRegistered); 350 | 351 | if(SplitIRCParams(strParams,strArg,sizeof(strArg)/sizeof(*strArg),0) != sizeof(strArg)/sizeof(*strArg)) 352 | { 353 | ConnectionSendFormat(pClient->pConnection,":%s 431 %s :No nickname given\r\n",c_strBouncerName,pClient->strNick ? pClient->strNick : "*"); 354 | return 1; 355 | } 356 | 357 | if(pClient->strNick && !strcmp(pClient->strNick,strArg[0])) 358 | return 1; 359 | 360 | if(!NickIsValid(strArg[0],DEFAULT_NICKLEN) ) 361 | { 362 | ConnectionSendFormat(pClient->pConnection,":%s 432 %s :Erroneus nickname\r\n",c_strBouncerName,pClient->strNick ? pClient->strNick : "*"); 363 | return 1; 364 | } 365 | 366 | if(pClient->strNick) 367 | FREE(char*,pClient->strNick); 368 | if(!(pClient->strNick = STRDUP(char*,strArg[0]))) 369 | { 370 | OUTOFMEMORY; 371 | ConnectionCloseAsync(pClient->pConnection); 372 | return 0; 373 | } 374 | 375 | if(pClient->strName) 376 | { 377 | ClientRegister(pClient); 378 | return 1; 379 | } 380 | 381 | return 1; 382 | strCommand = 0; 383 | } 384 | 385 | /* client handlers */ 386 | 387 | int ClientHandlerPass(PCLIENT pClient, char* strCommand, char* strParams) 388 | { 389 | ConnectionSendFormat(pClient->pConnection,":%s 462 %s :You may not reregister\r\n",c_strBouncerName,pClient->strNick); 390 | return 1; 391 | strParams = 0; 392 | strCommand = 0; 393 | } 394 | 395 | int ClientHandlerUser(PCLIENT pClient, char* strCommand, char* strParams) 396 | { 397 | ConnectionSendFormat(pClient->pConnection,":%s 462 %s :You may not reregister\r\n",c_strBouncerName,pClient->strNick); 398 | return 1; 399 | strParams = 0; 400 | strCommand = 0; 401 | } 402 | 403 | int ClientHandlerHelp(PCLIENT pClient, char* strCommand, char* strParams) 404 | { 405 | unsigned int i; 406 | char* strRealAction; 407 | char b = 0; 408 | PUSER pUser = pClient->pUser; 409 | 410 | ASSERT(pUser); 411 | 412 | strRealAction = strrchr(strCommand,' '); 413 | if(strRealAction) 414 | strRealAction++; 415 | else 416 | strRealAction = strCommand; 417 | 418 | for(i = 0; i < CLIENTHANDLER_COUNT; i++) 419 | if( g_pClientHandlers[i].nFlags & CHF_BOUNCER && 420 | g_pClientHandlers[i].pProc != ClientHandlerHelp && 421 | ((pUser->strAllowedCommands && ConfigFindVar(pUser->strAllowedCommands,g_pClientHandlers[i].strAction)) || (g_pClientHandlers[i].nFlags & CHF_ADMIN && pClient->bAdmin)) ) 422 | { 423 | strcpy(strRealAction,g_pClientHandlers[i].strAction); 424 | if(!ClientMessage(pClient,b ? " /%s help" : "Usage is /%s help",strCommand) ) 425 | return 1; 426 | b = 1; 427 | } 428 | 429 | return 1; 430 | strParams = 0; 431 | strCommand = 0; 432 | } 433 | -------------------------------------------------------------------------------- /src/md5.c: -------------------------------------------------------------------------------- 1 | /* md5.c - Functions to compute MD5 message digest of files or memory blocks 2 | according to the definition of MD5 in RFC 1321 from April 1992. 3 | Copyright (C) 1995, 1996 Free Software Foundation, Inc. 4 | NOTE: The canonical source of this file is maintained with the GNU C 5 | Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. 6 | 7 | This program is free software; you can redistribute it and/or modify it 8 | under the terms of the GNU General Public License as published by the 9 | Free Software Foundation; either version 2, or (at your option) any 10 | later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software Foundation, 19 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 | 21 | /* Written by Ulrich Drepper , 1995. */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | # include 25 | #endif 26 | 27 | #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(STDC_HEADERS) 28 | #define STDC_HEADERS 1 29 | #endif 30 | 31 | #include 32 | 33 | #if STDC_HEADERS || defined _LIBC 34 | # include 35 | # include 36 | #else 37 | # ifndef HAVE_MEMCPY 38 | # define memcpy(d, s, n) bcopy ((s), (d), (n)) 39 | # endif 40 | #endif 41 | 42 | #include "md5.h" 43 | 44 | #ifdef _LIBC 45 | # include 46 | # if __BYTE_ORDER == __BIG_ENDIAN 47 | # define WORDS_BIGENDIAN 1 48 | # endif 49 | #endif 50 | 51 | #ifdef WORDS_BIGENDIAN 52 | # define SWAP(n) \ 53 | (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) 54 | #else 55 | # define SWAP(n) (n) 56 | #endif 57 | 58 | 59 | /* This array contains the bytes used to pad the buffer to the next 60 | 64-byte boundary. (RFC 1321, 3.1: Step 1) */ 61 | static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; 62 | 63 | 64 | /* Initialize structure containing state of computation. 65 | (RFC 1321, 3.3: Step 3) */ 66 | void 67 | md5_init_ctx (ctx) 68 | struct md5_ctx *ctx; 69 | { 70 | ctx->A = 0x67452301; 71 | ctx->B = 0xefcdab89; 72 | ctx->C = 0x98badcfe; 73 | ctx->D = 0x10325476; 74 | 75 | ctx->total[0] = ctx->total[1] = 0; 76 | ctx->buflen = 0; 77 | } 78 | 79 | /* Put result from CTX in first 16 bytes following RESBUF. The result 80 | must be in little endian byte order. 81 | 82 | IMPORTANT: On some systems it is required that RESBUF is correctly 83 | aligned for a 32 bits value. */ 84 | void * 85 | md5_read_ctx (ctx, resbuf) 86 | const struct md5_ctx *ctx; 87 | void *resbuf; 88 | { 89 | ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); 90 | ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); 91 | ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); 92 | ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); 93 | 94 | return resbuf; 95 | } 96 | 97 | /* Process the remaining bytes in the internal buffer and the usual 98 | prolog according to the standard and write the result to RESBUF. 99 | 100 | IMPORTANT: On some systems it is required that RESBUF is correctly 101 | aligned for a 32 bits value. */ 102 | void * 103 | md5_finish_ctx (ctx, resbuf) 104 | struct md5_ctx *ctx; 105 | void *resbuf; 106 | { 107 | /* Take yet unprocessed bytes into account. */ 108 | md5_uint32 bytes = ctx->buflen; 109 | size_t pad; 110 | 111 | /* Now count remaining bytes. */ 112 | ctx->total[0] += bytes; 113 | if (ctx->total[0] < bytes) 114 | ++ctx->total[1]; 115 | 116 | pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; 117 | memcpy (&ctx->buffer[bytes], fillbuf, pad); 118 | 119 | /* Put the 64-bit file length in *bits* at the end of the buffer. */ 120 | *(md5_uint32 *) & ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3); 121 | *(md5_uint32 *) & ctx->buffer[bytes + pad + 4] = 122 | SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); 123 | 124 | /* Process last bytes. */ 125 | md5_process_block (ctx->buffer, bytes + pad + 8, ctx); 126 | 127 | return md5_read_ctx (ctx, resbuf); 128 | } 129 | 130 | /* Compute MD5 message digest for bytes read from STREAM. The 131 | resulting message digest number will be written into the 16 bytes 132 | beginning at RESBLOCK. */ 133 | int 134 | md5_stream (stream, resblock) 135 | FILE *stream; 136 | void *resblock; 137 | { 138 | /* Important: BLOCKSIZE must be a multiple of 64. */ 139 | #define BLOCKSIZE 4096 140 | struct md5_ctx ctx; 141 | char buffer[BLOCKSIZE + 72]; 142 | size_t sum; 143 | 144 | /* Initialize the computation context. */ 145 | md5_init_ctx (&ctx); 146 | 147 | /* Iterate over full file contents. */ 148 | while (1) 149 | { 150 | /* We read the file in blocks of BLOCKSIZE bytes. One call of the 151 | computation function processes the whole buffer so that with the 152 | next round of the loop another block can be read. */ 153 | size_t n; 154 | 155 | sum = 0; 156 | 157 | /* Read block. Take care for partial reads. */ 158 | do 159 | { 160 | n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); 161 | 162 | sum += n; 163 | } 164 | while (sum < BLOCKSIZE && n != 0); 165 | if (n == 0 && ferror (stream)) 166 | return 1; 167 | 168 | /* If end of file is reached, end the loop. */ 169 | if (n == 0) 170 | break; 171 | 172 | /* Process buffer with BLOCKSIZE bytes. Note that 173 | BLOCKSIZE % 64 == 0 174 | */ 175 | md5_process_block (buffer, BLOCKSIZE, &ctx); 176 | } 177 | 178 | /* Add the last bytes if necessary. */ 179 | if (sum > 0) 180 | md5_process_bytes (buffer, sum, &ctx); 181 | 182 | /* Construct result in desired memory. */ 183 | md5_finish_ctx (&ctx, resblock); 184 | return 0; 185 | } 186 | 187 | /* Compute MD5 message digest for LEN bytes beginning at BUFFER. The 188 | result is always in little endian byte order, so that a byte-wise 189 | output yields to the wanted ASCII representation of the message 190 | digest. */ 191 | void * 192 | md5_buffer (buffer, len, resblock) 193 | const char *buffer; 194 | size_t len; 195 | void *resblock; 196 | { 197 | struct md5_ctx ctx; 198 | 199 | /* Initialize the computation context. */ 200 | md5_init_ctx (&ctx); 201 | 202 | /* Process whole buffer but last len % 64 bytes. */ 203 | md5_process_bytes (buffer, len, &ctx); 204 | 205 | /* Put result in desired memory area. */ 206 | return md5_finish_ctx (&ctx, resblock); 207 | } 208 | 209 | 210 | void 211 | md5_process_bytes (buffer, len, ctx) 212 | const void *buffer; 213 | size_t len; 214 | struct md5_ctx *ctx; 215 | { 216 | /* When we already have some bits in our internal buffer concatenate 217 | both inputs first. */ 218 | if (ctx->buflen != 0) 219 | { 220 | size_t left_over = ctx->buflen; 221 | size_t add = 128 - left_over > len ? len : 128 - left_over; 222 | 223 | memcpy (&ctx->buffer[left_over], buffer, add); 224 | ctx->buflen += add; 225 | 226 | if (left_over + add > 64) 227 | { 228 | md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); 229 | /* The regions in the following copy operation cannot overlap. */ 230 | memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], 231 | (left_over + add) & 63); 232 | ctx->buflen = (left_over + add) & 63; 233 | } 234 | 235 | buffer = (const char *) buffer + add; 236 | len -= add; 237 | } 238 | 239 | /* Process available complete blocks. */ 240 | if (len > 64) 241 | { 242 | md5_process_block (buffer, len & ~63, ctx); 243 | buffer = (const char *) buffer + (len & ~63); 244 | len &= 63; 245 | } 246 | 247 | /* Move remaining bytes in internal buffer. */ 248 | if (len > 0) 249 | { 250 | memcpy (ctx->buffer, buffer, len); 251 | ctx->buflen = len; 252 | } 253 | } 254 | 255 | 256 | /* These are the four functions used in the four steps of the MD5 algorithm 257 | and defined in the RFC 1321. The first function is a little bit optimized 258 | (as found in Colin Plumbs public domain implementation). */ 259 | /* #define FF(b, c, d) ((b & c) | (~b & d)) */ 260 | #define FF(b, c, d) (d ^ (b & (c ^ d))) 261 | #define FG(b, c, d) FF (d, b, c) 262 | #define FH(b, c, d) (b ^ c ^ d) 263 | #define FI(b, c, d) (c ^ (b | ~d)) 264 | 265 | /* Process LEN bytes of BUFFER, accumulating context into CTX. 266 | It is assumed that LEN % 64 == 0. */ 267 | 268 | void 269 | md5_process_block (buffer, len, ctx) 270 | const void *buffer; 271 | size_t len; 272 | struct md5_ctx *ctx; 273 | { 274 | md5_uint32 correct_words[16]; 275 | const md5_uint32 *words = buffer; 276 | size_t nwords = len / sizeof (md5_uint32); 277 | const md5_uint32 *endp = words + nwords; 278 | md5_uint32 A = ctx->A; 279 | md5_uint32 B = ctx->B; 280 | md5_uint32 C = ctx->C; 281 | md5_uint32 D = ctx->D; 282 | 283 | /* First increment the byte count. RFC 1321 specifies the possible 284 | length of the file up to 2^64 bits. Here we only compute the 285 | number of bytes. Do a double word increment. */ 286 | ctx->total[0] += len; 287 | if (ctx->total[0] < len) 288 | ++ctx->total[1]; 289 | 290 | /* Process all bytes in the buffer with 64 bytes in each round of 291 | the loop. */ 292 | while (words < endp) 293 | { 294 | md5_uint32 *cwp = correct_words; 295 | md5_uint32 A_save = A; 296 | md5_uint32 B_save = B; 297 | md5_uint32 C_save = C; 298 | md5_uint32 D_save = D; 299 | 300 | /* First round: using the given function, the context and a constant 301 | the next context is computed. Because the algorithms processing 302 | unit is a 32-bit word and it is determined to work on words in 303 | little endian byte order we perhaps have to change the byte order 304 | before the computation. To reduce the work for the next steps 305 | we store the swapped words in the array CORRECT_WORDS. */ 306 | 307 | #define OP(a, b, c, d, s, T) \ 308 | do \ 309 | { \ 310 | a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ 311 | ++words; \ 312 | CYCLIC (a, s); \ 313 | a += b; \ 314 | } \ 315 | while (0) 316 | 317 | /* It is unfortunate that C does not provide an operator for 318 | cyclic rotation. Hope the C compiler is smart enough. */ 319 | #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) 320 | 321 | /* Before we start, one word to the strange constants. 322 | They are defined in RFC 1321 as 323 | 324 | T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 325 | */ 326 | 327 | /* Round 1. */ 328 | OP (A, B, C, D, 7, 0xd76aa478); 329 | OP (D, A, B, C, 12, 0xe8c7b756); 330 | OP (C, D, A, B, 17, 0x242070db); 331 | OP (B, C, D, A, 22, 0xc1bdceee); 332 | OP (A, B, C, D, 7, 0xf57c0faf); 333 | OP (D, A, B, C, 12, 0x4787c62a); 334 | OP (C, D, A, B, 17, 0xa8304613); 335 | OP (B, C, D, A, 22, 0xfd469501); 336 | OP (A, B, C, D, 7, 0x698098d8); 337 | OP (D, A, B, C, 12, 0x8b44f7af); 338 | OP (C, D, A, B, 17, 0xffff5bb1); 339 | OP (B, C, D, A, 22, 0x895cd7be); 340 | OP (A, B, C, D, 7, 0x6b901122); 341 | OP (D, A, B, C, 12, 0xfd987193); 342 | OP (C, D, A, B, 17, 0xa679438e); 343 | OP (B, C, D, A, 22, 0x49b40821); 344 | 345 | /* For the second to fourth round we have the possibly swapped words 346 | in CORRECT_WORDS. Redefine the macro to take an additional first 347 | argument specifying the function to use. */ 348 | #undef OP 349 | #define OP(f, a, b, c, d, k, s, T) \ 350 | do \ 351 | { \ 352 | a += f (b, c, d) + correct_words[k] + T; \ 353 | CYCLIC (a, s); \ 354 | a += b; \ 355 | } \ 356 | while (0) 357 | 358 | /* Round 2. */ 359 | OP (FG, A, B, C, D, 1, 5, 0xf61e2562); 360 | OP (FG, D, A, B, C, 6, 9, 0xc040b340); 361 | OP (FG, C, D, A, B, 11, 14, 0x265e5a51); 362 | OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); 363 | OP (FG, A, B, C, D, 5, 5, 0xd62f105d); 364 | OP (FG, D, A, B, C, 10, 9, 0x02441453); 365 | OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); 366 | OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); 367 | OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); 368 | OP (FG, D, A, B, C, 14, 9, 0xc33707d6); 369 | OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); 370 | OP (FG, B, C, D, A, 8, 20, 0x455a14ed); 371 | OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); 372 | OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); 373 | OP (FG, C, D, A, B, 7, 14, 0x676f02d9); 374 | OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); 375 | 376 | /* Round 3. */ 377 | OP (FH, A, B, C, D, 5, 4, 0xfffa3942); 378 | OP (FH, D, A, B, C, 8, 11, 0x8771f681); 379 | OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); 380 | OP (FH, B, C, D, A, 14, 23, 0xfde5380c); 381 | OP (FH, A, B, C, D, 1, 4, 0xa4beea44); 382 | OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); 383 | OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); 384 | OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); 385 | OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); 386 | OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); 387 | OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); 388 | OP (FH, B, C, D, A, 6, 23, 0x04881d05); 389 | OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); 390 | OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); 391 | OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); 392 | OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); 393 | 394 | /* Round 4. */ 395 | OP (FI, A, B, C, D, 0, 6, 0xf4292244); 396 | OP (FI, D, A, B, C, 7, 10, 0x432aff97); 397 | OP (FI, C, D, A, B, 14, 15, 0xab9423a7); 398 | OP (FI, B, C, D, A, 5, 21, 0xfc93a039); 399 | OP (FI, A, B, C, D, 12, 6, 0x655b59c3); 400 | OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); 401 | OP (FI, C, D, A, B, 10, 15, 0xffeff47d); 402 | OP (FI, B, C, D, A, 1, 21, 0x85845dd1); 403 | OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); 404 | OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); 405 | OP (FI, C, D, A, B, 6, 15, 0xa3014314); 406 | OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); 407 | OP (FI, A, B, C, D, 4, 6, 0xf7537e82); 408 | OP (FI, D, A, B, C, 11, 10, 0xbd3af235); 409 | OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); 410 | OP (FI, B, C, D, A, 9, 21, 0xeb86d391); 411 | 412 | /* Add the starting values of the context. */ 413 | A += A_save; 414 | B += B_save; 415 | C += C_save; 416 | D += D_save; 417 | } 418 | 419 | /* Put checksum in context given as argument. */ 420 | ctx->A = A; 421 | ctx->B = B; 422 | ctx->C = C; 423 | ctx->D = D; 424 | } 425 | -------------------------------------------------------------------------------- /src/motd.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: motd.c 3 | desciption: everything what has to do with the motd 4 | begin: 03/03/02 5 | copyright: (C) 2002 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /*HAVE_CONFIG_H*/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "bounced.h" 24 | 25 | char* g_strMotdDefaultFormatTime = "%A, %d of %B %Y %X"; 26 | char* g_strMotdDefaultFormatUptime = "%#D days, %#H hours, %#M minutes and %#S seconds"; 27 | char* g_strMotdFormatTime = 0; 28 | char* g_strMotdFormatUptime = 0; 29 | 30 | char g_strMotdCurrentTime[48]; 31 | char g_strMotdTotalConnections[21]; 32 | char g_strMotdIP[16]; 33 | char g_strMotdTotalLogins[21]; 34 | char* g_strMotdNick; 35 | char* g_strMotdUsername; 36 | char* g_strMotdRealName; 37 | char* g_strMotdEmail; 38 | char g_strMotdUsers[11]; 39 | char g_strMotdUptime[48]; 40 | char g_strMotdTimeStarted[48]; 41 | char g_strMotdIncomingTraffic[11]; 42 | char g_strMotdOutgoingTraffic[11]; 43 | char g_strMotdTraffic[11]; 44 | 45 | char g_strMotdConnections[11]; 46 | char g_strMotdServers[11]; 47 | char g_strMotdClients[11]; 48 | 49 | char g_strMotdTotalIncomingBytes[21]; 50 | char g_strMotdTotalOutgoingBytes[21]; 51 | char g_strMotdTotalBytes[21]; 52 | 53 | MOTDVAR_TABLE_START 54 | MOTDVAR('C', MotdSetCurrentTime, g_strMotdCurrentTime, MOTDV_REFRESH) 55 | MOTDVAR('c', MotdSetTotalConnections, g_strMotdTotalConnections, MOTDV_REFRESH) 56 | MOTDVAR('I', MotdSetIP, g_strMotdIP, MOTDV_REFRESH) 57 | MOTDVAR('l', MotdSetTotalLogins, g_strMotdTotalLogins, MOTDV_REFRESH) 58 | MOTDVAR('B', 0, &c_strBouncerName, MOTDV_NORMAL|MOTDV_POINTER) 59 | MOTDVAR('N', MotdSetNick, &g_strMotdNick, MOTDV_REFRESH|MOTDV_POINTER) 60 | MOTDVAR('U', MotdSetUsername, &g_strMotdUsername, MOTDV_REFRESH|MOTDV_POINTER) 61 | MOTDVAR('R', MotdSetRealName, &g_strMotdRealName, MOTDV_REFRESH|MOTDV_POINTER) 62 | MOTDVAR('E', MotdSetEmail, &g_strMotdEmail, MOTDV_REFRESH|MOTDV_POINTER) 63 | MOTDVAR('S', 0, g_strSystem, MOTDV_NORMAL) 64 | MOTDVAR('u', MotdSetUsers, g_strMotdUsers, MOTDV_REFRESH) 65 | MOTDVAR('V', 0, g_strVersion, MOTDV_NORMAL) 66 | MOTDVAR('W', MotdSetUptime, g_strMotdUptime, MOTDV_REFRESH) 67 | MOTDVAR('w', MotdSetTimeStarted, g_strMotdTimeStarted, MOTDV_NORMAL) 68 | 69 | MOTDVAR('i', MotdSetIncomingTraffic, g_strMotdIncomingTraffic, MOTDV_REFRESH) 70 | MOTDVAR('o', MotdSetOutgoingTraffic, g_strMotdOutgoingTraffic, MOTDV_REFRESH) 71 | MOTDVAR('t', MotdSetTraffic, g_strMotdTraffic, MOTDV_REFRESH) 72 | 73 | MOTDVAR('D', MotdSetConnections, g_strMotdConnections, MOTDV_REFRESH) 74 | MOTDVAR('U', MotdSetServers, g_strMotdServers, MOTDV_REFRESH) 75 | MOTDVAR('L', MotdSetClients, g_strMotdClients, MOTDV_REFRESH) 76 | 77 | MOTDVAR('J', MotdSetTotalIncomingBytes, g_strMotdTotalIncomingBytes, MOTDV_REFRESH) 78 | MOTDVAR('O', MotdSetTotalOutgoingBytes, g_strMotdTotalOutgoingBytes, MOTDV_REFRESH) 79 | MOTDVAR('T', MotdSetTotalBytes, g_strMotdTotalBytes, MOTDV_REFRESH) 80 | 81 | 82 | MOTDVAR_TABLE_END 83 | 84 | void MotdSetCurrentTime(PMOTDVAR pMotdVar, PCLIENT pClient) 85 | { 86 | strftimet(g_strMotdCurrentTime,sizeof(g_strMotdCurrentTime),g_strMotdFormatTime,g_timeNow); 87 | return; 88 | pMotdVar = 0; 89 | pClient = 0; 90 | } 91 | 92 | void MotdSetTotalConnections(PMOTDVAR pMotdVar, PCLIENT pClient) 93 | { 94 | strformat(g_strMotdTotalConnections,sizeof(g_strMotdTotalConnections),"%.0f",g_dConnections); 95 | return; 96 | pMotdVar = 0; 97 | pClient = 0; 98 | } 99 | 100 | void MotdSetIP(PMOTDVAR pMotdVar, PCLIENT pClient) 101 | { 102 | strcpy(g_strMotdIP,iptoa(pClient->pConnection->nIP)); 103 | return; 104 | pMotdVar = 0; 105 | } 106 | 107 | void MotdSetTotalLogins(PMOTDVAR pMotdVar, PCLIENT pClient) 108 | { 109 | strformat(g_strMotdTotalLogins,sizeof(g_strMotdTotalLogins),"%.0f",g_dLogins); 110 | return; 111 | pMotdVar = 0; 112 | pClient = 0; 113 | } 114 | 115 | void MotdSetConnections(PMOTDVAR pMotdVar, PCLIENT pClient) 116 | { 117 | strformat(g_strMotdConnections,sizeof(g_strMotdConnections),"%u",g_listConnections.nCount); 118 | return; 119 | pMotdVar = 0; 120 | pClient = 0; 121 | } 122 | 123 | void MotdSetServers(PMOTDVAR pMotdVar, PCLIENT pClient) 124 | { 125 | strformat(g_strMotdServers,sizeof(g_strMotdServers),"%u",g_listServers.nCount); 126 | return; 127 | pMotdVar = 0; 128 | pClient = 0; 129 | } 130 | 131 | void MotdSetClients(PMOTDVAR pMotdVar, PCLIENT pClient) 132 | { 133 | strformat(g_strMotdClients,sizeof(g_strMotdClients),"%u",g_listClients.nCount); 134 | return; 135 | pMotdVar = 0; 136 | pClient = 0; 137 | } 138 | 139 | void MotdSetTotalIncomingBytes(PMOTDVAR pMotdVar, PCLIENT pClient) 140 | { 141 | strformat(g_strMotdTotalIncomingBytes,sizeof(g_strMotdTotalIncomingBytes),"%.0f",g_dTotalBytesIn/1048576); 142 | return; 143 | pMotdVar = 0; 144 | pClient = 0; 145 | } 146 | 147 | void MotdSetTotalOutgoingBytes(PMOTDVAR pMotdVar, PCLIENT pClient) 148 | { 149 | strformat(g_strMotdTotalOutgoingBytes,sizeof(g_strMotdTotalOutgoingBytes),"%.0f",g_dTotalBytesOut/1048576); 150 | return; 151 | pMotdVar = 0; 152 | pClient = 0; 153 | } 154 | 155 | void MotdSetTotalBytes(PMOTDVAR pMotdVar, PCLIENT pClient) 156 | { 157 | strformat(g_strMotdTotalBytes,sizeof(g_strMotdTotalBytes),"%.0f",(g_dTotalBytesOut+g_dTotalBytesIn)/1048576); 158 | return; 159 | pMotdVar = 0; 160 | pClient = 0; 161 | } 162 | 163 | void MotdSetNick(PMOTDVAR pMotdVar, PCLIENT pClient) 164 | { 165 | g_strMotdNick = pClient->strNick; 166 | return; 167 | pMotdVar = 0; 168 | } 169 | 170 | void MotdSetUsername(PMOTDVAR pMotdVar, PCLIENT pClient) 171 | { 172 | g_strMotdUsername = pClient->pUser->strName; 173 | return; 174 | pMotdVar = 0; 175 | } 176 | 177 | void MotdSetRealName(PMOTDVAR pMotdVar, PCLIENT pClient) 178 | { 179 | g_strMotdRealName = pClient->strRealName; 180 | return; 181 | pMotdVar = 0; 182 | } 183 | 184 | void MotdSetEmail(PMOTDVAR pMotdVar, PCLIENT pClient) 185 | { 186 | g_strMotdEmail = pClient->pUser->strEmail; 187 | return; 188 | pMotdVar = 0; 189 | } 190 | 191 | void MotdSetUsers(PMOTDVAR pMotdVar, PCLIENT pClient) 192 | { 193 | strformat(g_strMotdUsers,sizeof(g_strMotdUsers),"%u",g_hashlistUsers.nCount); 194 | return; 195 | pMotdVar = 0; 196 | pClient = 0; 197 | } 198 | 199 | void MotdSetTimeStarted(PMOTDVAR pMotdVar, PCLIENT pClient) 200 | { 201 | strftimet(g_strMotdTimeStarted,sizeof(g_strMotdTimeStarted),g_strMotdFormatTime,g_timeStart); 202 | return; 203 | pMotdVar = 0; 204 | pClient = 0; 205 | } 206 | 207 | void MotdSetUptime(PMOTDVAR pMotdVar, PCLIENT pClient) 208 | { 209 | strftimetspan(g_strMotdUptime,sizeof(g_strMotdUptime),g_strMotdFormatUptime,g_timeNow-g_timeStart); 210 | return; 211 | pMotdVar = 0; 212 | pClient = 0; 213 | } 214 | 215 | void MotdSetIncomingTraffic(PMOTDVAR pMotdVar, PCLIENT pClient) 216 | { 217 | strformat(g_strMotdIncomingTraffic,sizeof(g_strMotdIncomingTraffic),"%.2f",((double)g_nLastIncomingTraffic)/1000); 218 | return; 219 | pMotdVar = 0; 220 | pClient = 0; 221 | } 222 | 223 | void MotdSetOutgoingTraffic(PMOTDVAR pMotdVar, PCLIENT pClient) 224 | { 225 | strformat(g_strMotdOutgoingTraffic,sizeof(g_strMotdOutgoingTraffic),"%.2f",((double)g_nLastOutgoingTraffic)/1000); 226 | return; 227 | pMotdVar = 0; 228 | pClient = 0; 229 | } 230 | 231 | void MotdSetTraffic(PMOTDVAR pMotdVar, PCLIENT pClient) 232 | { 233 | strformat(g_strMotdTraffic,sizeof(g_strMotdTraffic),"%.2f",((double)(g_nLastIncomingTraffic+g_nLastOutgoingTraffic))/1000); 234 | return; 235 | pMotdVar = 0; 236 | pClient = 0; 237 | } 238 | 239 | int MotdSend(PCLIENT pClient) 240 | { 241 | if(g_listMotd.pFirst) 242 | { 243 | unsigned int n; 244 | char* str,*strStart; 245 | PMOTDSTR pMotdStr; 246 | PMOTDVAR pMotdVar; 247 | 248 | /* make motd up to date */ 249 | for(pMotdVar = g_listMotdVars.pFirst; pMotdVar; pMotdVar = pMotdVar->ll.pNext) 250 | pMotdVar->pMotdVarProc(pMotdVar,pClient); 251 | 252 | if( !ConnectionSendFormat(pClient->pConnection,":%s 375 %s :- %s Message of the Day - \r\n",c_strBouncerName,pClient->strNick,c_strBouncerName) ) 253 | return 0; 254 | 255 | strStart = g_strOutBuffer+strformat(g_strOutBuffer,sizeof(g_strOutBuffer)-2,":%s 372 %s :- ",c_strBouncerName,pClient->strNick); 256 | str = strStart; 257 | 258 | for(pMotdStr = g_listMotd.pFirst; pMotdStr; pMotdStr = pMotdStr->ll.pNext) 259 | { 260 | if(pMotdStr->p) 261 | { 262 | if(pMotdStr->i < 0) 263 | { 264 | pMotdVar = (PMOTDVAR)pMotdStr->p; 265 | if(pMotdVar->cType & MOTDV_POINTER) 266 | { 267 | n = strlen(*(char**)pMotdVar->pVar); 268 | if(str-g_strOutBuffer+n < sizeof(g_strOutBuffer)-3) 269 | { 270 | memcpy(str,*(char**)pMotdVar->pVar,n); 271 | str += n; 272 | continue; 273 | } 274 | } 275 | else 276 | { 277 | n = strlen((char*)pMotdVar->pVar); 278 | if(str-g_strOutBuffer+n < sizeof(g_strOutBuffer)-3) 279 | { 280 | memcpy(str,(char*)pMotdVar->pVar,n); 281 | str += n; 282 | continue; 283 | } 284 | } 285 | } 286 | else 287 | { 288 | n = pMotdStr->i; 289 | if(str-g_strOutBuffer+n < sizeof(g_strOutBuffer)-3) 290 | { 291 | memcpy(str,pMotdStr->p,n); 292 | str += n; 293 | continue; 294 | } 295 | } 296 | } 297 | 298 | *(str++) = '\r'; 299 | *(str++) = '\n'; 300 | *str = '\0'; 301 | 302 | if(!ConnectionSend(pClient->pConnection,g_strOutBuffer,str-g_strOutBuffer)) 303 | return 0; 304 | 305 | str = strStart; 306 | } 307 | 308 | if( !ConnectionSendFormat(pClient->pConnection,":%s 376 %s :End of /MOTD command\r\n",c_strBouncerName,pClient->strNick) ) 309 | return 0; 310 | } 311 | else 312 | { 313 | if( !ConnectionSendFormat(pClient->pConnection,":%s 422 %s :MOTD File is missing\r\n",c_strBouncerName,pClient->strNick) ) 314 | return 0; 315 | } 316 | 317 | return 1; 318 | } 319 | 320 | PMOTDSTR MotdStrCreate(PMOTDSTR** pppMotdStr, void* p, int i) 321 | { 322 | PMOTDSTR pMotdStr; 323 | if( !(pMotdStr = CALLOC(PMOTDSTR,1,sizeof(MOTDSTR))) || 324 | (p && i > -1 && !(pMotdStr->p = STRDUP(char*,p))) ) 325 | { 326 | if(pMotdStr) 327 | { 328 | if(pMotdStr->p) 329 | FREE(char*,pMotdStr->p); 330 | } 331 | OUTOFMEMORY; 332 | return 0; 333 | } 334 | if(i < 0) 335 | pMotdStr->p = p; 336 | pMotdStr->i = i; 337 | 338 | LIST_INSERT(MOTD_LIST,g_listMotd,*pppMotdStr,pMotdStr); 339 | *pppMotdStr = &pMotdStr->ll.pNext; 340 | 341 | return pMotdStr; 342 | } 343 | 344 | void MotdStrFree(PMOTDSTR pMotdStr) 345 | { 346 | if(pMotdStr->p && pMotdStr->i > -1) 347 | FREE(char*,pMotdStr->p); 348 | FREE(PMOTDSTR,pMotdStr); 349 | } 350 | 351 | void MotdVarFree(PMOTDVAR pMotdVar) 352 | { 353 | pMotdVar->ll.pNext = 0; 354 | } 355 | 356 | int MotdLoad(void) 357 | { 358 | /* variables */ 359 | char strFile[MAX_PATH]; 360 | int iLength; 361 | unsigned int iLine = 0, 362 | iMotdLines = 0, 363 | nStopLength; 364 | unsigned int n; 365 | FILE* fp; 366 | char *str, 367 | *strStop; 368 | PMOTDSTR* ppMotdStr = &g_listMotd.pFirst; 369 | 370 | /* delete current motd */ 371 | MotdFree(); 372 | 373 | /* create file path */ 374 | /* snprintf(strFile,sizeof(strFile),"%s/%s",g_strConfigDir,MOTDFILE); */ 375 | BuildFilename(g_strConfigDir,MOTDFILE,strFile,sizeof(strFile)); 376 | 377 | /* read config file */ 378 | fp = fopen(strFile,"r"); 379 | if(!fp) 380 | { 381 | /* Log */ 382 | /* Log("error: Couldn't load motd from \"%s\"",strFile); */ 383 | return 0; 384 | } 385 | 386 | while(fgets(g_strOutBuffer,sizeof(g_strOutBuffer),fp)) 387 | { 388 | iLine++; 389 | if( *g_strOutBuffer == '#' || 390 | *g_strOutBuffer == ';' || 391 | isspace(*g_strOutBuffer)) 392 | continue; 393 | 394 | iLength = strlen(g_strOutBuffer); 395 | while(iLength > 0 && isspace(g_strOutBuffer[iLength-1])) 396 | iLength--; 397 | g_strOutBuffer[iLength] = '\0'; 398 | 399 | str = g_strOutBuffer; 400 | while(*str && *str != ' ') 401 | str++; 402 | if(*str == ' ') 403 | *(str++) = '\0'; 404 | 405 | if(!strcasecmp(g_strOutBuffer,"-")) 406 | { 407 | iMotdLines++; 408 | strStop = str; 409 | nStopLength = 0; 410 | for(str = strStop;*str;str++) 411 | { 412 | if(*str == '%' && *(++str)) 413 | { 414 | if(*str == '%') 415 | { 416 | memcpy(str,str+1,iLength-(str-g_strOutBuffer)); 417 | nStopLength += 2; 418 | continue; 419 | } 420 | for(n = 0; n < sizeof(g_pMotdVars)/sizeof(struct tagMOTDVAR); n++) 421 | { 422 | if(*str == g_pMotdVars[n].cName) 423 | { 424 | str[-1] = '\0'; 425 | MotdStrCreate(&ppMotdStr,strStop,nStopLength); 426 | nStopLength = -1; 427 | strStop = str+1; 428 | 429 | if(g_pMotdVars[n].pMotdVarProc) 430 | { 431 | if(g_pMotdVars[n].cType & MOTDV_REFRESH) 432 | { 433 | PMOTDVAR pMotdVar; 434 | for(pMotdVar = g_listMotdVars.pFirst; pMotdVar; pMotdVar = pMotdVar->ll.pNext) 435 | if(pMotdVar == &g_pMotdVars[n]) 436 | break; 437 | if(!pMotdVar) 438 | LIST_ADD(MOTDVAR_LIST,g_listMotdVars,&g_pMotdVars[n]); 439 | } 440 | else 441 | g_pMotdVars[n].pMotdVarProc(&g_pMotdVars[n],0); 442 | } 443 | else 444 | { 445 | ASSERT(!(g_pMotdVars[n].cType & MOTDV_REFRESH)); 446 | } 447 | 448 | if(g_pMotdVars[n].cType & MOTDV_REFRESH) 449 | { 450 | MotdStrCreate(&ppMotdStr,&g_pMotdVars[n],-1); 451 | } 452 | else 453 | { 454 | if(g_pMotdVars[n].cType & MOTDV_POINTER) 455 | MotdStrCreate(&ppMotdStr,*(char**)g_pMotdVars[n].pVar,(int)strlen(*(char**)g_pMotdVars[n].pVar)); 456 | else 457 | MotdStrCreate(&ppMotdStr,(char*)g_pMotdVars[n].pVar,(int)strlen((char*)g_pMotdVars[n].pVar)); 458 | } 459 | 460 | break; 461 | } 462 | } 463 | if(n >= sizeof(g_pMotdVars)/sizeof(struct tagMOTDVAR)) 464 | { 465 | Log("error: Unknown motd variable \"%c\" (Line %u)",*str,iLine); 466 | nStopLength++; 467 | } 468 | } 469 | nStopLength++; 470 | } 471 | 472 | if(nStopLength) 473 | MotdStrCreate(&ppMotdStr,strStop,nStopLength); 474 | MotdStrCreate(&ppMotdStr,0,0); /* line end */ 475 | } 476 | else 477 | { 478 | char* strEnd = &g_strOutBuffer[iLength-1]; 479 | if(str != strEnd && *str == '"' && *strEnd == '"' ) 480 | { 481 | str++; 482 | *strEnd = '\0'; 483 | } 484 | 485 | if(!strcasecmp(g_strOutBuffer,"FormatTime")) 486 | { 487 | char* strVal = STRDUP(char*,str); 488 | if(strVal) 489 | { 490 | if(g_strMotdFormatTime && g_strMotdFormatTime != g_strMotdDefaultFormatTime) 491 | FREE(char*,g_strMotdFormatTime); 492 | g_strMotdFormatTime = strVal; 493 | } 494 | } 495 | else if(!strcasecmp(g_strOutBuffer,"FormatUptime")) 496 | { 497 | char* strVal = STRDUP(char*,str); 498 | if(strVal) 499 | { 500 | if(g_strMotdFormatUptime && g_strMotdFormatUptime != g_strMotdDefaultFormatUptime) 501 | FREE(char*,g_strMotdFormatUptime); 502 | g_strMotdFormatUptime = strVal; 503 | } 504 | } 505 | else 506 | Log("error: Unknown directive \"%s\" in motd file (Line %u)",g_strOutBuffer,iLine); 507 | } 508 | } 509 | 510 | fclose(fp); 511 | 512 | /* debug */ 513 | g_DebugHasMotdCopied = 1; 514 | g_DebuglistMotd.pFirst = g_listMotd.pFirst; 515 | g_DebuglistMotd.nCount = g_listMotd.nCount; 516 | g_DebugMotdStrFirst.ll.pNext = g_listMotd.pFirst->ll.pNext; 517 | g_DebugMotdStrFirst.p = g_listMotd.pFirst->p; 518 | g_DebugMotdStrFirst.i = g_listMotd.pFirst->i; 519 | 520 | Log("Loaded %u motd lines from \"%s\"",iMotdLines,strFile); 521 | return 1; 522 | } 523 | 524 | void MotdFree(void) 525 | { 526 | if(g_strMotdFormatTime && g_strMotdFormatTime != g_strMotdDefaultFormatTime) 527 | FREE(char*,g_strMotdFormatTime); 528 | g_strMotdFormatTime = g_strMotdDefaultFormatTime; 529 | if(g_strMotdFormatUptime && g_strMotdFormatUptime != g_strMotdDefaultFormatUptime) 530 | FREE(char*,g_strMotdFormatUptime); 531 | g_strMotdFormatUptime = g_strMotdDefaultFormatUptime; 532 | 533 | /* delete current motd */ 534 | LIST_REMOVE_ALL(MOTD_LIST,g_listMotd); 535 | LIST_REMOVE_ALL(MOTDVAR_LIST,g_listMotdVars); 536 | } 537 | -------------------------------------------------------------------------------- /src/tools.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: tools.c 3 | desciption: logging functions and other helpful tools 4 | begin: 10/25/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #if !defined(_WIN32) || defined(__CYGWIN__) 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #endif /* !defined(_WIN32) || defined(__CYGWIN__) */ 31 | 32 | #include "bounced.h" 33 | 34 | size_t vstrformat(char* str, size_t maxsize, const char* format, va_list ap); 35 | 36 | 37 | static unsigned char g_bLogInMulti = 0; 38 | 39 | #ifndef _WINDOWS 40 | 41 | /* #define STDOUT_FILENO fileno(stdout) */ 42 | 43 | int LogOpenFile(void) 44 | { 45 | char strFile[MAX_PATH]; 46 | int fd; 47 | BuildFilename(g_strConfigDir,LOGFILE,strFile,sizeof(strFile)); 48 | fd = open(strFile,O_CREAT|O_WRONLY|O_APPEND,S_IRUSR|S_IWUSR); 49 | if(fd > 0) 50 | { 51 | /* close stdout */ 52 | if(dup2(fd, STDOUT_FILENO) == -1) 53 | { 54 | Log("error: Couldn't reopen stdout"); 55 | return 0; 56 | } 57 | close(fd); 58 | } 59 | else 60 | { 61 | Log("error: Couldn't open log file \"%s\"",strFile); 62 | return 0; 63 | } 64 | return 1; 65 | } 66 | 67 | int LogReopenFile(void) 68 | { 69 | char strFile[MAX_PATH]; 70 | char strFileOld[MAX_PATH]; 71 | int fd; 72 | BuildFilename(g_strConfigDir,LOGFILE,strFile,sizeof(strFile)); 73 | BuildFilename(g_strConfigDir,LOGOLDFILE,strFileOld,sizeof(strFileOld)); 74 | rename(strFile,strFileOld); 75 | fd = open(strFile,O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR); 76 | if(fd > 0) 77 | { 78 | if(dup2(fd, STDOUT_FILENO) == -1) 79 | { 80 | Log("error: Couldn't reopen stdout"); 81 | return 0; 82 | } 83 | close(fd); 84 | } 85 | else 86 | { 87 | Log("error: Couldn't open log file \"%s\"",strFile); 88 | return 0; 89 | } 90 | return 1; 91 | } 92 | 93 | #endif /*!_WINDOWS*/ 94 | 95 | int Log(const char* format, ...) 96 | { 97 | char strLog[512+210+2]; 98 | va_list ap; 99 | int iReturn; 100 | 101 | ASSERT(format); 102 | if(!format) 103 | return 0; 104 | 105 | if(g_bLogInMulti) 106 | { 107 | g_bLogInMulti = 0; 108 | fputc('\n',stdout); 109 | } 110 | 111 | iReturn = strftimet(strLog,sizeof(strLog),"[%X] ",g_timeNow); 112 | 113 | va_start (ap, format); 114 | iReturn += vstrformat(strLog+iReturn,sizeof(strLog)-iReturn-1,format, ap); 115 | va_end (ap); 116 | strLog[iReturn++] = '\n'; 117 | strLog[iReturn] = '\0'; 118 | 119 | /* reopen log file if file is to big */ 120 | #ifndef _WINDOWS 121 | if(g_bBackground) 122 | { 123 | struct stat buf; 124 | if( fstat(STDOUT_FILENO,&buf) == 0 && 125 | buf.st_size+iReturn >= LOGFILESIZE) 126 | LogReopenFile(); 127 | } 128 | #endif /* !_WINDOWS */ 129 | 130 | fputs(strLog,stdout); 131 | fflush(stdout); 132 | 133 | return iReturn; 134 | } 135 | 136 | int LogMultiStart(const char* format, ...) 137 | { 138 | char strLog[320]; 139 | va_list ap; 140 | int iReturn; 141 | 142 | ASSERT(format); 143 | if(!format) 144 | return 0; 145 | 146 | if(g_bLogInMulti) 147 | { 148 | g_bLogInMulti = 0; 149 | fputc('\n',stdout); 150 | } 151 | 152 | iReturn = strftimet(strLog,sizeof(strLog),"[%X] ",g_timeNow); 153 | 154 | va_start (ap, format); 155 | iReturn += vstrformat(strLog+iReturn,sizeof(strLog)-iReturn,format, ap); 156 | va_end (ap); 157 | 158 | /* reopen log file if file is to big */ 159 | #ifndef _WINDOWS 160 | if(g_bBackground) 161 | { 162 | struct stat buf; 163 | if( fstat(STDOUT_FILENO,&buf) == 0 && 164 | buf.st_size+iReturn+16 >= LOGFILESIZE) 165 | LogReopenFile(); 166 | } 167 | #endif /* !_WINDOWS */ 168 | 169 | fputs(strLog,stdout); 170 | fflush(stdout); 171 | 172 | g_bLogInMulti = 1; 173 | 174 | return iReturn; 175 | } 176 | 177 | int LogMultiEnd(const char* str) 178 | { 179 | ASSERT(str); 180 | if(!str) 181 | return 0; 182 | 183 | if(!g_bLogInMulti) 184 | return 0; 185 | 186 | fputs(str,stdout); 187 | fputc('\n',stdout); 188 | fflush(stdout); 189 | 190 | g_bLogInMulti = 0; 191 | 192 | return 1; 193 | } 194 | 195 | char* iptoa(unsigned int ip) 196 | { 197 | struct in_addr in; 198 | memset(&in,0,sizeof(struct in_addr)); 199 | in.s_addr = ip; 200 | return inet_ntoa(in); 201 | } 202 | 203 | size_t strftimet(char *strDest, size_t maxsize, const char *format, time_t timet) 204 | { 205 | struct tm* timeptr; 206 | size_t size; 207 | 208 | ASSERT(strDest); 209 | ASSERT(maxsize > 0); 210 | ASSERT(format); 211 | 212 | timeptr = localtime(&timet); 213 | maxsize--; 214 | size = strftime(strDest,maxsize,format,timeptr); 215 | if(/*size < 0 || */size >= maxsize) 216 | { 217 | strDest[maxsize] = '\0'; 218 | return maxsize; 219 | } 220 | return size; 221 | } 222 | 223 | size_t strftimespan(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr) 224 | { 225 | unsigned char b; 226 | char *strMax,*str; 227 | 228 | ASSERT(strDest); 229 | ASSERT(maxsize > 0); 230 | ASSERT(format); 231 | ASSERT(timeptr); 232 | 233 | strMax = strDest+(maxsize-1); 234 | for(str = strDest; *format && str < strMax; format++) 235 | { 236 | if(*format == '%') 237 | { 238 | if(*(++format) == '#') 239 | { 240 | b = 1; 241 | format++; 242 | } 243 | else 244 | b = 0; 245 | switch(*format) 246 | { 247 | case 'S': 248 | str += strformat(str,strMax-str,b ? "%d" : "%02d",timeptr->tm_sec); 249 | break; 250 | case 'M': 251 | str += strformat(str,strMax-str,b ? "%d" : "%02d",timeptr->tm_min); 252 | break; 253 | case 'H': 254 | str += strformat(str,strMax-str,b ? "%d" : "%02d",timeptr->tm_hour); 255 | break; 256 | case 'D': 257 | str += strformat(str,strMax-str,b ? "%d" : "%03d",timeptr->tm_yday); 258 | break; 259 | case '%': 260 | *(str++) = *format; 261 | break; 262 | default: 263 | *(str++) = '%'; 264 | if(str >= strMax) 265 | break; 266 | if(b) 267 | { 268 | *(str++) = '#'; 269 | if(str >= strMax) 270 | break; 271 | } 272 | *(str++) = *format; 273 | break; 274 | } 275 | } 276 | else 277 | *(str++) = *format; 278 | } 279 | *str = '\0'; 280 | return str-strDest; 281 | } 282 | 283 | size_t strftimetspan(char *strDest, size_t maxsize, const char *format, time_t timet) 284 | { 285 | struct tm stm; 286 | ASSERT(strDest); 287 | ASSERT(maxsize > 0); 288 | ASSERT(format); 289 | if(!strDest || maxsize <= 0 || !format) 290 | return 0; 291 | memset(&stm,0,sizeof(struct tm)); 292 | stm.tm_yday = timet/60/60/24; 293 | stm.tm_hour = (timet/60/60) % 24; 294 | stm.tm_min = (timet/60) % 60; 295 | stm.tm_sec = timet % 60; 296 | return strftimespan(strDest,maxsize,format,&stm); 297 | } 298 | 299 | unsigned int strsum(const char* str) 300 | { 301 | /* unsigned int h,g; 302 | for (h = 0; *str; str++) 303 | { 304 | h = (h<<4)+*str; 305 | if((g = h) & 0xF0000000) 306 | h ^= g >> 24; 307 | h &= ~g; 308 | } 309 | return h; 310 | */ 311 | unsigned int sum = 0; 312 | /* ASSERT(str); 313 | if(!str) 314 | return 0; */ 315 | while(*str) 316 | sum = (sum<<4)+*(str++); 317 | return sum; 318 | } 319 | 320 | unsigned int strcasesum(const char* str) 321 | { 322 | /* unsigned int h,g; 323 | for (h = 0; *str; str++) 324 | { 325 | h = (h<<4)+tolower(*str); 326 | if((g = h) & 0xF0000000) 327 | h ^= g >> 24; 328 | h &= ~g; 329 | } 330 | return h; 331 | */ 332 | unsigned int sum = 0; 333 | /* ASSERT(str); 334 | if(!str) 335 | return 0; */ 336 | while(*str) 337 | sum = (sum<<4)+tolower(*(str++)); 338 | return sum; 339 | } 340 | 341 | unsigned int SplitLine(char *pkt, char **template, unsigned int templatecount, char bPseudoTrailing) 342 | { 343 | unsigned int i = 0; 344 | ASSERT(pkt); 345 | ASSERT(template); 346 | if(!pkt || !template) 347 | return 0; 348 | while(*pkt && i < templatecount) 349 | { 350 | while(isspace(*pkt)) 351 | pkt++; 352 | if(*pkt == '"') 353 | { 354 | /* quoted string */ 355 | template[i++] = ++pkt; 356 | pkt = strpbrk(pkt, "\"\r\n"); 357 | if(!pkt) 358 | { 359 | /* bogus line */ 360 | return 0; 361 | } 362 | *pkt++ = 0; 363 | if(!*pkt) 364 | break; 365 | pkt++; /* skip the space */ 366 | } 367 | else if(*pkt) 368 | { 369 | template[i++] = pkt; 370 | if(i == templatecount && bPseudoTrailing) 371 | pkt = strpbrk (pkt, "\r\n"); 372 | else 373 | pkt = strpbrk (pkt, " \t\r\n"); 374 | if(!pkt) 375 | break; 376 | *pkt++ = 0; 377 | } 378 | } 379 | return i; 380 | } 381 | /* 382 | unsigned int SplitLinePointer(char **ppkt, char **template, unsigned int templatecount) 383 | { 384 | unsigned int i = 0; 385 | char* pkt; 386 | ASSERT(ppkt); 387 | ASSERT(template); 388 | if(!ppkt || !template) 389 | return 0; 390 | pkt = *ppkt; 391 | if(!pkt) 392 | return 0; 393 | while(*pkt && i < templatecount) 394 | { 395 | while(isspace(*pkt)) 396 | pkt++; 397 | if(*pkt == '"') 398 | { 399 | / * quoted string * / 400 | template[i++] = ++pkt; 401 | pkt = strchr(pkt, '"'); 402 | if(!pkt) 403 | { 404 | / * bogus line * / 405 | return 0; 406 | } 407 | *pkt++ = 0; 408 | if(!*pkt) 409 | break; 410 | pkt++; / * skip the space * / 411 | } 412 | else 413 | { 414 | template[i++] = pkt; 415 | pkt = strpbrk (pkt, " \t\r\n"); 416 | if(!pkt) 417 | { 418 | i--; 419 | pkt = template[i]+strlen(template[i]); 420 | i++; 421 | break; 422 | } 423 | *pkt++ = 0; 424 | } 425 | } 426 | *ppkt = pkt; 427 | return i; 428 | } 429 | */ 430 | int SplitIRCParams(char *pkt, char **template, unsigned int templatecount, char bAllowTrailing) 431 | { 432 | unsigned int i = 0; 433 | ASSERT(pkt); 434 | ASSERT(template); 435 | if(!pkt || !template) 436 | return 0; 437 | while(*pkt && i < templatecount) 438 | { 439 | if(*pkt == ':') 440 | { 441 | template[i++] = ++pkt; 442 | if(bAllowTrailing) 443 | pkt = strpbrk(pkt,"\r\n"); 444 | else 445 | pkt = strpbrk(pkt," \r\n"); 446 | if(!pkt) 447 | break; 448 | *pkt++ = '\0'; 449 | break; 450 | } 451 | else 452 | { 453 | if(*pkt == ' ') 454 | pkt++; 455 | template[i++] = pkt; 456 | pkt = strpbrk(pkt," \r\n"); 457 | if(!pkt) 458 | break; 459 | *pkt++ = '\0'; 460 | } 461 | } 462 | return i; 463 | } 464 | 465 | int SplitIRCParamsPointer(char **ppkt, char **template, unsigned int templatecount, char bAllowTrailing) 466 | { 467 | unsigned int i = 0; 468 | char* pkt; 469 | ASSERT(ppkt); 470 | ASSERT(template); 471 | if(!ppkt || !template) 472 | return 0; 473 | pkt = *ppkt; 474 | if(!pkt) 475 | return -1; 476 | while(*pkt && i < templatecount) 477 | { 478 | if(*pkt == ':') 479 | { 480 | template[i++] = ++pkt; 481 | if(bAllowTrailing) 482 | pkt = strpbrk(pkt,"\r\n"); 483 | else 484 | pkt = strpbrk(pkt," \r\n"); 485 | if(!pkt) 486 | break; 487 | *pkt++ = '\0'; 488 | break; 489 | } 490 | else 491 | { 492 | if(*pkt == ' ') 493 | pkt++; 494 | template[i++] = pkt; 495 | pkt = strpbrk(pkt," \r\n"); 496 | if(!pkt) 497 | break; 498 | *pkt++ = '\0'; 499 | } 500 | } 501 | *ppkt = pkt; 502 | return i; 503 | } 504 | 505 | int SplitIRCPrefixNick(char* strCommand, char** strNick) 506 | { 507 | ASSERT(strCommand); 508 | ASSERT(strNick); 509 | if(!strCommand || !strNick) 510 | return 0; 511 | if(*strCommand == ':') 512 | { 513 | char* str = strpbrk(++strCommand,"! "); 514 | if(str) 515 | { 516 | *strNick = strCommand; 517 | *str = '\0'; 518 | return 1; 519 | } 520 | } 521 | *strNick = 0; 522 | return 0; 523 | } 524 | 525 | int SplitIRCPrefix(char* strCommand, char** strPrefix) 526 | { 527 | ASSERT(strCommand); 528 | ASSERT(strPrefix); 529 | if(!strCommand || !strPrefix) 530 | return 0; 531 | if(*strCommand == ':') 532 | { 533 | char* str = strchr(++strCommand,' '); 534 | if(str) 535 | { 536 | *strPrefix = strCommand; 537 | *str = '\0'; 538 | return 1; 539 | } 540 | } 541 | *strPrefix = 0; 542 | return 0; 543 | } 544 | 545 | 546 | int CompareIRCPrefixNick(const char* strCommand, const char* strNick) 547 | { 548 | int i = strlen(strNick); 549 | ASSERT(strCommand); 550 | ASSERT(strNick); 551 | if(!strCommand || !strNick) 552 | return 0; 553 | if(*strCommand != ':') 554 | return 0; 555 | strCommand++; 556 | if(!strncasecmp(strCommand,strNick,i) && (strCommand[i] == '!' || isspace(strCommand[i])) ) 557 | return 1; 558 | return 0; 559 | } 560 | 561 | int CompareIRCAddressNick(const char* strParams, const char* strNick) 562 | { 563 | int i = strlen(strNick); 564 | ASSERT(strParams); 565 | ASSERT(strNick); 566 | if(!strParams || !strNick) 567 | return 0; 568 | if(!*strNick) 569 | return 0; 570 | if(*strParams == ':') 571 | strParams++; 572 | if(!strncasecmp(strParams,strNick,i) && isspace(strParams[i]) ) 573 | return 1; 574 | strParams = strchr(strParams,' '); 575 | if(!strParams) 576 | return 0; 577 | strParams++; 578 | if(*strParams == ':') 579 | strParams++; 580 | if(!strncasecmp(strParams,strNick,i) && isspace(strParams[i]) ) 581 | return 1; 582 | return 0; 583 | } 584 | 585 | char* NextArg(char **pkt) 586 | { 587 | char* strReturn; 588 | ASSERT(pkt); 589 | ASSERT(*pkt); 590 | if(!pkt || !*pkt) 591 | return 0; 592 | while (isspace (**pkt)) 593 | (*pkt)++; 594 | if (**pkt == '"') 595 | { 596 | strReturn = ++(*pkt); 597 | *pkt = strchr (*pkt, '"'); 598 | if (!*pkt || !**pkt) 599 | { 600 | *pkt = strReturn +strlen(strReturn); 601 | return strReturn; 602 | } 603 | *(*pkt)++ = '\0'; 604 | } 605 | else 606 | { 607 | strReturn = *pkt; 608 | *pkt = strpbrk (*pkt, " \t\r\n"); 609 | if (!*pkt || !**pkt) 610 | { 611 | *pkt = strReturn +strlen(strReturn); 612 | return strReturn; 613 | } 614 | *(*pkt)++ = '\0'; 615 | } 616 | return strReturn; 617 | } 618 | 619 | unsigned int SolveHostname(const char* host) 620 | { 621 | struct in_addr sin_addr; 622 | ASSERT(host); 623 | if(!host) 624 | return 0; 625 | if((sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) 626 | { 627 | struct hostent *pHost; 628 | LogMultiStart("Solving hostname %s... ",host); 629 | if(!(pHost = (struct hostent*)gethostbyname(host))) 630 | { 631 | LogMultiEnd("failed"); 632 | return INADDR_NONE; 633 | } 634 | sin_addr.s_addr = ((struct in_addr*)pHost->h_addr)->s_addr; 635 | LogMultiEnd(iptoa(sin_addr.s_addr)); 636 | } 637 | return sin_addr.s_addr; 638 | } 639 | 640 | unsigned int SolveIP(const char* ip) 641 | { 642 | ASSERT(ip); 643 | if(!ip) 644 | return 0; 645 | return inet_addr(ip); 646 | } 647 | 648 | int BuildFilename(const char* strPath, const char* strFile, char* strOut, unsigned int nSize) 649 | { 650 | ASSERT(strPath); 651 | ASSERT(strFile); 652 | ASSERT(strOut); 653 | ASSERT(nSize > 0); 654 | if(!strPath || !strFile || !strOut || nSize <= 0) 655 | return 0; 656 | if(*strFile == '/') 657 | strformat(strOut,nSize,"%s",strFile); 658 | else if(*strFile == '~') 659 | strformat(strOut,nSize,"%s%s",getenv("HOME"),strFile+1); 660 | else if(*strPath == '~') 661 | strformat(strOut,nSize,"%s%s/%s",getenv("HOME"),strPath+1,strFile); 662 | else 663 | strformat(strOut,nSize,"%s/%s",strPath,strFile); 664 | return 1; 665 | } 666 | 667 | unsigned long atoul(const char* str) 668 | { 669 | /* ASSERT(str); 670 | if(!str) 671 | return 0; 672 | */ if(*str >= '0' && *str <= '9') 673 | { 674 | unsigned long l = *(str++)-'0'; 675 | while(*str >= '0' && *str <= '9') 676 | { 677 | l *= 10; 678 | l += *(str++)-'0'; 679 | } 680 | return l; 681 | } 682 | return 0; 683 | } 684 | 685 | char* strcasestr(const char* str, const char* sea) 686 | { 687 | const char *strcom,*seacom; 688 | /* ASSERT(str); 689 | ASSERT(sea); 690 | if(!str || !sea) 691 | return 0; 692 | */ for(; *str; str++) 693 | if(tolower(*str) == tolower(*sea)) 694 | { 695 | for(seacom = sea+1,strcom = str+1; *seacom && *strcom; seacom++,strcom++) 696 | if(tolower(*strcom) != tolower(*seacom)) 697 | break; 698 | if(!*seacom) 699 | return (char*)str; 700 | } 701 | return 0; 702 | } 703 | 704 | size_t vstrformat(char* str, size_t maxsize, const char* format, va_list ap) 705 | { 706 | size_t size; 707 | 708 | ASSERT(str); 709 | ASSERT(maxsize > 0); 710 | ASSERT(format); 711 | ASSERT(ap); 712 | 713 | maxsize--; 714 | #ifdef _WINDOWS 715 | size = _vsnprintf(str,maxsize,format,ap); 716 | #else 717 | size = vsnprintf(str,maxsize,format,ap); 718 | #endif 719 | if(/*size < 0 || */ size >= maxsize) 720 | { 721 | str[maxsize] = '\0'; 722 | return maxsize; 723 | } 724 | return size; 725 | } 726 | 727 | size_t strformat(char* str, size_t maxsize, const char* format, ...) 728 | { 729 | va_list ap; 730 | size_t size; 731 | 732 | va_start (ap, format); 733 | size = vstrformat(str,maxsize,format,ap); 734 | va_end (ap); 735 | 736 | return size; 737 | } 738 | -------------------------------------------------------------------------------- /src/bounced.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: bounced.c 3 | desciption: main source file 4 | begin: 10/25/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /* HAVE_CONFIG_H */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #if !defined(_WIN32) || defined(__CYGWIN__) 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #if defined(USE_UID) && defined (USE_GID) 30 | #include 31 | #include 32 | #endif /* defined(USE_UID) && defined (USE_GID) */ 33 | #else 34 | #include 35 | #endif /* !defined(_WIN32) || defined(__CYGWIN__) */ 36 | 37 | #include "bounced.h" 38 | 39 | char g_strVersion[sizeof(PACKAGE)+1+sizeof(VERSION)+1]; 40 | char g_strSystem[32]; 41 | time_t g_timeNow = 0; 42 | time_t g_timeStart = 0; 43 | time_t g_timeLastStats = 0; 44 | char* g_strConfigDir = CONFIGDIR; 45 | #ifndef _WINDOWS 46 | int g_nfds = 0; 47 | #endif /* _WINDOWS */ 48 | fd_set g_fdsR; 49 | fd_set g_fdsW; 50 | fd_set g_fdsE; 51 | SOCKET g_sServer = 0; 52 | char g_strOutBuffer[OUTBUFFER]; 53 | char g_strInBuffer[INBUFFER]; 54 | char g_strInBufferCopy[INBUFFER]; 55 | char* g_strCurrentCommand; 56 | unsigned int g_nCurrentCommandLength; 57 | char g_bShutdown = 0; 58 | char g_bUsersChanged = 0; 59 | char g_bConfigChanged = 0; 60 | char* g_strDefaultPrefix = DEFAULT_PREFIX; 61 | char* g_strDefaultChanModes = DEFAULT_CHANMODES; 62 | #ifndef _WINDOWS 63 | unsigned char g_bBackground = 1; 64 | #endif 65 | 66 | double g_dConnections = 0; 67 | double g_dLogins = 0; 68 | double g_dTotalBytesIn = 0; 69 | double g_dTotalBytesOut = 0; 70 | double g_dLastConnections = 0; 71 | double g_dLastLogins = 0; 72 | double g_dLastTotalBytesIn = 0; 73 | double g_dLastTotalBytesOut = 0; 74 | unsigned int g_nLastIncomingTraffic = 0; 75 | unsigned int g_nLastOutgoingTraffic = 0; 76 | 77 | char g_DebugHasMotdCopied = 0;/* 4 debug */ 78 | LIST(MOTD_LIST) g_DebuglistMotd; /* 4 debug */ 79 | MOTDSTR g_DebugMotdStrFirst;/* 4 debug */ 80 | 81 | LIST(CONNECTION_LIST) g_listConnections; 82 | LIST(CONNECTIONASYNC_LIST) g_listConnectionAsyncs; 83 | LIST(FDR_LIST) g_listFDR; 84 | LIST(FDW_LIST) g_listFDW; 85 | LIST(FDE_LIST) g_listFDE; 86 | LIST(CLIENT_LIST) g_listClients; 87 | LIST(SERVER_LIST) g_listServers; 88 | HASHLIST(USER_HASHLIST) g_hashlistUsers; 89 | LIST(MOTD_LIST) g_listMotd; 90 | LIST(MOTDVAR_LIST) g_listMotdVars; 91 | 92 | int Args(int argc, char* argv[]) 93 | { 94 | int i; 95 | for(i = 0; i < argc; i++) 96 | { 97 | if((*argv[i] == '-' || *argv[i] == '/') && argv[i][1] != '\0' && argv[i][2] == '\0') 98 | switch(argv[i][1]) 99 | { 100 | case 'c': 101 | if(i+1 < argc /* && *argv[i+1] != '-' && *argv[i+1] != '/' */) 102 | { 103 | i++; 104 | g_strConfigDir = argv[i]; 105 | } 106 | break; 107 | case 'v': 108 | fprintf(stderr,"%s %s\n",PACKAGE,VERSION); 109 | fprintf(stderr,"Copyright (C) 2003 Colin Graf (addition@users.sourceforge.net)\n"); 110 | exit(0); 111 | break; 112 | 113 | #ifndef _WINDOWS 114 | case 'd': 115 | g_bBackground = 0; 116 | break; 117 | #endif 118 | default: 119 | #ifndef _WINDOWS 120 | fprintf(stderr,"usage: %s [ -d ] [ -c DIR ] [ -h ] [ -v ]\n",PACKAGE); 121 | fputs(" -d run not as a background process (debug)\n", stderr); 122 | #else 123 | fprintf(stderr,"usage: %s [ -c DIR ] [ -h ] [ -v ]\n",PACKAGE); 124 | #endif 125 | fprintf(stderr," -c DIR read config files from DIR (default: %s)\n",CONFIGDIR); 126 | fputs(" -h print this help message\n", stderr); 127 | fputs(" -v display version information\n", stderr); 128 | exit(0); 129 | break; 130 | } 131 | } 132 | 133 | Log("Starting %s %s...",PACKAGE,VERSION); 134 | 135 | /* change umask to something more secure */ 136 | #ifndef _WINDOWS 137 | umask(077); 138 | #endif 139 | 140 | /* switch user */ 141 | #if !defined(_WINDOWS) && defined(USE_UID) && defined (USE_GID) 142 | if(getuid () == 0) 143 | { 144 | unsigned int n; 145 | char *p; 146 | struct passwd *pw; 147 | struct group *gr; 148 | 149 | n = strtol(USE_GID,&p,10); 150 | if(*p) 151 | { 152 | /* probably a string */ 153 | gr = getgrnam(USE_GID); 154 | if(!gr) 155 | { 156 | Log("error: Unable to find gid for group %s",USE_GID); 157 | return 0; 158 | } 159 | n = gr->gr_gid; 160 | } 161 | if(setgid(n)) 162 | { 163 | Log("error: Couldn't switch to group %u",n); 164 | return 0; 165 | } 166 | 167 | n = strtol(USE_UID,&p,10); 168 | if(*p) 169 | { 170 | /* probably a string */ 171 | pw = getpwnam(USE_UID); 172 | if(!pw) 173 | { 174 | Log("error: Unable to find uid for user %s",USE_UID); 175 | return 0; 176 | } 177 | n = pw->pw_uid; 178 | } 179 | if(setuid(n)) 180 | { 181 | Log("error: Couldn't switch to user %u",n); 182 | return 0; 183 | } 184 | 185 | Log("Running as user %s and group %s",USE_UID,USE_GID); 186 | } 187 | #endif /* !defined(_WINDOWS) && defined(USE_UID) && defined (USE_GID) */ 188 | 189 | /* if running in daemon mode, reopen stdout as a log file */ 190 | #ifndef _WINDOWS 191 | if(g_bBackground) 192 | if(!LogOpenFile()) 193 | return 0; 194 | #endif 195 | 196 | /* switch to background */ 197 | #ifndef _WINDOWS 198 | if(g_bBackground) 199 | { 200 | if(fork() == 0) 201 | setsid(); 202 | else 203 | exit(0); 204 | } 205 | #endif /* _WINDOWS */ 206 | 207 | return 1; 208 | } 209 | 210 | 211 | int Init(void) 212 | { 213 | /* zero structs */ 214 | LIST_INIT(CONNECTION_LIST,g_listConnections); 215 | LIST_INIT(CONNECTIONASYNC_LIST,g_listConnectionAsyncs); 216 | LIST_INIT(FDR_LIST,g_listFDR); 217 | LIST_INIT(FDW_LIST,g_listFDW); 218 | LIST_INIT(FDE_LIST,g_listFDE); 219 | LIST_INIT(CLIENT_LIST,g_listClients); 220 | LIST_INIT(SERVER_LIST,g_listServers); 221 | HASHLIST_INIT(USER_HASHLIST,g_hashlistUsers); 222 | LIST_INIT(MOTD_LIST,g_listMotd); 223 | LIST_INIT(MOTDVAR_LIST,g_listMotdVars); 224 | 225 | /* clean fd_sets */ 226 | FD_ZERO(&g_fdsR); 227 | FD_ZERO(&g_fdsW); 228 | FD_ZERO(&g_fdsE); 229 | 230 | /* init debug stuff */ 231 | #ifdef DEBUG 232 | printf("Debug: Enabled!\n"); 233 | #endif 234 | if( !DebugMemoryInit() ) 235 | return 0; 236 | 237 | /* init sockets */ 238 | #ifdef _WINDOWS 239 | { 240 | WSADATA wsaData; 241 | if (WSAStartup(MAKEWORD(1, 1), &wsaData) || 242 | MAKEWORD(1, 1) != wsaData.wVersion) 243 | { 244 | Log("error: WSAStartup failed"); 245 | return 0; 246 | } 247 | } 248 | #endif /*_WINDOWS*/ 249 | 250 | /* hook signals */ 251 | #ifndef _WINDOWS 252 | { 253 | struct sigaction sa; 254 | memset(&sa,0,sizeof(sa)); 255 | sa.sa_handler = SignalHandler; 256 | sigaction(SIGHUP,&sa,0); 257 | sigaction(SIGTERM,&sa,0); 258 | sigaction(SIGINT,&sa,0); 259 | sigaction(SIGUSR1,&sa,0); 260 | sigaction(SIGPIPE,&sa,0); 261 | } 262 | #else 263 | signal(SIGABRT,SignalHandler); 264 | signal(SIGINT,SignalHandler); 265 | signal(SIGBREAK,SignalHandler); 266 | signal(SIGTERM,SignalHandler); 267 | #endif /* _WINDOWS */ 268 | 269 | /* build version string */ 270 | strformat(g_strVersion,sizeof(g_strVersion),"%s %s",PACKAGE,VERSION); 271 | 272 | /* build system info string */ 273 | { 274 | #ifdef _WIN32 275 | DWORD dw = GetVersion(); 276 | #ifdef __CYGWIN__ 277 | char* strCYGWIN = " CYGWIN"; 278 | #else 279 | char* strCYGWIN = ""; 280 | #endif 281 | if(dw < 0x80000000) /* nt, win2k, winxp */ 282 | { 283 | if(LOBYTE(LOWORD(dw)) == 5 && HIBYTE(LOWORD(dw)) == 0) /* win2k */ 284 | strformat(g_strSystem,sizeof(g_strSystem),"Windows 2000%s",strCYGWIN); 285 | else if(LOBYTE(LOWORD(dw)) == 5 && HIBYTE(LOWORD(dw)) == 1) /* winxp */ 286 | strformat(g_strSystem,sizeof(g_strSystem),"Windows XP%s",strCYGWIN); 287 | else 288 | strformat(g_strSystem,sizeof(g_strSystem),"Windows NT %u%s",LOBYTE(LOWORD(dw)),strCYGWIN); 289 | } 290 | else /* win98, win95, win3.1, winme?*/ 291 | { 292 | if(LOBYTE(LOWORD(dw)) == 4 && HIBYTE(LOWORD(dw)) == 1) /* win95 */ 293 | strformat(g_strSystem,sizeof(g_strSystem),"Windows 95%s",strCYGWIN); 294 | if(LOBYTE(LOWORD(dw)) == 4 && HIBYTE(LOWORD(dw)) == 6) /* win98 */ 295 | strformat(g_strSystem,sizeof(g_strSystem),"Windows 98%s",strCYGWIN); 296 | else 297 | strformat(g_strSystem,sizeof(g_strSystem),"Windows %u.%u%s",LOBYTE(LOWORD(dw)),HIBYTE(LOWORD(dw)),strCYGWIN); 298 | } 299 | #else 300 | struct utsname buf; 301 | uname(&buf); 302 | strformat(g_strSystem,sizeof(g_strSystem),buf.release ? "%s %s" : "%s", buf.sysname,buf.release); 303 | #endif 304 | } 305 | 306 | /* init client handler.. (can't go wrong) */ 307 | ClientHandlersInit(); 308 | ServerHandlersInit(); /* same here */ 309 | ProfileHandlersInit(); /* same here */ 310 | 311 | /* load config */ 312 | if(!ConfigLoad(1)) 313 | return 0; 314 | 315 | /* load users */ 316 | if(!UsersLoad()) 317 | return 0; 318 | if(!ProfilesLoad(1)) 319 | return 0; 320 | 321 | /* load motd */ 322 | MotdLoad(); 323 | 324 | return 1; 325 | } 326 | 327 | 328 | void Cleanup(void) 329 | { 330 | ASSERT(g_listConnectionAsyncs.nCount == 0); 331 | LIST_REMOVE_ALL(CONNECTION_LIST,g_listConnections); 332 | ASSERT(g_listFDR.nCount == 0); 333 | ASSERT(g_listFDW.nCount == 0); 334 | ASSERT(g_listFDE.nCount == 0); 335 | 336 | ASSERT(g_listClients.nCount == 0); 337 | ASSERT(g_listServers.nCount == 0); 338 | 339 | HASHLIST_REMOVE_ALL(USER_HASHLIST,g_hashlistUsers); 340 | 341 | MotdFree(); 342 | ASSERT(g_listMotd.nCount == 0); 343 | ASSERT(g_listMotdVars.nCount == 0); 344 | 345 | ConfigFree(); 346 | 347 | #ifdef _WINDOWS 348 | WSACleanup(); 349 | WSACleanup(); 350 | #endif /*_WINDOWS*/ 351 | 352 | /* cleanup debug stuff (look for memory leaks) */ 353 | if( !DebugMemoryCleanup() ) 354 | return; 355 | 356 | Log("Exit"); 357 | } 358 | 359 | void SignalHandler(int iSig) 360 | { 361 | Log("Received signal \"%d\"",iSig); 362 | #ifndef _WINDOWS 363 | switch(iSig) 364 | { 365 | case SIGHUP: 366 | ConfigLoad(0); 367 | MotdLoad(); 368 | break; 369 | case SIGPIPE: /* i have no idea why this signal sometimes appear. in my opinion are all sockets clean when i try to send to them */ 370 | break; /* ignore them. don't let the process die */ 371 | default: 372 | #endif 373 | { 374 | SOCKET s = g_sServer; 375 | g_sServer = 0; 376 | g_bShutdown = 1; 377 | closesocket(s); /* this causes select stop */ 378 | } 379 | #ifndef _WINDOWS 380 | break; 381 | } 382 | #endif 383 | } 384 | 385 | void StatsTimer(void* pData) /* called from timer */ 386 | { 387 | time_t timeDelta; 388 | 389 | timeDelta = g_timeNow-g_timeLastStats; 390 | if(!timeDelta) 391 | timeDelta = 1; 392 | 393 | g_nLastIncomingTraffic = (unsigned int)((g_dTotalBytesIn-g_dLastTotalBytesIn)/timeDelta); 394 | g_nLastOutgoingTraffic = (unsigned int)((g_dTotalBytesOut-g_dLastTotalBytesOut)/timeDelta); 395 | 396 | Log("************************ %s stats ************************",g_strVersion); 397 | strftimet(g_strInBuffer,sizeof(g_strInBuffer),"%A, %d of %B %Y %X",g_timeStart); 398 | Log(" Started: %s",g_strInBuffer); 399 | strftimetspan(g_strInBuffer,sizeof(g_strInBuffer),"%#D days, %#H hours, %#M minutes and %#S seconds",g_timeNow-g_timeStart); 400 | Log(" Uptime: %s",g_strInBuffer); 401 | Log("Total connections: %.0f (%.0f Logins)",g_dConnections,g_dLogins); 402 | Log(" Total traffic: %.0f MB in, %.0f MB out",g_dTotalBytesIn/1048576,g_dTotalBytesOut/1048576); 403 | Log("********************************************************************"); 404 | Log(" Connections: %u (%u Clients, %u Servers)",g_listConnections.nCount,g_listClients.nCount,g_listServers.nCount); 405 | Log(" Users: %u",g_hashlistUsers.nCount); 406 | Log(" Traffic: %.2f kB/s (%.2f kB/s in, %.2f kB/s out)",((double)(g_nLastIncomingTraffic+g_nLastOutgoingTraffic))/1000,((double)g_nLastIncomingTraffic)/1000,((double)g_nLastOutgoingTraffic)/1000); 407 | Log("********************************************************************"); 408 | 409 | #ifdef DEBUG_MEMORY 410 | DebugMemoryShowStats(); 411 | #endif /* DEBUG_MEMORY */ 412 | 413 | g_timeLastStats = g_timeNow; 414 | g_dLastConnections = g_dConnections; 415 | g_dLastLogins = g_dLogins; 416 | g_dLastTotalBytesIn = g_dTotalBytesIn; 417 | g_dLastTotalBytesOut = g_dTotalBytesOut; 418 | 419 | return; 420 | pData = 0; 421 | } 422 | 423 | int main(int argc, char* argv[]) 424 | { 425 | PCONNECTION pCon,pConnection; 426 | struct timeval tv; 427 | fd_set fdsr, fdsw, fdse; 428 | 429 | tv.tv_usec = 0; 430 | 431 | /* get start time */ 432 | g_timeNow = g_timeStart = time(0); 433 | 434 | /* parse args */ 435 | if(!Args(argc,argv)) 436 | return 1; 437 | 438 | Log("*bounce*"); 439 | 440 | /* init */ 441 | if(!Init()) 442 | { 443 | Cleanup(); 444 | return 1; 445 | } 446 | 447 | /* init server socket */ 448 | { 449 | /* create socket */ 450 | if((g_sServer = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET || 451 | !ConnectionSetNonBlocking(g_sServer) || 452 | #ifndef _WINDOWS 453 | !ConnectionSetReuseAddress(g_sServer) || 454 | #endif 455 | !ConnectionSetInterface(g_sServer,(unsigned short)c_nListenPort,SolveIP(c_strListenInterface)) ) 456 | { 457 | if(g_sServer < 0) 458 | Log("error: Couldn't listen on port \"%u\": %s (%u)",c_nListenPort,strerror(ERRNO),ERRNO); 459 | else 460 | closesocket(g_sServer); 461 | Cleanup(); 462 | return 1; 463 | } 464 | 465 | /* listen */ 466 | if(listen(g_sServer, SOMAXCONN) < 0) 467 | { 468 | Log("error: Couldn't listen on port \"%u\": %s (%u)",c_nListenPort,strerror(ERRNO),ERRNO); 469 | if(g_sServer > 0) 470 | closesocket(g_sServer); 471 | Cleanup(); 472 | return 1; 473 | } 474 | 475 | /* add socket to select() */ 476 | #ifndef _WINDOWS 477 | g_nfds = g_sServer+1; 478 | #endif /* _WINDOWS */ 479 | FD_SET(g_sServer, &g_fdsR); 480 | Log("Listening on port \"%u\"",c_nListenPort); 481 | } 482 | 483 | /* dump pid */ 484 | #ifndef _WINDOWS 485 | { 486 | char strFile[MAX_PATH]; 487 | FILE *fp; 488 | /* if(*PIDFILE == '/') 489 | strcpy(strFile,PIDFILE); 490 | else 491 | snprintf(strFile,sizeof(strFile),"%s/%s",g_strConfigDir,PIDFILE); */ 492 | BuildFilename(g_strConfigDir,PIDFILE,strFile,sizeof(strFile)); 493 | if(!(fp = fopen(strFile,"w"))) 494 | { 495 | Log("error: Couldn't open pid file \"%s\"",strFile); 496 | if(g_sServer > 0) 497 | closesocket(g_sServer); 498 | Cleanup(); 499 | return 1; 500 | } 501 | fprintf(fp,"%u",getpid()); 502 | fclose(fp); 503 | } 504 | #endif /* _WINDOWS */ 505 | 506 | /* show stats (just for fun) */ 507 | StatsTimer(&g_timeNow); 508 | 509 | /* maybe there are already connections to close (when dns lookup failed after profile loading) */ 510 | ConnectionsClose(); 511 | 512 | /* select loop */ 513 | while(g_sServer) 514 | { 515 | /* set timeout */ 516 | tv.tv_sec = TimerNext(g_timeNow,60); 517 | 518 | fdsr = g_fdsR; 519 | fdsw = g_fdsW; 520 | fdse = g_fdsE; 521 | 522 | /* wait for any action */ 523 | #ifdef DEBUG 524 | Log("select: Read=%u Write=%u Error=%u Timeout=%u",g_listFDR.nCount+1,g_listFDW.nCount,g_listFDE.nCount,tv.tv_sec); 525 | #endif 526 | if(select(g_nfds,&fdsr, &fdsw, &fdse, &tv) < 0) 527 | { 528 | if(g_sServer) 529 | Log("error: Select returned \"-1\": %s (%u)",strerror(ERRNO),ERRNO); 530 | continue; 531 | } 532 | /* ASSERT(ERRNO == 0); */ 533 | 534 | /* get time */ 535 | g_timeNow = time(0); 536 | 537 | /* new connection? */ 538 | if(FD_ISSET(g_sServer, &fdsr)) 539 | ConnectionsAccept(); 540 | 541 | /* where can i read ? */ 542 | pCon = g_listFDR.pFirst; 543 | while(pCon) 544 | { 545 | if(FD_ISSET(pCon->s,&fdsr)) 546 | { 547 | pConnection = pCon; 548 | pCon = pCon->llFDR.pNext; 549 | ConnectionRead(pConnection); 550 | continue; 551 | } 552 | pCon = pCon->llFDR.pNext; 553 | } 554 | 555 | /* where can i write ? */ 556 | pCon = g_listFDW.pFirst; 557 | while(pCon) 558 | { 559 | if(FD_ISSET(pCon->s,&fdsw)) 560 | { 561 | pConnection = pCon; 562 | pCon = pCon->llFDW.pNext; 563 | ConnectionWrite(pConnection); 564 | continue; 565 | } 566 | pCon = pCon->llFDW.pNext; 567 | } 568 | 569 | /* where r errors? */ 570 | pCon = g_listFDE.pFirst; 571 | while(pCon) 572 | { 573 | if(FD_ISSET(pCon->s,&fdse)) 574 | { 575 | pConnection = pCon; 576 | pCon = pCon->llFDE.pNext; 577 | ConnectionError(pConnection); 578 | continue; 579 | } 580 | pCon = pCon->llFDE.pNext; 581 | } 582 | 583 | TimerExec(g_timeNow); 584 | ConnectionsClose(); 585 | 586 | /* debug.. check if everything is ok */ 587 | #ifdef DEBUG_MEMORY 588 | DebugMemoryCheckBlocks(); 589 | #endif 590 | } 591 | 592 | /* close socket */ 593 | if(g_sServer) 594 | { 595 | closesocket(g_sServer); 596 | g_sServer = 0; 597 | } 598 | Log("Stopped listening"); 599 | g_bShutdown = 1; 600 | 601 | /* dump config stuff */ 602 | ConfigDump(); 603 | UsersDump(); 604 | ProfilesDump(); 605 | 606 | /* show stats at end (just for fun) */ 607 | g_timeNow = time(0); 608 | StatsTimer(&g_timeNow); 609 | 610 | /* delete pid file*/ 611 | #ifndef _WINDOWS 612 | { 613 | char strFile[MAX_PATH]; 614 | /* if(*PIDFILE == '/') 615 | strcpy(strFile,PIDFILE); 616 | else 617 | snprintf(strFile,sizeof(strFile),"%s/%s",g_strConfigDir,PIDFILE); */ 618 | BuildFilename(g_strConfigDir,PIDFILE,strFile,sizeof(strFile)); 619 | if(unlink(strFile)) 620 | Log("error: Couldn't delete pid file \"%s\"",strFile); 621 | } 622 | #endif /* _WINDOWS */ 623 | 624 | /* cleanup */ 625 | Cleanup(); 626 | return 0; 627 | } 628 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., [http://fsf.org/] 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /src/connection.c: -------------------------------------------------------------------------------- 1 | /* 2 | file: connection.c 3 | desciption: handle socket connections 4 | begin: 10/25/03 5 | copyright: (C) 2003 by Colin Graf 6 | email: addition@users.sourceforge.net 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 2 of the License, or 11 | (at your option) any later version. 12 | */ 13 | 14 | #ifdef HAVE_CONFIG_H 15 | #include 16 | #endif /*HAVE_CONFIG_H*/ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #if !defined(_WIN32) || defined(__CYGWIN__) 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #endif /* !defined(_WIN32) || defined(__CYGWIN__) */ 31 | 32 | #include "bounced.h" 33 | 34 | size_t vstrformat(char* str, size_t maxsize, const char* format, va_list ap); 35 | 36 | /* helper functions */ 37 | 38 | int ConnectionSetNonBlocking(SOCKET s) 39 | { 40 | #ifdef _WINDOWS 41 | int val = 1; 42 | #endif 43 | ASSERT(s >= 0); 44 | if(s < 0) 45 | return 0; 46 | #ifdef _WINDOWS 47 | if(ioctlsocket(s,FIONBIO,&val)) 48 | #else 49 | if(fcntl(s,F_SETFL,O_NONBLOCK)) 50 | #endif /* !_WINDOWS */ 51 | { 52 | Log("error: Couldn't set socket to nonblocking: %s (%u)",strerror(ERRNO),ERRNO); 53 | return 0; 54 | } 55 | return 1; 56 | } 57 | 58 | int ConnectionSetKeepAlive(SOCKET s) 59 | { 60 | int val = 1; 61 | ASSERT(s >= 0); 62 | if(s < 0) 63 | return 0; 64 | if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*) & val, sizeof (val)) != 0) 65 | { 66 | Log("error: Couldn't set socket to keepalive: %s (%u)",strerror(ERRNO),ERRNO); 67 | return 0; 68 | } 69 | return 1; 70 | } 71 | 72 | int ConnectionSetReuseAddress(SOCKET s) 73 | { 74 | int val = 1; 75 | ASSERT(s >= 0); 76 | if(s < 0) 77 | return 0; 78 | if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) & val, sizeof (val)) != 0) 79 | { 80 | Log("error: Couldn't set socket to reuse address: %s (%u)",strerror(ERRNO),ERRNO); 81 | return 0; 82 | } 83 | return 1; 84 | } 85 | 86 | int ConnectionSetInterface(SOCKET s, unsigned short sPort, unsigned int nInterfaceIP) 87 | { 88 | struct sockaddr_in sin; 89 | ASSERT(s > 0); 90 | if(s < 0) 91 | return 0; 92 | 93 | /* create sin */ 94 | memset(&sin,0,sizeof(sin)); 95 | sin.sin_family = AF_INET; 96 | sin.sin_port = htons(sPort); 97 | sin.sin_addr.s_addr = (nInterfaceIP == INADDR_NONE) ? INADDR_ANY : nInterfaceIP; 98 | 99 | if((sin.sin_addr.s_addr != INADDR_ANY || sin.sin_port != 0) && 100 | bind(s,(struct sockaddr*)&sin,sizeof(sin)) < 0) 101 | { 102 | Log("error: Couldn't set socket to interface %s:%u: %s (%u)",iptoa(sin.sin_addr.s_addr),htons(sin.sin_port),strerror(ERRNO),ERRNO); 103 | return 0; 104 | } 105 | return 1; 106 | } 107 | 108 | void ConnectionFDRSet(PCONNECTION pConnection) 109 | { 110 | SOCKET s = pConnection->s; 111 | 112 | ASSERT(!pConnection->bClosing); 113 | ASSERT(pConnection->llFDR.ppPreviousNext == 0); 114 | LIST_ADD(FDR_LIST,g_listFDR,pConnection); 115 | 116 | FD_SET(s,&g_fdsR); 117 | #ifndef _WINDOWS 118 | if((int)++s > g_nfds) 119 | g_nfds = s; 120 | #endif /* _WINDOWS */ 121 | } 122 | 123 | void ConnectionFDRClear(PCONNECTION pConnection) 124 | { 125 | SOCKET s = pConnection->s; 126 | 127 | ASSERT(pConnection->llFDR.ppPreviousNext != 0); 128 | LIST_REMOVE_ITEM(FDR_LIST,g_listFDR,pConnection); 129 | pConnection->llFDR.ppPreviousNext = 0; 130 | 131 | FD_CLR(s,&g_fdsR); 132 | #ifndef _WINDOWS 133 | if((int)s+1 >= g_nfds) 134 | { 135 | g_nfds = g_sServer; 136 | for(pConnection = g_listFDR.pFirst; pConnection; pConnection = pConnection->llFDR.pNext) 137 | if((int)pConnection->s > g_nfds) 138 | g_nfds = pConnection->s; 139 | g_nfds++; 140 | } 141 | #endif /* _WINDOWS */ 142 | } 143 | 144 | void ConnectionFDWSet(PCONNECTION pConnection) 145 | { 146 | ASSERT(!pConnection->bClosing); 147 | ASSERT(pConnection->llFDW.ppPreviousNext == 0); 148 | LIST_ADD(FDW_LIST,g_listFDW,pConnection); 149 | 150 | FD_SET(pConnection->s,&g_fdsW); 151 | } 152 | 153 | void ConnectionFDWClear(PCONNECTION pConnection) 154 | { 155 | ASSERT(pConnection->llFDW.ppPreviousNext != 0); 156 | LIST_REMOVE_ITEM(FDW_LIST,g_listFDW,pConnection); 157 | pConnection->llFDW.ppPreviousNext = 0; 158 | 159 | FD_CLR(pConnection->s,&g_fdsW); 160 | } 161 | 162 | void ConnectionFDESet(PCONNECTION pConnection) 163 | { 164 | ASSERT(!pConnection->bClosing); 165 | ASSERT(pConnection->llFDE.ppPreviousNext == 0); 166 | LIST_ADD(FDE_LIST,g_listFDE,pConnection); 167 | 168 | FD_SET(pConnection->s,&g_fdsE); 169 | } 170 | 171 | void ConnectionFDEClear(PCONNECTION pConnection) 172 | { 173 | ASSERT(pConnection->llFDE.ppPreviousNext != 0); 174 | LIST_REMOVE_ITEM(FDE_LIST,g_listFDE,pConnection); 175 | pConnection->llFDE.ppPreviousNext = 0; 176 | 177 | FD_CLR(pConnection->s,&g_fdsE); 178 | } 179 | 180 | /* global functions */ 181 | 182 | PCONNECTION ConnectionCreate(SOCKET s, unsigned int nIP, unsigned short sPort, time_t timeConnected, unsigned char cType, void* pData) 183 | { 184 | PCONNECTION pConnection; 185 | 186 | if( !(pConnection = CALLOC(PCONNECTION,1,sizeof(CONNECTION))) ) 187 | { 188 | OUTOFMEMORY; 189 | if(pConnection) 190 | ConnectionFree(pConnection); 191 | return 0; 192 | } 193 | pConnection->s = s; 194 | pConnection->nIP = nIP; 195 | pConnection->nPort = sPort; 196 | pConnection->timeConnected = timeConnected; 197 | pConnection->cType = cType; 198 | pConnection->pData = pData; 199 | 200 | LIST_ADD(CONNECTION_LIST,g_listConnections,pConnection); 201 | 202 | return pConnection; 203 | } 204 | 205 | void ConnectionFree(PCONNECTION pConnection) 206 | { 207 | if(pConnection->cType == CT_CLIENT) 208 | LIST_REMOVE_ITEM(CLIENT_LIST,g_listClients,(PCLIENT)pConnection->pData) 209 | else if(pConnection->cType == CT_SERVER) 210 | LIST_REMOVE_ITEM(SERVER_LIST,g_listServers,(PSERVER)pConnection->pData); 211 | 212 | if(pConnection->llFDR.ppPreviousNext) 213 | ConnectionFDRClear(pConnection); 214 | if(pConnection->llFDW.ppPreviousNext) 215 | ConnectionFDWClear(pConnection); 216 | if(pConnection->llFDE.ppPreviousNext) 217 | ConnectionFDEClear(pConnection); 218 | 219 | if(pConnection->strInBuffer) 220 | FREE(char*,pConnection->strInBuffer); 221 | 222 | if(pConnection->s) 223 | closesocket(pConnection->s); 224 | 225 | FREE(PCONNECTION,pConnection); 226 | } 227 | 228 | void ConnectionCloseAsync(PCONNECTION pConnection) 229 | { 230 | if(pConnection->bClosing) 231 | return; 232 | 233 | pConnection->bClosing = 1; 234 | LIST_ADD(CONNECTIONASYNC_LIST,g_listConnectionAsyncs,pConnection); 235 | 236 | if(pConnection->llFDR.ppPreviousNext) 237 | ConnectionFDRClear(pConnection); 238 | if(pConnection->llFDW.ppPreviousNext) 239 | ConnectionFDWClear(pConnection); 240 | if(pConnection->llFDE.ppPreviousNext) 241 | ConnectionFDEClear(pConnection); 242 | } 243 | 244 | void ConnectionsClose(void) 245 | { 246 | LIST_REMOVE_ALL(CONNECTIONASYNC_LIST,g_listConnectionAsyncs); 247 | } 248 | 249 | int ConnectionConnect(PCONNECTION pConnection, unsigned int nIP, unsigned short sPort, unsigned int nInterfaceIP) 250 | { 251 | SOCKET s; 252 | struct sockaddr_in sin; 253 | 254 | ASSERT(pConnection->s == 0); 255 | ASSERT(!pConnection->bClosing); 256 | 257 | if((s = socket(AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET) 258 | { 259 | ConnectionCloseAsync(pConnection); 260 | return 0; 261 | } 262 | 263 | if( !ConnectionSetNonBlocking(s) || 264 | !ConnectionSetKeepAlive(s) || 265 | #ifndef _WINDOWS 266 | !ConnectionSetReuseAddress(s) || 267 | #endif /*!_WINDOWS*/ 268 | !ConnectionSetInterface(s,0,nInterfaceIP) ) 269 | { 270 | closesocket(s); 271 | ConnectionCloseAsync(pConnection); 272 | return 0; 273 | } 274 | 275 | memset(&sin,0,sizeof(sin)); 276 | sin.sin_family = AF_INET; 277 | sin.sin_port = htons(sPort); 278 | pConnection->nIP = sin.sin_addr.s_addr = nIP; 279 | 280 | if(connect(s,(struct sockaddr*)&sin,sizeof(sin)) < 0) 281 | { 282 | int iErrno = ERRNO; 283 | if(iErrno && iErrno != EINPROGRESS 284 | #ifdef _WINDOWS 285 | && iErrno != EWOULDBLOCK 286 | #endif 287 | ) 288 | { 289 | pConnection->nIP = 0; 290 | closesocket(s); 291 | ConnectionCloseAsync(pConnection); 292 | return 0; 293 | } 294 | } 295 | 296 | pConnection->s = s; 297 | 298 | ConnectionFDRSet(pConnection); 299 | ConnectionFDWSet(pConnection); 300 | ConnectionFDESet(pConnection); 301 | 302 | return 1; 303 | } 304 | 305 | int ConnectionSend(PCONNECTION pConnection, const char* strBuffer, int iLength) 306 | { 307 | ASSERT(pConnection); 308 | ASSERT(strBuffer); 309 | 310 | if( pConnection->bClosing || 311 | pConnection->llFDE.ppPreviousNext ) 312 | return 0; 313 | 314 | if(iLength < 0) 315 | iLength = strlen(strBuffer); 316 | 317 | #ifdef DEBUG_PROTOCOL 318 | /*if(pConnection->nIP == INADDR_LOOPBACK) 319 | { 320 | FILE* fp; 321 | fp = fopen("127.0.0.1.log","a"); 322 | if(fp) 323 | { 324 | fprintf(fp,"%s",strBuffer); 325 | fclose(fp); 326 | } 327 | }*/ 328 | Log("%s < %s",(pConnection->cType == CT_CLIENT) ? (((PCLIENT)pConnection->pData)->strName ? ((PCLIENT)pConnection->pData)->strName : iptoa(pConnection->nIP)) : ((PSERVER)pConnection->pData)->strServer,strBuffer); 329 | #endif /* DEBUG_PROTOCOL */ 330 | 331 | if(pConnection->strOutBuffer) 332 | { 333 | if(pConnection->nOutBuffer-(pConnection->nOutBufferOffset+pConnection->nOutBufferUse) >= (unsigned int)iLength) 334 | { 335 | memcpy(pConnection->strOutBuffer+(pConnection->nOutBufferOffset+pConnection->nOutBufferUse),strBuffer,iLength); 336 | pConnection->nOutBufferUse += iLength; 337 | } 338 | else 339 | { 340 | if(pConnection->nOutBuffer-pConnection->nOutBufferUse >= (unsigned int)iLength) 341 | { 342 | memcpy(pConnection->strOutBuffer,pConnection->strOutBuffer+pConnection->nOutBufferOffset,pConnection->nOutBufferUse); 343 | pConnection->nOutBufferOffset = 0; 344 | memcpy(pConnection->strOutBuffer+pConnection->nOutBufferUse,strBuffer,iLength); 345 | pConnection->nOutBufferUse += iLength; 346 | } 347 | else 348 | { 349 | char* strNew; 350 | pConnection->nOutBuffer = pConnection->nOutBufferUse+iLength; 351 | if( !(strNew = MALLOC(char*,pConnection->nOutBuffer)) ) 352 | { 353 | OUTOFMEMORY; 354 | ConnectionCloseAsync(pConnection); 355 | return 0; 356 | } 357 | memcpy(strNew,pConnection->strOutBuffer+pConnection->nOutBufferOffset,pConnection->nOutBufferUse); 358 | pConnection->nOutBufferOffset = 0; 359 | memcpy(strNew+pConnection->nOutBufferUse,strBuffer,iLength); 360 | pConnection->nOutBufferUse += iLength; 361 | FREE(char*,pConnection->strOutBuffer); 362 | pConnection->strOutBuffer = strNew; 363 | } 364 | } 365 | return 1; 366 | } 367 | else 368 | { 369 | int i; 370 | i = send(pConnection->s,strBuffer,iLength,0); 371 | if(i <= 0) 372 | { 373 | if(i == 0 || ERRNO != EWOULDBLOCK) 374 | { 375 | ConnectionCloseAsync(pConnection); 376 | return 0; 377 | } 378 | i = 0; 379 | } 380 | g_dTotalBytesOut += i; 381 | if(i == iLength) 382 | return 1; 383 | 384 | ASSERT(pConnection->nOutBufferOffset == 0); 385 | ASSERT(pConnection->nOutBuffer == 0); 386 | ASSERT(pConnection->nOutBufferUse == 0); 387 | ASSERT(pConnection->strOutBuffer == 0); 388 | ASSERT(pConnection->llFDW.ppPreviousNext == 0); 389 | 390 | pConnection->nOutBufferUse = iLength-i; 391 | pConnection->nOutBuffer = pConnection->nOutBufferUse; 392 | if( !(pConnection->strOutBuffer = MALLOC(char*,pConnection->nOutBuffer)) ) 393 | { 394 | ConnectionCloseAsync(pConnection); 395 | return 0; 396 | } 397 | memcpy(pConnection->strOutBuffer,strBuffer+i,pConnection->nOutBufferUse); 398 | 399 | ConnectionFDWSet(pConnection); 400 | 401 | return 1; 402 | } 403 | } 404 | 405 | int ConnectionSendFormat(PCONNECTION pConnection, const char* format,...) 406 | { 407 | va_list ap; 408 | unsigned short sLength; 409 | 410 | if(pConnection->bClosing) 411 | return 0; 412 | 413 | va_start (ap, format); 414 | sLength = vstrformat(g_strOutBuffer,sizeof(g_strOutBuffer),format, ap); 415 | va_end (ap); 416 | 417 | return ConnectionSend(pConnection,g_strOutBuffer,sLength); 418 | } 419 | 420 | int ConnectionRead(PCONNECTION pConnection) 421 | { 422 | unsigned int nInBuffer = 0; 423 | int i; 424 | 425 | ASSERT(pConnection->cType == CT_CLIENT || pConnection->cType == CT_SERVER); 426 | 427 | if(pConnection->bClosing) 428 | return 0; 429 | 430 | if(pConnection->strInBuffer) 431 | { 432 | ASSERT(pConnection->nInBuffer); 433 | memcpy(g_strInBuffer,pConnection->strInBuffer,pConnection->nInBuffer); 434 | nInBuffer += pConnection->nInBuffer; 435 | FREE(char*,pConnection->strInBuffer); 436 | pConnection->strInBuffer = 0; 437 | pConnection->nInBuffer = 0; 438 | } 439 | 440 | if((i = recv(pConnection->s,g_strInBuffer+nInBuffer,sizeof(g_strInBuffer)-nInBuffer-1,0)) <= 0) 441 | { 442 | if(i == 0 || ERRNO != EWOULDBLOCK) 443 | { 444 | if(pConnection->llFDE.ppPreviousNext) 445 | return ConnectionError(pConnection); 446 | ConnectionCloseAsync(pConnection); 447 | return 0; 448 | } 449 | i = 0; 450 | } 451 | if(i > 0) 452 | { 453 | char *str,*strStart; 454 | char c; 455 | 456 | g_dTotalBytesIn += i; 457 | nInBuffer += i; 458 | g_strInBuffer[nInBuffer] = '\0'; 459 | 460 | for(strStart = g_strInBuffer; (str = strpbrk(strStart,"\n\r")); strStart = str) 461 | { 462 | str++; 463 | if(isspace(*str)) 464 | str++; 465 | 466 | c = *str; 467 | *str = '\0'; 468 | 469 | #ifdef DEBUG_PROTOCOL 470 | Log("%s > %s",(pConnection->cType == CT_CLIENT) ? (((PCLIENT)pConnection->pData)->strName ? ((PCLIENT)pConnection->pData)->strName : iptoa(pConnection->nIP)) : ((PSERVER)pConnection->pData)->strServer,strStart); 471 | #endif /* DEBUG_PROTOCOL */ 472 | 473 | if(pConnection->cType == CT_CLIENT) 474 | ClientHandleCommand((PCLIENT)pConnection->pData,strStart,str-strStart); 475 | else 476 | ServerHandleCommand((PSERVER)pConnection->pData,strStart,str-strStart); 477 | 478 | #ifdef DEBUG_MEMORY 479 | DebugMemoryCheckBlocks(); /* check if memory ain't brocken after this cmd */ 480 | #endif 481 | 482 | if(pConnection->bClosing) 483 | return 0; 484 | 485 | *str = c; 486 | } 487 | 488 | /* only crap received */ 489 | if(strStart == g_strInBuffer && nInBuffer == sizeof(g_strInBuffer)-1) 490 | { 491 | Log("error: %s in buffer overflow",iptoa(pConnection->nIP)); 492 | ConnectionCloseAsync(pConnection); 493 | return 0; 494 | } 495 | 496 | if(strStart < g_strInBuffer+nInBuffer) 497 | { 498 | pConnection->nInBuffer = nInBuffer-(strStart-g_strInBuffer); 499 | if( !(pConnection->strInBuffer = MALLOC(char*,pConnection->nInBuffer)) ) 500 | { 501 | pConnection->nInBuffer = 0; 502 | OUTOFMEMORY; 503 | ConnectionCloseAsync(pConnection); 504 | return 0; 505 | } 506 | memcpy(pConnection->strInBuffer,strStart,pConnection->nInBuffer); 507 | } 508 | } 509 | else if(nInBuffer) 510 | { 511 | if( !(pConnection->strInBuffer = MALLOC(char*,nInBuffer)) ) 512 | { 513 | OUTOFMEMORY; 514 | ConnectionCloseAsync(pConnection); 515 | return 0; 516 | } 517 | pConnection->nInBuffer = nInBuffer; 518 | memcpy(pConnection->strInBuffer,g_strInBuffer,nInBuffer); 519 | } 520 | 521 | return 1; 522 | } 523 | 524 | int ConnectionWrite(PCONNECTION pConnection) 525 | { 526 | int i; 527 | 528 | if(pConnection->bClosing) /* wenn das connecten unterbrochen wurde, als schon ein write/error selected war */ 529 | return 0; 530 | 531 | if(pConnection->llFDE.ppPreviousNext) 532 | return ConnectionComplete(pConnection); 533 | 534 | ASSERT(pConnection->nOutBuffer); 535 | ASSERT(pConnection->nOutBufferUse); 536 | ASSERT(pConnection->strOutBuffer); 537 | 538 | i = send(pConnection->s,pConnection->strOutBuffer+pConnection->nOutBufferOffset,pConnection->nOutBufferUse,0); 539 | if(i <= 0) 540 | { 541 | if(i == 0 || ERRNO != EWOULDBLOCK) 542 | { 543 | ConnectionCloseAsync(pConnection); 544 | return 0; 545 | } 546 | i = 0; 547 | } 548 | g_dTotalBytesOut += i; 549 | 550 | if((unsigned int)i >= pConnection->nOutBufferUse) 551 | { 552 | pConnection->nOutBufferUse = 0; 553 | pConnection->nOutBufferOffset = 0; 554 | pConnection->nOutBuffer = 0; 555 | FREE(char*,pConnection->strOutBuffer); 556 | pConnection->strOutBuffer = 0; 557 | 558 | ConnectionFDWClear(pConnection); 559 | } 560 | else 561 | { 562 | pConnection->nOutBufferUse -= i; 563 | pConnection->nOutBufferOffset += i; 564 | } 565 | 566 | return 1; 567 | } 568 | 569 | int ConnectionError(PCONNECTION pConnection) 570 | { 571 | ASSERT(pConnection->cType == CT_SERVER); 572 | 573 | if(pConnection->bClosing) /* wenn das connecten unterbrochen wurde, als schon ein write/error selected war */ 574 | return 0; 575 | 576 | ConnectionFDRClear(pConnection); 577 | ConnectionFDEClear(pConnection); 578 | ConnectionFDWClear(pConnection); 579 | 580 | ConnectionCloseAsync(pConnection); 581 | 582 | return 0; 583 | } 584 | 585 | int ConnectionComplete(PCONNECTION pConnection) 586 | { 587 | ConnectionFDEClear(pConnection); 588 | ConnectionFDWClear(pConnection); 589 | 590 | ASSERT(pConnection->cType == CT_SERVER); 591 | 592 | if(!ServerRegister(pConnection->pData)) 593 | return 0; 594 | 595 | return 1; 596 | } 597 | 598 | int ConnectionsAccept(void) 599 | { 600 | /* variables */ 601 | SOCKET s; 602 | struct sockaddr_in sin; 603 | 604 | /* try to accept */ 605 | { 606 | int val = sizeof(sin); 607 | if((s = accept(g_sServer,(struct sockaddr *)&sin,&val)) == INVALID_SOCKET) 608 | return 0; 609 | } 610 | 611 | g_dConnections++; 612 | 613 | /* set nonblocking and keepalive */ 614 | if( !ConnectionSetNonBlocking(s) || 615 | !ConnectionSetKeepAlive(s) ) 616 | { 617 | closesocket(s); 618 | return 0; 619 | } 620 | 621 | /* hard limit reached (i hope this will never happen) */ 622 | if(g_listConnections.nCount+1 >= FD_SETSIZE) 623 | { 624 | closesocket(s); 625 | return 0; 626 | } 627 | 628 | /* create client struct */ 629 | { 630 | PCONNECTION pConnection; 631 | PCLIENT pClient; 632 | 633 | if( !(pClient = ClientCreate()) ) 634 | return 0; 635 | 636 | if(!(pConnection = ConnectionCreate(s,sin.sin_addr.s_addr,ntohs(sin.sin_port),g_timeNow,CT_CLIENT,pClient))) 637 | { 638 | ClientFree(pClient); 639 | closesocket(s); 640 | return 0; /* out of memory */ 641 | } 642 | ConnectionFDRSet(pConnection); 643 | 644 | pClient->pConnection = pConnection; 645 | 646 | #ifdef DEBUG 647 | Log("%s accept",iptoa(pConnection->nIP)); 648 | #endif /* DEBUG */ 649 | 650 | } 651 | 652 | return 1; 653 | } 654 | --------------------------------------------------------------------------------