From 73b9d0c5cb02f0ea8350de28bc3687e0af70ea0f Mon Sep 17 00:00:00 2001 From: brain Date: Thu, 23 Jan 2003 19:45:57 +0000 Subject: [PATCH 1/1] Initial revision git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@132 e03df62e-2008-0410-955e-edbf42e46eb7 --- Makefile.FreeBSD | 32 + Makefile.Linux | 32 + conf/inspire.motd | 12 + conf/inspire.quotes | 174 + conf/inspire.rules | 3 + configure | 333 ++ docs/COPYING | 339 ++ docs/ChangeLog | 49 + docs/SUPPORTED | 62 + docs/inspircd.conf.example | 231 + docs/module-doc/annotated.html | 32 + docs/module-doc/channels_8h-source.html | 146 + docs/module-doc/channels_8h.html | 248 + docs/module-doc/classAdmin-members.html | 19 + docs/module-doc/classAdmin.html | 160 + docs/module-doc/classBanItem-members.html | 20 + docs/module-doc/classBanItem.html | 34 + docs/module-doc/classBanItem.png | Bin 0 -> 303 bytes .../module-doc/classConfigReader-members.html | 22 + docs/module-doc/classConfigReader.html | 324 ++ .../module-doc/classConnectClass-members.html | 18 + docs/module-doc/classConnectClass.html | 106 + docs/module-doc/classExemptItem-members.html | 20 + docs/module-doc/classExemptItem.html | 34 + docs/module-doc/classExemptItem.png | Bin 0 -> 333 bytes docs/module-doc/classFileReader-members.html | 22 + docs/module-doc/classFileReader.html | 312 ++ docs/module-doc/classHostItem-members.html | 20 + docs/module-doc/classHostItem.html | 185 + docs/module-doc/classHostItem.png | Bin 0 -> 511 bytes docs/module-doc/classInviteItem-members.html | 20 + docs/module-doc/classInviteItem.html | 34 + docs/module-doc/classInviteItem.png | Bin 0 -> 318 bytes docs/module-doc/classInvited-members.html | 16 + docs/module-doc/classInvited.html | 58 + docs/module-doc/classModule-members.html | 22 + docs/module-doc/classModule.html | 315 ++ .../classModuleFactory-members.html | 18 + docs/module-doc/classModuleFactory.html | 134 + docs/module-doc/classServer-members.html | 34 + docs/module-doc/classServer.html | 913 ++++ docs/module-doc/classVersion-members.html | 20 + docs/module-doc/classVersion.html | 191 + docs/module-doc/classchanrec-members.html | 32 + docs/module-doc/classchanrec.html | 534 +++ docs/module-doc/classes.html | 26 + docs/module-doc/classucrec-members.html | 19 + docs/module-doc/classucrec.html | 161 + docs/module-doc/classuserrec-members.html | 47 + docs/module-doc/classuserrec.html | 1085 +++++ docs/module-doc/doxygen.css | 49 + docs/module-doc/doxygen.png | Bin 0 -> 2351 bytes docs/module-doc/files.html | 21 + docs/module-doc/ftv2blank.png | Bin 0 -> 173 bytes docs/module-doc/ftv2doc.png | Bin 0 -> 254 bytes docs/module-doc/ftv2folderclosed.png | Bin 0 -> 258 bytes docs/module-doc/ftv2folderopen.png | Bin 0 -> 260 bytes docs/module-doc/ftv2lastnode.png | Bin 0 -> 232 bytes docs/module-doc/ftv2link.png | Bin 0 -> 357 bytes docs/module-doc/ftv2mlastnode.png | Bin 0 -> 159 bytes docs/module-doc/ftv2mnode.png | Bin 0 -> 193 bytes docs/module-doc/ftv2node.png | Bin 0 -> 234 bytes docs/module-doc/ftv2plastnode.png | Bin 0 -> 164 bytes docs/module-doc/ftv2pnode.png | Bin 0 -> 199 bytes docs/module-doc/ftv2vertline.png | Bin 0 -> 228 bytes docs/module-doc/functions.html | 191 + docs/module-doc/globals.html | 57 + docs/module-doc/hierarchy.html | 34 + docs/module-doc/index.html | 7 + docs/module-doc/main.html | 16 + docs/module-doc/modules_8cpp-source.html | 249 + docs/module-doc/modules_8cpp.html | 24 + docs/module-doc/modules_8h-source.html | 159 + docs/module-doc/modules_8h.html | 96 + docs/module-doc/tree.html | 11 + docs/module-doc/tree.js | 44 + docs/module-doc/treeview.js | 500 ++ docs/module-doc/users_8cpp-source.html | 109 + docs/module-doc/users_8cpp.html | 24 + docs/module-doc/users_8h-source.html | 158 + docs/module-doc/users_8h.html | 239 + include/channels.h | 199 + include/ctables.h | 53 + include/dynamic.h | 114 + include/globals.h | 59 + include/inspircd.h | 94 + include/inspircd_io.h | 43 + include/inspircd_util.h | 14 + include/modules.h | 334 ++ include/users.h | 248 + include/wildcard.h | 7 + makeconf | 693 +++ src/dynamic.cpp | 70 + src/inspircd | Bin 0 -> 245026 bytes src/inspircd.cpp | 4209 +++++++++++++++++ src/inspircd_io.cpp | 371 ++ src/inspircd_util.cpp | 77 + src/modules.cpp | 232 + src/modules/.make | 3 + src/modules/m_cloaking.cpp | 73 + src/modules/m_foobar.cpp | 113 + src/modules/m_randquote.cpp | 89 + src/users.cpp | 92 + src/version.sh | 2 + src/wildcard.cpp | 90 + 105 files changed, 15935 insertions(+) create mode 100644 Makefile.FreeBSD create mode 100644 Makefile.Linux create mode 100644 conf/inspire.motd create mode 100644 conf/inspire.quotes create mode 100644 conf/inspire.rules create mode 100755 configure create mode 100644 docs/COPYING create mode 100644 docs/ChangeLog create mode 100644 docs/SUPPORTED create mode 100644 docs/inspircd.conf.example create mode 100644 docs/module-doc/annotated.html create mode 100644 docs/module-doc/channels_8h-source.html create mode 100644 docs/module-doc/channels_8h.html create mode 100644 docs/module-doc/classAdmin-members.html create mode 100644 docs/module-doc/classAdmin.html create mode 100644 docs/module-doc/classBanItem-members.html create mode 100644 docs/module-doc/classBanItem.html create mode 100644 docs/module-doc/classBanItem.png create mode 100644 docs/module-doc/classConfigReader-members.html create mode 100644 docs/module-doc/classConfigReader.html create mode 100644 docs/module-doc/classConnectClass-members.html create mode 100644 docs/module-doc/classConnectClass.html create mode 100644 docs/module-doc/classExemptItem-members.html create mode 100644 docs/module-doc/classExemptItem.html create mode 100644 docs/module-doc/classExemptItem.png create mode 100644 docs/module-doc/classFileReader-members.html create mode 100644 docs/module-doc/classFileReader.html create mode 100644 docs/module-doc/classHostItem-members.html create mode 100644 docs/module-doc/classHostItem.html create mode 100644 docs/module-doc/classHostItem.png create mode 100644 docs/module-doc/classInviteItem-members.html create mode 100644 docs/module-doc/classInviteItem.html create mode 100644 docs/module-doc/classInviteItem.png create mode 100644 docs/module-doc/classInvited-members.html create mode 100644 docs/module-doc/classInvited.html create mode 100644 docs/module-doc/classModule-members.html create mode 100644 docs/module-doc/classModule.html create mode 100644 docs/module-doc/classModuleFactory-members.html create mode 100644 docs/module-doc/classModuleFactory.html create mode 100644 docs/module-doc/classServer-members.html create mode 100644 docs/module-doc/classServer.html create mode 100644 docs/module-doc/classVersion-members.html create mode 100644 docs/module-doc/classVersion.html create mode 100644 docs/module-doc/classchanrec-members.html create mode 100644 docs/module-doc/classchanrec.html create mode 100644 docs/module-doc/classes.html create mode 100644 docs/module-doc/classucrec-members.html create mode 100644 docs/module-doc/classucrec.html create mode 100644 docs/module-doc/classuserrec-members.html create mode 100644 docs/module-doc/classuserrec.html create mode 100644 docs/module-doc/doxygen.css create mode 100644 docs/module-doc/doxygen.png create mode 100644 docs/module-doc/files.html create mode 100644 docs/module-doc/ftv2blank.png create mode 100644 docs/module-doc/ftv2doc.png create mode 100644 docs/module-doc/ftv2folderclosed.png create mode 100644 docs/module-doc/ftv2folderopen.png create mode 100644 docs/module-doc/ftv2lastnode.png create mode 100644 docs/module-doc/ftv2link.png create mode 100644 docs/module-doc/ftv2mlastnode.png create mode 100644 docs/module-doc/ftv2mnode.png create mode 100644 docs/module-doc/ftv2node.png create mode 100644 docs/module-doc/ftv2plastnode.png create mode 100644 docs/module-doc/ftv2pnode.png create mode 100644 docs/module-doc/ftv2vertline.png create mode 100644 docs/module-doc/functions.html create mode 100644 docs/module-doc/globals.html create mode 100644 docs/module-doc/hierarchy.html create mode 100644 docs/module-doc/index.html create mode 100644 docs/module-doc/main.html create mode 100644 docs/module-doc/modules_8cpp-source.html create mode 100644 docs/module-doc/modules_8cpp.html create mode 100644 docs/module-doc/modules_8h-source.html create mode 100644 docs/module-doc/modules_8h.html create mode 100644 docs/module-doc/tree.html create mode 100644 docs/module-doc/tree.js create mode 100644 docs/module-doc/treeview.js create mode 100644 docs/module-doc/users_8cpp-source.html create mode 100644 docs/module-doc/users_8cpp.html create mode 100644 docs/module-doc/users_8h-source.html create mode 100644 docs/module-doc/users_8h.html create mode 100644 include/channels.h create mode 100644 include/ctables.h create mode 100644 include/dynamic.h create mode 100644 include/globals.h create mode 100644 include/inspircd.h create mode 100644 include/inspircd_io.h create mode 100644 include/inspircd_util.h create mode 100644 include/modules.h create mode 100644 include/users.h create mode 100644 include/wildcard.h create mode 100755 makeconf create mode 100644 src/dynamic.cpp create mode 100644 src/inspircd create mode 100644 src/inspircd.cpp create mode 100644 src/inspircd_io.cpp create mode 100644 src/inspircd_util.cpp create mode 100644 src/modules.cpp create mode 100644 src/modules/.make create mode 100644 src/modules/m_cloaking.cpp create mode 100644 src/modules/m_foobar.cpp create mode 100644 src/modules/m_randquote.cpp create mode 100644 src/users.cpp create mode 100755 src/version.sh create mode 100644 src/wildcard.cpp diff --git a/Makefile.FreeBSD b/Makefile.FreeBSD new file mode 100644 index 000000000..04484d56a --- /dev/null +++ b/Makefile.FreeBSD @@ -0,0 +1,32 @@ +# Insp Main Makefile +# +# +# +# + +CC = g++ +PROGS = inspircd +FLAGS = -fPIC -frtti -O3 +LDLIBS = -ldl +MODPATH = modules/ +MODULES = m_cloaking.so m_foobar.so m_randquote.so +MAKEARGS = 'PROGS=${PROGS}' 'FLAGS=${FLAGS}' 'CC=${CC}' 'LDLIBS=${LDLIBS}' 'MODULES=${MODULES}' + +all : ircd mods + +mods: + make -C src/modules DIRNAME="src/modules" $(MAKEARGS) + mv src/modules/*.so $(MODPATH) + +ircd: + make -C src DIRNAME="src" $(MAKEARGS) + cp src/inspircd bin/inspircd + +clean: + rm -rf src/*.o + rm -rf src/modules/*.o + +modclean: + rm -rf modules/*.so + +squeakyclean: modclean clean diff --git a/Makefile.Linux b/Makefile.Linux new file mode 100644 index 000000000..04484d56a --- /dev/null +++ b/Makefile.Linux @@ -0,0 +1,32 @@ +# Insp Main Makefile +# +# +# +# + +CC = g++ +PROGS = inspircd +FLAGS = -fPIC -frtti -O3 +LDLIBS = -ldl +MODPATH = modules/ +MODULES = m_cloaking.so m_foobar.so m_randquote.so +MAKEARGS = 'PROGS=${PROGS}' 'FLAGS=${FLAGS}' 'CC=${CC}' 'LDLIBS=${LDLIBS}' 'MODULES=${MODULES}' + +all : ircd mods + +mods: + make -C src/modules DIRNAME="src/modules" $(MAKEARGS) + mv src/modules/*.so $(MODPATH) + +ircd: + make -C src DIRNAME="src" $(MAKEARGS) + cp src/inspircd bin/inspircd + +clean: + rm -rf src/*.o + rm -rf src/modules/*.o + +modclean: + rm -rf modules/*.so + +squeakyclean: modclean clean diff --git a/conf/inspire.motd b/conf/inspire.motd new file mode 100644 index 000000000..67df9d3db --- /dev/null +++ b/conf/inspire.motd @@ -0,0 +1,12 @@ + + _____ _____ _____ _____ _ +|_ _| |_ _| | __ \ / ____| | | + | | _ __ ___ _ __ | | | |__) || | __| | + | | | '_ \ / __| | '_ \ | | | _ / | | / _` | + _| |_ | | | | \__ \ | |_) | _| |_ | | \ \ | |____ | (_| | +|_____| |_| |_| |___/ | .__/ |_____| |_| \_\ \_____| \__,_| + __________________| |_______________________________ + |__________________|_|_______________________________| + + Insert something funkeh here + diff --git a/conf/inspire.quotes b/conf/inspire.quotes new file mode 100644 index 000000000..ca406beee --- /dev/null +++ b/conf/inspire.quotes @@ -0,0 +1,174 @@ +Men are from Mars. Women are from Venus. Computers are from hell +Computer /nm./: a device designed to speed and automate errors +Hardware /nm./: the part of the computer that you can kick. +Maniac /n./ An early computer built by nuts. +RAM /abr./: Rarely Adequate Memory. +Programmer /n./ A red-eyed, mumbling mammal capable of conversing with inanimate objects +Multitasking /adj./ 3 PCs and a chair with wheels +Plonk /excl./: The sound a newbie makes as he falls to the bottom of a kill file +hURL /n./: a link to a web site that makes you want to puke +SUPERCOMPUTER: what it sounded like before you bought it. +If it's really a supercomputer, how come the bullets don't bounce off when I shoot it? . The Covert Comic. +A computer is like an Old Testament god, with a lot of rules and no mercy. . Joseph Campbell +I dropped my computer on my foot! That Megahurtz!! +A computer's attention span is as long as it's power cord +586: The average IQ needed to understand a PC +Memory is like an orgasm. It's a lot better if you don't have to fake it +If it jams, force it. If it breaks, it needed replacing anyway. +A bus station is where a bus stops. A train station is where a train stops. On my desk I have a workstation.. +Want to come see my HARD DRIVE ? I promise it isn't 3.5 inches and it ain't floppy. . Geek pick-up line. +If you torture the data enough, it will confess. . Ronald Coase +If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime +ASCII stupid question, get a stupid ANSI! +Use the source, Luke... +Programming is an art form that fights back +MacOS, Windows, BeOS: they're all just Xerox copies +Whenever you think you have a clever programming trick... forget it! +Managing senior programmers is like herding cats. . Dave Platt +Your program is sick ! Shoot it and put it out of its memory +/* You are not expected to understand this */ +To define recursion, we must first define recursion +ERROR: Computer possessed; Load EXOR.SYS ? [Y/N] +Linux is only free if your time is worthless +Linux: find out what you've been missing while you've been rebooting Windows NT +unzip; strip; touch; finger; mount; fsck; more; yes; unmount; sleep +Profanity is the one language all programmers know best +It's 5.50 a.m.... Do you know where your stack pointer is? +#define QUESTION ((bb) || !(bb)) . Shakespeare +The more I C, the less I see. +Confucius say: He who play in root, eventually kill tree. +Unix is the answer, but only if you phrase the question very carefully +C++: Hard to learn and built to stay that way +Java is, in many ways, C++-- . Michael Feldman. +They don't make bugs like Bunny anymore . Olav Mjelde +If debugging is the process of removing software bugs, then programming must be the process of putting them in +When the only tool you own is a hammer, every problem you encounter resembles a nail +System Error: press F13 to continue... +To err is human, but for a real disaster you need a computer +Computers make very fast, very accurate mistakes +Life would be so much easier if we only had the source code +Who is this 'General Failure' and why is he reading my disk? +hAS aNYONE sEEN MY cAPSLOCK kEY? +InspIRCd, now with excessive ammounts of Cheeze +I'm in the computer business, I make Out-Of-Order signs +Kevorkian Virus: helps your computer shut down whenever it wants to. + [OUT OF QUOTES, PLEASE ORDER MORE] +Error, no keyboard . press F1 to continue. +Cannot delete tmp150---3.tmp: There is not enough free disk space. Delete one or more files to free disk space, and then try again +File not found. Should I fake it ? (Y/N) +The definition of an upgrade: Take old bugs out, put new ones in +If it's not on fire, it's a software problem +My software never has bugs. It just develops random features +It's a little-known fact that the Y1K problem caused the Dark Ages +Artificial Intelligence usually beats natural stupidity +Making fun of AOL users is like making fun of the kid in the wheel chair +Daddy, why doesn't this magnet pick up this floppy disk? +Daddy, what does FORMATTING DRIVE C mean? +See daddy ? All the keys are in alphabetical order now. +If you can't beat your computer at chess, do what I did . try kick-boxing. +Enter any 11-digit prime number to continue... +ASCII and ye shall receive. +The web is a dominatrix. Every where I turn, I see little buttons ordering me to Submit. + NO, You cannot dial 999, I'm downloading my mail ;/ +640K ought to be enough for anybody. . Bill Gates, 1981 +Windows not found, [P]arty, [C]elebrate, [D]rink? +English, the Microsoft of languages... +It's been said that Bill Gates named his company after his dick... +Ever notice how fast Windows runs ? -- Neither did I +If at first you don't succeed, work for Microsoft +We are Microsoft. Resistance Is Futile. You Will Be Assimilated +"Microsoft Works." . Oxymoron +Windows isn't a virus, viruses do something +PANIC! buffer = :NickServ WRITE_DB(3). <-- JUST KIDDING! +It just keeps going and going and going and going and goi +All that I know is that nukes are comming from 127.0.0.1 +I know all about the irc and the mirc cops. +M re ink n ed d, ple s r fil +Please refrain from feeding the IRC Operators. Thank you. +I know all about mirc stuff, hmm.. I think this channel is experiencing packet loss.. +MacDonalds claims Macintosh stole their next idea of the iMac +I can't hold her any longer, captain, she's gonna bl.. sorry, got caught up in the moment +I recommend purchasing a Cyrix CPU for testing nuclear meltdowns +Is it an international rule to have the worst picture possible on your driver license? +Have you hugged your services coder, today? +Ever wonder why they make the colon flash on alarm clocks? +Whats this?.. blue screen with a VXD error?!.. I'VE BEEN NUKED! +do-do-bop-doo-doo-do-do-doo.. For those of you who know that song, you have problems.. +be wery wery quiet... hunting wabbit... +I've been IRC Nuked"Great warrior? War does not make one great." - Yoda +"I find your lack of faith.....disturbing." - Darth Vader +"I have a bad feeling about this.."--All of the Star Wars characters. +Can I upgrade my Hard Drive to a WARP drive? +Canadian DOS prompt: EH?\> +Canadian DOS: "Yer sure, eh?" [y/n] +CONGRESS.SYS Corrupted: Re-boot Washington D.C (Y/n)? +I don't have a solution but I admire the problem. +Famous Last Words: Trust me. I know what I'm doing. +Hey Captain, I just created a black ho-÷p!%$û NO CARRIER +I like work ... I can sit and watch it for hours. +Access denied--nah nah na nah nah! +Bad command. Bad, bad command! Sit! Stay! Staaay.. +Error: Keyboard not attached. Press F1 to continue. +*grumble* "You're just supposed to sit here?" +"Hey, what's this button d.." -W. Crusher +"He has become One with Himself!" "He's passed out!" "That too."-B5 +For a funny quote, call back later. +Famous last words: 'You saw a WHAT around the corner?!' +I like work ... I can sit and watch it for hours. +If debugging is the process of removing bugs, then programming must be the process of putting them in. +Copywight 1994 Elmer Fudd. All wights wesewved. +Cannot find REALITY.SYS. Universe halted. +BUFFERS=20 FILES=15 2nd down, 4th quarter, 5 yards to go! +My software never has bugs. It just develops random features. +Why doesn't DOS ever say 'EXCELLENT command or filename!? +Who's General Failure & why's he reading my disk? +Shell to DOS... Come in DOS, do you copy? Shell to DOS... +Computing Definition - Network-Admin: Primary person who just got set up for the blame of the system crash. +An expert is a person who has made all the mistakes which can be made in a very narrow field. +Famous last words: This is the safe way to do it....... +Famous Last Words: Trust me. I know what I'm doing. +Clinton, "I didn't say that - er, well - yes, but I didn't mean..." +CLINTON LEGACY??...even Pharaoh had only ten plagues... +IBM I Bought McIntosh +IBM I Bring Manuals +IBM I've Been Moved +IBM Idolized By Management +IBM Impenetrable Brain Matter +IBM Imperialism By Marketing +IBM Incorrigible Boisterous Mammoth +IBM Inertia Breeds Mediocrity +IBM Ingenuity Becomes Mysterious +IBM Ingrained Batch Mentality +IBM Innovation By Management +IBM Insipid Belligerent Mossbacks +IBM Insipidly Bankrolling Millions +IBM Inspect Before Multiusing +IBM Install Bigger Memory +IBM Institution By Machiavelli +IBM Insultingly Boring Merchandisers +IBM Intellectuals Being Moronized +IBM Intelligence Belittling Meaning +IBM Intimidated, Buffaloed Management +IBM Into Building Money +IBM Intolerant of Beards & Moustaches +IBM Invest Before Multi-tasking +IBM Investigate Baffling Malodor +IBM Irresponsible Behave Multinational +IBM It Beats Mattel +IBM It's a Big Mess +IBM It's Better Manually +IBM Itty Bitty Machine +IBM Institute for Black Magic +100,000 lemmings can't be wrong. +Murphy's Eighth Law: If everything seems to be going well, you have obviously overlooked something. +Rules of the game: Do not believe in miracles - rely on them. +Rules of the game: Any given program, once running, is obsolete. +Computing Definition - Error: What someone else has made when they disagree with your computer output. +Backup not found: (A)bort (R)etry (P)anic +WinErr 653: Multitasking attempted - system confused. +Cannot join #real_life (invite only) +"Unfortunatly, no one can be told what the Matrix is. You have to see it for yourself." - Matrix +"Reality is a thing of the past" - Matrix +"The future will not be user friendly" - Matrix +"The general idea in chat is to make yourself understandable... ..." - Peer +"heh i am talkin to someone...she not dead...yet anyways" - Stinky diff --git a/conf/inspire.rules b/conf/inspire.rules new file mode 100644 index 000000000..e51f0afd9 --- /dev/null +++ b/conf/inspire.rules @@ -0,0 +1,3 @@ +This is the InspIRCd rules file. + +Place any network or server rules here :) diff --git a/configure b/configure new file mode 100755 index 000000000..d3e63a19e --- /dev/null +++ b/configure @@ -0,0 +1,333 @@ +#!/bin/sh +# InspIRCd Configuration Script +# +# Copyright 2003 The ChatSpike Development Team +# +# +# +# $Id$ +# +# Some shell code based on the configure script of IRC Services. +# IRC Services is copyright (c) 1996-2002 Andrew Church. +# E-mail: +# +# +######################################## + +# echo -e "\033[1;37mtest\033[0;37m" + +echo "Configuring default values..." +mkdir fdscount +echo "#include " >> fdscount/fdcounter.c +echo "#include " >> fdscount/fdcounter.c +echo "main()" >> fdscount/fdcounter.c +echo "{" >> fdscount/fdcounter.c +echo " int i;" >> fdscount/fdcounter.c +echo " int s;" >> fdscount/fdcounter.c +echo "" >> fdscount/fdcounter.c +echo " for (i = 1; i <= 10000; i++)" >> fdscount/fdcounter.c +echo " {" >> fdscount/fdcounter.c +echo " s = socket(AF_INET, SOCK_STREAM, 0);" >> fdscount/fdcounter.c +echo " if (s < 0)" >> fdscount/fdcounter.c +echo " {" >> fdscount/fdcounter.c +echo " printf(\"%i\", i + 2);" >> fdscount/fdcounter.c +echo " exit(-1);" >> fdscount/fdcounter.c +echo " }" >> fdscount/fdcounter.c +echo " }" >> fdscount/fdcounter.c +echo "}" >> fdscount/fdcounter.c + +echo "PROGS = fdcounter" >> fdscount/Makefile +echo "OBJS = fdcounter.o" >> fdscount/Makefile +echo "" >> fdscount/Makefile +echo "CC = gcc" >> fdscount/Makefile +echo "CXXFLAGS = -fPIC -frtti -O" >> fdscount/Makefile +echo "" >> fdscount/Makefile +echo "all : \$(PROGS)" >> fdscount/Makefile +echo "" >> fdscount/Makefile +echo "\$(PROGS): \$(OBJS)" >> fdscount/Makefile +echo " \$(CXX) -rdynamic \$^ -o \$@" >> fdscount/Makefile +echo "" >> fdscount/Makefile +echo ".PHONY: clean" >> fdscount/Makefile +echo "clean:" >> fdscount/Makefile +echo " rm -f *.o core" >> fdscount/Makefile + +cd fdscount +make +cd .. + +ME=`pwd` +PERL=`which perl` +CONFIG_DIR=$ME/conf +MODULE_DIR=$ME/modules +MAX_CLIENT=`fdscount/fdcounter` +NICK_LENGT=32 +CHAN_LENGT=64 +MAX_CHANNE=20 +MAXI_MODES=20 + +rm -rf fdscount + +if [ "$PERL" = "" ] ; then + echo "You require perl to run this program." + exit; +fi + + +OSNAME=`(uname -s) 2>/dev/null` || OSNAME="unknown" + +c="" +n="" +if [ "`eval echo -n 'a'`" = "-n a" ] ; then + c="\c" +else + n="-n" +fi + +exists () { # because some shells don't have test -e + if [ -f $1 -o -d $1 -o -p $1 -o -c $1 -o -b $1 ] ; then + return 0 + else + return 1 + fi +} + +clear +echo -e "'\033[1;33m####\033[0;37m:'\033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m::'\033[1;33m######\033[0;37m::'\033[1;33m########\033[0;37m::'\033[1;33m####\033[0;37m:'\033[1;33m########\033[0;37m:::'\033[1;33m######\033[0;37m::'\033[1;33m########\033[0;37m::" +echo -e ". \033[1;33m##\033[0;37m:: \033[1;33m###\033[0;37m:: \033[1;33m##\033[0;37m:'\033[1;33m##\033[0;37m... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:. \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:'\033[1;33m##\033[0;37m... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::..:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::..:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m \033[1;33m##\033[0;37m \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m########\033[0;37m::: \033[1;33m##\033[0;37m:: \033[1;33m########\033[0;37m:: \033[1;33m##\033[0;37m::::::: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m. \033[1;33m####\033[0;37m::..... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.....:::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m.. \033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m::::::: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:. \033[1;33m###\033[0;37m:'\033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m::::::::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m::. \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e "'\033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m::. \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m##\033[0;37m::::::::'\033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m:::. \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m########\033[0;37m::" +echo -e "\033[0;37m\033[0;37m....::..::::..:::......:::..:::::::::....::..:::::..:::......:::........:::" +echo "" +echo -e "\033[1;37mWelcome to the InspIRCd Configuration program!" +echo "" +echo "*** If you are unsure of any of these values, leave it blank for ***" +echo "*** standard settings that will work, and your server will run ***" +echo "*** using them. If you are running this server as part of a ***" +echo "*** larger network, you must consult with your network admins ***" +echo "*** for the proper values to use, or server links will be unstable! ***" +echo -e "\033[0;37m" +echo -e "Press \033[1;37m\033[0;37m to accept the default for any option, or enter" +echo -e "a new value. Please note: You will \033[1;37mHAVE\033[0;37m to read the docs" +echo -e "dir, otherwise you won't have a config file!" +echo "" +echo -e "Your operating system is: \033[1;37m$OSNAME\033[0;37m (`uname -mnr`), fdmax: $MAX_CLIENT" +echo "" + +############################################################################# + + ok=0 + asked=1 + echo "In what directory are the configuration files?" + while [ $ok -eq 0 ] ; do + echo -e $n "[\033[1;32m$CONFIG_DIR\033[0;37m] -> $c" + if read INPUT ; then : ; else echo "" ; exit 1 ; fi + if [ ! "$INPUT" ] ; then + INPUT=$CONFIG_DIR + default=1 + fi + if echo "$INPUT" | grep -q \[\'\"\\\] ; then + echo 'Please use a pathname without the characters: '\'' " \' + elif [ ! "$NO_DIR_CHECK" -a ! -d "$INPUT" ] ; then + if exists "$INPUT" ; then + echo "$INPUT exists, but is not a directory!" + else + echo "$INPUT does not exist. Create it?" + echo -e $n "[\033[1;32my\033[0;37m] $c" + read YN + if [ "$YN" != "n" ] ; then + if mkdir -p "$INPUT" ; then + ok=1 + fi + fi + fi + else + ok=1 + fi + done + CONFIG_DIR=$INPUT + echo "" + + +############################################################################## + + ok=0 + asked=1 + echo "In What directory are the modules to be compiled to?" + while [ $ok -eq 0 ] ; do + echo -e $n "[\033[1;32m$MODULE_DIR\033[0;37m] -> $c" + if read INPUT ; then : ; else echo "" ; exit 1 ; fi + if [ ! "$INPUT" ] ; then + INPUT=$MODULE_DIR + default=1 + fi + if echo "$INPUT" | grep -q \[\'\"\\\] ; then + echo 'Please use a pathname without the characters: '\'' " \' + elif [ ! "$NO_DIR_CHECK" -a ! -d "$INPUT" ] ; then + if exists "$INPUT" ; then + echo "$INPUT exists, but is not a directory!" + else + echo "$INPUT does not exist. Create it?" + echo -e $n "[\033[1;32my\033[0;37m] $c" + read YN + if [ "$YN" != "n" ] ; then + if mkdir -p "$INPUT" ; then + ok=1 + fi + fi + fi + else + ok=1 + fi + done + MODULE_DIR=$INPUT + echo "" + + +############################################################################### + + echo -e "Maximum number of clients at any one time (\033[1;32m1-$MAX_CLIENT\033[0;37m)?" + echo -e $n "[\033[1;32m$MAX_CLIENT\033[0;37m] -> $c" + read cc + if [ "$cc" ] ; then + if [ "$cc" > "$MAX_CLIENT" ] ; then + echo -e "Number entered was above the maximum allowed by your OS." + echo -e "Max clients was set to the highest possible value, \033[1;32m$MAX_CLIENT\033[0;37m" + else + MAX_CLIENT=$cc + fi + fi + echo "" + +############################################################################### + + echo "What is the Maximum length of nicknames?" + echo -e $n "[\033[1;32m$NICK_LENGT\033[0;37m] -> $c" + read cc + if [ "$cc" ] ; then + NICK_LENGT=$cc + fi + echo "" + +############################################################################### + + echo "What is the Maximum length of channel names?" + echo -e $n "[\033[1;32m$CHAN_LENGT\033[0;37m] -> $c" + read cc + if [ "$cc" ] ; then + CHAN_LENGT=$cc + fi + echo "" + +############################################################################### + + echo "What is the Maximum Number of channels a user may Join?" + echo -e $n "[\033[1;32m$MAX_CHANNE\033[0;37m] -> $c" + read cc + if [ "$cc" ] ; then + MAX_CHANNE_LENGT=$cc + fi + echo "" + +############################################################################### + + echo "What is the Maximum number of mode changes in one line?" + echo -e $n "[\033[1;32m$MAXI_MODES\033[0;37m] -> $c" + read cc + if [ "$cc" ] ; then + MAXI_MODES=$cc + fi + echo "" + +############################################################################### + + +echo -e "\033[1;32mPre-build configuration is complete!\033[0;37m" +echo "" +echo -e "\033[0;37mConfig path:\033[1;32m\t\t\t$CONFIG_DIR" +echo -e "\033[0;37mModule path:\033[1;32m\t\t\t$MODULE_DIR" +echo -e "\033[0;37mMax connections:\033[1;32m\t\t$MAX_CLIENT" +echo -e "\033[0;37mMax User Channels\033[1;32m\t\t$MAX_CHANNE" +echo -e "\033[0;37mMax nickname length:\033[1;32m\t\t$NICK_LENGT" +echo -e "\033[0;37mMax channel length:\033[1;32m\t\t$CHAN_LENGT" +echo -e "\033[0;37mMax mode length:\033[1;32m\t\t$MAXI_MODES" +echo -e "\033[0;37m" +echo "Writing inspircd_config.h ..." + + +echo "/* Auto generated by configure, do not modify! */" >inspircd_config.h +echo "" >>inspircd_config.h +echo "#define SYSLOG_FACILITY LOG_DAEMON" >>inspircd_config.h +echo "#define SYSLOG_LEVEL LOG_NOTICE" >>inspircd_config.h +echo "#define CONFIG_FILE \"$CONFIG_DIR/inspircd.conf\"" >>inspircd_config.h +echo "#define MOD_PATH \"$MODULE_DIR\"" >>inspircd_config.h +echo "#define VERSION \"`sh ./version.sh`\"" >>inspircd_config.h +echo "#define MAXCLIENTS $MAX_CLIENT" >>inspircd_config.h +echo "#define NICKMAX $NICK_LENGT" >>inspircd_config.h +echo "#define CHANMAX $CHAN_LENGT" >>inspircd_config.h +echo "#define MAXCHANS $MAX_CHANNE" >>inspircd_config.h +echo "#define MAXMODES $MAXI_MODES" >>inspircd_config.h +echo "#define SYSTEM \"`uname -n -s -r`\"" >>inspircd_config.h +echo "#define MAXBUF 514">>inspircd_config.h +echo "$MODULE_DIR">.modpath + +touch inspircd_config.h +rm -rf *.o core $MOD_PATH/*.so + +echo "" +echo -e "\033[1;32mDetecting modules...\033[0;37m" +MODLINE="" +for module in m_*.cpp ; do + mod=`perl -e '$a='$module';print substr($a,0,length($a)-3)'` + dmod=`perl -e '$a="'$mod'";while (length($a)<30) { $a = "$a ";}; print $a;'` + desc=`perl -e 'open (F, "<'$module'");local($/)=undef;$blah=;$blah=~/\$ModDesc(.*)\*\//;print substr($1,13,length($1));close F;'` + echo -e "Found \033[1;32m$dmod\033[0;37m$desc" + MODLINE="$mod.so $MODLINE" +done +echo "" +echo -e "Module list: \033[1;32m$MODLINE\033[0;37m" +echo "" + + + +echo -e "Writing \033[1;37m${OSNAME}\033[0;37m makefile" + +cp -f Makefile.${OSNAME} Makefile + +echo "" +echo "Do you want to compile the IRCd binaries?" +echo -e $n "[\033[1;32my\033[0;37m] $c" +read YN +if [ "$YN" != "n" ] ; then + echo "" + echo -e "\033[1;32mCompiling...\033[0;37m" + echo "" + cd $ME + make + echo "" + echo "Done!" + echo "" +else + echo "" + echo "Done!" + echo "" + echo -e "To build your server with these settings, please type '\033[1;32mmake\033[0;37m' now." + echo "" + echo -e "*** \033[1;32mRemember to edit your configuration files!!!\033[0;37m ***" + echo "" +fi + + +echo "" +echo "Do you want to run the config file maker?" +echo -e $n "[\033[1;32my\033[0;37m] $c" +read YN +if [ "$YN" != "n" ] ; then + sh makeconf +fi + +echo -e "*** \033[1;32mRemember to edit your configuration files!!!\033[0;37m ***" +echo "" + diff --git a/docs/COPYING b/docs/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/docs/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/docs/ChangeLog b/docs/ChangeLog new file mode 100644 index 000000000..085f93e01 --- /dev/null +++ b/docs/ChangeLog @@ -0,0 +1,49 @@ +1.0 alpha 5 + +* Changed channel array to a hash_map similar to the one used for users, faster and more efficient +* Changed ./configure, no longer asks for hard channel limit (depreciated) +* Added support for users to be disconnected once MAXUSERS is reached +* Changed code a lot, major overhauls for C++ and STL use for added stability and speed +* Changed entire user system to use the hash_map container type instead of an array +* Added /TIME command +* Added /INFO command +* Added restart and die passwords +* Partially implemented /RESTART command +* Fixed amusing bug which allowed partially connected clients to issue commands under the context of other users! *gulp!* (reported again by Craig) +* Fixed SegFault caused when doing a /who 0 or /who * whilst not in channels (Reported by Craig, Fixed by Craig :p) +* Added /who 0 o to display online Opers (Craigs First Scratch of Code :p) +* Fixed Typo in LUSERS (Reported by MrBOFH and CC) +* Fixed Joining Channels withough a # bug. (Reported by MrBOFH) + + +1.0 alpha 4 + +* Fixed parameters bug discovered by Allan +* Fixed /NICK repeating bug found by piggles. +* Added /REHASH command +* Added /LUSERS command +* Added ability to kill -HUP to rehash +* Fixed lock up after ping timeout +* Added system to /VERSION +* Added DNS lookups on connect (*FIXME* this needs to be asyncronous!) +* Fixed IRCop status shown on wrong users +* Fixed socket linger option via setsockopt (can restart faster as sockets arent in use after shutdown!) +* Added operators can now see real userhost in WHOIS +* Added oper-up failed msg to online opers +* Changed layout of /motd command start numeric +* Fixed empty channels are now purged upon user quit +* Changed: support for WHO * as well as WHO 0 (do the same thing) +* Fixed ability to kick users when you arent on the channel :) +* Fixed grammatical error when halfop tries to kick an op, "You must be at least a half-operator" + + +1.0 alpha 3 + +* Fixed problem where nicks containing control codes were allowed +* Added support so that ircd honours channel mode +n +* Added support so that ircd honours channel mode +t +* Fixed linefeeds in middle of line bug (reported by Craig) +* Fixed buffer overflow in channel names (reported by Allan) +* Fixed close() on nonblocking sockets problem +* Added /KILL command >:) +* Added /KICK command diff --git a/docs/SUPPORTED b/docs/SUPPORTED new file mode 100644 index 000000000..c172ccf71 --- /dev/null +++ b/docs/SUPPORTED @@ -0,0 +1,62 @@ +As this release is ALPHA, not everything is supported. Because of this, this +document will show you the commands and modes that are supported in this +version. All commands listed below are as listed in request for comments (RFC) +number 1459, the original IRC documentation. Anything extra to this RFC +(with the exception of commands for loading plugins etc) will be a loadable +module and not implemented in the core. + +Unimplemented user commands: + + WHOWAS + +Unimplimented server to server commands: + + SERVER CONNECT + LINKS SQUIT + +Implemented commands: + + NICK USER + OPER QUIT + JOIN MODE + TOPIC NAMES + LIST KICK + VERSION STATS + TIME ADMIN + INFO PRIVMSG + NOTICE WHO + WHOIS KILL + PING PONG + AWAY REHASH + RESTART SUMMON + USERS WALLOPS + USERHOST ISON + INVITE PASS + TRACE + +------------------------------------------------------------------------------ + +CHANNEL MODES: i,m,n,t,k,l,p,s,o,h**,v +USER MODES: i,w,s,o + +------------------------------------------------------------------------------ + +* WARNING: In this Alpha, RESTART will not work, it will perform the same as /DIE + until implemented. + +** CHANNEL MODE h will be optional, and eventually be enabled or disabled by a stub + module. + +The following features are supported: + + * Dynamic module support + * Object orientated architecture to save memory and increase speed + * Connection multiplexing, one process for all (no forking!) + +The following operating systems are supported: + + * Linux (i386, possibly others) + Tested on: RedHat, Slackware + * FreeBSD (i386, possibly others) + Tested on: 4.7-STABLE + diff --git a/docs/inspircd.conf.example b/docs/inspircd.conf.example new file mode 100644 index 000000000..3402a2c60 --- /dev/null +++ b/docs/inspircd.conf.example @@ -0,0 +1,231 @@ +######################################################################## +# # +# --------------------------- # +# InspIRCd Configuration File # +# --------------------------- # +# # +##################################||#################################### + #||# +##################################||#################################### +# # +# This is an example of the config file for InspIRCd. # +# Change the options to suit your network # +# # +# Last updated on : 30/10/2002 # +# Written by : CC (cc@backchat.co.za) # +# # +######################################################################## + + + +#-#-#-#-#-#-#-#-#-#-#-#- SERVER DESCRIPTION -#-#-#-#-#-#-#-#-#-#-#-#- +# # +# Here is where you enter the information about your server. # +# # +# Syntax is as follows: # +# # +# # + + + + +#-#-#-#-#-#-#-#-#-#-#-#- ADMIN INFORMATION -#-#-#-#-#-#-#-#-#-#-#-# +# # +# Describes the Server Administrator's real name, nick # +# and email address. # +# # +# Syntax is as follows: # +# # +# # + + + + +#-#-#-#-#-#-#-#-#-#-#-#- PORT CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#- +# # +# Enter the port and address bindings here. # +# # +# bind address - specifies which the address which ports bind # +# port - opens an unused port # +# # +# Leaving address empty binds to all available interfaces # +# # +# Syntax is as follows: # +# # +# # + + + + + +#-#-#-#-#-#-#-#-#-#- DIE/RESTART CONFIGURATION -#-#-#-#-#-#-#-#-#-#- +# # +# You can configure the passwords here which you wish to use for # +# the die and restart commands. Only trusted ircops who will # +# need this ability should know the die and restart password. # +# # +# Syntax is as follows: # +# # +# # + + + + +#-#-#-#-#-#-#-#-#-#- CONNECTIONS CONFIGURATION -#-#-#-#-#-#-#-#-#-#- +# # +# This is where you can configure which connections are allowed # +# and denied access onto your server. # +# The password is optional. # +# You may have as many of these as you require. # +# To allow/deny all connections use a * # +# # +# Syntax is as follows: # +# # +# # +# # +# # + + + + + + + +#-#-#-#-#-#-#-#-#-#-#-#- CLASS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#- +# # +# Classes are a group of commands which are grouped together # +# and given a unique name. They used to define which commands # +# are available to certain types of Operators. # +# # +# Syntax is as follow: # +# # +# # + + + + + + + + +#-#-#-#-#-#-#-#-#-#-#-#- OPERATOR COMPOSITION -#-#-#-#-#-#-#-#-#-#-# +# # +# This is where you specify which types of operators you have on # +# your server, as well as the commands they are allowed to use. # +# This works alongside with the classes specified above. # +# # +# type name - a name for the combined class types # +# classes - specified above, used for flexibility for the # +# server admin to decide on which operators get # +# what commands # +# host - hostmask operators will recieve on oper-up # +# # +# Syntax is as follows: # +# # +# # + + + + + + + +#-#-#-#-#-#-#-#-#-#-#- OPERATOR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-# +# # +# Opers are defined here. This is a very important section. # +# Remember to only make operators out of truthworthy people. # +# # +# name - oper name, best to use lower-case # +# password - password to oper-up, # +# encryption not yet available # +# host - host of client allowed to oper-up, more hostmasks # +# seperated by spaces, wildcards accepted # +# type - specified above, defines the kind of operator # +# # +# Syntax is as follows: # +# # +# # + + + + +#-#-#-#-#-#-#-#-#-#- MISCELLANEOUS CONFIGURATION -#-#-#-#-#-#-#-#-#- +# # +# These options let you define the path to your motd and rules # +# files. # +# # + + + + + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- RTFM LINE -#-#-#-#-#-#-#-#-#-#-#-#-#-# +# # +# Just remove this... Its here to make you read ALL of the config # +# file options ;) # + + + + + +#-#-#-#-#-#-#-#-#-#-#-#-#- SERVER OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# +# # +# Settings to define which features are useable on your server. # +# # +# prefixquit - a prefix for a client's quit message # +# debug - provides an in-depth log file, # +# this should not need to be enabled # +# allowhalfop - allows the +h channel mode # +# allowprotect - allows the +a channel mode # +# allowfounder - allows the +q channel mode # +# # + + + + + +#-#-#-#-#-#-#-#-#-#-#-#-#- MODULE OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-# +# # +# These tags define which modules will be loaded on startup by your # +# server. Add modules without any paths. When you make your ircd # +# using the 'make' command, all compiled modules will be moved into # +# the folder you specified when you ran ./configure. The module tag # +# automatically looks for modules in this location. # + + + + + +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- YAWN -#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# # +# You should already know what to do here :) # + + + + +######################################################################### +# # +# -InspIRCd Development and Coding Team- # +# www.inspircd.org # +# # +######################################################################### diff --git a/docs/module-doc/annotated.html b/docs/module-doc/annotated.html new file mode 100644 index 000000000..5e88bcf06 --- /dev/null +++ b/docs/module-doc/annotated.html @@ -0,0 +1,32 @@ + + +Annotated Index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd Compound List

Here are the classes, structs, unions and interfaces with brief descriptions: + + + + + + + + + + + + + + + + +
AdminHolds /ADMIN data This class contains the admin details of the local server
BanItemA subclass of HostItem designed to hold channel bans (+b)
chanrecHolds all relevent information for a channel
ConfigReaderAllows reading of values from configuration files This class allows a module to read from either the main configuration file (inspircd.conf) or from a module-specified configuration file
ConnectClassHolds information relevent to <connect allow> and <connect deny> tags in the config file
ExemptItemA subclass of HostItem designed to hold channel exempts (+e)
FileReaderCaches a text file into memory and can be used to retrieve lines from it
HostItemHolds an entry for a ban list, exemption list, or invite list
InvitedHolds a channel name to which a user has been invited
InviteItemA subclass of HostItem designed to hold channel invites (+I)
ModuleBase class for all InspIRCd modules This class is the base class for InspIRCd modules
ModuleFactoryInstantiates classes inherited from Module This class creates a class inherited from type Module, using new
ServerAllows server output and query functions This class contains methods which allow a module to query the state of the irc server, and produce output to users and other servers
ucrecHolds a user's modes on a channel This class associates a users privilages with a channel by creating a pointer link between a userrec and chanrec class
userrecHolds all information about a user This class stores all information about a user connected to the irc server
VersionHolds a module's Version information The four members (set by the constructor only) indicate details as to the version number of a module
+
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/channels_8h-source.html b/docs/module-doc/channels_8h-source.html new file mode 100644 index 000000000..ba7592c81 --- /dev/null +++ b/docs/module-doc/channels_8h-source.html @@ -0,0 +1,146 @@ + + +channels.h Source File + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

channels.h

Go to the documentation of this file.
00001 /*
+00002 
+00003 $Log$
+00003 Revision 1.1  2003/01/23 19:45:57  brain
+00003 Initial revision
+00003 
+00003 Revision 1.6  2003/01/22 20:59:12  brain
+00003 Added FileReader class documentation
+00003 
+00004 Revision 1.7  2003/01/22 00:44:26  brain
+00005 Added documentation comments
+00006 
+00007 Revision 1.6  2003/01/21 21:11:17  brain
+00008 Added documentation
+00009 
+00010 Revision 1.5  2003/01/16 20:11:55  brain
+00011 fixed some ugly pointer bugs (thanks dblack and a|KK|y!)
+00012 
+00013 Revision 1.4  2003/01/15 22:47:44  brain
+00014 Changed user and channel structs to classes (finally)
+00015 
+00016    
+00017 */
+00018 
+00019 #include "inspircd_config.h"
+00020 #include <time.h>
+00021 #include <vector>
+00022 
+00023 #ifndef __CHANNELS_H__
+00024 #define __CHANNELS_H__
+00025 
+00029 class HostItem
+00030 {
+00031  public:
+00032         time_t set_time;
+00033         char set_by[NICKMAX];
+00034         char data[MAXBUF];
+00035 
+00036         HostItem() { /* stub */ }
+00037         virtual ~HostItem() { /* stub */ }
+00038 };
+00039 
+00040 // banlist is inherited from HostList mainly for readability
+00041 // reasons only
+00042 
+00045 class BanItem : public HostItem
+00046 {
+00047 };
+00048 
+00049 // same with this...
+00050 
+00053 class ExemptItem : public HostItem
+00054 {
+00055 };
+00056 
+00057 // and this...
+00058 
+00061 class InviteItem : public HostItem
+00062 {
+00063 };
+00064 
+00065 
+00068 typedef vector<BanItem>         BanList;
+00069 
+00072 typedef vector<ExemptItem>      ExemptList;
+00073 
+00076 typedef vector<InviteItem>      InviteList;
+00077 
+00082 class chanrec
+00083 {
+00084  public:
+00087         char name[CHANMAX]; /* channel name */
+00091         char custom_modes[MAXMODES];     /* modes handled by modules */
+00095         char topic[MAXBUF];
+00098         time_t created;
+00102         time_t topicset;
+00106         char setby[NICKMAX];
+00107 
+00111         long limit;
+00112         
+00116         char key[32];
+00117         
+00120         short int topiclock;
+00121         
+00124         short int noexternal;
+00125         
+00128         short int inviteonly;
+00129         
+00132         short int moderated;
+00133         
+00137         short int secret;
+00138         
+00142         short int c_private;
+00143         
+00146         BanList bans;
+00147 
+00150         chanrec()
+00151         {
+00152                 strcpy(name,"");
+00153                 strcpy(custom_modes,"");
+00154                 strcpy(topic,"");
+00155                 strcpy(setby,"");
+00156                 strcpy(key,"");
+00157                 created = topicset = limit = 0;
+00158                 topiclock = noexternal = inviteonly = moderated = secret = c_private = false;
+00159         }
+00160 
+00161         virtual ~chanrec() { /* stub */ }
+00162 };
+00163 
+00164 /* used to hold a channel and a users modes on that channel, e.g. +v, +h, +o
+00165  * needs to come AFTER struct chanrec */
+00166 
+00167 #define UCMODE_OP      1
+00168 #define UCMODE_VOICE   2
+00169 #define UCMODE_HOP     4
+00170 #define UCMODE_PROTECT 8
+00171 #define UCMODE_FOUNDER 16
+00172  
+00178 class ucrec
+00179 {
+00180  public:
+00184         long uc_modes;
+00185         
+00189         chanrec *channel;
+00190 
+00191         ucrec() { /* stub */ }
+00192         virtual ~ucrec() { /* stub */ }
+00193 };
+00194 
+00195 #endif
+00196 
+

Generated on Wed Jan 22 20:56:46 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/channels_8h.html b/docs/module-doc/channels_8h.html new file mode 100644 index 000000000..1eadc5857 --- /dev/null +++ b/docs/module-doc/channels_8h.html @@ -0,0 +1,248 @@ + + +channels.h File Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

channels.h File Reference

#include "inspircd_config.h"
+#include <time.h>
+#include <vector>
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Compounds

class  BanItem
 A subclass of HostItem designed to hold channel bans (+b). More...

class  chanrec
 Holds all relevent information for a channel. More...

class  ExemptItem
 A subclass of HostItem designed to hold channel exempts (+e). More...

class  HostItem
 Holds an entry for a ban list, exemption list, or invite list. More...

class  InviteItem
 A subclass of HostItem designed to hold channel invites (+I). More...

class  ucrec
 Holds a user's modes on a channel This class associates a users privilages with a channel by creating a pointer link between a userrec and chanrec class. More...


Defines

#define UCMODE_OP   1
#define UCMODE_VOICE   2
#define UCMODE_HOP   4
#define UCMODE_PROTECT   8
#define UCMODE_FOUNDER   16

Typedefs

typedef vector< BanItemBanList
 Holds a complete ban list.

typedef vector< ExemptItemExemptList
 Holds a complete exempt list.

typedef vector< InviteItemInviteList
 Holds a complete invite list.

+


Define Documentation

+

+ + + + +
+ + +
#define UCMODE_FOUNDER   16 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 171 of file channels.h.

+

+ + + + +
+ + +
#define UCMODE_HOP   4 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 169 of file channels.h.

+

+ + + + +
+ + +
#define UCMODE_OP   1 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 167 of file channels.h.

+

+ + + + +
+ + +
#define UCMODE_PROTECT   8 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 170 of file channels.h.

+

+ + + + +
+ + +
#define UCMODE_VOICE   2 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 168 of file channels.h.

+


Typedef Documentation

+

+ + + + +
+ + +
typedef vector<BanItem> BanList +
+
+ + + + + +
+   + + +

+Holds a complete ban list. +

+ +

+Definition at line 68 of file channels.h.

+

+ + + + +
+ + +
typedef vector<ExemptItem> ExemptList +
+
+ + + + + +
+   + + +

+Holds a complete exempt list. +

+ +

+Definition at line 72 of file channels.h.

+

+ + + + +
+ + +
typedef vector<InviteItem> InviteList +
+
+ + + + + +
+   + + +

+Holds a complete invite list. +

+ +

+Definition at line 76 of file channels.h.

+


Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classAdmin-members.html b/docs/module-doc/classAdmin-members.html new file mode 100644 index 000000000..39b406601 --- /dev/null +++ b/docs/module-doc/classAdmin-members.html @@ -0,0 +1,19 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Admin Member List

This is the complete list of members for Admin, including all inherited members. + + + + +
Admin(string name, string email, string nick)Admin
EmailAdmin
NameAdmin
NickAdmin

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classAdmin.html b/docs/module-doc/classAdmin.html new file mode 100644 index 000000000..663193311 --- /dev/null +++ b/docs/module-doc/classAdmin.html @@ -0,0 +1,160 @@ + + +Admin class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Admin Class Reference

Holds /ADMIN data This class contains the admin details of the local server. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + +

Public Methods

 Admin (string name, string email, string nick)

Public Attributes

const string Name
const string Email
const string Nick
+


Detailed Description

+Holds /ADMIN data This class contains the admin details of the local server. +

+It is constructed by class Server, and has three read-only values, Name, Email and Nick that contain the specified values for the server where the module is running. +

+ +

+Definition at line 67 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Admin::Admin string   name,
string   email,
string   nick
+
+ + + + + +
+   + + +

+ +

+Definition at line 33 of file modules.cpp. +

+

00033 : Name(name), Email(email), Nick(nick) { };
+
+


Member Data Documentation

+

+ + + + +
+ + +
const string Admin::Email +
+
+ + + + + +
+   + + +

+ +

+Definition at line 70 of file modules.h.

+

+ + + + +
+ + +
const string Admin::Name +
+
+ + + + + +
+   + + +

+ +

+Definition at line 70 of file modules.h.

+

+ + + + +
+ + +
const string Admin::Nick +
+
+ + + + + +
+   + + +

+ +

+Definition at line 70 of file modules.h.

+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classBanItem-members.html b/docs/module-doc/classBanItem-members.html new file mode 100644 index 000000000..11295cdc7 --- /dev/null +++ b/docs/module-doc/classBanItem-members.html @@ -0,0 +1,20 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

BanItem Member List

This is the complete list of members for BanItem, including all inherited members. + + + + + +
dataHostItem
HostItem()HostItem [inline]
set_byHostItem
set_timeHostItem
~HostItem()HostItem [inline, virtual]

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classBanItem.html b/docs/module-doc/classBanItem.html new file mode 100644 index 000000000..194010968 --- /dev/null +++ b/docs/module-doc/classBanItem.html @@ -0,0 +1,34 @@ + + +BanItem class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

BanItem Class Reference

A subclass of HostItem designed to hold channel bans (+b). +More... +

+#include <channels.h> +

+

Inheritance diagram for BanItem: +

+ +HostItem + +List of all members. + +
+

Detailed Description

+A subclass of HostItem designed to hold channel bans (+b). +

+ +

+Definition at line 45 of file channels.h.


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classBanItem.png b/docs/module-doc/classBanItem.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a7f35b231ea68485b32d2bfd161cf75718c410 GIT binary patch literal 303 zcmeAS@N?&q;$mQ6;PUiv2?EmAKpeor3?xG>1SEl!M1W6->;M1%fz1E^56qvRFagK{ z;{yi{R3G~P1juD93GxeOaCmkj4ahm>>EaktG3V{2K)xme9<~QxTc7{k>sZaSSo~Ax zZ~23pdQVQ6a^&cOwlu|5`B>>q1)m=Yt$TIkp-$#ffz--&)>Q!p&AOt$*Coz-b!rp4 zvljD-HB*ZxFT2I(fBS&h^~0sz)AwGVqb|N}C5!J@_y0e)e>&%ym&}p(=0nB%2Z=J) zJBmL|_W$SKCT{5Re#7HRsls~;!uuM(%@F8#BWjqs^W|h+W$j*7=C#$cL-c&7wV&t7 wDToPSpC5iTIG-uiZ?gHF@4@wx|91aj@DeEazW9Z_IM7E7p00i_>zopr08+SuYybcN literal 0 HcmV?d00001 diff --git a/docs/module-doc/classConfigReader-members.html b/docs/module-doc/classConfigReader-members.html new file mode 100644 index 000000000..d27bbd43e --- /dev/null +++ b/docs/module-doc/classConfigReader-members.html @@ -0,0 +1,22 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ConfigReader Member List

This is the complete list of members for ConfigReader, including all inherited members. + + + + + + + +
ConfigReader()ConfigReader
ConfigReader(string filename)ConfigReader
Enumerate(string tag)ConfigReader
fnameConfigReader [protected]
ReadValue(string tag, string name, int index)ConfigReader
Verify()ConfigReader
~ConfigReader()ConfigReader

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classConfigReader.html b/docs/module-doc/classConfigReader.html new file mode 100644 index 000000000..f0221a1a1 --- /dev/null +++ b/docs/module-doc/classConfigReader.html @@ -0,0 +1,324 @@ + + +ConfigReader class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ConfigReader Class Reference

Allows reading of values from configuration files This class allows a module to read from either the main configuration file (inspircd.conf) or from a module-specified configuration file. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + + + + + + + + + + + +

Public Methods

 ConfigReader ()
 Default constructor.

 ConfigReader (string filename)
 Overloaded constructor.

 ~ConfigReader ()
 Default destructor.

string ReadValue (string tag, string name, int index)
 Retrieves a value from the config file.

int Enumerate (string tag)
 Counts the number of times a given tag appears in the config file.

bool Verify ()
 Returns true if a config file is valid.


Protected Attributes

string fname
 The filename of the configuration file, as set by the constructor.

+


Detailed Description

+Allows reading of values from configuration files This class allows a module to read from either the main configuration file (inspircd.conf) or from a module-specified configuration file. +

+It may either be instantiated with one parameter or none. Constructing the class using one parameter allows you to specify a path to your own configuration file, otherwise, inspircd.conf is read. +

+ +

+Definition at line 226 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
ConfigReader::ConfigReader  
+
+ + + + + +
+   + + +

+Default constructor. +

+This constructor initialises the ConfigReader class to read the inspircd.conf file as specified when running ./configure. +

+Definition at line 161 of file modules.cpp. +

+References fname. +

+

00162 {
+00163         fname = CONFIG_FILE;
+00164 }
+
+

+ + + + +
+ + + + + + + + + + +
ConfigReader::ConfigReader string   filename
+
+ + + + + +
+   + + +

+Overloaded constructor. +

+This constructor initialises the ConfigReader class to read a user-specified config file +

+Definition at line 172 of file modules.cpp. +

+

00172 : fname(filename) { };
+
+

+ + + + +
+ + + + + + + + + +
ConfigReader::~ConfigReader  
+
+ + + + + +
+   + + +

+Default destructor. +

+This method destroys the ConfigReader class. +

+Definition at line 167 of file modules.cpp. +

+

00168 {
+00169 }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + + +
int ConfigReader::Enumerate string   tag
+
+ + + + + +
+   + + +

+Counts the number of times a given tag appears in the config file. +

+This method counts the number of times a tag appears in a config file, for use where there are several tags of the same kind, e.g. with opers and connect types. It can be used with the index value of ConfigReader::ReadValue to loop through all copies of a multiple instance tag. +

+Definition at line 183 of file modules.cpp. +

+References fname. +

+

00184 {
+00185         return EnumConf(fname.c_str(),tag.c_str());
+00186 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
string ConfigReader::ReadValue string   tag,
string   name,
int   index
+
+ + + + + +
+   + + +

+Retrieves a value from the config file. +

+This method retrieves a value from the config file. Where multiple copies of the tag exist in the config file, index indicates which of the values to retrieve. +

+Definition at line 174 of file modules.cpp. +

+References fname. +

+

00175 {
+00176         char val[MAXBUF];
+00177         ReadConf(fname.c_str(),tag.c_str(),name.c_str(),index,val);
+00178         string s = val;
+00179         return s;
+00180 }
+
+

+ + + + +
+ + + + + + + + + +
bool ConfigReader::Verify  
+
+ + + + + +
+   + + +

+Returns true if a config file is valid. +

+This method is unimplemented and will always return true. +

+Definition at line 189 of file modules.cpp. +

+

00190 {
+00191         return true;
+00192 }
+
+


Member Data Documentation

+

+ + + + +
+ + +
string ConfigReader::fname [protected] +
+
+ + + + + +
+   + + +

+The filename of the configuration file, as set by the constructor. +

+ +

+Definition at line 231 of file modules.h. +

+Referenced by ConfigReader(), Enumerate(), and ReadValue().

+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classConnectClass-members.html b/docs/module-doc/classConnectClass-members.html new file mode 100644 index 000000000..f8b7a913a --- /dev/null +++ b/docs/module-doc/classConnectClass-members.html @@ -0,0 +1,18 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ConnectClass Member List

This is the complete list of members for ConnectClass, including all inherited members. + + + +
hostConnectClass
passConnectClass
typeConnectClass

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classConnectClass.html b/docs/module-doc/classConnectClass.html new file mode 100644 index 000000000..7fd64062e --- /dev/null +++ b/docs/module-doc/classConnectClass.html @@ -0,0 +1,106 @@ + + +ConnectClass class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ConnectClass Class Reference

Holds information relevent to <connect allow> and <connect deny> tags in the config file. +More... +

+#include <users.h> +

+List of all members. + + + + + +

Public Attributes

int type
char host [MAXBUF]
char pass [MAXBUF]
+


Detailed Description

+Holds information relevent to <connect allow> and <connect deny> tags in the config file. +

+ +

+Definition at line 56 of file users.h.


Member Data Documentation

+

+ + + + +
+ + +
char ConnectClass::host[MAXBUF] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 60 of file users.h.

+

+ + + + +
+ + +
char ConnectClass::pass[MAXBUF] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 61 of file users.h.

+

+ + + + +
+ + +
int ConnectClass::type +
+
+ + + + + +
+   + + +

+ +

+Definition at line 59 of file users.h.

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classExemptItem-members.html b/docs/module-doc/classExemptItem-members.html new file mode 100644 index 000000000..37ac533e3 --- /dev/null +++ b/docs/module-doc/classExemptItem-members.html @@ -0,0 +1,20 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ExemptItem Member List

This is the complete list of members for ExemptItem, including all inherited members. + + + + + +
dataHostItem
HostItem()HostItem [inline]
set_byHostItem
set_timeHostItem
~HostItem()HostItem [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classExemptItem.html b/docs/module-doc/classExemptItem.html new file mode 100644 index 000000000..de865231d --- /dev/null +++ b/docs/module-doc/classExemptItem.html @@ -0,0 +1,34 @@ + + +ExemptItem class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ExemptItem Class Reference

A subclass of HostItem designed to hold channel exempts (+e). +More... +

+#include <channels.h> +

+

Inheritance diagram for ExemptItem: +

+ +HostItem + +List of all members. + +
+

Detailed Description

+A subclass of HostItem designed to hold channel exempts (+e). +

+ +

+Definition at line 53 of file channels.h.


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classExemptItem.png b/docs/module-doc/classExemptItem.png new file mode 100644 index 0000000000000000000000000000000000000000..6aa67a9efaaf260fb5d9a2053c1dff80d67f619c GIT binary patch literal 333 zcmeAS@N?&q;$mQ6;PUiv2?EkyKpeor3?zLv|Jx6wBm#UwT>t<74`lxTe_;Ongb6?v z7#}!rp!(4NCqOP^NswPKgTu2MX+X{sPZ!6KiaBpDI|?-`@URAKDm;6h%PIdt+zRdY z^(|~GI~t~KEPK_|v)DyW(PDAsmX@8n&lm3A_2?y+bLU}wksF-cE)Uw*>{)c=WQfNh zfkSgN860=6m^QaN>X0L2wN~D%Zy}eiw{fLkSr==Oys~WZYS*oQGgEn{mb+j5VdKm7 zxMG&o*PhtYt5^4nL>;=(_NpY+)gkX~R%O7`S6r!I*NLw66OLpOd}b5)WV*IWZT@nV zXPNN^DbsF#nfZ;i|N5)B&#h;znRaq&nS6R~t^3<-yT$Vr-Ue;9TwnkD)91fYQww9S dep$YkVOMc`{BA+@OrU=mJYD@<);T3K0RR#zl}7*o literal 0 HcmV?d00001 diff --git a/docs/module-doc/classFileReader-members.html b/docs/module-doc/classFileReader-members.html new file mode 100644 index 000000000..e61cf78d8 --- /dev/null +++ b/docs/module-doc/classFileReader-members.html @@ -0,0 +1,22 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

FileReader Member List

This is the complete list of members for FileReader, including all inherited members. + + + + + + + +
fcFileReader [private]
FileReader()FileReader
FileReader(string filename)FileReader
FileSize()FileReader
GetLine(int x)FileReader
LoadFile(string filename)FileReader
~FileReader()FileReader

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classFileReader.html b/docs/module-doc/classFileReader.html new file mode 100644 index 000000000..ee84a6d74 --- /dev/null +++ b/docs/module-doc/classFileReader.html @@ -0,0 +1,312 @@ + + +FileReader class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

FileReader Class Reference

Caches a text file into memory and can be used to retrieve lines from it. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + + + + + + + + + + +

Public Methods

 FileReader ()
 Default constructor.

 FileReader (string filename)
 Secondary constructor.

 ~FileReader ()
 Default destructor.

void LoadFile (string filename)
 Used to load a file.

string GetLine (int x)
 Retrieve one line from the file.

int FileSize ()
 Returns the size of the file in lines.


Private Attributes

file_cache fc
+


Detailed Description

+Caches a text file into memory and can be used to retrieve lines from it. +

+This class contains methods for read-only manipulation of a text file in memory. Either use the constructor type with one parameter to load a file into memory at construction, or use the LoadFile method to load a file. +

+ +

+Definition at line 271 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
FileReader::FileReader  
+
+ + + + + +
+   + + +

+Default constructor. +

+This method does not load any file into memory, you must use the LoadFile method after constructing the class this way. +

+Definition at line 202 of file modules.cpp. +

+

00203 {
+00204 }
+
+

+ + + + +
+ + + + + + + + + + +
FileReader::FileReader string   filename
+
+ + + + + +
+   + + +

+Secondary constructor. +

+This method initialises the class with a file loaded into it ready for GetLine and and other methods to be called. If the file could not be loaded, FileReader::FileSize returns 0. +

+Definition at line 195 of file modules.cpp. +

+References fc, and file_cache. +

+

00196 {
+00197         file_cache c;
+00198         readfile(c,filename.c_str());
+00199         this->fc = c;
+00200 }
+
+

+ + + + +
+ + + + + + + + + +
FileReader::~FileReader  
+
+ + + + + +
+   + + +

+Default destructor. +

+This deletes the memory allocated to the file. +

+Definition at line 213 of file modules.cpp. +

+

00214 {
+00215 }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + +
int FileReader::FileSize  
+
+ + + + + +
+   + + +

+Returns the size of the file in lines. +

+This method returns the number of lines in the read file. If it is 0, no lines have been read into memory, either because the file is empty or it does not exist, or cannot be opened due to permission problems. +

+Definition at line 224 of file modules.cpp. +

+References fc. +

+

00225 {
+00226         return fc.size();
+00227 }
+
+

+ + + + +
+ + + + + + + + + + +
string FileReader::GetLine int   x
+
+ + + + + +
+   + + +

+Retrieve one line from the file. +

+This method retrieves one line from the text file. If an empty non-NULL string is returned, the index was out of bounds, or the line had no data on it. +

+Definition at line 217 of file modules.cpp. +

+References fc. +

+

00218 {
+00219         if ((x<0) || (x>fc.size()))
+00220                 return "";
+00221         return fc[x];
+00222 }
+
+

+ + + + +
+ + + + + + + + + + +
void FileReader::LoadFile string   filename
+
+ + + + + +
+   + + +

+Used to load a file. +

+This method loads a file into the class ready for GetLine and and other methods to be called. If the file could not be loaded, FileReader::FileSize returns 0. +

+Definition at line 206 of file modules.cpp. +

+References fc, and file_cache. +

+

00207 {
+00208         file_cache c;
+00209         readfile(c,filename.c_str());
+00210         this->fc = c;
+00211 }
+
+


Member Data Documentation

+

+ + + + +
+ + +
file_cache FileReader::fc [private] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 273 of file modules.h. +

+Referenced by FileReader(), FileSize(), GetLine(), and LoadFile().

+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classHostItem-members.html b/docs/module-doc/classHostItem-members.html new file mode 100644 index 000000000..bf8242760 --- /dev/null +++ b/docs/module-doc/classHostItem-members.html @@ -0,0 +1,20 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

HostItem Member List

This is the complete list of members for HostItem, including all inherited members. + + + + + +
dataHostItem
HostItem()HostItem [inline]
set_byHostItem
set_timeHostItem
~HostItem()HostItem [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classHostItem.html b/docs/module-doc/classHostItem.html new file mode 100644 index 000000000..de0e216f6 --- /dev/null +++ b/docs/module-doc/classHostItem.html @@ -0,0 +1,185 @@ + + +HostItem class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

HostItem Class Reference

Holds an entry for a ban list, exemption list, or invite list. +More... +

+#include <channels.h> +

+

Inheritance diagram for HostItem: +

+ +BanItem +ExemptItem +InviteItem + +List of all members. + + + + + + + + +

Public Methods

 HostItem ()
virtual ~HostItem ()

Public Attributes

time_t set_time
char set_by [NICKMAX]
char data [MAXBUF]
+

Detailed Description

+Holds an entry for a ban list, exemption list, or invite list. +

+This class contains a single element in a channel list, such as a banlist. +

+ +

+Definition at line 29 of file channels.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
HostItem::HostItem   [inline]
+
+ + + + + +
+   + + +

+ +

+Definition at line 36 of file channels.h. +

+

00036 { /* stub */ }
+
+

+ + + + +
+ + + + + + + + + +
virtual HostItem::~HostItem   [inline, virtual]
+
+ + + + + +
+   + + +

+ +

+Definition at line 37 of file channels.h. +

+

00037 { /* stub */ }
+
+


Member Data Documentation

+

+ + + + +
+ + +
char HostItem::data[MAXBUF] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 34 of file channels.h.

+

+ + + + +
+ + +
char HostItem::set_by[NICKMAX] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 33 of file channels.h.

+

+ + + + +
+ + +
time_t HostItem::set_time +
+
+ + + + + +
+   + + +

+ +

+Definition at line 32 of file channels.h.

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classHostItem.png b/docs/module-doc/classHostItem.png new file mode 100644 index 0000000000000000000000000000000000000000..99f88aacdf10c0c5425d51b63fafdf34f987e754 GIT binary patch literal 511 zcmVBV-6;#3Kyfv zn{ysW_O(rwC46mJ#X+U_{Pae(id92tXTn$z z6s{{-nKW}iuGjvYY&ysqjn>L2RIZi&n~|-MGFRk8VvU-#pDR{d$kOJ!d4JQ!;rDa{W2l2 + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InviteItem Member List

This is the complete list of members for InviteItem, including all inherited members. + + + + + +
dataHostItem
HostItem()HostItem [inline]
set_byHostItem
set_timeHostItem
~HostItem()HostItem [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classInviteItem.html b/docs/module-doc/classInviteItem.html new file mode 100644 index 000000000..80336bca9 --- /dev/null +++ b/docs/module-doc/classInviteItem.html @@ -0,0 +1,34 @@ + + +InviteItem class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InviteItem Class Reference

A subclass of HostItem designed to hold channel invites (+I). +More... +

+#include <channels.h> +

+

Inheritance diagram for InviteItem: +

+ +HostItem + +List of all members. + +
+

Detailed Description

+A subclass of HostItem designed to hold channel invites (+I). +

+ +

+Definition at line 61 of file channels.h.


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classInviteItem.png b/docs/module-doc/classInviteItem.png new file mode 100644 index 0000000000000000000000000000000000000000..8ebdd840379469dd98c275ea9b3d64cf3c6b44d4 GIT binary patch literal 318 zcmeAS@N?&q;$mQ6;PUiv2?Ej%Kpeor3?!o`=9K{{i2$Dv*Z=?j1DXH-ADBNsVFHi^ z#s>}@s6O=n36RTJ666=m;PC858jy3<)5S5QV$R!1-h9mlJT7m2ug|-4;3d~B?$V=w z`vZ*VvNE!r*^3)p^I_HH@jmD%3Km-aR&rKc=uNr^QrVp_6kd#;#J z2?N6lhj$HTS8p5)`oXk;twi&ak%7%&nH8ZKn?7r*@g2AS`k(pX*7>hYXa5x1Vd~zv zjI*faz(*~;2TXbgS{zhvx7CO>*egH0xy;aEb;ALtO3vu>avYt%w=#5DPgjsT#h`P^ zT8H7%+Ry_!r)3^6Y+$>hczx0_hTsW@7}qytiQ0Z>t}m=p*!3-csd59CN6f6#Ko2r_ My85}Sb4q9e0OVAH_W%F@ literal 0 HcmV?d00001 diff --git a/docs/module-doc/classInvited-members.html b/docs/module-doc/classInvited-members.html new file mode 100644 index 000000000..bd4003b69 --- /dev/null +++ b/docs/module-doc/classInvited-members.html @@ -0,0 +1,16 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Invited Member List

This is the complete list of members for Invited, including all inherited members. + +
channelInvited

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classInvited.html b/docs/module-doc/classInvited.html new file mode 100644 index 000000000..c6d945068 --- /dev/null +++ b/docs/module-doc/classInvited.html @@ -0,0 +1,58 @@ + + +Invited class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Invited Class Reference

Holds a channel name to which a user has been invited. +More... +

+#include <users.h> +

+List of all members. + + + +

Public Attributes

char channel [CHANMAX]
+


Detailed Description

+Holds a channel name to which a user has been invited. +

+ +

+Definition at line 47 of file users.h.


Member Data Documentation

+

+ + + + +
+ + +
char Invited::channel[CHANMAX] +
+
+ + + + + +
+   + + +

+ +

+Definition at line 50 of file users.h. +

+Referenced by userrec::InviteTo().

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classModule-members.html b/docs/module-doc/classModule-members.html new file mode 100644 index 000000000..3a1f87ed4 --- /dev/null +++ b/docs/module-doc/classModule-members.html @@ -0,0 +1,22 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Module Member List

This is the complete list of members for Module, including all inherited members. + + + + + + + +
GetVersion()Module [virtual]
Module()Module
OnUserConnect(userrec *user)Module [virtual]
OnUserJoin(userrec *user, chanrec *channel)Module [virtual]
OnUserPart(userrec *user, chanrec *channel)Module [virtual]
OnUserQuit(userrec *user)Module [virtual]
~Module()Module [virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classModule.html b/docs/module-doc/classModule.html new file mode 100644 index 000000000..519fbeb27 --- /dev/null +++ b/docs/module-doc/classModule.html @@ -0,0 +1,315 @@ + + +Module class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Module Class Reference

Base class for all InspIRCd modules This class is the base class for InspIRCd modules. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + + + + + + + + + + +

Public Methods

 Module ()
 Default constructor creates a module class.

virtual ~Module ()
 Default destructor destroys a module class.

virtual Version GetVersion ()
 Returns the version number of a Module.

virtual void OnUserConnect (userrec *user)
 Called when a user connects.

virtual void OnUserQuit (userrec *user)
 Called when a user quits.

virtual void OnUserJoin (userrec *user, chanrec *channel)
 Called when a user joins a channel.

virtual void OnUserPart (userrec *user, chanrec *channel)
 Called when a user parts a channel.

+


Detailed Description

+Base class for all InspIRCd modules This class is the base class for InspIRCd modules. +

+All modules must inherit from this class, its methods will be called when irc server events occur. class inherited from module must be instantiated by the ModuleFactory class (see relevent section) for the plugin to be initialised. +

+ +

+Definition at line 79 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
Module::Module  
+
+ + + + + +
+   + + +

+Default constructor creates a module class. +

+ +

+Definition at line 40 of file modules.cpp. +

+

00040 { }
+
+

+ + + + +
+ + + + + + + + + +
Module::~Module   [virtual]
+
+ + + + + +
+   + + +

+Default destructor destroys a module class. +

+ +

+Definition at line 41 of file modules.cpp. +

+

00041 { }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + +
Version Module::GetVersion   [virtual]
+
+ + + + + +
+   + + +

+Returns the version number of a Module. +

+The method should return a Version object with its version information assigned via Version::Version +

+Definition at line 46 of file modules.cpp. +

+

00046 { return Version(1,0,0,0); }
+
+

+ + + + +
+ + + + + + + + + + +
void Module::OnUserConnect userrec  user [virtual]
+
+ + + + + +
+   + + +

+Called when a user connects. +

+The details of the connecting user are available to you in the parameter userrec *user +

+Definition at line 42 of file modules.cpp. +

+

00042 { }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
void Module::OnUserJoin userrec  user,
chanrec  channel
[virtual]
+
+ + + + + +
+   + + +

+Called when a user joins a channel. +

+The details of the joining user are available to you in the parameter userrec *user, and the details of the channel they have joined is available in the variable chanrec *channel +

+Definition at line 44 of file modules.cpp. +

+

00044 { }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
void Module::OnUserPart userrec  user,
chanrec  channel
[virtual]
+
+ + + + + +
+   + + +

+Called when a user parts a channel. +

+The details of the leaving user are available to you in the parameter userrec *user, and the details of the channel they have left is available in the variable chanrec *channel +

+Definition at line 45 of file modules.cpp. +

+

00045 { }
+
+

+ + + + +
+ + + + + + + + + + +
void Module::OnUserQuit userrec  user [virtual]
+
+ + + + + +
+   + + +

+Called when a user quits. +

+The details of the exiting user are available to you in the parameter userrec *user +

+Definition at line 43 of file modules.cpp. +

+

00043 { }
+
+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classModuleFactory-members.html b/docs/module-doc/classModuleFactory-members.html new file mode 100644 index 000000000..bd8a7618c --- /dev/null +++ b/docs/module-doc/classModuleFactory-members.html @@ -0,0 +1,18 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ModuleFactory Member List

This is the complete list of members for ModuleFactory, including all inherited members. + + + +
CreateModule()=0ModuleFactory [pure virtual]
ModuleFactory()ModuleFactory [inline]
~ModuleFactory()ModuleFactory [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classModuleFactory.html b/docs/module-doc/classModuleFactory.html new file mode 100644 index 000000000..12bf82cef --- /dev/null +++ b/docs/module-doc/classModuleFactory.html @@ -0,0 +1,134 @@ + + +ModuleFactory class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ModuleFactory Class Reference

Instantiates classes inherited from Module This class creates a class inherited from type Module, using new. +More... +

+#include <modules.h> +

+List of all members. + + + + + + +

Public Methods

 ModuleFactory ()
virtual ~ModuleFactory ()
virtual ModuleCreateModule ()=0
 Creates a new module.

+


Detailed Description

+Instantiates classes inherited from Module This class creates a class inherited from type Module, using new. +

+This is to allow for modules to create many different variants of Module, dependent on architecture, configuration, etc. In most cases, the simple class shown in the example module m_foobar.so will suffice for most modules. +

+ +

+Definition at line 316 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
ModuleFactory::ModuleFactory   [inline]
+
+ + + + + +
+   + + +

+ +

+Definition at line 319 of file modules.h. +

+

00319 { }
+
+

+ + + + +
+ + + + + + + + + +
virtual ModuleFactory::~ModuleFactory   [inline, virtual]
+
+ + + + + +
+   + + +

+ +

+Definition at line 320 of file modules.h. +

+

00320 { }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + +
virtual Module* ModuleFactory::CreateModule   [pure virtual]
+
+ + + + + +
+   + + +

+Creates a new module. +

+Your inherited class of ModuleFactory must return a pointer to your Module class using this method.

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classServer-members.html b/docs/module-doc/classServer-members.html new file mode 100644 index 000000000..63c331106 --- /dev/null +++ b/docs/module-doc/classServer-members.html @@ -0,0 +1,34 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Server Member List

This is the complete list of members for Server, including all inherited members. + + + + + + + + + + + + + + + + + + + +
ChanMode(userrec *User, chanrec *Chan)Server [virtual]
CommonChannels(userrec *u1, userrec *u2)Server [virtual]
Debug(string s)Server [virtual]
FindChannel(string channel)Server [virtual]
FindNick(string nick)Server [virtual]
GetAdmin()Server [virtual]
GetNetworkName()Server [virtual]
GetServerName()Server [virtual]
IsNick(string nick)Server [virtual]
Send(int Socket, string s)Server [virtual]
SendChannel(userrec *User, chanrec *Channel, string s, bool IncludeSender)Server [virtual]
SendCommon(userrec *User, string text, bool IncludeSender)Server [virtual]
SendFrom(int Socket, userrec *User, string s)Server [virtual]
SendOpers(string s)Server [virtual]
SendServ(int Socket, string s)Server [virtual]
SendTo(userrec *Source, userrec *Dest, string s)Server [virtual]
SendWallops(userrec *User, string text)Server [virtual]
Server()Server
~Server()Server [virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classServer.html b/docs/module-doc/classServer.html new file mode 100644 index 000000000..d7a809046 --- /dev/null +++ b/docs/module-doc/classServer.html @@ -0,0 +1,913 @@ + + +Server class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Server Class Reference

Allows server output and query functions This class contains methods which allow a module to query the state of the irc server, and produce output to users and other servers. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Methods

 Server ()
 Default constructor.

virtual ~Server ()
 Default destructor.

virtual void SendOpers (string s)
 Sends text to all opers.

virtual void Debug (string s)
 Sends a debug string.

virtual void Send (int Socket, string s)
 Sends a line of text down a TCP/IP socket.

virtual void SendServ (int Socket, string s)
 Sends text from the server to a socket.

virtual void SendFrom (int Socket, userrec *User, string s)
 Sends text from a user to a socket.

virtual void SendTo (userrec *Source, userrec *Dest, string s)
 Sends text from a user to another user.

virtual void SendChannel (userrec *User, chanrec *Channel, string s, bool IncludeSender)
 Sends text from a user to a channel (mulicast).

virtual bool CommonChannels (userrec *u1, userrec *u2)
 Returns true if two users share a common channel.

virtual void SendCommon (userrec *User, string text, bool IncludeSender)
 Sends text from a user to one or more channels (mulicast).

virtual void SendWallops (userrec *User, string text)
 Sends a WALLOPS message.

virtual bool IsNick (string nick)
 Returns true if a nick is valid.

virtual userrecFindNick (string nick)
 Attempts to look up a nick and return a pointer to it.

virtual chanrecFindChannel (string channel)
 Attempts to look up a channel and return a pointer to it.

virtual string ChanMode (userrec *User, chanrec *Chan)
 Attempts to look up a user's privilages on a channel.

virtual string GetServerName ()
 Returns the server name of the server where the module is loaded.

virtual string GetNetworkName ()
 Returns the network name, global to all linked servers.

virtual Admin GetAdmin ()
 Returns the information of the server as returned by the /ADMIN command.

+


Detailed Description

+Allows server output and query functions This class contains methods which allow a module to query the state of the irc server, and produce output to users and other servers. +

+All modules should instantiate at least one copy of this class, and use its member functions to perform their tasks. +

+ +

+Definition at line 121 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
Server::Server  
+
+ + + + + +
+   + + +

+Default constructor. +

+Creates a Server object. +

+Definition at line 52 of file modules.cpp. +

+

00053 {
+00054 }
+
+

+ + + + +
+ + + + + + + + + +
Server::~Server   [virtual]
+
+ + + + + +
+   + + +

+Default destructor. +

+Destroys a Server object. +

+Definition at line 56 of file modules.cpp. +

+

00057 {
+00058 }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
string Server::ChanMode userrec  User,
chanrec  Chan
[virtual]
+
+ + + + + +
+   + + +

+Attempts to look up a user's privilages on a channel. +

+This function will return a string containing either @, , +, or an empty string, representing the user's privilages upon the channel you specify. +

+Definition at line 139 of file modules.cpp. +

+

00140 {
+00141         string mode = cmode(User,Chan);
+00142         return mode;
+00143 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
bool Server::CommonChannels userrec  u1,
userrec  u2
[virtual]
+
+ + + + + +
+   + + +

+Returns true if two users share a common channel. +

+This method is used internally by the NICK and QUIT commands, and the Server::SendCommon method. +

+Definition at line 102 of file modules.cpp. +

+

00103 {
+00104         return (common_channels(u1,u2) != 0);
+00105 }
+
+

+ + + + +
+ + + + + + + + + + +
void Server::Debug string   s [virtual]
+
+ + + + + +
+   + + +

+Sends a debug string. +

+This method writes a line of text to the debug log. If debugging is disabled in the configuration, this command has no effect. +

+Definition at line 65 of file modules.cpp. +

+

00066 {
+00067         debug("%s",s.c_str());
+00068 }
+
+

+ + + + +
+ + + + + + + + + + +
chanrec * Server::FindChannel string   channel [virtual]
+
+ + + + + +
+   + + +

+Attempts to look up a channel and return a pointer to it. +

+This function will return NULL if the channel does not exist. +

+Definition at line 134 of file modules.cpp. +

+

00135 {
+00136         return FindChan(channel.c_str());
+00137 }
+
+

+ + + + +
+ + + + + + + + + + +
userrec * Server::FindNick string   nick [virtual]
+
+ + + + + +
+   + + +

+Attempts to look up a nick and return a pointer to it. +

+This function will return NULL if the nick does not exist. +

+Definition at line 129 of file modules.cpp. +

+

00130 {
+00131         return Find(nick);
+00132 }
+
+

+ + + + +
+ + + + + + + + + +
Admin Server::GetAdmin   [virtual]
+
+ + + + + +
+   + + +

+Returns the information of the server as returned by the /ADMIN command. +

+See the Admin class for further information of the return value. The members Admin::Nick, Admin::Email and Admin::Name contain the information for the server where the module is loaded. +

+Definition at line 155 of file modules.cpp. +

+

00156 {
+00157         return Admin(getadminname(),getadminemail(),getadminnick());
+00158 }
+
+

+ + + + +
+ + + + + + + + + +
string Server::GetNetworkName   [virtual]
+
+ + + + + +
+   + + +

+Returns the network name, global to all linked servers. +

+ +

+Definition at line 150 of file modules.cpp. +

+

00151 {
+00152         return getnetworkname();
+00153 }
+
+

+ + + + +
+ + + + + + + + + +
string Server::GetServerName   [virtual]
+
+ + + + + +
+   + + +

+Returns the server name of the server where the module is loaded. +

+ +

+Definition at line 145 of file modules.cpp. +

+

00146 {
+00147         return getservername();
+00148 }
+
+

+ + + + +
+ + + + + + + + + + +
bool Server::IsNick string   nick [virtual]
+
+ + + + + +
+   + + +

+Returns true if a nick is valid. +

+Nicks for unregistered connections will return false. +

+Definition at line 124 of file modules.cpp. +

+

00125 {
+00126         return (isnick(nick.c_str()) != 0);
+00127 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
void Server::Send int   Socket,
string   s
[virtual]
+
+ + + + + +
+   + + +

+Sends a line of text down a TCP/IP socket. +

+This method writes a line of text to an established socket, cutting it to 510 characters plus a carriage return and linefeed if required. +

+Definition at line 70 of file modules.cpp. +

+

00071 {
+00072         Write(Socket,"%s",s.c_str());
+00073 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
void Server::SendChannel userrec  User,
chanrec  Channel,
string   s,
bool   IncludeSender
[virtual]
+
+ + + + + +
+   + + +

+Sends text from a user to a channel (mulicast). +

+This method writes a line of text to a channel, with the given user's nick/ident /host combination prepended, as used in PRIVMSG etc commands (see RFC 1459). If the IncludeSender flag is set, then the text is also sent back to the user from which it originated, as seen in MODE (see RFC 1459). +

+Definition at line 90 of file modules.cpp. +

+

00091 {
+00092         if (IncludeSender)
+00093         {
+00094                 WriteChannel(Channel,User,"%s",s.c_str());
+00095         }
+00096         else
+00097         {
+00098                 ChanExceptSender(Channel,User,"%s",s.c_str());
+00099         }
+00100 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
void Server::SendCommon userrec  User,
string   text,
bool   IncludeSender
[virtual]
+
+ + + + + +
+   + + +

+Sends text from a user to one or more channels (mulicast). +

+This method writes a line of text to all users which share a common channel with a given user, with the user's nick/ident/host combination prepended, as used in PRIVMSG etc commands (see RFC 1459). If the IncludeSender flag is set, then the text is also sent back to the user from which it originated, as seen in NICK (see RFC 1459). Otherwise, it is only sent to the other recipients, as seen in QUIT. +

+Definition at line 107 of file modules.cpp. +

+

00108 {
+00109         if (IncludeSender)
+00110         {
+00111                 WriteCommon(User,"%s",text.c_str());
+00112         }
+00113         else
+00114         {
+00115                 WriteCommonExcept(User,"%s",text.c_str());
+00116         }
+00117 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
void Server::SendFrom int   Socket,
userrec  User,
string   s
[virtual]
+
+ + + + + +
+   + + +

+Sends text from a user to a socket. +

+This method writes a line of text to an established socket, with the given user's nick/ident /host combination prepended, as used in PRIVSG etc commands (see RFC 1459) +

+Definition at line 80 of file modules.cpp. +

+

00081 {
+00082         WriteFrom(Socket,User,"%s",s.c_str());
+00083 }
+
+

+ + + + +
+ + + + + + + + + + +
void Server::SendOpers string   s [virtual]
+
+ + + + + +
+   + + +

+Sends text to all opers. +

+This method sends a server notice to all opers with the usermode +s. +

+Definition at line 60 of file modules.cpp. +

+

00061 {
+00062         WriteOpers("%s",s.c_str());
+00063 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
void Server::SendServ int   Socket,
string   s
[virtual]
+
+ + + + + +
+   + + +

+Sends text from the server to a socket. +

+This method writes a line of text to an established socket, with the servername prepended as used by numerics (see RFC 1459) +

+Definition at line 75 of file modules.cpp. +

+

00076 {
+00077         WriteServ(Socket,"%s",s.c_str());
+00078 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
void Server::SendTo userrec  Source,
userrec  Dest,
string   s
[virtual]
+
+ + + + + +
+   + + +

+Sends text from a user to another user. +

+This method writes a line of text to a user, with a user's nick/ident /host combination prepended, as used in PRIVMSG etc commands (see RFC 1459) +

+Definition at line 85 of file modules.cpp. +

+

00086 {
+00087         WriteTo(Source,Dest,"%s",s.c_str());
+00088 }
+
+

+ + + + +
+ + + + + + + + + + + + + + + + + + + +
void Server::SendWallops userrec  User,
string   text
[virtual]
+
+ + + + + +
+   + + +

+Sends a WALLOPS message. +

+This method writes a WALLOPS message to all users with the +w flag, originating from the specified user. +

+Definition at line 119 of file modules.cpp. +

+

00120 {
+00121         WriteWallOps(User,"%s",text.c_str());
+00122 }
+
+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classVersion-members.html b/docs/module-doc/classVersion-members.html new file mode 100644 index 000000000..438f2645f --- /dev/null +++ b/docs/module-doc/classVersion-members.html @@ -0,0 +1,20 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Version Member List

This is the complete list of members for Version, including all inherited members. + + + + + +
BuildVersion
MajorVersion
MinorVersion
RevisionVersion
Version(int major, int minor, int revision, int build)Version

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classVersion.html b/docs/module-doc/classVersion.html new file mode 100644 index 000000000..3c3e53d8c --- /dev/null +++ b/docs/module-doc/classVersion.html @@ -0,0 +1,191 @@ + + +Version class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

Version Class Reference

Holds a module's Version information The four members (set by the constructor only) indicate details as to the version number of a module. +More... +

+#include <modules.h> +

+List of all members. + + + + + + + + +

Public Methods

 Version (int major, int minor, int revision, int build)

Public Attributes

const int Major
const int Minor
const int Revision
const int Build
+


Detailed Description

+Holds a module's Version information The four members (set by the constructor only) indicate details as to the version number of a module. +

+A class of type Version is returned by the GetVersion method of the Module class. +

+ +

+Definition at line 54 of file modules.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Version::Version int   major,
int   minor,
int   revision,
int   build
+
+ + + + + +
+   + + +

+ +

+Definition at line 29 of file modules.cpp. +

+

00029 : Major(major), Minor(minor), Revision(revision), Build(build) { };
+
+


Member Data Documentation

+

+ + + + +
+ + +
const int Version::Build +
+
+ + + + + +
+   + + +

+ +

+Definition at line 57 of file modules.h.

+

+ + + + +
+ + +
const int Version::Major +
+
+ + + + + +
+   + + +

+ +

+Definition at line 57 of file modules.h.

+

+ + + + +
+ + +
const int Version::Minor +
+
+ + + + + +
+   + + +

+ +

+Definition at line 57 of file modules.h.

+

+ + + + +
+ + +
const int Version::Revision +
+
+ + + + + +
+   + + +

+ +

+Definition at line 57 of file modules.h.

+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classchanrec-members.html b/docs/module-doc/classchanrec-members.html new file mode 100644 index 000000000..7d34a88a0 --- /dev/null +++ b/docs/module-doc/classchanrec-members.html @@ -0,0 +1,32 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

chanrec Member List

This is the complete list of members for chanrec, including all inherited members. + + + + + + + + + + + + + + + + + +
banschanrec
c_privatechanrec
chanrec()chanrec [inline]
createdchanrec
custom_modeschanrec
inviteonlychanrec
keychanrec
limitchanrec
moderatedchanrec
namechanrec
noexternalchanrec
secretchanrec
setbychanrec
topicchanrec
topiclockchanrec
topicsetchanrec
~chanrec()chanrec [inline, virtual]

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classchanrec.html b/docs/module-doc/classchanrec.html new file mode 100644 index 000000000..bf8299560 --- /dev/null +++ b/docs/module-doc/classchanrec.html @@ -0,0 +1,534 @@ + + +chanrec class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

chanrec Class Reference

Holds all relevent information for a channel. +More... +

+#include <channels.h> +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Methods

 chanrec ()
 Creates a channel record and initialises it with default values.

virtual ~chanrec ()

Public Attributes

char name [CHANMAX]
 The channels name.

char custom_modes [MAXMODES]
 Custom modes for the channel.

char topic [MAXBUF]
 Channel topic.

time_t created
 Creation time.

time_t topicset
 Time topic was set.

char setby [NICKMAX]
 The last user to set the topic.

long limit
 Contains the channel user limit.

char key [32]
 Contains the channel key.

short int topiclock
 Nonzero if the mode +t is set.

short int noexternal
 Nonzero if the mode +n is set.

short int inviteonly
 Nonzero if the mode +i is set.

short int moderated
 Nonzero if the mode +m is set.

short int secret
 Nonzero if the mode +s is set.

short int c_private
 Nonzero if the mode +p is set.

BanList bans
 The list of all bans set on the channel.

+


Detailed Description

+Holds all relevent information for a channel. +

+This class represents a channel, and contains its name, modes, time created, topic, topic set time, etc, and an instance of the BanList type. +

+ +

+Definition at line 82 of file channels.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
chanrec::chanrec   [inline]
+
+ + + + + +
+   + + +

+Creates a channel record and initialises it with default values. +

+ +

+Definition at line 150 of file channels.h. +

+

00151         {
+00152                 strcpy(name,"");
+00153                 strcpy(custom_modes,"");
+00154                 strcpy(topic,"");
+00155                 strcpy(setby,"");
+00156                 strcpy(key,"");
+00157                 created = topicset = limit = 0;
+00158                 topiclock = noexternal = inviteonly = moderated = secret = c_private = false;
+00159         }
+
+

+ + + + +
+ + + + + + + + + +
virtual chanrec::~chanrec   [inline, virtual]
+
+ + + + + +
+   + + +

+ +

+Definition at line 161 of file channels.h. +

+

00161 { /* stub */ }
+
+


Member Data Documentation

+

+ + + + +
+ + +
BanList chanrec::bans +
+
+ + + + + +
+   + + +

+The list of all bans set on the channel. +

+ +

+Definition at line 146 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::c_private +
+
+ + + + + +
+   + + +

+Nonzero if the mode +p is set. +

+This value cannot be set at the same time as chanrec::secret +

+Definition at line 142 of file channels.h.

+

+ + + + +
+ + +
time_t chanrec::created +
+
+ + + + + +
+   + + +

+Creation time. +

+ +

+Definition at line 98 of file channels.h.

+

+ + + + +
+ + +
char chanrec::custom_modes[MAXMODES] +
+
+ + + + + +
+   + + +

+Custom modes for the channel. +

+Plugins may use this field in any way they see fit. +

+Definition at line 91 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::inviteonly +
+
+ + + + + +
+   + + +

+Nonzero if the mode +i is set. +

+ +

+Definition at line 128 of file channels.h.

+

+ + + + +
+ + +
char chanrec::key[32] +
+
+ + + + + +
+   + + +

+Contains the channel key. +

+If this value is an empty string, there is no channel key in place. +

+Definition at line 116 of file channels.h.

+

+ + + + +
+ + +
long chanrec::limit +
+
+ + + + + +
+   + + +

+Contains the channel user limit. +

+If this value is zero, there is no limit in place. +

+Definition at line 111 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::moderated +
+
+ + + + + +
+   + + +

+Nonzero if the mode +m is set. +

+ +

+Definition at line 132 of file channels.h.

+

+ + + + +
+ + +
char chanrec::name[CHANMAX] +
+
+ + + + + +
+   + + +

+The channels name. +

+ +

+Definition at line 87 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::noexternal +
+
+ + + + + +
+   + + +

+Nonzero if the mode +n is set. +

+ +

+Definition at line 124 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::secret +
+
+ + + + + +
+   + + +

+Nonzero if the mode +s is set. +

+This value cannot be set at the same time as chanrec::c_private +

+Definition at line 137 of file channels.h.

+

+ + + + +
+ + +
char chanrec::setby[NICKMAX] +
+
+ + + + + +
+   + + +

+The last user to set the topic. +

+If this member is an empty string, no topic was ever set. +

+Definition at line 106 of file channels.h.

+

+ + + + +
+ + +
char chanrec::topic[MAXBUF] +
+
+ + + + + +
+   + + +

+Channel topic. +

+If this is an empty string, no channel topic is set. +

+Definition at line 95 of file channels.h.

+

+ + + + +
+ + +
short int chanrec::topiclock +
+
+ + + + + +
+   + + +

+Nonzero if the mode +t is set. +

+ +

+Definition at line 120 of file channels.h.

+

+ + + + +
+ + +
time_t chanrec::topicset +
+
+ + + + + +
+   + + +

+Time topic was set. +

+If no topic was ever set, this will be equal to chanrec::created +

+Definition at line 102 of file channels.h.

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classes.html b/docs/module-doc/classes.html new file mode 100644 index 000000000..d305624f7 --- /dev/null +++ b/docs/module-doc/classes.html @@ -0,0 +1,26 @@ + + +Alphabetical index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd Compound Index

+
  A  
+
ConfigReader   
  H  
+
  M  
+
  U  
+
Admin   ConnectClass   HostItem   Module   ucrec   
  B  
+
  E  
+
  I  
+
ModuleFactory   userrec   
BanItem   ExemptItem   Invited   
  S  
+
  V  
+
  C  
+
  F  
+
InviteItem   Server   Version   
chanrec   FileReader   

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classucrec-members.html b/docs/module-doc/classucrec-members.html new file mode 100644 index 000000000..43e5c1cca --- /dev/null +++ b/docs/module-doc/classucrec-members.html @@ -0,0 +1,19 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ucrec Member List

This is the complete list of members for ucrec, including all inherited members. + + + + +
channelucrec
uc_modesucrec
ucrec()ucrec [inline]
~ucrec()ucrec [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classucrec.html b/docs/module-doc/classucrec.html new file mode 100644 index 000000000..c95b8a3b6 --- /dev/null +++ b/docs/module-doc/classucrec.html @@ -0,0 +1,161 @@ + + +ucrec class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

ucrec Class Reference

Holds a user's modes on a channel This class associates a users privilages with a channel by creating a pointer link between a userrec and chanrec class. +More... +

+#include <channels.h> +

+List of all members. + + + + + + + + + +

Public Methods

 ucrec ()
virtual ~ucrec ()

Public Attributes

long uc_modes
 Contains a bitmask of the UCMODE_OP ...

chanrecchannel
 Points to the channel record where the given modes apply.

+


Detailed Description

+Holds a user's modes on a channel This class associates a users privilages with a channel by creating a pointer link between a userrec and chanrec class. +

+The uc_modes member holds a bitmask of which privilages the user has on the channel, such as op, voice, etc. +

+ +

+Definition at line 178 of file channels.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
ucrec::ucrec   [inline]
+
+ + + + + +
+   + + +

+ +

+Definition at line 191 of file channels.h. +

+

00191 { /* stub */ }
+
+

+ + + + +
+ + + + + + + + + +
virtual ucrec::~ucrec   [inline, virtual]
+
+ + + + + +
+   + + +

+ +

+Definition at line 192 of file channels.h. +

+

00192 { /* stub */ }
+
+


Member Data Documentation

+

+ + + + +
+ + +
chanrec* ucrec::channel +
+
+ + + + + +
+   + + +

+Points to the channel record where the given modes apply. +

+If the record is not in use, this value will be NULL. +

+Definition at line 189 of file channels.h. +

+Referenced by userrec::userrec().

+

+ + + + +
+ + +
long ucrec::uc_modes +
+
+ + + + + +
+   + + +

+Contains a bitmask of the UCMODE_OP ... +

+UCMODE_FOUNDER values. If this value is zero, the user has no privilages upon the channel. +

+Definition at line 184 of file channels.h.

+


The documentation for this class was generated from the following file: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classuserrec-members.html b/docs/module-doc/classuserrec-members.html new file mode 100644 index 000000000..78781c9e8 --- /dev/null +++ b/docs/module-doc/classuserrec-members.html @@ -0,0 +1,47 @@ + + +Member List + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

userrec Member List

This is the complete list of members for userrec, including all inherited members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
awaymsguserrec
bytes_inuserrec
bytes_outuserrec
chansuserrec
cmds_inuserrec
cmds_outuserrec
dhostuserrec
fduserrec
fullnameuserrec
GetFullHost()userrec [virtual]
GetFullRealHost()userrec [virtual]
haspasseduserrec
hostuserrec
identuserrec
idle_lastmsguserrec
inbufuserrec
invitesuserrec [private]
InviteTo(char *channel)userrec [virtual]
ipuserrec
IsInvited(char *channel)userrec [virtual]
lastpinguserrec
modesuserrec
nickuserrec
npinguserrec
portuserrec
registereduserrec
RemoveInvite(char *channel)userrec [virtual]
resultuserrec
serveruserrec
signonuserrec
userrec()userrec
~userrec()userrec [inline, virtual]

Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/classuserrec.html b/docs/module-doc/classuserrec.html new file mode 100644 index 000000000..d4be7912e --- /dev/null +++ b/docs/module-doc/classuserrec.html @@ -0,0 +1,1085 @@ + + +userrec class Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

userrec Class Reference

Holds all information about a user This class stores all information about a user connected to the irc server. +More... +

+#include <users.h> +

+List of all members. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Public Methods

 userrec ()
virtual ~userrec ()
virtual char * GetFullHost ()
 Returns the full displayed host of the user This member function returns the hostname of the user as seen by other users on the server, in nick!identhost form.

virtual char * GetFullRealHost ()
 Returns the full real host of the user This member function returns the hostname of the user as seen by other users on the server, in nick!identhost form.

virtual bool IsInvited (char *channel)
 Returns true if a user is invited to a channel.

virtual void InviteTo (char *channel)
 Adds a channel to a users invite list (invites them to a channel).

virtual void RemoveInvite (char *channel)
 Removes a channel from a users invite list.


Public Attributes

char nick [NICKMAX]
 The users nickname.

unsigned long ip
 The users ip address in network order.

char ident [64]
 The users ident reply.

char host [256]
 The users hostname, or ip address in string form.

char dhost [256]
 The host displayed to non-opers (used for cloaking etc).

char fullname [128]
 The users full name.

int fd
 The users file descriptor.

char modes [32]
 The user's mode string.

char inbuf [MAXBUF]
 The users input buffer.

time_t lastping
 The last time the user was pinged by the core.

time_t signon
 The users signon time.

time_t idle_lastmsg
 The time the user last sent a message.

time_t nping
 True if the user replied to their last ping.

int registered
 Bit 1 is set if the user sent a NICK command, bit 2 is set if the user sent a USER command.

ucrec chans [MAXCHANS]
 A list of the channels the user is currently on.

char server [256]
 The server the user is connected to.

char awaymsg [512]
 The user's away message.

int port
 The port that the user connected to.

long bytes_in
 Stores the number of incoming bytes from the connection.

long bytes_out
 Stores the number of outgoing bytes to the connection.

long cmds_in
 Stores the number of incoming commands from the connection.

long cmds_out
 Stores the number of outgoing commands to the connection.

char result [256]
 Stores the result of the last GetFullHost or GetRealHost call.

bool haspassed
 True if a correct password has been given using PASS command.


Private Attributes

InvitedList invites
 A list of channels the user has a pending invite to.

+


Detailed Description

+Holds all information about a user This class stores all information about a user connected to the irc server. +

+Everything about a connection is stored here primarily, from the user's socket ID (file descriptor) through to the user's nickname and hostname. Use the Find method of the server class to locate a specific user by nickname. +

+ +

+Definition at line 80 of file users.h.


Constructor & Destructor Documentation

+

+ + + + +
+ + + + + + + + + +
userrec::userrec  
+
+ + + + + +
+   + + +

+ +

+Definition at line 23 of file users.cpp. +

+References bytes_in, bytes_out, ucrec::channel, chans, cmds_in, cmds_out, fd, haspassed, idle_lastmsg, invites, ip, lastping, nping, port, registered, and signon. +

+

00024 {
+00025         // the PROPER way to do it, AVOID bzero at *ALL* costs
+00026         strcpy(nick,"");
+00027         ip = 0;
+00028         strcpy(ident,"");
+00029         strcpy(host,"");
+00030         strcpy(dhost,"");
+00031         strcpy(fullname,"");
+00032         strcpy(modes,"");
+00033         strcpy(inbuf,"");
+00034         strcpy(server,"");
+00035         strcpy(awaymsg,"");
+00036         fd = lastping = signon = idle_lastmsg = nping = registered = 0;
+00037         port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+00038         haspassed = false;
+00039         strcpy(result,"");
+00040         for (int i = 0; i < MAXCHANS; i++)
+00041         {
+00042                 chans[i].channel = NULL;
+00043         }
+00044         invites.clear();
+00045 }
+
+

+ + + + +
+ + + + + + + + + +
virtual userrec::~userrec   [inline, virtual]
+
+ + + + + +
+   + + +

+ +

+Definition at line 213 of file users.h. +

+

00213 {  }
+
+


Member Function Documentation

+

+ + + + +
+ + + + + + + + + +
char * userrec::GetFullHost   [virtual]
+
+ + + + + +
+   + + +

+Returns the full displayed host of the user This member function returns the hostname of the user as seen by other users on the server, in nick!identhost form. +

+ +

+Definition at line 48 of file users.cpp. +

+References result. +

+

00049 {
+00050         sprintf(result,"%s!%s@%s",nick,ident,dhost);
+00051         return result;
+00052 }
+
+

+ + + + +
+ + + + + + + + + +
char * userrec::GetFullRealHost   [virtual]
+
+ + + + + +
+   + + +

+Returns the full real host of the user This member function returns the hostname of the user as seen by other users on the server, in nick!identhost form. +

+If any form of hostname cloaking is in operation, e.g. through a module, then this method will ignore it and return the true hostname. +

+Definition at line 55 of file users.cpp. +

+References result. +

+

00056 {
+00057         sprintf(result,"%s!%s@%s",nick,ident,host);
+00058         return result;
+00059 }
+
+

+ + + + +
+ + + + + + + + + + +
void userrec::InviteTo char *   channel [virtual]
+
+ + + + + +
+   + + +

+Adds a channel to a users invite list (invites them to a channel). +

+ +

+Definition at line 72 of file users.cpp. +

+References Invited::channel, and invites. +

+

00073 {
+00074         Invited i;
+00075         strcpy(i.channel,channel);
+00076         invites.push_back(i);
+00077 }
+
+

+ + + + +
+ + + + + + + + + + +
bool userrec::IsInvited char *   channel [virtual]
+
+ + + + + +
+   + + +

+Returns true if a user is invited to a channel. +

+ +

+Definition at line 61 of file users.cpp. +

+References invites. +

+

00062 {
+00063         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+00064         {
+00065                 if (!strcasecmp(i->channel,channel))
+00066                 {
+00067                         return true;
+00068                 }
+00069         }
+00070 }
+
+

+ + + + +
+ + + + + + + + + + +
void userrec::RemoveInvite char *   channel [virtual]
+
+ + + + + +
+   + + +

+Removes a channel from a users invite list. +

+This member function is called on successfully joining an invite only channel to which the user has previously been invited, to clear the invitation. +

+Definition at line 79 of file users.cpp. +

+References invites. +

+

00080 {
+00081         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+00082         {
+00083                 if (!strcasecmp(i->channel,channel))
+00084                 {
+00085                         invites.erase(i);
+00086                         return;
+00087                 }
+00088         }
+00089 }
+
+


Member Data Documentation

+

+ + + + +
+ + +
char userrec::awaymsg[512] +
+
+ + + + + +
+   + + +

+The user's away message. +

+If this string is empty, the user is not marked as away. +

+Definition at line 174 of file users.h.

+

+ + + + +
+ + +
long userrec::bytes_in +
+
+ + + + + +
+   + + +

+Stores the number of incoming bytes from the connection. +

+Used by /STATS +

+Definition at line 183 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
long userrec::bytes_out +
+
+ + + + + +
+   + + +

+Stores the number of outgoing bytes to the connection. +

+Used by /STATS +

+Definition at line 188 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
ucrec userrec::chans[MAXCHANS] +
+
+ + + + + +
+   + + +

+A list of the channels the user is currently on. +

+If any of these values are NULL, the record is not in use and may be associated with a channel by the JOIN command. see RFC 1459. +

+Definition at line 165 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
long userrec::cmds_in +
+
+ + + + + +
+   + + +

+Stores the number of incoming commands from the connection. +

+Used by /STATS +

+Definition at line 193 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
long userrec::cmds_out +
+
+ + + + + +
+   + + +

+Stores the number of outgoing commands to the connection. +

+Used by /STATS +

+Definition at line 198 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::dhost[256] +
+
+ + + + + +
+   + + +

+The host displayed to non-opers (used for cloaking etc). +

+This usually matches the value of userrec::host. +

+Definition at line 110 of file users.h.

+

+ + + + +
+ + +
int userrec::fd +
+
+ + + + + +
+   + + +

+The users file descriptor. +

+If this is zero, the socket has been closed and the core has not yet realised and removed the record from memory. +

+Definition at line 120 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::fullname[128] +
+
+ + + + + +
+   + + +

+The users full name. +

+ +

+Definition at line 114 of file users.h.

+

+ + + + +
+ + +
bool userrec::haspassed +
+
+ + + + + +
+   + + +

+True if a correct password has been given using PASS command. +

+If the user is a member of a connection class that does not require a password, the value stored here is of no use. +

+Definition at line 209 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::host[256] +
+
+ + + + + +
+   + + +

+The users hostname, or ip address in string form. +

+ +

+Definition at line 105 of file users.h.

+

+ + + + +
+ + +
char userrec::ident[64] +
+
+ + + + + +
+   + + +

+The users ident reply. +

+ +

+Definition at line 101 of file users.h.

+

+ + + + +
+ + +
time_t userrec::idle_lastmsg +
+
+ + + + + +
+   + + +

+The time the user last sent a message. +

+See also userrec::lastping and userrec::signon +

+Definition at line 147 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::inbuf[MAXBUF] +
+
+ + + + + +
+   + + +

+The users input buffer. +

+Used by the C recv() function. +

+Definition at line 131 of file users.h.

+

+ + + + +
+ + +
InvitedList userrec::invites [private] +
+
+ + + + + +
+   + + +

+A list of channels the user has a pending invite to. +

+ +

+Definition at line 86 of file users.h. +

+Referenced by InviteTo(), IsInvited(), RemoveInvite(), and userrec().

+

+ + + + +
+ + +
unsigned long userrec::ip +
+
+ + + + + +
+   + + +

+The users ip address in network order. +

+ +

+Definition at line 97 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
time_t userrec::lastping +
+
+ + + + + +
+   + + +

+The last time the user was pinged by the core. +

+When this value is more than 120 seconds difference from 'time(NULL)', a ping is sent to the client. If the user has an outstanding PING request the next time this event occurs after 4 total minutes, they are disconnected. +

+Definition at line 138 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::modes[32] +
+
+ + + + + +
+   + + +

+The user's mode string. +

+This may contain any of the following RFC characters: o, w, s, i Your module may define other mode characters as it sees fit. +

+Definition at line 126 of file users.h.

+

+ + + + +
+ + +
char userrec::nick[NICKMAX] +
+
+ + + + + +
+   + + +

+The users nickname. +

+An invalid nickname indicates an unregistered connection prior to the NICK command. +

+Definition at line 93 of file users.h.

+

+ + + + +
+ + +
time_t userrec::nping +
+
+ + + + + +
+   + + +

+True if the user replied to their last ping. +

+If this is true, the user can be sent another ping at the specified time, otherwise they will be discnnected. See also userrec::lastping +

+Definition at line 153 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
int userrec::port +
+
+ + + + + +
+   + + +

+The port that the user connected to. +

+ +

+Definition at line 178 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
int userrec::registered +
+
+ + + + + +
+   + + +

+Bit 1 is set if the user sent a NICK command, bit 2 is set if the user sent a USER command. +

+If both bits are set then the connection is awaiting MOTD. Sending of MOTD sets bit 3, and makes the value of userrec::registered == 7, showing a fully established client session. +

+Definition at line 159 of file users.h. +

+Referenced by userrec().

+

+ + + + +
+ + +
char userrec::result[256] +
+
+ + + + + +
+   + + +

+Stores the result of the last GetFullHost or GetRealHost call. +

+You may use this to increase the speed of use of this class. +

+Definition at line 203 of file users.h. +

+Referenced by GetFullHost(), and GetFullRealHost().

+

+ + + + +
+ + +
char userrec::server[256] +
+
+ + + + + +
+   + + +

+The server the user is connected to. +

+ +

+Definition at line 169 of file users.h.

+

+ + + + +
+ + +
time_t userrec::signon +
+
+ + + + + +
+   + + +

+The users signon time. +

+ +

+Definition at line 142 of file users.h. +

+Referenced by userrec().

+


The documentation for this class was generated from the following files: +
Generated on Wed Jan 22 20:56:48 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/doxygen.css b/docs/module-doc/doxygen.css new file mode 100644 index 000000000..8cb8b2e5b --- /dev/null +++ b/docs/module-doc/doxygen.css @@ -0,0 +1,49 @@ +H1 { text-align: center; } +CAPTION { font-weight: bold } +A.qindex {} +A.qindexRef {} +A.el { text-decoration: none; font-weight: bold } +A.elRef { font-weight: bold } +A.code { text-decoration: none; font-weight: normal; color: #4444ee } +A.codeRef { font-weight: normal; color: #4444ee } +A:hover { text-decoration: none; background-color: #f2f2ff } +DL.el { margin-left: -1cm } +DIV.fragment { width: 100%; border: none; background-color: #eeeeee } +DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } +TD.md { background-color: #f2f2ff; font-weight: bold; } +TD.mdname1 { background-color: #f2f2ff; font-weight: bold; color: #602020; } +TD.mdname { background-color: #f2f2ff; font-weight: bold; color: #602020; width: 600px; } +DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold } +DIV.groupText { margin-left: 16px; font-style: italic; font-size: smaller } +BODY { background: white; color: black } +TD.indexkey { + background-color: #eeeeff; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px +} +TD.indexvalue { + background-color: #eeeeff; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px +} +span.keyword { color: #008000 } +span.keywordtype { color: #604020 } +span.keywordflow { color: #e08000 } +span.comment { color: #800000 } +span.preprocessor { color: #806020 } +span.stringliteral { color: #002080 } +span.charliteral { color: #008080 } diff --git a/docs/module-doc/doxygen.png b/docs/module-doc/doxygen.png new file mode 100644 index 0000000000000000000000000000000000000000..5bb475e231869d2a4c1359f23773733ba357f2e0 GIT binary patch literal 2351 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 FzX8ZOWc>gD literal 0 HcmV?d00001 diff --git a/docs/module-doc/files.html b/docs/module-doc/files.html new file mode 100644 index 000000000..ba6de9b92 --- /dev/null +++ b/docs/module-doc/files.html @@ -0,0 +1,21 @@ + + +File Index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd File List

Here is a list of all files with brief descriptions: + + + + + +
channels.h [code]
modules.cpp [code]
modules.h [code]
users.cpp [code]
users.h [code]
+
Generated on Wed Jan 22 20:56:46 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/ftv2blank.png b/docs/module-doc/ftv2blank.png new file mode 100644 index 0000000000000000000000000000000000000000..3f626d64ffea1e2e8fa021a8c4b4489b4f0cd8ac GIT binary patch literal 173 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF@xBp9b%6LbgCOeH~n!3>OyQ~s_4NtL)plmzFe zm6RtIr81;vrWqCFr7IZendliUj&tV&s!#=~aL&)oP0cG|2+c`NOi^(6bW;e%)r1HA5y3bxY&r9t02UPF*q}!P@O|m zO6pVtV@%9}DT^jBbp&|_u?A%)r1HA5y3bJOOx?IsVW7)mfxvFRX-9N^>Kv;A}!rn%1phFluUHx3vIVCg!05T_K A3jhEB literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2folderopen.png b/docs/module-doc/ftv2folderopen.png new file mode 100644 index 0000000000000000000000000000000000000000..30e9a2c37d61d537efa58dd2b231f0dc15e42c78 GIT binary patch literal 260 zcmeAS@N?&q;$mQ6;PUiv2?Ej*KrF_>%)r1HA5y3b%)r3t(`*^J h;DA35Gs_8MIR=&G3>^ZejBSC^44$rjF6*2UngFG=HD&++ literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2link.png b/docs/module-doc/ftv2link.png new file mode 100644 index 0000000000000000000000000000000000000000..f2549516c83976e945e0f97d7c8a710cfe4ce4eb GIT binary patch literal 357 zcmeAS@N?&q;$mQ6;PUiv2?Ej*KrF_>%)r1HA5y3b6vLp1$pTTMtUZC zMvLRz`G6|aKq{Q`b8}PkN*F?OQWH}Y+&$eCf^!p#N`e#1Qi~MAfY?aSK$7Vu=Tk4B zjtQPFjv*DdYI`Ydyt}R;Z=G1wrhQf^raMyJ=(DrR&adoM47k92 z^6bNX;tVSonjSQ!)gG7^Sl}Rgel5F%bjgI6NYQA({8?>Hj#-UN}{I Up+Ln2P(U$wy85}Sb4q9e0B=Bgv;Y7A literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2mlastnode.png b/docs/module-doc/ftv2mlastnode.png new file mode 100644 index 0000000000000000000000000000000000000000..0de7e451fe631a96b916d13ec8a15747f7a8c313 GIT binary patch literal 159 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF_@%)r2S`0$ZRAcr%+C&cyt|NjjQ4M3hv+-@Bp z#aI&L7tG-B>_!@pBUa)XQ4*Y=R#Ki=l**8vnPyawm#$!>XQF4cIL@69s6yG(#WAGf zR&s&@HwTA;09QhbV9&yZ3TzWjuGktNaEhrjk&z)+oN3pAJDDed${9Re{an^LB{Ts5 D*xD^d literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2mnode.png b/docs/module-doc/ftv2mnode.png new file mode 100644 index 0000000000000000000000000000000000000000..72f185b0bbf63bbecfba788ed379843978e72f51 GIT binary patch literal 193 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF_>%)r3t(`-L1ke-=lRFIdhV5DcFXS6uZoe!u&%hSa% zq~ca`!UDYqY)&Oi%Y#DLzUL`4d_0(R$H&X-&Ye3alnhK~+`1^qu)UI9ebx7AK({e4 Nc)I$ztaD0e0stQuGd%zR literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2node.png b/docs/module-doc/ftv2node.png new file mode 100644 index 0000000000000000000000000000000000000000..c23e9f9437a9c28143fd7320cda1721ab5156342 GIT binary patch literal 234 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF_>%)r3t(`*^J k;DA35GfPKU&mjf|y3zg(>z0u?ZLy85}Sb4q9e04{7dng9R* literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2plastnode.png b/docs/module-doc/ftv2plastnode.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc6181abb638974cdff8ea22261fba301269288 GIT binary patch literal 164 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF_@%)r2S`0$ZRAcr%+C&cyt|NjjQ4M3hv+-@Bp z#aI&L7tG-B>_!@pBUa)XQ4*Y=R#Ki=l**8vnPyawm#$!>XQF4cIL@69s6xZj#WAGf zR&s&@HwT9SN2B0`Mka|wmgEeL2?%)r3t(`-L1ke-=lRFIdhV5DcFXS6uZoe!wOz|+Ms zq~ca`!UDYqY)))>Y8H%-9))zBdT@`6MZiwjrDwLMXXotM(vd97*n+LCm>G6uv+J)q REuRl^jHj!g%Q~loCIHraF+%_V literal 0 HcmV?d00001 diff --git a/docs/module-doc/ftv2vertline.png b/docs/module-doc/ftv2vertline.png new file mode 100644 index 0000000000000000000000000000000000000000..f5a03787bae6a024d44879c634aa1aeb9f7ab8d1 GIT binary patch literal 228 zcmeAS@N?&q;$mQ6;PUiv2?EjrKrF_>%)r3t(`*^J d;DCQL8-t< + +Compound Member Index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd Compound Members

+a | b | c | d | e | f | g | h | i | k | l | m | n | o | p | r | s | t | u | v | ~
+ +

+Here is a list of all class members with links to the classes they belong to:

- a - +

+

- b - +

+

- c - +

+

- d - +

+

- e - +

+

- f - +

+

- g - +

+

- h - +

+

- i - +

+

- k - +

+

- l - +

+

- m - +

+

- n - +

+

- o - +

+

- p - +

+

- r - +

+

- s - +

+

- t - +

+

- u - +

+

- v - +

+

- ~ - +

+
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/globals.html b/docs/module-doc/globals.html new file mode 100644 index 000000000..6a9878c0d --- /dev/null +++ b/docs/module-doc/globals.html @@ -0,0 +1,57 @@ + + +File Member Index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd File Members

+b | c | e | f | i | s | u
+ +

+Here is a list of all file members with links to the files they belong to:

- b - +

+

- c - +

+

- e - +

+

- f - +

+

- i - +

+

- s - +

+

- u - +

+
Generated on Wed Jan 22 20:56:49 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/hierarchy.html b/docs/module-doc/hierarchy.html new file mode 100644 index 000000000..35e1d316c --- /dev/null +++ b/docs/module-doc/hierarchy.html @@ -0,0 +1,34 @@ + + +Hierarchical Index + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd Class Hierarchy

This inheritance list is sorted roughly, but not completely, alphabetically: +
Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/index.html b/docs/module-doc/index.html new file mode 100644 index 000000000..752d21b2d --- /dev/null +++ b/docs/module-doc/index.html @@ -0,0 +1,7 @@ + +InspIRCd + + + + + diff --git a/docs/module-doc/main.html b/docs/module-doc/main.html new file mode 100644 index 000000000..2080402f5 --- /dev/null +++ b/docs/module-doc/main.html @@ -0,0 +1,16 @@ + + +Main Page + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

InspIRCd Documentation

+

+


Generated on Wed Jan 22 20:56:46 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/modules_8cpp-source.html b/docs/module-doc/modules_8cpp-source.html new file mode 100644 index 000000000..b651919d5 --- /dev/null +++ b/docs/module-doc/modules_8cpp-source.html @@ -0,0 +1,249 @@ + + +modules.cpp Source File + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

modules.cpp

Go to the documentation of this file.
00001 /*
+00002 
+00003 $Log$
+00003 Revision 1.1  2003/01/23 19:45:58  brain
+00003 Initial revision
+00003 
+00003 Revision 1.9  2003/01/22 20:59:12  brain
+00003 Added FileReader class documentation
+00003 
+00004 Revision 1.7  2003/01/22 20:49:16  brain
+00005 Added FileReader file-caching class
+00006 Changed m_randquote to use FileReader class
+00007 
+00008 Revision 1.6  2003/01/21 20:31:24  brain
+00009 Modified to add documentation
+00010 Added ConfigReader class for modules
+00011 
+00012 Revision 1.5  2003/01/13 22:30:50  brain
+00013 Added Admin class (holds /admin info for modules)
+00014 Added methods to Server class
+00015 
+00016 
+00017 */
+00018 
+00019 
+00020 
+00021 #include <typeinfo>
+00022 #include <iostream.h>
+00023 #include "globals.h"
+00024 #include "modules.h"
+00025 #include "inspircd_io.h"
+00026 
+00027 // version is a simple class for holding a modules version number
+00028 
+00029 Version::Version(int major, int minor, int revision, int build) : Major(major), Minor(minor), Revision(revision), Build(build) { };
+00030 
+00031 // admin is a simple class for holding a server's administrative info
+00032 
+00033 Admin::Admin(string name, string email, string nick) : Name(name), Email(email), Nick(nick) { };
+00034 
+00035 //
+00036 // Announce to the world that the Module base
+00037 // class has been created or destroyed
+00038 //
+00039 
+00040 Module::Module() { }
+00041 Module::~Module() { }
+00042 void Module::OnUserConnect(userrec* user) { }
+00043 void Module::OnUserQuit(userrec* user) { }
+00044 void Module::OnUserJoin(userrec* user, chanrec* channel) { }
+00045 void Module::OnUserPart(userrec* user, chanrec* channel) { }
+00046 Version Module::GetVersion() { return Version(1,0,0,0); }
+00047 
+00048 // server is a wrapper class that provides methods to all of the C-style
+00049 // exports in the core
+00050 //
+00051 
+00052 Server::Server()
+00053 {
+00054 }
+00055 
+00056 Server::~Server()
+00057 {
+00058 }
+00059 
+00060 void Server::SendOpers(string s)
+00061 {
+00062         WriteOpers("%s",s.c_str());
+00063 }
+00064 
+00065 void Server::Debug(string s)
+00066 {
+00067         debug("%s",s.c_str());
+00068 }
+00069 
+00070 void Server::Send(int Socket, string s)
+00071 {
+00072         Write(Socket,"%s",s.c_str());
+00073 }
+00074 
+00075 void Server::SendServ(int Socket, string s)
+00076 {
+00077         WriteServ(Socket,"%s",s.c_str());
+00078 }
+00079 
+00080 void Server::SendFrom(int Socket, userrec* User, string s)
+00081 {
+00082         WriteFrom(Socket,User,"%s",s.c_str());
+00083 }
+00084 
+00085 void Server::SendTo(userrec* Source, userrec* Dest, string s)
+00086 {
+00087         WriteTo(Source,Dest,"%s",s.c_str());
+00088 }
+00089 
+00090 void Server::SendChannel(userrec* User, chanrec* Channel, string s,bool IncludeSender)
+00091 {
+00092         if (IncludeSender)
+00093         {
+00094                 WriteChannel(Channel,User,"%s",s.c_str());
+00095         }
+00096         else
+00097         {
+00098                 ChanExceptSender(Channel,User,"%s",s.c_str());
+00099         }
+00100 }
+00101 
+00102 bool Server::CommonChannels(userrec* u1, userrec* u2)
+00103 {
+00104         return (common_channels(u1,u2) != 0);
+00105 }
+00106 
+00107 void Server::SendCommon(userrec* User, string text,bool IncludeSender)
+00108 {
+00109         if (IncludeSender)
+00110         {
+00111                 WriteCommon(User,"%s",text.c_str());
+00112         }
+00113         else
+00114         {
+00115                 WriteCommonExcept(User,"%s",text.c_str());
+00116         }
+00117 }
+00118 
+00119 void Server::SendWallops(userrec* User, string text)
+00120 {
+00121         WriteWallOps(User,"%s",text.c_str());
+00122 }
+00123 
+00124 bool Server::IsNick(string nick)
+00125 {
+00126         return (isnick(nick.c_str()) != 0);
+00127 }
+00128 
+00129 userrec* Server::FindNick(string nick)
+00130 {
+00131         return Find(nick);
+00132 }
+00133 
+00134 chanrec* Server::FindChannel(string channel)
+00135 {
+00136         return FindChan(channel.c_str());
+00137 }
+00138 
+00139 string Server::ChanMode(userrec* User, chanrec* Chan)
+00140 {
+00141         string mode = cmode(User,Chan);
+00142         return mode;
+00143 }
+00144 
+00145 string Server::GetServerName()
+00146 {
+00147         return getservername();
+00148 }
+00149 
+00150 string Server::GetNetworkName()
+00151 {
+00152         return getnetworkname();
+00153 }
+00154 
+00155 Admin Server::GetAdmin()
+00156 {
+00157         return Admin(getadminname(),getadminemail(),getadminnick());
+00158 }
+00159 
+00160 
+00161 ConfigReader::ConfigReader()
+00162 {
+00163         fname = CONFIG_FILE;
+00164 }
+00165 
+00166 
+00167 ConfigReader::~ConfigReader()
+00168 {
+00169 }
+00170 
+00171 
+00172 ConfigReader::ConfigReader(string filename) : fname(filename) { };
+00173 
+00174 string ConfigReader::ReadValue(string tag, string name, int index)
+00175 {
+00176         char val[MAXBUF];
+00177         ReadConf(fname.c_str(),tag.c_str(),name.c_str(),index,val);
+00178         string s = val;
+00179         return s;
+00180 }
+00181 
+00182 
+00183 int ConfigReader::Enumerate(string tag)
+00184 {
+00185         return EnumConf(fname.c_str(),tag.c_str());
+00186 }
+00187 
+00188 
+00189 bool ConfigReader::Verify()
+00190 {
+00191         return true;
+00192 }
+00193 
+00194 
+00195 FileReader::FileReader(string filename)
+00196 {
+00197         file_cache c;
+00198         readfile(c,filename.c_str());
+00199         this->fc = c;
+00200 }
+00201 
+00202 FileReader::FileReader()
+00203 {
+00204 }
+00205 
+00206 void FileReader::LoadFile(string filename)
+00207 {
+00208         file_cache c;
+00209         readfile(c,filename.c_str());
+00210         this->fc = c;
+00211 }
+00212 
+00213 FileReader::~FileReader()
+00214 {
+00215 }
+00216 
+00217 string FileReader::GetLine(int x)
+00218 {
+00219         if ((x<0) || (x>fc.size()))
+00220                 return "";
+00221         return fc[x];
+00222 }
+00223 
+00224 int FileReader::FileSize()
+00225 {
+00226         return fc.size();
+00227 }
+00228 
+00229 
+

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/modules_8cpp.html b/docs/module-doc/modules_8cpp.html new file mode 100644 index 000000000..cfa3fa3a3 --- /dev/null +++ b/docs/module-doc/modules_8cpp.html @@ -0,0 +1,24 @@ + + +modules.cpp File Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

modules.cpp File Reference

#include <typeinfo>
+#include <iostream.h>
+#include "globals.h"
+#include "modules.h"
+#include "inspircd_io.h"
+ +

+Go to the source code of this file. + +
+


Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/modules_8h-source.html b/docs/module-doc/modules_8h-source.html new file mode 100644 index 000000000..9f80e2ea5 --- /dev/null +++ b/docs/module-doc/modules_8h-source.html @@ -0,0 +1,159 @@ + + +modules.h Source File + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

modules.h

Go to the documentation of this file.
00001 /*
+00002 
+00003 $Log$
+00003 Revision 1.1  2003/01/23 19:45:58  brain
+00003 Initial revision
+00003 
+00003 Revision 1.9  2003/01/22 20:59:12  brain
+00003 Added FileReader class documentation
+00003 
+00004 Revision 1.11  2003/01/22 20:49:16  brain
+00005 Added FileReader file-caching class
+00006 Changed m_randquote to use FileReader class
+00007 
+00008 Revision 1.10  2003/01/22 00:57:27  brain
+00009 Changes to documentation
+00010 
+00011 Revision 1.9  2003/01/22 00:44:26  brain
+00012 Added documentation comments
+00013 
+00014 Revision 1.8  2003/01/21 20:31:24  brain
+00015 Modified to add documentation
+00016 Added ConfigReader class for modules
+00017 
+00018 Revision 1.7  2003/01/15 22:47:44  brain
+00019 Changed user and channel structs to classes (finally)
+00020 
+00021 Revision 1.6  2003/01/13 22:30:50  brain
+00022 Added Admin class (holds /admin info for modules)
+00023 Added methods to Server class
+00024 
+00025 
+00026 */
+00027 
+00028 
+00029 #ifndef __PLUGIN_H
+00030 #define __PLUGIN_H
+00031 
+00032 #include "dynamic.h"
+00033 #include <string>
+00034 #include <deque>
+00035 
+00038 typedef deque<string> file_cache;
+00039 
+00040 
+00041 // This #define allows us to call a method in all
+00042 // loaded modules in a readable simple way, e.g.:
+00043 // 'FOREACH_MOD OnConnect(user);'
+00044 
+00045 #define FOREACH_MOD for (int i = 0; i <= MODCOUNT; i++) modules[i]->
+00046 
+00047 // class Version holds the version information of a Module, returned
+00048 // by Module::GetVersion (thanks RD)
+00049 
+00054 class Version
+00055 {
+00056  public:
+00057          const int Major, Minor, Revision, Build;
+00058          Version(int major, int minor, int revision, int build);
+00059 };
+00060 
+00061 
+00067 class Admin
+00068 {
+00069  public:
+00070          const string Name, Email, Nick;
+00071          Admin(string name,string email,string nick);
+00072 };
+00073 
+00079 class Module
+00080 {
+00081  public:
+00085         Module();
+00089         virtual ~Module();
+00094         virtual Version GetVersion();
+00098         virtual void OnUserConnect(userrec* user);
+00102         virtual void OnUserQuit(userrec* user);
+00107         virtual void OnUserJoin(userrec* user, chanrec* channel);
+00112         virtual void OnUserPart(userrec* user, chanrec* channel);
+00113 };
+00114 
+00115 
+00121 class Server
+00122 {
+00123  public:
+00127         Server();
+00131         virtual ~Server();
+00132 
+00136         virtual void SendOpers(string s);
+00141         virtual void Debug(string s);
+00146         virtual void Send(int Socket, string s);
+00151         virtual void SendServ(int Socket, string s);
+00156         virtual void SendFrom(int Socket, userrec* User, string s);
+00161         virtual void SendTo(userrec* Source, userrec* Dest, string s);
+00168         virtual void SendChannel(userrec* User, chanrec* Channel, string s,bool IncludeSender);
+00173         virtual bool CommonChannels(userrec* u1, userrec* u2);
+00181         virtual void SendCommon(userrec* User, string text,bool IncludeSender);
+00186         virtual void SendWallops(userrec* User, string text);
+00187 
+00191         virtual bool IsNick(string nick);
+00195         virtual userrec* FindNick(string nick);
+00199         virtual chanrec* FindChannel(string channel);
+00204         virtual string ChanMode(userrec* User, chanrec* Chan);
+00207         virtual string GetServerName();
+00210         virtual string GetNetworkName();
+00216         virtual Admin GetAdmin();
+00217          
+00218 };
+00219 
+00226 class ConfigReader
+00227 {
+00228   protected:
+00231         string fname;
+00232   public:
+00237         ConfigReader();                 // default constructor reads ircd.conf
+00241         ConfigReader(string filename);  // read a module-specific config
+00245         ~ConfigReader();
+00250         string ReadValue(string tag, string name, int index);
+00257         int Enumerate(string tag);
+00261         bool Verify();
+00262 };
+00263 
+00264 
+00265 
+00271 class FileReader
+00272 {
+00273  file_cache fc;
+00274  public:
+00279          FileReader();
+00285          FileReader(string filename);
+00289          ~FileReader();
+00295          void LoadFile(string filename);
+00300          string GetLine(int x);
+00306          int FileSize();
+00307 };
+00308 
+00309 
+00316 class ModuleFactory
+00317 {
+00318  public:
+00319         ModuleFactory() { }
+00320         virtual ~ModuleFactory() { }
+00325         virtual Module * CreateModule() = 0;
+00326 };
+00327 
+00328 #endif
+

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/modules_8h.html b/docs/module-doc/modules_8h.html new file mode 100644 index 000000000..6c9237a27 --- /dev/null +++ b/docs/module-doc/modules_8h.html @@ -0,0 +1,96 @@ + + +modules.h File Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

modules.h File Reference

#include "dynamic.h"
+#include <string>
+#include <deque>
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + + +

Compounds

class  Admin
 Holds /ADMIN data This class contains the admin details of the local server. More...

class  ConfigReader
 Allows reading of values from configuration files This class allows a module to read from either the main configuration file (inspircd.conf) or from a module-specified configuration file. More...

class  FileReader
 Caches a text file into memory and can be used to retrieve lines from it. More...

class  Module
 Base class for all InspIRCd modules This class is the base class for InspIRCd modules. More...

class  ModuleFactory
 Instantiates classes inherited from Module This class creates a class inherited from type Module, using new. More...

class  Server
 Allows server output and query functions This class contains methods which allow a module to query the state of the irc server, and produce output to users and other servers. More...

class  Version
 Holds a module's Version information The four members (set by the constructor only) indicate details as to the version number of a module. More...


Defines

#define FOREACH_MOD   for (int i = 0; i <= MODCOUNT; i++) modules[i]->

Typedefs

typedef deque< string > file_cache
 Low level definition of a FileReader classes file cache area.

+


Define Documentation

+

+ + + + +
+ + +
#define FOREACH_MOD   for (int i = 0; i <= MODCOUNT; i++) modules[i]-> +
+
+ + + + + +
+   + + +

+ +

+Definition at line 45 of file modules.h.

+


Typedef Documentation

+

+ + + + +
+ + +
typedef deque<string> file_cache +
+
+ + + + + +
+   + + +

+Low level definition of a FileReader classes file cache area. +

+ +

+Definition at line 38 of file modules.h. +

+Referenced by FileReader::FileReader(), and FileReader::LoadFile().

+


Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/tree.html b/docs/module-doc/tree.html new file mode 100644 index 000000000..ca32b1db7 --- /dev/null +++ b/docs/module-doc/tree.html @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/docs/module-doc/tree.js b/docs/module-doc/tree.js new file mode 100644 index 000000000..ff40787d6 --- /dev/null +++ b/docs/module-doc/tree.js @@ -0,0 +1,44 @@ +foldersTree = gFld("InspIRCd", "", "") + insDoc(foldersTree, gLnk("Main Page", "", "main.html")) +aux1 = insFld(foldersTree, gFld("File List", "", "files.html")) + insDoc(aux1, gLnk("channels.h", "", "channels_8h.html")) + insDoc(aux1, gLnk("modules.cpp", "", "modules_8cpp.html")) + insDoc(aux1, gLnk("modules.h", "", "modules_8h.html")) + insDoc(aux1, gLnk("users.cpp", "", "users_8cpp.html")) + insDoc(aux1, gLnk("users.h", "", "users_8h.html")) +aux1 = insFld(foldersTree, gFld("Compound List", "", "annotated.html")) + insDoc(aux1, gLnk("Admin", "", "classAdmin.html")) + insDoc(aux1, gLnk("BanItem", "", "classBanItem.html")) + insDoc(aux1, gLnk("chanrec", "", "classchanrec.html")) + insDoc(aux1, gLnk("ConfigReader", "", "classConfigReader.html")) + insDoc(aux1, gLnk("ConnectClass", "", "classConnectClass.html")) + insDoc(aux1, gLnk("ExemptItem", "", "classExemptItem.html")) + insDoc(aux1, gLnk("FileReader", "", "classFileReader.html")) + insDoc(aux1, gLnk("HostItem", "", "classHostItem.html")) + insDoc(aux1, gLnk("Invited", "", "classInvited.html")) + insDoc(aux1, gLnk("InviteItem", "", "classInviteItem.html")) + insDoc(aux1, gLnk("Module", "", "classModule.html")) + insDoc(aux1, gLnk("ModuleFactory", "", "classModuleFactory.html")) + insDoc(aux1, gLnk("Server", "", "classServer.html")) + insDoc(aux1, gLnk("ucrec", "", "classucrec.html")) + insDoc(aux1, gLnk("userrec", "", "classuserrec.html")) + insDoc(aux1, gLnk("Version", "", "classVersion.html")) +aux1 = insFld(foldersTree, gFld("Class Hierarchy", "", "hierarchy.html")) + insDoc(aux1, gLnk("Admin", "", "classAdmin.html")) + insDoc(aux1, gLnk("chanrec", "", "classchanrec.html")) + insDoc(aux1, gLnk("ConfigReader", "", "classConfigReader.html")) + insDoc(aux1, gLnk("ConnectClass", "", "classConnectClass.html")) + insDoc(aux1, gLnk("FileReader", "", "classFileReader.html")) + aux2 = insFld(aux1, gFld("HostItem", "", "classHostItem.html")) + insDoc(aux2, gLnk("BanItem", "", "classBanItem.html")) + insDoc(aux2, gLnk("ExemptItem", "", "classExemptItem.html")) + insDoc(aux2, gLnk("InviteItem", "", "classInviteItem.html")) + insDoc(aux1, gLnk("Invited", "", "classInvited.html")) + insDoc(aux1, gLnk("Module", "", "classModule.html")) + insDoc(aux1, gLnk("ModuleFactory", "", "classModuleFactory.html")) + insDoc(aux1, gLnk("Server", "", "classServer.html")) + insDoc(aux1, gLnk("ucrec", "", "classucrec.html")) + insDoc(aux1, gLnk("userrec", "", "classuserrec.html")) + insDoc(aux1, gLnk("Version", "", "classVersion.html")) + insDoc(foldersTree, gLnk("Compound Members", "", "functions.html")) + insDoc(foldersTree, gLnk("File Members", "", "globals.html")) diff --git a/docs/module-doc/treeview.js b/docs/module-doc/treeview.js new file mode 100644 index 000000000..6b5ef5110 --- /dev/null +++ b/docs/module-doc/treeview.js @@ -0,0 +1,500 @@ +//**************************************************************** +// You are free to copy the "Folder-Tree" script as long as you +// keep this copyright notice: +// Script found in: http://www.geocities.com/Paris/LeftBank/2178/ +// Author: Marcelino Alves Martins (martins@hks.com) December '97. +//**************************************************************** + +//Log of changes: +// 17 Feb 98 - Fix initialization flashing problem with Netscape +// +// 27 Jan 98 - Root folder starts open; support for USETEXTLINKS; +// make the ftien4 a js file +// +// DvH: Dec 2000 - Made some minor changes to support external +// references + +// Definition of class Folder +// ***************************************************************** + +function Folder(folderDescription, tagName, hreference) //constructor +{ + //constant data + this.desc = folderDescription + this.tagName = tagName + this.hreference = hreference + this.id = -1 + this.navObj = 0 + this.iconImg = 0 + this.nodeImg = 0 + this.isLastNode = 0 + + //dynamic data + this.isOpen = true + this.iconSrc = "ftv2folderopen.png" + this.children = new Array + this.nChildren = 0 + + //methods + this.initialize = initializeFolder + this.setState = setStateFolder + this.addChild = addChild + this.createIndex = createEntryIndex + this.hide = hideFolder + this.display = display + this.renderOb = drawFolder + this.totalHeight = totalHeight + this.subEntries = folderSubEntries + this.outputLink = outputFolderLink +} + +function setStateFolder(isOpen) +{ + var subEntries + var totalHeight + var fIt = 0 + var i=0 + + if (isOpen == this.isOpen) + return + + if (browserVersion == 2) + { + totalHeight = 0 + for (i=0; i < this.nChildren; i++) + totalHeight = totalHeight + this.children[i].navObj.clip.height + subEntries = this.subEntries() + if (this.isOpen) + totalHeight = 0 - totalHeight + for (fIt = this.id + subEntries + 1; fIt < nEntries; fIt++) + indexOfEntries[fIt].navObj.moveBy(0, totalHeight) + } + this.isOpen = isOpen + propagateChangesInState(this) +} + +function propagateChangesInState(folder) +{ + var i=0 + + if (folder.isOpen) + { + if (folder.nodeImg) + if (folder.isLastNode) + folder.nodeImg.src = "ftv2mlastnode.png" + else + folder.nodeImg.src = "ftv2mnode.png" + folder.iconImg.src = "ftv2folderopen.png" + for (i=0; i 0) + auxEv = "" + else + auxEv = "" + + if (level>0) + if (lastNode) //the last 'brother' in the children array + { + this.renderOb(leftSide + auxEv + "") + leftSide = leftSide + "" + this.isLastNode = 1 + } + else + { + this.renderOb(leftSide + auxEv + "") + leftSide = leftSide + "" + this.isLastNode = 0 + } + else + this.renderOb("") + + if (nc > 0) + { + level = level + 1 + for (i=0 ; i < this.nChildren; i++) + { + if (i == this.nChildren-1) + this.children[i].initialize(level, 1, leftSide) + else + this.children[i].initialize(level, 0, leftSide) + } + } +} + +function drawFolder(leftSide) +{ + if (browserVersion == 2) { + if (!doc.yPos) + doc.yPos=8 + doc.write("") + } + if (browserVersion == 3) + { + doc.write("
") + } + + doc.write("\n") + doc.write("\n\n") + doc.write("\n
") + doc.write(leftSide) + this.outputLink() + doc.write("") + doc.write("") + if (USETEXTLINKS) + { + this.outputLink() + doc.write(this.desc + "") + } + else + doc.write(this.desc) + if (this.tagName!="") + { + doc.write(" [external]") + } + doc.write("
\n") + + if (browserVersion == 2) { + doc.write("") + } + if (browserVersion == 3) { + doc.write("
") + } + + if (browserVersion == 1) { + this.navObj = doc.all["folder"+this.id] + this.iconImg = doc.all["folderIcon"+this.id] + this.nodeImg = doc.all["nodeIcon"+this.id] + } else if (browserVersion == 2) { + this.navObj = doc.layers["folder"+this.id] + this.iconImg = this.navObj.document.images["folderIcon"+this.id] + this.nodeImg = this.navObj.document.images["nodeIcon"+this.id] + doc.yPos=doc.yPos+this.navObj.clip.height + } else if (browserVersion == 3) { + this.navObj = doc.getElementById("folder"+this.id) + this.iconImg = doc.images.namedItem("folderIcon"+this.id) + this.nodeImg = doc.images.namedItem("nodeIcon"+this.id) + } +} + +function outputFolderLink() +{ + if (this.hreference) + { + doc.write(" 0) + doc.write("onClick='javascript:clickOnFolder("+this.id+")'") + doc.write(">") + } + else + doc.write("") +} + +function addChild(childNode) +{ + this.children[this.nChildren] = childNode + this.nChildren++ + return childNode +} + +function folderSubEntries() +{ + var i = 0 + var se = this.nChildren + + for (i=0; i < this.nChildren; i++){ + if (this.children[i].children) //is a folder + se = se + this.children[i].subEntries() + } + + return se +} + + +// Definition of class Item (a document or link inside a Folder) +// ************************************************************* + +function Item(itemDescription, tagName, itemLink) // Constructor +{ + // constant data + this.desc = itemDescription + this.tagName = tagName + this.link = itemLink + this.id = -1 //initialized in initalize() + this.navObj = 0 //initialized in render() + this.iconImg = 0 //initialized in render() + this.iconSrc = "ftv2doc.png" + + // methods + this.initialize = initializeItem + this.createIndex = createEntryIndex + this.hide = hideItem + this.display = display + this.renderOb = drawItem + this.totalHeight = totalHeight +} + +function hideItem() +{ + if (browserVersion == 1 || browserVersion == 3) { + if (this.navObj.style.display == "none") + return + this.navObj.style.display = "none" + } else { + if (this.navObj.visibility == "hidden") + return + this.navObj.visibility = "hidden" + } +} + +function initializeItem(level, lastNode, leftSide) +{ + this.createIndex() + + if (level>0) + if (lastNode) //the last 'brother' in the children array + { + this.renderOb(leftSide + "") + leftSide = leftSide + "" + } + else + { + this.renderOb(leftSide + "") + leftSide = leftSide + "" + } + else + this.renderOb("") +} + +function drawItem(leftSide) +{ + if (browserVersion == 2) + doc.write("") + if (browserVersion == 3) + doc.write("
") + + doc.write("\n\n") + doc.write("\n
") + doc.write(leftSide) + if (this.link!="") + { + doc.write("") + } + doc.write("") + if (this.link!="") + { + doc.write("") + } + doc.write("") + if (USETEXTLINKS && this.link!="") + doc.write("" + this.desc + "") + else + doc.write(this.desc) + if (this.tagName!="") + { + doc.write(" [external]"); + } + doc.write("\n
\n") + + if (browserVersion == 2) + doc.write("") + if (browserVersion == 3) + doc.write("
") + + if (browserVersion == 1) { + this.navObj = doc.all["item"+this.id] + this.iconImg = doc.all["itemIcon"+this.id] + } else if (browserVersion == 2) { + this.navObj = doc.layers["item"+this.id] + this.iconImg = this.navObj.document.images["itemIcon"+this.id] + doc.yPos=doc.yPos+this.navObj.clip.height + } else if (browserVersion == 3) { + this.navObj = doc.getElementById("item"+this.id) + this.iconImg = doc.images.namedItem("itemIcon"+this.id) + } +} + + +// Methods common to both objects (pseudo-inheritance) +// ******************************************************** + +function display() +{ + if (browserVersion == 1 || browserVersion == 3) + this.navObj.style.display = "block" + else + this.navObj.visibility = "show" +} + +function createEntryIndex() +{ + this.id = nEntries + indexOfEntries[nEntries] = this + nEntries++ +} + +// total height of subEntries open +function totalHeight() //used with browserVersion == 2 +{ + var h = this.navObj.clip.height + var i = 0 + + if (this.isOpen) //is a folder and _is_ open + for (i=0 ; i < this.nChildren; i++) + h = h + this.children[i].totalHeight() + + return h +} + + +// Events +// ********************************************************* + +function clickOnFolder(folderId) +{ + var clicked = indexOfEntries[folderId] + + if (!clicked.isOpen) + clickOnNode(folderId) + + return + + if (clicked.isSelected) + return +} + +function clickOnNode(folderId) +{ + var clickedFolder = 0 + var state = 0 + + clickedFolder = indexOfEntries[folderId] + state = clickedFolder.isOpen + + clickedFolder.setState(!state) //open<->close +} + +function initializeDocument() +{ + doc = document; + if (doc.all) + browserVersion = 1 //IE4 + else + if (doc.layers) + browserVersion = 2 //NS4 + else if(navigator.userAgent.toLowerCase().indexOf('gecko') != -1) + browserVersion = 3 //mozilla + else + browserVersion = 0 //other + + foldersTree.initialize(0, 1, "") + foldersTree.display() + + if (browserVersion > 0) + { + if(browserVersion != 3) + doc.write(" ") + + // close the whole tree + clickOnNode(0) + // open the root folder + clickOnNode(0) + } +} + +// Auxiliary Functions for Folder-Treee backward compatibility +// ********************************************************* + +function gFld(description, tagName, hreference) +{ + folder = new Folder(description, tagName, hreference) + return folder +} + +function gLnk(description, tagName, linkData) +{ + fullLink = "" + + if (linkData!="") + { + fullLink = "'"+linkData+"' target=\"basefrm\"" + } + + linkItem = new Item(description, tagName, fullLink) + return linkItem +} + +function insFld(parentFolder, childFolder) +{ + return parentFolder.addChild(childFolder) +} + +function insDoc(parentFolder, document) +{ + parentFolder.addChild(document) +} + +// Global variables +// **************** + +USETEXTLINKS = 1 +indexOfEntries = new Array +nEntries = 0 +doc = document +browserVersion = 0 +selectedFolder=0 diff --git a/docs/module-doc/users_8cpp-source.html b/docs/module-doc/users_8cpp-source.html new file mode 100644 index 000000000..8575303e7 --- /dev/null +++ b/docs/module-doc/users_8cpp-source.html @@ -0,0 +1,109 @@ + + +users.cpp Source File + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

users.cpp

Go to the documentation of this file.
00001 /*
+00002 
+00003 $Log$
+00003 Revision 1.1  2003/01/23 19:45:58  brain
+00003 Initial revision
+00003 
+00003 Revision 1.6  2003/01/22 20:59:12  brain
+00003 Added FileReader class documentation
+00003 
+00004 Revision 1.3  2003/01/17 13:21:38  brain
+00005 Added CONNECT ALLOW and CONNECT DENY config tags
+00006 Added PASS command
+00007 
+00008 Revision 1.2  2003/01/17 10:37:55  brain
+00009 Added /INVITE command and relevent structures
+00010 
+00011 Revision 1.1  2003/01/16 01:10:04  brain
+00012 forgot to add this
+00013 
+00014 
+00015 */
+00016 
+00017 #include "inspircd_config.h" 
+00018 #include "channels.h"
+00019 #include "users.h"
+00020 #include "inspircd.h"
+00021 #include <stdio.h>
+00022 
+00023 userrec::userrec()
+00024 {
+00025         // the PROPER way to do it, AVOID bzero at *ALL* costs
+00026         strcpy(nick,"");
+00027         ip = 0;
+00028         strcpy(ident,"");
+00029         strcpy(host,"");
+00030         strcpy(dhost,"");
+00031         strcpy(fullname,"");
+00032         strcpy(modes,"");
+00033         strcpy(inbuf,"");
+00034         strcpy(server,"");
+00035         strcpy(awaymsg,"");
+00036         fd = lastping = signon = idle_lastmsg = nping = registered = 0;
+00037         port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+00038         haspassed = false;
+00039         strcpy(result,"");
+00040         for (int i = 0; i < MAXCHANS; i++)
+00041         {
+00042                 chans[i].channel = NULL;
+00043         }
+00044         invites.clear();
+00045 }
+00046 
+00047  
+00048 char* userrec::GetFullHost()
+00049 {
+00050         sprintf(result,"%s!%s@%s",nick,ident,dhost);
+00051         return result;
+00052 }
+00053 
+00054 
+00055 char* userrec::GetFullRealHost()
+00056 {
+00057         sprintf(result,"%s!%s@%s",nick,ident,host);
+00058         return result;
+00059 }
+00060 
+00061 bool userrec::IsInvited(char* channel)
+00062 {
+00063         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+00064         {
+00065                 if (!strcasecmp(i->channel,channel))
+00066                 {
+00067                         return true;
+00068                 }
+00069         }
+00070 }
+00071 
+00072 void userrec::InviteTo(char* channel)
+00073 {
+00074         Invited i;
+00075         strcpy(i.channel,channel);
+00076         invites.push_back(i);
+00077 }
+00078 
+00079 void userrec::RemoveInvite(char* channel)
+00080 {
+00081         for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++)
+00082         {
+00083                 if (!strcasecmp(i->channel,channel))
+00084                 {
+00085                         invites.erase(i);
+00086                         return;
+00087                 }
+00088         }
+00089 }
+

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/users_8cpp.html b/docs/module-doc/users_8cpp.html new file mode 100644 index 000000000..10c198675 --- /dev/null +++ b/docs/module-doc/users_8cpp.html @@ -0,0 +1,24 @@ + + +users.cpp File Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

users.cpp File Reference

#include "inspircd_config.h"
+#include "channels.h"
+#include "users.h"
+#include "inspircd.h"
+#include <stdio.h>
+ +

+Go to the source code of this file. + +
+


Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/users_8h-source.html b/docs/module-doc/users_8h-source.html new file mode 100644 index 000000000..446423af1 --- /dev/null +++ b/docs/module-doc/users_8h-source.html @@ -0,0 +1,158 @@ + + +users.h Source File + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

users.h

Go to the documentation of this file.
00001 /*
+00002 
+00003 $Log$
+00003 Revision 1.1  2003/01/23 19:45:58  brain
+00003 Initial revision
+00003 
+00003 Revision 1.6  2003/01/22 20:59:12  brain
+00003 Added FileReader class documentation
+00003 
+00004 Revision 1.9  2003/01/22 00:44:26  brain
+00005 Added documentation comments
+00006 
+00007 Revision 1.8  2003/01/21 21:11:17  brain
+00008 Added documentation
+00009 
+00010 Revision 1.7  2003/01/17 13:21:38  brain
+00011 Added CONNECT ALLOW and CONNECT DENY config tags
+00012 Added PASS command
+00013 
+00014 Revision 1.6  2003/01/17 10:37:55  brain
+00015 Added /INVITE command and relevent structures
+00016 
+00017 Revision 1.5  2003/01/16 20:11:56  brain
+00018 fixed some ugly pointer bugs (thanks dblack and a|KK|y!)
+00019 
+00020 Revision 1.4  2003/01/15 22:47:44  brain
+00021 Changed user and channel structs to classes (finally)
+00022 
+00023 Revision 1.3  2003/01/14 21:14:30  brain
+00024 added /ISON command (for mIRC etc basic notify)
+00025 
+00026 
+00027 */
+00028 
+00029 #include "inspircd_config.h" 
+00030 #include "channels.h"
+00031 
+00032 #include <string>
+00033  
+00034 #ifndef __USERS_H__ 
+00035 #define __USERS_H__ 
+00036  
+00037 #define STATUS_OP       4
+00038 #define STATUS_HOP      2
+00039 #define STATUS_VOICE    1
+00040 #define STATUS_NORMAL   0
+00041 
+00042 #define CC_ALLOW        0
+00043 #define CC_DENY         1
+00044 
+00047 class Invited
+00048 {
+00049  public:
+00050         char channel[CHANMAX];
+00051 };
+00052 
+00053 
+00056 class ConnectClass
+00057 {
+00058  public:
+00059         int type;
+00060         char host[MAXBUF];
+00061         char pass[MAXBUF];
+00062 };
+00063 
+00066 typedef vector<Invited> InvitedList;
+00067 
+00068 
+00069 
+00072 typedef vector<ConnectClass> ClassVector;
+00073 
+00080 class userrec
+00081 {
+00082  private:
+00083 
+00086         InvitedList invites;
+00087  public:
+00088         
+00093         char nick[NICKMAX];
+00094         
+00097         unsigned long ip;
+00098 
+00101         char ident[64];
+00102 
+00105         char host[256];
+00106         
+00110         char dhost[256];
+00111         
+00114         char fullname[128];
+00115         
+00120         int fd;
+00121         
+00126         char modes[32];
+00127         
+00131         char inbuf[MAXBUF];
+00132         
+00138         time_t lastping;
+00139         
+00142         time_t signon;
+00143         
+00147         time_t idle_lastmsg;
+00148         
+00153         time_t nping;
+00154         
+00159         int registered;
+00160         
+00165         ucrec chans[MAXCHANS];
+00166         
+00169         char server[256];
+00170         
+00174         char awaymsg[512];
+00175         
+00178         int port;
+00179         
+00183         long bytes_in;
+00184         
+00188         long bytes_out;
+00189         
+00193         long cmds_in;
+00194         
+00198         long cmds_out;
+00199         
+00203         char result[256];
+00204         
+00209         bool haspassed;
+00210 
+00211         userrec();
+00212         
+00213         virtual ~userrec() {  }
+00214         
+00219         virtual char* GetFullHost();
+00220         
+00226         virtual char* GetFullRealHost();
+00227         
+00230         virtual bool IsInvited(char* channel);
+00231         
+00234         virtual void InviteTo(char* channel);
+00235         
+00240         virtual void RemoveInvite(char* channel);
+00241         
+00242 };
+00243 
+00244 
+00245 #endif
+

Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/docs/module-doc/users_8h.html b/docs/module-doc/users_8h.html new file mode 100644 index 000000000..2593a2dcb --- /dev/null +++ b/docs/module-doc/users_8h.html @@ -0,0 +1,239 @@ + + +users.h File Reference + + + +
+Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  
+

users.h File Reference

#include "inspircd_config.h"
+#include "channels.h"
+#include <string>
+ +

+Go to the source code of this file. + + + + + + + + + + + + + + + + + + + + +

Compounds

class  ConnectClass
 Holds information relevent to <connect allow> and <connect deny> tags in the config file. More...

class  Invited
 Holds a channel name to which a user has been invited. More...

class  userrec
 Holds all information about a user This class stores all information about a user connected to the irc server. More...


Defines

#define STATUS_OP   4
#define STATUS_HOP   2
#define STATUS_VOICE   1
#define STATUS_NORMAL   0
#define CC_ALLOW   0
#define CC_DENY   1

Typedefs

typedef vector< InvitedInvitedList
 Holds a complete list of all channels to which a user has been invited and has not yet joined.

typedef vector< ConnectClassClassVector
 Holds a complete list of all allow and deny tags from the configuration file (connection classes).

+


Define Documentation

+

+ + + + +
+ + +
#define CC_ALLOW   0 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 42 of file users.h.

+

+ + + + +
+ + +
#define CC_DENY   1 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 43 of file users.h.

+

+ + + + +
+ + +
#define STATUS_HOP   2 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 38 of file users.h.

+

+ + + + +
+ + +
#define STATUS_NORMAL   0 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 40 of file users.h.

+

+ + + + +
+ + +
#define STATUS_OP   4 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 37 of file users.h.

+

+ + + + +
+ + +
#define STATUS_VOICE   1 +
+
+ + + + + +
+   + + +

+ +

+Definition at line 39 of file users.h.

+


Typedef Documentation

+

+ + + + +
+ + +
typedef vector<ConnectClass> ClassVector +
+
+ + + + + +
+   + + +

+Holds a complete list of all allow and deny tags from the configuration file (connection classes). +

+ +

+Definition at line 72 of file users.h.

+

+ + + + +
+ + +
typedef vector<Invited> InvitedList +
+
+ + + + + +
+   + + +

+Holds a complete list of all channels to which a user has been invited and has not yet joined. +

+ +

+Definition at line 66 of file users.h.

+


Generated on Wed Jan 22 20:56:47 2003 for InspIRCd by + +doxygen1.3-rc2
+ + diff --git a/include/channels.h b/include/channels.h new file mode 100644 index 000000000..c9cdd7b31 --- /dev/null +++ b/include/channels.h @@ -0,0 +1,199 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.7 2003/01/22 00:44:26 brain +Added documentation comments + +Revision 1.6 2003/01/21 21:11:17 brain +Added documentation + +Revision 1.5 2003/01/16 20:11:55 brain +fixed some ugly pointer bugs (thanks dblack and a|KK|y!) + +Revision 1.4 2003/01/15 22:47:44 brain +Changed user and channel structs to classes (finally) + + +*/ + +#include "inspircd_config.h" +#include +#include + +#ifndef __CHANNELS_H__ +#define __CHANNELS_H__ + +/** Holds an entry for a ban list, exemption list, or invite list. + * This class contains a single element in a channel list, such as a banlist. + */ +class HostItem +{ + public: + time_t set_time; + char set_by[NICKMAX]; + char data[MAXBUF]; + + HostItem() { /* stub */ } + virtual ~HostItem() { /* stub */ } +}; + +// banlist is inherited from HostList mainly for readability +// reasons only + +/** A subclass of HostItem designed to hold channel bans (+b) + */ +class BanItem : public HostItem +{ +}; + +// same with this... + +/** A subclass of HostItem designed to hold channel exempts (+e) + */ +class ExemptItem : public HostItem +{ +}; + +// and this... + +/** A subclass of HostItem designed to hold channel invites (+I) + */ +class InviteItem : public HostItem +{ +}; + + +/** Holds a complete ban list + */ +typedef vector BanList; + +/** Holds a complete exempt list + */ +typedef vector ExemptList; + +/** Holds a complete invite list + */ +typedef vector InviteList; + +/** Holds all relevent information for a channel. + * This class represents a channel, and contains its name, modes, time created, topic, topic set time, + * etc, and an instance of the BanList type. + */ +class chanrec +{ + public: + /** The channels name. + */ + char name[CHANMAX]; /* channel name */ + /** Custom modes for the channel. + * Plugins may use this field in any way they see fit. + */ + char custom_modes[MAXMODES]; /* modes handled by modules */ + /** Channel topic. + * If this is an empty string, no channel topic is set. + */ + char topic[MAXBUF]; + /** Creation time. + */ + time_t created; + /** Time topic was set. + * If no topic was ever set, this will be equal to chanrec::created + */ + time_t topicset; + /** The last user to set the topic. + * If this member is an empty string, no topic was ever set. + */ + char setby[NICKMAX]; + + /** Contains the channel user limit. + * If this value is zero, there is no limit in place. + */ + long limit; + + /** Contains the channel key. + * If this value is an empty string, there is no channel key in place. + */ + char key[32]; + + /** Nonzero if the mode +t is set. + */ + short int topiclock; + + /** Nonzero if the mode +n is set. + */ + short int noexternal; + + /** Nonzero if the mode +i is set. + */ + short int inviteonly; + + /** Nonzero if the mode +m is set. + */ + short int moderated; + + /** Nonzero if the mode +s is set. + * This value cannot be set at the same time as chanrec::c_private + */ + short int secret; + + /** Nonzero if the mode +p is set. + * This value cannot be set at the same time as chanrec::secret + */ + short int c_private; + + /** The list of all bans set on the channel. + */ + BanList bans; + + /** Creates a channel record and initialises it with default values + */ + chanrec() + { + strcpy(name,""); + strcpy(custom_modes,""); + strcpy(topic,""); + strcpy(setby,""); + strcpy(key,""); + created = topicset = limit = 0; + topiclock = noexternal = inviteonly = moderated = secret = c_private = false; + } + + virtual ~chanrec() { /* stub */ } +}; + +/* used to hold a channel and a users modes on that channel, e.g. +v, +h, +o + * needs to come AFTER struct chanrec */ + +#define UCMODE_OP 1 +#define UCMODE_VOICE 2 +#define UCMODE_HOP 4 +#define UCMODE_PROTECT 8 +#define UCMODE_FOUNDER 16 + +/** Holds a user's modes on a channel + * This class associates a users privilages with a channel by creating a pointer link between + * a userrec and chanrec class. The uc_modes member holds a bitmask of which privilages the user + * has on the channel, such as op, voice, etc. + */ +class ucrec +{ + public: + /** Contains a bitmask of the UCMODE_OP ... UCMODE_FOUNDER values. + * If this value is zero, the user has no privilages upon the channel. + */ + long uc_modes; + + /** Points to the channel record where the given modes apply. + * If the record is not in use, this value will be NULL. + */ + chanrec *channel; + + ucrec() { /* stub */ } + virtual ~ucrec() { /* stub */ } +}; + +#endif + diff --git a/include/ctables.h b/include/ctables.h new file mode 100644 index 000000000..78eb150d9 --- /dev/null +++ b/include/ctables.h @@ -0,0 +1,53 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * Inspire is copyright (C) 2002-2003 ChatSpike-Dev. + * E-mail: + * + * + * + * Written by Craig Edwards, Craig McLure, and others. + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + + $Log$ + Revision 1.1 2003/01/23 19:45:58 brain + Initial revision + + Revision 1.3 2003/01/15 22:47:44 brain + Changed user and channel structs to classes (finally) + + Revision 1.2 2003/01/09 21:09:50 brain + added '/stats M' command + + Revision 1.1 2003/01/07 01:02:14 brain + + definitions for command table types + + + * --------------------------------------------------- + */ +#include "inspircd_config.h" +#include "inspircd.h" + +#ifndef __CTABLES_H__ +#define __CTABLES_H__ + +typedef void (handlerfunc) (char**, int, userrec*); + +/* a structure that defines a command */ + +struct command_t { + char command[MAXBUF]; /* command name */ + handlerfunc *handler_function; /* handler function as in typedef */ + char flags_needed; /* user flags needed to execute the command or 0 */ + int min_params; /* minimum number of parameters command takes */ + long use_count; /* used by /stats m */ + long total_bytes; /* used by /stats m */ +}; + +#endif + diff --git a/include/dynamic.h b/include/dynamic.h new file mode 100644 index 000000000..b34f2358b --- /dev/null +++ b/include/dynamic.h @@ -0,0 +1,114 @@ +#ifndef __DLL_H +#define __DLL_H + +// +// class DLLManager is the simple ELF C++ Library manager. +// +// It tries to dynamically load the specified shared library +// when it is construted. +// +// You should call LastError() before doing anything. If it +// returns NULL there is no error. +// + + +class DLLManager +{ + public: + DLLManager( const char *fname ); + virtual ~DLLManager(); + + + bool GetSymbol( void **, const char *sym_name ); + + const char *LastError() + { + return err; + } + + protected: + void *h; + const char *err; +}; + + +// +// class DLLFactoryBase is the base class used for the DLLFactory +// template class. +// +// It inherits from the DLLManager class and must be constructed with +// the file name of the shared library and the function name within that +// library which will create the desired C++ factory class. +// If you do not provide func_name to the constructor, it defaults to +// the undecorated "C" symbol "factory0" +// +// factory_func will be set to a pointer to the requested factory creator +// function. If there was an error linking to the shared library, +// factory_func will be 0. +// +// You can call 'LastError()' to find the error message that occurred. +// +// + +class DLLFactoryBase : public DLLManager +{ + public: + DLLFactoryBase( + const char *fname, + const char *func_name=0 + ); + + virtual ~DLLFactoryBase(); + + void * (*factory_func)(void); +}; + + +// +// The DLLFactory template class inherits from DLLFactoryBase. +// The constructor takes the file name of the shared library +// and the undecorated "C" symbol name of the factory creator +// function. The factory creator function in your shared library +// MUST either return a pointer to an object that is a subclass +// of 'T' or it must return 0. +// +// If everything is cool, then 'factory' will point to the +// requested factory class. If not, it will be 0. +// +// Since the DLLFactory template ultimately inherits DLLManager, +// you can call LastError() to get any error code information +// +// The created factory is OWNED by the DLLFactory class. +// The created factory will get deleted when the DLLFactory class +// is deleted, because the DLL will get unloaded as well. +// + +template +class DLLFactory : public DLLFactoryBase +{ + public: + DLLFactory( + const char *fname, + const char *func_name=0 + ) : DLLFactoryBase( fname, func_name ) + { + if( factory_func ) + factory = (T *)factory_func(); + else + factory = 0; + } + + ~DLLFactory() + { + delete factory; + } + + T *factory; +}; + + + + + + +#endif diff --git a/include/globals.h b/include/globals.h new file mode 100644 index 000000000..93d5a448c --- /dev/null +++ b/include/globals.h @@ -0,0 +1,59 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.5 2003/01/22 20:49:16 brain +Added FileReader file-caching class +Changed m_randquote to use FileReader class + +Revision 1.4 2003/01/15 22:47:44 brain +Changed user and channel structs to classes (finally) + +Revision 1.3 2003/01/13 22:30:50 brain +Added Admin class (holds /admin info for modules) +Added methods to Server class + + +*/ + + +#ifndef __WORLD_H +#define __WORLD_H + +// include the common header files + +#include +#include +#include +#include +#include "users.h" +#include "channels.h" + +typedef deque file_cache; + +void WriteOpers(char* text, ...); +void debug(char *text, ...); +void Write(int sock,char *text, ...); +void WriteServ(int sock, char* text, ...); +void WriteFrom(int sock, userrec *user,char* text, ...); +void WriteTo(userrec *source, userrec *dest,char *data, ...); +void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...); +void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...); +int common_channels(userrec *u, userrec *u2); +void WriteCommon(userrec *u, char* text, ...); +void WriteCommonExcept(userrec *u, char* text, ...); +void WriteWallOps(userrec *source, char* text, ...); +int isnick(const char *n); +userrec* Find(string nick); +chanrec* FindChan(const char* chan); +char* cmode(userrec *user, chanrec *chan); +string getservername(); +string getnetworkname(); +string getadminname(); +string getadminemail(); +string getadminnick(); +void readfile(file_cache &F, const char* fname); + +#endif diff --git a/include/inspircd.h b/include/inspircd.h new file mode 100644 index 000000000..dab7258f3 --- /dev/null +++ b/include/inspircd.h @@ -0,0 +1,94 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.7 2003/01/22 20:49:16 brain +Added FileReader file-caching class +Changed m_randquote to use FileReader class + +Revision 1.6 2003/01/19 20:12:24 brain +Fixed ident max length to 10 + +Revision 1.5 2003/01/15 22:47:44 brain +Changed user and channel structs to classes (finally) + +Revision 1.4 2003/01/13 22:30:50 brain +Added Admin class (holds /admin info for modules) +Added methods to Server class + + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _LINUX_C_LIB_VERSION +#include +#include +#include +#endif +#include +#include +#include + +#include "inspircd_config.h" +#include "inspircd_io.h" +#include "inspircd_util.h" +#include "users.h" +#include "channels.h" + +#define ERROR -1 +#define TRUE 1 +#define FALSE 0 +#define IDENTMAX 9 +/* max sockets we can open */ +#define MAXSOCKS 64 + +typedef deque file_cache; + +/* prototypes */ +int InspIRCd(void); +int InitConfig(void); +void Error(int status); +void send_error(char *s); +void ReadConfig(void); +void strlower(char *n); + +void WriteOpers(char* text, ...); +void debug(char *text, ...); +void Write(int sock,char *text, ...); +void WriteServ(int sock, char* text, ...); +void WriteFrom(int sock, userrec *user,char* text, ...); +void WriteTo(userrec *source, userrec *dest,char *data, ...); +void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...); +void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...); +int common_channels(userrec *u, userrec *u2); +void WriteCommon(userrec *u, char* text, ...); +void WriteCommonExcept(userrec *u, char* text, ...); +void WriteWallOps(userrec *source, char* text, ...); +int isnick(const char *n); +userrec* Find(string nick); +chanrec* FindChan(const char* chan); +char* cmode(userrec *user, chanrec *chan); +string getservername(); +string getnetworkname(); +string getadminname(); +string getadminemail(); +string getadminnick(); +void readfile(file_cache &F, const char* fname); + diff --git a/include/inspircd_io.h b/include/inspircd_io.h new file mode 100644 index 000000000..bdf9d3e18 --- /dev/null +++ b/include/inspircd_io.h @@ -0,0 +1,43 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * Inspire is copyright (C) 2002-2003 ChatSpike-Dev. + * E-mail: + * + * + * + * Written by Craig Edwards, Craig McLure, and others. + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + + $Log$ + Revision 1.1 2003/01/23 19:45:58 brain + Initial revision + + Revision 1.5 2003/01/21 20:31:24 brain + Modified to add documentation + Added ConfigReader class for modules + + Revision 1.4 2003/01/06 23:38:29 brain + + just playing with header tags + + + * --------------------------------------------------- + */ + +void Exit (int); +void Start (void); +int DaemonSeed (void); +int CheckConfig (void); +int OpenTCPSocket (void); +int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr); + +int ConfValue(char* tag, char* var, int index, char *result); +int ReadConf(const char* filename,const char* tag, const char* var, int index, char *result); +int ConfValueEnum(char* tag); +int EnumConf(const char* filename,const char* tag); + diff --git a/include/inspircd_util.h b/include/inspircd_util.h new file mode 100644 index 000000000..f65594d34 --- /dev/null +++ b/include/inspircd_util.h @@ -0,0 +1,14 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.2 2003/01/15 22:49:18 brain +Added log macros + + +*/ + +char * SafeStrncpy (char *, const char *, size_t ); +char * CleanIpAddr (char *, const char *); diff --git a/include/modules.h b/include/modules.h new file mode 100644 index 000000000..971f3ec26 --- /dev/null +++ b/include/modules.h @@ -0,0 +1,334 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.12 2003/01/22 20:59:10 brain +Added FileReader class documentation + +Revision 1.11 2003/01/22 20:49:16 brain +Added FileReader file-caching class +Changed m_randquote to use FileReader class + +Revision 1.10 2003/01/22 00:57:27 brain +Changes to documentation + +Revision 1.9 2003/01/22 00:44:26 brain +Added documentation comments + +Revision 1.8 2003/01/21 20:31:24 brain +Modified to add documentation +Added ConfigReader class for modules + +Revision 1.7 2003/01/15 22:47:44 brain +Changed user and channel structs to classes (finally) + +Revision 1.6 2003/01/13 22:30:50 brain +Added Admin class (holds /admin info for modules) +Added methods to Server class + + +*/ + + +#ifndef __PLUGIN_H +#define __PLUGIN_H + +#include "dynamic.h" +#include +#include + +/** Low level definition of a FileReader classes file cache area + */ +typedef deque file_cache; + + +// This #define allows us to call a method in all +// loaded modules in a readable simple way, e.g.: +// 'FOREACH_MOD OnConnect(user);' + +#define FOREACH_MOD for (int i = 0; i <= MODCOUNT; i++) modules[i]-> + +// class Version holds the version information of a Module, returned +// by Module::GetVersion (thanks RD) + +/** Holds a module's Version information + * The four members (set by the constructor only) indicate details as to the version number + * of a module. A class of type Version is returned by the GetVersion method of the Module class. + */ +class Version +{ + public: + const int Major, Minor, Revision, Build; + Version(int major, int minor, int revision, int build); +}; + + +/** Holds /ADMIN data + * This class contains the admin details of the local server. It is constructed by class Server, + * and has three read-only values, Name, Email and Nick that contain the specified values for the + * server where the module is running. + */ +class Admin +{ + public: + const string Name, Email, Nick; + Admin(string name,string email,string nick); +}; + +/** Base class for all InspIRCd modules + * This class is the base class for InspIRCd modules. All modules must inherit from this class, + * its methods will be called when irc server events occur. class inherited from module must be + * instantiated by the ModuleFactory class (see relevent section) for the plugin to be initialised. + */ +class Module +{ + public: + /** Default constructor + * creates a module class + */ + Module(); + /** Default destructor + * destroys a module class + */ + virtual ~Module(); + /** Returns the version number of a Module. + * The method should return a Version object with its version information assigned via + * Version::Version + */ + virtual Version GetVersion(); + /** Called when a user connects. + * The details of the connecting user are available to you in the parameter userrec *user + */ + virtual void OnUserConnect(userrec* user); + /** Called when a user quits. + * The details of the exiting user are available to you in the parameter userrec *user + */ + virtual void OnUserQuit(userrec* user); + /** Called when a user joins a channel. + * The details of the joining user are available to you in the parameter userrec *user, + * and the details of the channel they have joined is available in the variable chanrec *channel + */ + virtual void OnUserJoin(userrec* user, chanrec* channel); + /** Called when a user parts a channel. + * The details of the leaving user are available to you in the parameter userrec *user, + * and the details of the channel they have left is available in the variable chanrec *channel + */ + virtual void OnUserPart(userrec* user, chanrec* channel); +}; + + +/** Allows server output and query functions + * This class contains methods which allow a module to query the state of the irc server, and produce + * output to users and other servers. All modules should instantiate at least one copy of this class, + * and use its member functions to perform their tasks. + */ +class Server +{ + public: + /** Default constructor. + * Creates a Server object. + */ + Server(); + /** Default destructor. + * Destroys a Server object. + */ + virtual ~Server(); + + /** Sends text to all opers. + * This method sends a server notice to all opers with the usermode +s. + */ + virtual void SendOpers(string s); + /** Sends a debug string. + * This method writes a line of text to the debug log. If debugging is disabled + * in the configuration, this command has no effect. + */ + virtual void Debug(string s); + /** Sends a line of text down a TCP/IP socket. + * This method writes a line of text to an established socket, cutting it to 510 characters + * plus a carriage return and linefeed if required. + */ + virtual void Send(int Socket, string s); + /** Sends text from the server to a socket. + * This method writes a line of text to an established socket, with the servername prepended + * as used by numerics (see RFC 1459) + */ + virtual void SendServ(int Socket, string s); + /** Sends text from a user to a socket. + * This method writes a line of text to an established socket, with the given user's nick/ident + * /host combination prepended, as used in PRIVSG etc commands (see RFC 1459) + */ + virtual void SendFrom(int Socket, userrec* User, string s); + /** Sends text from a user to another user. + * This method writes a line of text to a user, with a user's nick/ident + * /host combination prepended, as used in PRIVMSG etc commands (see RFC 1459) + */ + virtual void SendTo(userrec* Source, userrec* Dest, string s); + /** Sends text from a user to a channel (mulicast). + * This method writes a line of text to a channel, with the given user's nick/ident + * /host combination prepended, as used in PRIVMSG etc commands (see RFC 1459). If the + * IncludeSender flag is set, then the text is also sent back to the user from which + * it originated, as seen in MODE (see RFC 1459). + */ + virtual void SendChannel(userrec* User, chanrec* Channel, string s,bool IncludeSender); + /** Returns true if two users share a common channel. + * This method is used internally by the NICK and QUIT commands, and the Server::SendCommon + * method. + */ + virtual bool CommonChannels(userrec* u1, userrec* u2); + /** Sends text from a user to one or more channels (mulicast). + * This method writes a line of text to all users which share a common channel with a given + * user, with the user's nick/ident/host combination prepended, as used in PRIVMSG etc + * commands (see RFC 1459). If the IncludeSender flag is set, then the text is also sent + * back to the user from which it originated, as seen in NICK (see RFC 1459). Otherwise, it + * is only sent to the other recipients, as seen in QUIT. + */ + virtual void SendCommon(userrec* User, string text,bool IncludeSender); + /** Sends a WALLOPS message. + * This method writes a WALLOPS message to all users with the +w flag, originating from the + * specified user. + */ + virtual void SendWallops(userrec* User, string text); + + /** Returns true if a nick is valid. + * Nicks for unregistered connections will return false. + */ + virtual bool IsNick(string nick); + /** Attempts to look up a nick and return a pointer to it. + * This function will return NULL if the nick does not exist. + */ + virtual userrec* FindNick(string nick); + /** Attempts to look up a channel and return a pointer to it. + * This function will return NULL if the channel does not exist. + */ + virtual chanrec* FindChannel(string channel); + /** Attempts to look up a user's privilages on a channel. + * This function will return a string containing either @, %, +, or an empty string, + * representing the user's privilages upon the channel you specify. + */ + virtual string ChanMode(userrec* User, chanrec* Chan); + /** Returns the server name of the server where the module is loaded. + */ + virtual string GetServerName(); + /** Returns the network name, global to all linked servers. + */ + virtual string GetNetworkName(); + /** Returns the information of the server as returned by the /ADMIN command. + * See the Admin class for further information of the return value. The members + * Admin::Nick, Admin::Email and Admin::Name contain the information for the + * server where the module is loaded. + */ + virtual Admin GetAdmin(); + +}; + +/** Allows reading of values from configuration files + * This class allows a module to read from either the main configuration file (inspircd.conf) or from + * a module-specified configuration file. It may either be instantiated with one parameter or none. + * Constructing the class using one parameter allows you to specify a path to your own configuration + * file, otherwise, inspircd.conf is read. + */ +class ConfigReader +{ + protected: + /** The filename of the configuration file, as set by the constructor. + */ + string fname; + public: + /** Default constructor. + * This constructor initialises the ConfigReader class to read the inspircd.conf file + * as specified when running ./configure. + */ + ConfigReader(); // default constructor reads ircd.conf + /** Overloaded constructor. + * This constructor initialises the ConfigReader class to read a user-specified config file + */ + ConfigReader(string filename); // read a module-specific config + /** Default destructor. + * This method destroys the ConfigReader class. + */ + ~ConfigReader(); + /** Retrieves a value from the config file. + * This method retrieves a value from the config file. Where multiple copies of the tag + * exist in the config file, index indicates which of the values to retrieve. + */ + string ReadValue(string tag, string name, int index); + /** Counts the number of times a given tag appears in the config file. + * This method counts the number of times a tag appears in a config file, for use where + * there are several tags of the same kind, e.g. with opers and connect types. It can be + * used with the index value of ConfigReader::ReadValue to loop through all copies of a + * multiple instance tag. + */ + int Enumerate(string tag); + /** Returns true if a config file is valid. + * This method is unimplemented and will always return true. + */ + bool Verify(); +}; + + + +/** Caches a text file into memory and can be used to retrieve lines from it. + * This class contains methods for read-only manipulation of a text file in memory. + * Either use the constructor type with one parameter to load a file into memory + * at construction, or use the LoadFile method to load a file. + */ +class FileReader +{ + file_cache fc; + public: + /** Default constructor. + * This method does not load any file into memory, you must use the LoadFile method + * after constructing the class this way. + */ + FileReader(); + /** Secondary constructor. + * This method initialises the class with a file loaded into it ready for GetLine and + * and other methods to be called. If the file could not be loaded, FileReader::FileSize + * returns 0. + */ + FileReader(string filename); + /** Default destructor. + * This deletes the memory allocated to the file. + */ + ~FileReader(); + /** Used to load a file. + * This method loads a file into the class ready for GetLine and + * and other methods to be called. If the file could not be loaded, FileReader::FileSize + * returns 0. + */ + void LoadFile(string filename); + /** Retrieve one line from the file. + * This method retrieves one line from the text file. If an empty non-NULL string is returned, + * the index was out of bounds, or the line had no data on it. + */ + string GetLine(int x); + /** Returns the size of the file in lines. + * This method returns the number of lines in the read file. If it is 0, no lines have been + * read into memory, either because the file is empty or it does not exist, or cannot be + * opened due to permission problems. + */ + int FileSize(); +}; + + +/** Instantiates classes inherited from Module + * This class creates a class inherited from type Module, using new. This is to allow for modules + * to create many different variants of Module, dependent on architecture, configuration, etc. + * In most cases, the simple class shown in the example module m_foobar.so will suffice for most + * modules. + */ +class ModuleFactory +{ + public: + ModuleFactory() { } + virtual ~ModuleFactory() { } + /** Creates a new module. + * Your inherited class of ModuleFactory must return a pointer to your Module class + * using this method. + */ + virtual Module * CreateModule() = 0; +}; + +#endif diff --git a/include/users.h b/include/users.h new file mode 100644 index 000000000..dddda8dd6 --- /dev/null +++ b/include/users.h @@ -0,0 +1,248 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.9 2003/01/22 00:44:26 brain +Added documentation comments + +Revision 1.8 2003/01/21 21:11:17 brain +Added documentation + +Revision 1.7 2003/01/17 13:21:38 brain +Added CONNECT ALLOW and CONNECT DENY config tags +Added PASS command + +Revision 1.6 2003/01/17 10:37:55 brain +Added /INVITE command and relevent structures + +Revision 1.5 2003/01/16 20:11:56 brain +fixed some ugly pointer bugs (thanks dblack and a|KK|y!) + +Revision 1.4 2003/01/15 22:47:44 brain +Changed user and channel structs to classes (finally) + +Revision 1.3 2003/01/14 21:14:30 brain +added /ISON command (for mIRC etc basic notify) + + +*/ + +#include "inspircd_config.h" +#include "channels.h" + +#include + +#ifndef __USERS_H__ +#define __USERS_H__ + +#define STATUS_OP 4 +#define STATUS_HOP 2 +#define STATUS_VOICE 1 +#define STATUS_NORMAL 0 + +#define CC_ALLOW 0 +#define CC_DENY 1 + +/** Holds a channel name to which a user has been invited. + */ +class Invited +{ + public: + char channel[CHANMAX]; +}; + + +/** Holds information relevent to <connect allow> and <connect deny> tags in the config file. + */ +class ConnectClass +{ + public: + int type; + char host[MAXBUF]; + char pass[MAXBUF]; +}; + +/** Holds a complete list of all channels to which a user has been invited and has not yet joined. + */ +typedef vector InvitedList; + + + +/** Holds a complete list of all allow and deny tags from the configuration file (connection classes) + */ +typedef vector ClassVector; + +/** Holds all information about a user + * This class stores all information about a user connected to the irc server. Everything about a + * connection is stored here primarily, from the user's socket ID (file descriptor) through to the + * user's nickname and hostname. Use the Find method of the server class to locate a specific user + * by nickname. + */ +class userrec +{ + private: + + /** A list of channels the user has a pending invite to. + */ + InvitedList invites; + public: + + /** The users nickname. + * An invalid nickname indicates an unregistered connection prior to the NICK command. + */ + + char nick[NICKMAX]; + + /** The users ip address in network order. + */ + unsigned long ip; + + /** The users ident reply. + */ + char ident[64]; + + /** The users hostname, or ip address in string form. + */ + char host[256]; + + /** The host displayed to non-opers (used for cloaking etc). + * This usually matches the value of userrec::host. + */ + char dhost[256]; + + /** The users full name. + */ + char fullname[128]; + + /** The users file descriptor. + * If this is zero, the socket has been closed and the core has not yet + * realised and removed the record from memory. + */ + int fd; + + /** The user's mode string. + * This may contain any of the following RFC characters: o, w, s, i + * Your module may define other mode characters as it sees fit. + */ + char modes[32]; + + /** The users input buffer. + * Used by the C recv() function. + */ + char inbuf[MAXBUF]; + + /** The last time the user was pinged by the core. + * When this value is more than 120 seconds difference from 'time(NULL)', a ping is sent + * to the client. If the user has an outstanding PING request the next time this + * event occurs after 4 total minutes, they are disconnected. + */ + time_t lastping; + + /** The users signon time. + */ + time_t signon; + + /** The time the user last sent a message. + * See also userrec::lastping and userrec::signon + */ + time_t idle_lastmsg; + + /** True if the user replied to their last ping. + * If this is true, the user can be sent another ping at the specified time, otherwise + * they will be discnnected. See also userrec::lastping + */ + time_t nping; + + /** Bit 1 is set if the user sent a NICK command, bit 2 is set if the user sent a USER command. + * If both bits are set then the connection is awaiting MOTD. Sending of MOTD sets bit 3, and + * makes the value of userrec::registered == 7, showing a fully established client session. + */ + int registered; + + /** A list of the channels the user is currently on. + * If any of these values are NULL, the record is not in use and may be associated with + * a channel by the JOIN command. see RFC 1459. + */ + ucrec chans[MAXCHANS]; + + /** The server the user is connected to. + */ + char server[256]; + + /** The user's away message. + * If this string is empty, the user is not marked as away. + */ + char awaymsg[512]; + + /** The port that the user connected to. + */ + int port; + + /** Stores the number of incoming bytes from the connection. + * Used by /STATS + */ + long bytes_in; + + /** Stores the number of outgoing bytes to the connection. + * Used by /STATS + */ + long bytes_out; + + /** Stores the number of incoming commands from the connection. + * Used by /STATS + */ + long cmds_in; + + /** Stores the number of outgoing commands to the connection. + * Used by /STATS + */ + long cmds_out; + + /** Stores the result of the last GetFullHost or GetRealHost call. + * You may use this to increase the speed of use of this class. + */ + char result[256]; + + /** True if a correct password has been given using PASS command. + * If the user is a member of a connection class that does not require a password, + * the value stored here is of no use. + */ + bool haspassed; + + userrec(); + + virtual ~userrec() { } + + /** Returns the full displayed host of the user + * This member function returns the hostname of the user as seen by other users + * on the server, in nick!ident&at;host form. + */ + virtual char* GetFullHost(); + + /** Returns the full real host of the user + * This member function returns the hostname of the user as seen by other users + * on the server, in nick!ident&at;host form. If any form of hostname cloaking is in operation, + * e.g. through a module, then this method will ignore it and return the true hostname. + */ + virtual char* GetFullRealHost(); + + /** Returns true if a user is invited to a channel. + */ + virtual bool IsInvited(char* channel); + + /** Adds a channel to a users invite list (invites them to a channel) + */ + virtual void InviteTo(char* channel); + + /** Removes a channel from a users invite list. + * This member function is called on successfully joining an invite only channel + * to which the user has previously been invited, to clear the invitation. + */ + virtual void RemoveInvite(char* channel); + +}; + + +#endif diff --git a/include/wildcard.h b/include/wildcard.h new file mode 100644 index 000000000..ab6e6d71e --- /dev/null +++ b/include/wildcard.h @@ -0,0 +1,7 @@ +#include +#include "inspircd_config.h" + +void Delete(char* str,int pos); +void Insert(char* substr,char* str,int pos); +bool match(char* literal, char* mask); + diff --git a/makeconf b/makeconf new file mode 100755 index 000000000..7df9226bc --- /dev/null +++ b/makeconf @@ -0,0 +1,693 @@ +#!/bin/sh +# InspIRCd Configuration Creator +# +# Copyright 2003 The ChatSpike Development Team +# +# +# +# $Id$ +# +######################################################## + +echo "Configuring Default Values" + +PERL=`which perl` +if [ "$PERL" = "" ] ; then + echo "You require perl to run this program." + exit; +fi + +ME=`pwd` +SERV_NAME="my.server.name" +SERV_DESC="My InspIRCd Server" +SERV_NET="MyNetwork" + +ADMIN_NAME="My Name" +ADMIN_NICK="MyNick" +ADMIN_MAIL="My@E-Mail.Address" + +DIE_PASS="DieNow" +RESTART_PASS="RestartNow" +DIE_WAIT="5" + +CONNECT_ALLOW="*" +CONNECT_PASS="ServerPass" + +VHOST_DOMAIN="inspircd.org" + +OPER_NICK="Fred" +OPER_PASS="mysecret" +OPER_HOST="*@*" +OPER_TYPE="NetAdmin" + +FILES_MOTD="$ME/conf/inspire.motd" +FILES_RULE="$ME/conf/inspire.rules" + +OP_PREFIX="Quit: " +OP_DEBUG="off" +OP_HALFY="yes" +OP_PROTE="yes" +OP_FOUND="yes" + +rm -f makeconf.temp + +c="" +n="" + +if [ "`eval echo -n 'a'`" = "-n a" ] ; then + c="\c" + else + n="-n" +fi + +clear +echo -e "'\033[1;33m####\033[0;37m:'\033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m::'\033[1;33m######\033[0;37m::'\033[1;33m########\033[0;37m::'\033[1;33m####\033[0;37m:'\033[1;33m########\033[0;37m:::'\033[1;33m######\033[0;37m::'\033[1;33m########\033[0;37m::" +echo -e ". \033[1;33m##\033[0;37m:: \033[1;33m###\033[0;37m:: \033[1;33m##\033[0;37m:'\033[1;33m##\033[0;37m... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:. \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:'\033[1;33m##\033[0;37m... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.... \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::..:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::..:: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m \033[1;33m##\033[0;37m \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m########\033[0;37m::: \033[1;33m##\033[0;37m:: \033[1;33m########\033[0;37m:: \033[1;33m##\033[0;37m::::::: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m. \033[1;33m####\033[0;37m::..... \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m.....:::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m.. \033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m::::::: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e ": \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m:. \033[1;33m###\033[0;37m:'\033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m::::::::: \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m::. \033[1;33m##\033[0;37m:: \033[1;33m##\033[0;37m::: \033[1;33m##\033[0;37m: \033[1;33m##\033[0;37m:::: \033[1;33m##\033[0;37m:" +echo -e "'\033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m::. \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m##\033[0;37m::::::::'\033[1;33m####\033[0;37m: \033[1;33m##\033[0;37m:::. \033[1;33m##\033[0;37m:. \033[1;33m######\033[0;37m:: \033[1;33m########\033[0;37m::" +echo -e "\033[0;37m\033[0;37m....::..::::..:::......:::..:::::::::....::..:::::..:::......:::........:::" +echo "" +echo -e "\033[1;37mWelcome to the inspircd.conf file maker!!" +echo -e "\033[0;37m" +echo -e "*** Although with most values, hitting \033[1;37m\033[0;37m will use the default, ***" +echo "*** others are not like this. Where possible, Please fill in all the ***" +echo "*** values manually. Once complete, you *WILL* be required to edit ***" +echo "*** the created file manually, to ensure values are correct. Enjoy! ***" +echo -e "*** Between the [\033[1;32mBRACKETS\033[0;37m] will be default / example values to help ***" + +echo "" +echo "" + +echo "The first Part of this is the server Configuration. Here we will take" +echo "Details, Such as the servers name, Description, and The administrators" +echo "information. Once complete, the Screen will clear, and stage 2 will begin" + +echo "" +echo "Enter Servers Name" +echo -e $n "[\033[1;32m$SERV_NAME\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + SERV_NAME=$cc +fi + + +echo "" +echo "Enter Server Description" +echo -e $n "[\033[1;32m$SERV_DESC\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + SERV_DESC=$cc +fi + + +echo "" +echo "Enter Your Network Name" +echo -e $n "[\033[1;32m$SERV_NET\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + SERV_NET=$cc +fi + + +echo "" +echo "" + +echo "" +echo "Enter Administrators Full Name" +echo -e $n "[\033[1;32m$ADMIN_NAME\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + ADMIN_NAME=$cc +fi + + +echo "" +echo "Enter Administrators NickName" +echo -e $n "[\033[1;32m$ADMIN_NICK\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + ADMIN_NICK=$cc +fi + + +echo "" +echo "Enter Administrators Email Address" +echo -e $n "[\033[1;32m$ADMIN_MAIL\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + ADMIN_MAIL=$cc +fi + + +echo "Section Complete, Writing Config File Header." + +### +# Config file header Here! +### + +echo "########################################################################" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# --------------------------- #" >> makeconf.temp +echo "# InspIRCd Configuration File #" >> makeconf.temp +echo "# --------------------------- #" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "##################################||####################################" >> makeconf.temp +echo " #||#" >> makeconf.temp +echo "##################################||####################################" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# This is an example of the config file for InspIRCd. #" >> makeconf.temp +echo "# Change the options to suit your network #" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# Written by : makeconf (Craig@inspircd.org) #" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "########################################################################" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +### +# Complete, server tag now +### + +echo "#-#-#-#-#-#-#-#-#-#-#-#- SERVER DESCRIPTION -#-#-#-#-#-#-#-#-#-#-#-#-" >> makeconf.temp +echo "> makeconf.temp +echo " description=\"$SERV_DESC\"" >> makeconf.temp +echo " network=\"$SERV_NET\">" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +### +# Admin Tag.. +### + +echo "#-#-#-#-#-#-#-#-#-#-#-#- ADMIN INFORMATION -#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "> makeconf.temp +echo " nick=\"$ADMIN_NICK\"" >> makeconf.temp +echo " email=\"$ADMIN_MAIL\">" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +### +# Complete. +### + +clear +echo "Congratulations, you have successfully Configured your Server and Administrator" +echo "Information Correctly. Proceeding to Servers Port Configuration." + +echo "" +echo "" + +echo "Now its time to specify which IP and ports you wish to run the IRCd on." +echo "When asked please enter the IP Address, and ports. As a note, you may" +echo "Leave the IP Address blank to bind to all avaliable interfaces." +echo "" +echo "To end, either type \"done\" as the IP, or leave the Port Blank." +echo "" + +### +# Write Config Header.. +### + +echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- RTFM LINE -#-#-#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# Just remove this... Its here to make you read through this file #" >> makeconf.temp +echo "# properly after running \"makeconf\" #" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + + +echo "#-#-#-#-#-#-#-#-#-#-#-#- PORT CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-" >> makeconf.temp + +### +# Ok, done.. Proceed :) +### + +BOUND_PORT="" +ok=0 +default=0 +while [ $ok -eq 0 ] ; do + echo "Enter the IP" + echo $n "[] -> $c" + read cc + if [ "$cc" == "done" ] ; then + ok=1 + else + BIND_IP=$cc + fi + if [ "$ok" != "1" ] ; then + echo -e "Ports Already Bound: \033[1;32m$BOUND_PORT\033[0;37m" + echo "Enter Port to Bind to $BIND_IP" + echo $n "[] -> $c" + read cc + if [ ! "$cc" ] ; then + ok=1 + else + default=1 + BOUND_PORT="$BOUND_PORT $cc" + echo "" >> makeconf.temp + fi + fi +done + +if [ "$default" == "0" ] ; then + echo "" >> makeconf.temp +fi + +### +# OoOok.. Finishing section +### + +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +### +# Finished, Port Configuration Complete :D +### + + +clear +if [ "$default" == "0" ] ; then + echo "" >> makeconf.temp + echo "" + echo "" +fi +echo "See? that wasnt so hard, The next bit is easier, just more important." + +echo "" +echo "" +echo "I now need you to specify Passwords which will shut down, and restart" +echo "your server, these are _IMPORTANT_ and i will not allow you to use the" +echo "default passwords, you must use your own." +ok=0 +while [ $ok -eq 0 ] ; do + echo "" + echo "Enter the password to Kill the IRCd" + echo -e $n "[\033[1;32m$DIE_PASS\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + echo "" + echo "You _MUST_ specify your Own Password, try again." + else + DIE_PASS=$cc + ok=1 + fi +done + +echo "" +echo "" +ok=0 +while [ $ok -eq 0 ] ; do + echo "" + echo "Now Enter the Password you will use to Restart." + echo -e $n "[\033[1;32m$RESTART_PASS\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + echo "" + echo "You _MUST_ specify your Own Password, try again." + else + RESTART_PASS=$cc + ok=1 + fi +done + +echo "" +echo "Enter the Pause Between Issuing a DIE/RESTART request to the IRCd Actually doing it [in Seconds]" +echo -e $n "[\033[1;32m$DIE_WAIT\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + DIE_WAIT=$cc +fi + +### +# Now Write the config.. What phun +### + +echo "#-#-#-#-#-#-#-#-#-#- DIE/RESTART CONFIGURATION -#-#-#-#-#-#-#-#-#-#-" >> makeconf.temp +echo "> makeconf.temp +echo " restartpass=\"$RESTART_PASS\"" >> makeconf.temp +echo " pause=\"$DIE_WAIT\">" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +### +# +### +clear +echo "ok, seeing as we managed that, we have to Arrange a list of people allowed to connect :)" +echo "" +echo "" + +echo "This section allows you to Specify who is allowed Access to the IRCd. IP Addresses only Please" +echo "Although you can choose to use wildcards if you please. The default is * with no password." +echo "Type \"done\" at the IP Address, or leave it blank to finish, you do _NOT_ have to specify" +echo "any passwords" +echo "" + + +### +# Just another Friendly Header :p +### + +echo "#-#-#-#-#-#-#-#-#-#- CONNECTIONS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-" >> makeconf.temp + +ok=0 +default=0 + +while [ $ok -eq 0 ] ; do + echo "" + echo "Enter The IP Address" + echo -e $n "[\033[1;32m$CONNECT_ALLOW\033[0;37m] -> $c" + read cc + if [ "$cc" == "done" ] ; then + ok=1 + elif [ ! "$cc" ] ; then + ok=1 + else + ALLOW_IP=$cc + fi + if [ "$ok" != "1" ] ; then + echo "Enter Password [If Applicable]" + echo $n "[] -> $c" + read cc + if [ ! "$cc" ] ; then + default=1 + echo "" >> makeconf.temp + else + echo "" >> makeconf.temp + fi + fi +done +if [ "$default" == "0" ] ; then + echo "" >> makeconf.temp +fi + +### +# Insert Line Break before deny +### + +echo "" >> makeconf.temp + + +### +# Another part done +### + +if [ "$default" == "0" ] ; then + echo "No allow lines Specified, using defaults." +fi +echo "" +echo "" +echo "Now For the denies.. These will prevent users accessing the server, once again," +echo "entering nothing, or \"done\" will complete the cycle, and allow you to continue" +echo "" +echo "Enter the IP Address" +ok=0 +while [ $ok -eq 0 ] ; do + echo -e $n "[\033[1;32m$CONNECT_ALLOW\033[0;37m] -> $c" + read cc + if [ "$cc" == "done" ] ; then + ok=1 + elif [ ! "$cc" ] ; then + ok=1 + else + echo "" >> makeconf.temp + fi +done + +### +# Footer Now +### + +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +clear +echo "Ok, now thats finished, we come to oper Classes And Compositions. Due to the Nature" +echo "of this, this Script will set the default tags, if you wish to change them, you will" +echo "have to edit the Finished config manually, in most cases they shouldnt be changed." + +echo "" +echo "" +echo "Before we do that thou, i need to ask for the Domain name of your server, for example," +echo "chatspike.net. This will be used To generate your vhosts." +echo -e $n "[\033[1;32m$VHOST_DOMAIN\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + VHOST_DOMAIN=$cc +fi + +echo "#-#-#-#-#-#-#-#-#-#-#-#- CLASS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#-" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "#-#-#-#-#-#-#-#-#-#-#-#- OPERATOR COMPOSITION -#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +clear +echo "Yay, now comes the fun Part, time to specify Opers." + +echo "" +echo "" +echo "Ok, heres the deal, gonna ask you four questions, all require answering. They are as follows:" +echo "1) The Opers Login, This part will replace in /oper " +echo "2) The Opers Password, This will replace in /oper " +echo "3) The Opers Host, The oper must be connecting from this host for /oper to work [user@host]" +echo "4) The Opers Class, currently all avaliable are: \"NetAdmin\", \"GlobalOp\", \"LocalOp\" and \"Helper\"" +echo "" +echo "You may re-configure the classes later, and if you enter nothing for part one, we will proceed to the next step" + + +### +# Stolen another few lines >;) +### + +echo "#-#-#-#-#-#-#-#-#-#-#- OPERATOR CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp + +### +# Done :p +### + +ok=0 +while [ $ok -eq 0 ] ; do + echo "Enter the opers login name" + echo -e $n "[\033[1;32m$OPER_NICK\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + ok=1 + else + OPER_LOGIN=$cc + fi + if [ $ok -eq 0 ] ; then + ok2=0 + while [ $ok2 -eq 0 ] ; do + echo "Enter the Opers Password" + echo -e $n "[\033[1;32m$OPER_PASS\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + echo "You _MUST_ Enter a password" + else + OPER_PASS=$cc + ok2=1 + fi + done + echo "Enter Opers Host [Format User@host]" + echo -e $n "[\033[1;32m$OPER_HOST\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + OPER_HOST=$OPER_HOST + else + OPER_HOST=$cc + fi + echo "Enter Opers Type [Avaliable: NetAdmin, GlobalOp, LocalOp and Helper] CHOOSE ONLY ONE" + echo -e $n "[\033[1;32m$OPER_TYPE\033[0;37m] -> $c" + read cc + if [ ! "$cc" ] ; then + OPER_TYPE=$OPER_TYPE + else + OPER_TYPE=$cc + fi + echo "Coming for a re-run" + + echo "> makeconf.temp + echo " password=\"$OPER_PASS\"" >> makeconf.temp + echo " host=\"$OPER_HOST\"" >> makeconf.temp + echo " type=\"$OPER_TYPE\">" >> makeconf.temp + + fi +done + +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- RTFM LINE -#-#-#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "# You should know what to do here.. if not.. RTFM!! muahahahahaha #" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + + +clear +echo "Congratulations, Your Opers are configured!" +echo "" +echo "" +echo "Right, i have guessed where you Message of the Day and Rules Files will be." +echo "If these are correct, just hit return, else, type in the correct Location." +echo "" +echo "First The Message of the day." +echo -e $n "[\033[1;32m$FILES_MOTD\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + FILES_MOTD=$cc +fi +echo "" +echo "Right, now the Rules file." +echo -e $n "[\033[1;32m$FILES_RULE\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + FILES_RULE=$cc +fi + +echo "#-#-#-#-#-#-#-#-#-#- MISCELLANEOUS CONFIGURATION -#-#-#-#-#-#-#-#-#-" >> makeconf.temp +echo "> makeconf.temp +echo " rules=\"$FILES_RULE\">" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +clear +echo "Module Time!!" +echo "" +echo "" +echo "Enter the Names of the modules you wish to load, one at a time, below." +echo "Type in the name, hit return, type in another one, etc. Once complete, just hit return to end." +echo "" +echo "The Following Modules are avaliable:" +echo "" +MODLINE="" +for module in m_*.cpp ; do + mod=`perl -e '$a='$module';print substr($a,0,length($a)-3)'` + dmod=`perl -e '$a="'$mod.so'";while (length($a)<30) { $a = "$a ";}; print $a;'` + desc=`perl -e 'open (F, "<'$module'");local($/)=undef;$blah=;$blah=~/\$ModDesc(.*)\*\//;print substr($1,13,length($1));close F;'` + echo -e "\033[1;32m$dmod\033[0;37m$desc" +done +echo "" + +### +# Module Header :p +### + +echo "#-#-#-#-#-#-#-#-#-#-#-#-#- MODULE OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp + +### +# End header +### +ok=0 +while [ "$ok" -eq 0 ] ; do +echo $n "[] -> $c" +read cc +if [ "$cc" ] ; then + echo "" >> makeconf.temp +else + ok=1 +fi +done + +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +clear + +echo "This is it, The final set of Variables.. Then your config is complete." +echo "" +echo "" +echo "These are just a few tiny Simple things, well explained.. BEGIN!" +echo "" +echo "Quit Prefix, This comes before all users Quits, it can be what you like." +echo -e $n "[\033[1;32m$OP_PREFIX\033[0;37m] -> $c" +read cc +if [ $cc ] ; then + OP_PREFIX=$cc +fi + +echo "" +echo "Debug [on / off] Switch on or off Extensive IRCd loggin to ircd.log" +echo -e $n "[\033[1;32m$OP_DEBUG\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + OP_DEBUG=$cc +fi + +echo "" +echo "Enable Halfops [Channel Mode +h], [yes/no]" +echo -e $n "[\033[1;32m$OP_HALFY\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + OP_HALFY=$cc +fi + +echo "" +echo "Enable User Channel Protection [Channel Mode +a] [yes/no]" +echo -e $n "[\033[1;32m$OP_PROTE\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + OP_PROTE=$cc +fi + +echo "" +echo "Enable Channel Founder? [Channel Mode +q] [yes/no]" +echo -e $n "[\033[1;32m$OP_FOUND\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + OP_DEBUG=$cc +fi + +echo "#-#-#-#-#-#-#-#-#-#-#-#-#- SERVER OPTIONS -#-#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "> makeconf.temp +echo " debug=\"$OP_DEBUG\"" >> makeconf.temp +echo " allowhalfop=\"$OP_HALFY\"" >> makeconf.temp +echo " allowprotect=\"$OP_PROTE\"" >> makeconf.temp +echo " allowfounder=\"$OP_FOUND\">" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp + +ME=`pwd` +DIR=$ME/conf/inspircd.conf +echo "" +echo "LAST QUESTION!!" +echo "Where am i gonna be placed? [eg. $DIR]" +echo -e $n "[\033[1;32m$DIR\033[0;37m] -> $c" +read cc +if [ "$cc" ] ; then + DIR=$cc +fi + +echo "#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#- YAWN -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# You should already know what to do here :) #" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "" >> makeconf.temp +echo "#########################################################################" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "# -InspIRCd Development and Coding Team- #" >> makeconf.temp +echo "# www.inspircd.org #" >> makeconf.temp +echo "# #" >> makeconf.temp +echo "#########################################################################" >> makeconf.temp + + + + +mv makeconf.temp $DIR diff --git a/src/dynamic.cpp b/src/dynamic.cpp new file mode 100644 index 000000000..e9cddcbbf --- /dev/null +++ b/src/dynamic.cpp @@ -0,0 +1,70 @@ +#include "globals.h" +#include +#include "dynamic.h" + + + +DLLManager::DLLManager( const char *fname ) +{ + // Try to open the library now and get any error message. + + h=dlopen( fname, RTLD_NOW ); + err=dlerror(); +} + +DLLManager::~DLLManager() +{ + // close the library if it isn't null + if( h!=0 ) + dlclose(h); +} + + +bool DLLManager::GetSymbol( + void **v, + const char *sym_name + ) +{ + // try extract a symbol from the library + // get any error message is there is any + + if( h!=0 ) + { + *v = dlsym( h, sym_name ); + err=dlerror(); + if( err==0 ) + return true; + else + return false; + } + else + { + return false; + } + +} + + +DLLFactoryBase::DLLFactoryBase( + const char *fname, + const char *factory=0 + ) : DLLManager(fname) +{ + // try get the factory function if there is no error yet + + factory_func=0; + + if( LastError()==0 ) + { + GetSymbol( (void **)&factory_func, factory ? factory : "init_module" ); + } + +} + + +DLLFactoryBase::~DLLFactoryBase() +{ +} + + + diff --git a/src/inspircd b/src/inspircd new file mode 100644 index 0000000000000000000000000000000000000000..e2bea5dd21bf09742065a4577fe2ba7fa38ffea9 GIT binary patch literal 245026 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 z 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 Db+I6_ literal 0 HcmV?d00001 diff --git a/src/inspircd.cpp b/src/inspircd.cpp new file mode 100644 index 000000000..b942e5700 --- /dev/null +++ b/src/inspircd.cpp @@ -0,0 +1,4209 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * Inspire is copyright (C) 2002-2003 ChatSpike-Dev. + * E-mail: + * + * + * + * Written by Craig Edwards, Craig McLure, and others. + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + + $Log$ + Revision 1.1 2003/01/23 19:45:58 brain + Initial revision + + Revision 1.56 2003/01/22 20:49:16 brain + Added FileReader file-caching class + Changed m_randquote to use FileReader class + + Revision 1.55 2003/01/21 16:56:19 brain + Fixed a few minor bugs + + Revision 1.54 2003/01/21 02:07:10 brain + optimisations galore! + + Revision 1.53 2003/01/21 00:18:40 brain + fixed random crash on kill_link (AGAIN) - was /stats + improved speed 10x (because i can...) + + Revision 1.52 2003/01/19 20:12:24 brain + Fixed ident max length to 10 + + Revision 1.51 2003/01/18 22:02:11 brain + fixed multiple /MODE +l bugs (thanks to akky and BOFH bugging meh!) + + Revision 1.50 2003/01/18 01:19:14 brain + Added code to tidy up bans (e.g. max nick length) - i blame mIRC! + + Revision 1.49 2003/01/17 22:03:57 brain + Fixed dodgy mode glitches (the ones Craig loves to play with, awww) + + Revision 1.48 2003/01/17 21:20:43 brain + Implemented usermode +s + + Revision 1.47 2003/01/17 21:13:40 brain + Added channel modes, +k, +l, +i, +m etc + Added user and channel modes +i, +p, +s + + Revision 1.46 2003/01/17 18:44:27 brain + Implemented channel mode +m + + Revision 1.45 2003/01/17 18:26:42 brain + added /TRACE command + + Revision 1.44 2003/01/17 15:21:03 brain + Fixed: /LUSERS cant count :P + + Revision 1.43 2003/01/17 13:21:38 brain + Added CONNECT ALLOW and CONNECT DENY config tags + Added PASS command + + Revision 1.42 2003/01/17 10:37:55 brain + Added /INVITE command and relevent structures + + Revision 1.41 2003/01/16 20:11:55 brain + fixed some ugly pointer bugs (thanks dblack and a|KK|y!) + + Revision 1.40 2003/01/16 08:31:44 brain + Fixed parameter error in QUIT code (was showing junk chars on BSD) + + Revision 1.39 2003/01/15 22:47:44 brain + Changed user and channel structs to classes (finally) + + Revision 1.38 2003/01/15 20:56:58 brain + Added wildcard support + Added channel bans + + Revision 1.37 2003/01/15 16:08:42 brain + Attempted to fix closed client sessions not being detected + + Revision 1.36 2003/01/15 09:36:13 brain + added pause= value to /die and /restart in config + + Revision 1.35 2003/01/14 22:08:31 brain + attemted to fix weird crash on /kill + + Revision 1.34 2003/01/14 21:44:25 brain + Added /USERS stub + Added /SUMMON stub + Changed optimisation to -O3 (much faster!) + + Revision 1.33 2003/01/14 21:14:30 brain + added /ISON command (for mIRC etc basic notify) + + Revision 1.32 2003/01/14 20:55:02 brain + Fixed more param crunching bugs + Added /AWAY + + Revision 1.31 2003/01/14 00:46:02 brain + Added m_cloaking.so module, provides host masking + + Revision 1.30 2003/01/13 22:30:50 brain + Added Admin class (holds /admin info for modules) + Added methods to Server class + + Revision 1.29 2003/01/13 00:43:29 brain + Added Server class + Added more code to example module demonstrating use of Server class + + Revision 1.28 2003/01/12 17:40:44 brain + ./configure improved by Craig (better prompts, dir creation) + '/stats z' added detail + + Revision 1.27 2003/01/12 16:49:53 brain + Added '/stats z' + + Revision 1.26 2003/01/12 15:01:18 brain + Added hostname/ip caching to speed up connects + + Revision 1.25 2003/01/11 21:39:57 brain + Made ircd cache message of the day in a vector (faster!) + Added support for multiple lines of /NAMES on large channels + + Revision 1.24 2003/01/11 19:00:10 brain + Added /USERHOST command + + Revision 1.23 2003/01/11 17:57:28 brain + Added '/STATS O' + Added more module error checking + + Revision 1.22 2003/01/11 00:48:44 brain + removed random debug output + + Revision 1.21 2003/01/11 00:06:46 brain + Fixed random crash on nickchange + Fine tuned ability to handle >300 users + + Revision 1.20 2003/01/09 22:24:59 brain + added '/stats L' (connect-info) + + Revision 1.19 2003/01/09 21:38:51 brain + '/stats u' support added (server uptime) + + Revision 1.18 2003/01/09 21:09:50 brain + added '/stats M' command + + Revision 1.17 2003/01/08 22:11:38 brain + + Added extra dynamic module support, new methods to Module class + + Revision 1.16 2003/01/08 17:48:48 brain + + fixed "user lingering" problem in kill_link + + Revision 1.15 2003/01/07 23:17:51 brain + + Fixed wallops and command parameter counting bugs + + Revision 1.14 2003/01/07 20:47:34 brain + + Fixes random crash on nickchange (must keep classfactory pointers!) + + Revision 1.13 2003/01/07 19:57:56 brain + + Dynamix module support, preliminary release + + Revision 1.12 2003/01/07 01:01:30 brain + + Changed command table to a vector of command_t types + + Revision 1.11 2003/01/06 23:43:30 brain + + extra debug output + + Revision 1.10 2003/01/06 23:38:29 brain + + just playing with header tags + + + * --------------------------------------------------- + */ + +/* Now with added unF! ;) */ + +#include "inspircd.h" +#include "inspircd_io.h" +#include "inspircd_util.h" +#include "inspircd_config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "users.h" +#include "ctables.h" +#include "globals.h" +#include "modules.h" +#include "dynamic.h" +#include "wildcard.h" + +using namespace std; + +char ServerName[MAXBUF]; +char Network[MAXBUF]; +char ServerDesc[MAXBUF]; +char AdminName[MAXBUF]; +char AdminEmail[MAXBUF]; +char AdminNick[MAXBUF]; +char diepass[MAXBUF]; +char restartpass[MAXBUF]; +char motd[MAXBUF]; +char rules[MAXBUF]; +char list[MAXBUF]; +char PrefixQuit[MAXBUF]; +char DieValue[MAXBUF]; +int debugging = 0; +int MODCOUNT = -1; +int DieDelay = 5; +time_t startup_time = time(NULL); + +template<> struct hash +{ + size_t operator()(const struct in_addr &a) const + { + size_t q; + memcpy(&q,&a,sizeof(size_t)); + return q; + } +}; + +template<> struct hash +{ + size_t operator()(const string &s) const + { + char a[MAXBUF]; + static struct hash strhash; + strcpy(a,s.c_str()); + strlower(a); + return strhash(a); + } +}; + + + +struct StrHashComp +{ + + bool operator()(const string& s1, const string& s2) const + { + char a[MAXBUF],b[MAXBUF]; + strcpy(a,s1.c_str()); + strcpy(b,s2.c_str()); + return (strcasecmp(a,b) == 0); + } + +}; + +struct InAddr_HashComp +{ + + bool operator()(const in_addr &s1, const in_addr &s2) const + { + size_t q; + size_t p; + + memcpy(&q,&s1,sizeof(size_t)); + memcpy(&p,&s2,sizeof(size_t)); + + return (q == p); + } + +}; + + +typedef hash_map, StrHashComp> user_hash; +typedef hash_map, StrHashComp> chan_hash; +typedef hash_map, InAddr_HashComp> address_cache; +typedef deque command_table; +typedef DLLFactory ircd_module; + +user_hash clientlist; +chan_hash chanlist; +command_table cmdlist; +file_cache MOTD; +file_cache RULES; +address_cache IP; +vector modules(255); +vector factory(255); +ClassVector Classes; + +struct linger linger = { 0 }; +char bannerBuffer[MAXBUF]; +int boundPortCount = 0; + +/* prototypes */ + +int has_channel(userrec *u, chanrec *c); +int usercount(chanrec *c); +int usercount_i(chanrec *c); +void update_stats_l(int fd,int data_out); +char* Passwd(userrec *user); +bool IsDenied(userrec *user); + + +void safedelete(userrec *p) +{ + if (p) + { + debug("deleting %s %s %s %s",p->nick,p->ident,p->dhost,p->fullname); + debug("safedelete(userrec*): pointer is safe to delete"); + delete p; + } + else + { + debug("safedelete(userrec*): unsafe pointer operation squished"); + } +} + +void safedelete(chanrec *p) +{ + if (p) + { + delete p; + debug("safedelete(chanrec*): pointer is safe to delete"); + } + else + { + debug("safedelete(chanrec*): unsafe pointer operation squished"); + } +} + + +/* chop a string down to 512 characters and preserve linefeed (irc max + * line length) */ + +void chop(char* str) +{ + if (strlen(str) > 512) + { + str[510] = '\r'; + str[511] = '\n'; + str[512] = '\0'; + } +} + + +string getservername() +{ + return ServerName; +} + +string getnetworkname() +{ + return Network; +} + +string getadminname() +{ + return AdminName; +} + +string getadminemail() +{ + return AdminEmail; +} + +string getadminnick() +{ + return AdminNick; +} + +void debug(char *text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + FILE *f; + time_t rawtime; + struct tm * timeinfo; + + time(&rawtime); + timeinfo = localtime (&rawtime); + + if (debugging) + { + f = fopen("ircd.log","a+"); + if (f) + { + char b[MAXBUF]; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + strcpy(b,asctime(timeinfo)); + b[strlen(b)-1] = ':'; + fprintf(f,"%s %s\n",b,textbuffer); + fclose(f); + } + else + { + printf("Can't write log file, bailing!!!"); + Exit(ERROR); + } + } +} + +void readfile(file_cache &F, const char* fname) +{ + FILE* file; + char linebuf[MAXBUF]; + + debug("readfile: loading %s",fname); + F.clear(); + file = fopen(fname,"r"); + if (file) + { + while (!feof(file)) + { + fgets(linebuf,sizeof(linebuf),file); + linebuf[strlen(linebuf)-1]='\0'; + if (!strcmp(linebuf,"")) + { + strcpy(linebuf," "); + } + if (!feof(file)) + { + F.push_back(linebuf); + } + } + fclose(file); + } + else + { + debug("readfile: failed to load file: %s",fname); + } + debug("readfile: loaded %s, %d lines",fname,F.size()); +} + +void ReadConfig(void) +{ + char dbg[MAXBUF],pauseval[MAXBUF],Value[MAXBUF]; + ConnectClass c; + + ConfValue("server","name",0,ServerName); + ConfValue("server","description",0,ServerDesc); + ConfValue("server","network",0,Network); + ConfValue("admin","name",0,AdminName); + ConfValue("admin","email",0,AdminEmail); + ConfValue("admin","nick",0,AdminNick); + ConfValue("files","motd",0,motd); + ConfValue("files","rules",0,rules); + ConfValue("power","diepass",0,diepass); + ConfValue("power","pause",0,pauseval); + ConfValue("power","restartpass",0,restartpass); + ConfValue("options","prefixquit",0,PrefixQuit); + ConfValue("die","value",0,DieValue); + ConfValue("options","debug",0,dbg); + debugging = 0; + if (!strcmp(dbg,"on")) + { + debugging = 1; + } + DieDelay = atoi(pauseval); + readfile(MOTD,motd); + readfile(RULES,rules); + debug("Reading connect classes"); + Classes.clear(); + for (int i = 0; i < ConfValueEnum("connect"); i++) + { + strcpy(Value,""); + ConfValue("connect","allow",i,Value); + if (strcmp(Value,"")) + { + strcpy(c.host,Value); + c.type = CC_ALLOW; + strcpy(Value,""); + ConfValue("connect","password",i,Value); + strcpy(c.pass,Value); + Classes.push_back(c); + debug("Read connect class type ALLOW, host=%s password=%s",c.host,c.pass); + } + else + { + ConfValue("connect","deny",i,Value); + strcpy(c.host,Value); + c.type = CC_DENY; + Classes.push_back(c); + debug("Read connect class type DENY, host=%s",c.host); + } + + } +} + +void Blocking(int s) +{ + int flags; + debug("Blocking: %d",s); + flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags ^ O_NONBLOCK); +} + +void NonBlocking(int s) +{ + int flags; + debug("NonBlocking: %d",s); + flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); +} + + +int CleanAndResolve (char *resolvedHost, const char *unresolvedHost) +{ + struct hostent *hostPtr = NULL; + struct in_addr addr; + + memset (resolvedHost, '\0',MAXBUF); + if(unresolvedHost == NULL) + return(ERROR); + if ((inet_aton(unresolvedHost,&addr)) == 0) + return(ERROR); + hostPtr = gethostbyaddr ((char *)&addr.s_addr,sizeof(addr.s_addr),AF_INET); + if (hostPtr != NULL) + snprintf(resolvedHost,MAXBUF,"%s",hostPtr->h_name); + else + snprintf(resolvedHost,MAXBUF,"%s",unresolvedHost); + return (TRUE); +} + +/* write formatted text to a socket, in same format as printf */ + +void Write(int sock,char *text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + char tb[MAXBUF]; + + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + sprintf(tb,"%s\r\n",textbuffer); + chop(tb); + write(sock,tb,strlen(tb)); + update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */ +} + +/* write a server formatted numeric response to a single socket */ + +void WriteServ(int sock, char* text, ...) +{ + char textbuffer[MAXBUF],tb[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + sprintf(tb,":%s %s\r\n",ServerName,textbuffer); + chop(tb); + write(sock,tb,strlen(tb)); + update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */ +} + +/* write text from an originating user to originating user */ + +void WriteFrom(int sock, userrec *user,char* text, ...) +{ + char textbuffer[MAXBUF],tb[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + sprintf(tb,":%s!%s@%s %s\r\n",user->nick,user->ident,user->dhost,textbuffer); + chop(tb); + write(sock,tb,strlen(tb)); + update_stats_l(sock,strlen(tb)); /* add one line-out to stats L for this fd */ +} + +/* write text to an destination user from a source user (e.g. user privmsg) */ + +void WriteTo(userrec *source, userrec *dest,char *data, ...) +{ + char textbuffer[MAXBUF],tb[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, data); + if ((!dest) || (!source)) + { + return; + } + vsnprintf(textbuffer, MAXBUF, data, argsPtr); + va_end(argsPtr); + chop(tb); + WriteFrom(dest->fd,source,"%s",textbuffer); +} + +/* write formatted text from a source user to all users on a channel + * including the sender (NOT for privmsg, notice etc!) */ + +void WriteChannel(chanrec* Ptr, userrec* user, char* text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (has_channel(i->second,Ptr)) + { + WriteTo(user,i->second,"%s",textbuffer); + } + } +} + +/* write formatted text from a source user to all users on a channel except + * for the sender (for privmsg etc) */ + +void ChanExceptSender(chanrec* Ptr, userrec* user, char* text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (has_channel(i->second,Ptr) && (user != i->second)) + { + WriteTo(user,i->second,"%s",textbuffer); + } + } +} + +int c_count(userrec* u) +{ + int z = 0; + for (int i =0; i != MAXCHANS; i++) + if (u->chans[i].channel) + z++; + return z; + +} + +/* return 0 or 1 depending if users u and u2 share one or more common channels + * (used by QUIT, NICK etc which arent channel specific notices) */ + +int common_channels(userrec *u, userrec *u2) +{ + int i = 0; + int z = 0; + + if ((!u) || (!u2)) + { + return 0; + } + for (i = 0; i != MAXCHANS; i++) + { + for (z = 0; z != MAXCHANS; z++) + { + if ((u->chans[i].channel == u2->chans[z].channel) && (u->chans[i].channel) && (u2->chans[z].channel) && (u->registered == 7) && (u2->registered == 7)) + { + if ((c_count(u)) && (c_count(u2))) + { + return 1; + } + } + } + } + return 0; +} + +/* write a formatted string to all users who share at least one common + * channel, including the source user e.g. for use in NICK */ + +void WriteCommon(userrec *u, char* text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + WriteFrom(u->fd,u,"%s",textbuffer); + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (common_channels(u,i->second) && (i->second != u)) + { + WriteFrom(i->second->fd,u,"%s",textbuffer); + } + } +} + +/* write a formatted string to all users who share at least one common + * channel, NOT including the source user e.g. for use in QUIT */ + +void WriteCommonExcept(userrec *u, char* text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((common_channels(u,i->second)) && (u != i->second)) + { + WriteFrom(i->second->fd,u,"%s",textbuffer); + } + } +} + +void WriteOpers(char* text, ...) +{ + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (strchr(i->second->modes,'o')) + { + if (strchr(i->second->modes,'s')) + { + // send server notices to all with +s + // (TODO: needs SNOMASKs) + WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,textbuffer); + } + } + } +} + +void WriteWallOps(userrec *source, char* text, ...) +{ + int i = 0; + char textbuffer[MAXBUF]; + va_list argsPtr; + va_start (argsPtr, text); + vsnprintf(textbuffer, MAXBUF, text, argsPtr); + va_end(argsPtr); + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (strchr(i->second->modes,'w')) + { + WriteTo(source,i->second,"WALLOPS %s",textbuffer); + } + } +} + +/* convert a string to lowercase. Note following special circumstances + * taken from RFC 1459. Many "official" server branches still hold to this + * rule so i will too; + * + * Because of IRC's scandanavian origin, the characters {}| are + * considered to be the lower case equivalents of the characters []\, + * respectively. This is a critical issue when determining the + * equivalence of two nicknames. + */ + +void strlower(char *n) +{ + if (!n) + { + return; + } + for (int i = 0; i != strlen(n); i++) + { + n[i] = tolower(n[i]); + if (n[i] == '[') + n[i] = '{'; + if (n[i] == ']') + n[i] = '}'; + if (n[i] == '\\') + n[i] = '|'; + } +} + +/* verify that a user's nickname is valid */ + +int isnick(const char* n) +{ + int i = 0; + char v[MAXBUF]; + if (!n) + { + return 0; + } + if (!strcmp(n,"")) + { + return 0; + } + if (strlen(n) > NICKMAX-1) + { + return 0; + } + for (i = 0; i != strlen(n); i++) + { + if ((n[i] < 33) || (n[i] > 125)) + { + return 0; + } + /* can't occur ANYWHERE in a nickname! */ + if (strchr("<>,./?:;@'~#=+()*&%$£ \"!",n[i])) + { + return 0; + } + /* can't occur as the first char of a nickname... */ + if ((strchr("0123456789",n[i])) && (!i)) + { + return 0; + } + } + return 1; +} + +/* Find a user record by nickname and return a pointer to it */ + +userrec* Find(string nick) +{ + user_hash::iterator iter = clientlist.find(nick); + + if (iter == clientlist.end()) + /* Couldn't find it */ + return NULL; + + return iter->second; +} + +void update_stats_l(int fd,int data_out) /* add one line-out to stats L for this fd */ +{ + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (i->second->fd == fd) + { + i->second->bytes_out+=data_out; + i->second->cmds_out++; + } + } +} + + +/* find a channel record by channel name and return a pointer to it */ + +chanrec* FindChan(const char* chan) +{ + chan_hash::iterator iter = chanlist.find(chan); + + if (iter == chanlist.end()) + /* Couldn't find it */ + return NULL; + + return iter->second; +} + + +void purge_empty_chans(void) +{ + int go_again = 1, purge = 0; + + while (go_again) + { + go_again = 0; + for (chan_hash::iterator i = chanlist.begin(); i != chanlist.end(); i++) + { + if (i->second) { + if (!usercount(i->second)) + { + /* kill the record */ + if (i != chanlist.end()) + { + debug("del_channel: destroyed: %s",i->second->name); + delete i->second; + chanlist.erase(i); + go_again = 1; + purge++; + break; + } + } + } + } + } + debug("completed channel purge, killed %d",purge); +} + +/* returns the status character for a given user on a channel, e.g. @ for op, + * % for halfop etc. If the user has several modes set, the highest mode + * the user has must be returned. */ + +char* cmode(userrec *user, chanrec *chan) +{ + int i; + for (i = 0; i != MAXCHANS; i++) + { + if ((user->chans[i].channel == chan) && (chan != NULL)) + { + if ((user->chans[i].uc_modes & UCMODE_OP) > 0) + { + return "@"; + } + if ((user->chans[i].uc_modes & UCMODE_HOP) > 0) + { + return "%"; + } + if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0) + { + return "+"; + } + return ""; + } + } +} + +char scratch[MAXMODES]; + +char* chanmodes(chanrec *chan) +{ + strcpy(scratch,""); + if (chan->noexternal) + { + strcat(scratch,"n"); + } + if (chan->topiclock) + { + strcat(scratch,"t"); + } + if (strcmp(chan->key,"")) + { + strcat(scratch,"k"); + } + if (chan->limit) + { + strcat(scratch,"l"); + } + if (chan->inviteonly) + { + strcat(scratch,"i"); + } + if (chan->moderated) + { + strcat(scratch,"m"); + } + if (chan->secret) + { + strcat(scratch,"s"); + } + if (chan->c_private) + { + strcat(scratch,"p"); + } + if (strcmp(chan->key,"")) + { + strcat(scratch," "); + strcat(scratch,chan->key); + } + if (chan->limit) + { + char foo[24]; + sprintf(foo," %d",chan->limit); + strcat(scratch,foo); + } + debug("chanmodes: %s %s",chan->name,scratch); + return scratch; +} + +/* returns the status value for a given user on a channel, e.g. STATUS_OP for + * op, STATUS_VOICE for voice etc. If the user has several modes set, the + * highest mode the user has must be returned. */ + +int cstatus(userrec *user, chanrec *chan) +{ + int i; + for (i = 0; i != MAXCHANS; i++) + { + if ((user->chans[i].channel == chan) && (chan != NULL)) + { + if ((user->chans[i].uc_modes & UCMODE_OP) > 0) + { + return STATUS_OP; + } + if ((user->chans[i].uc_modes & UCMODE_HOP) > 0) + { + return STATUS_HOP; + } + if ((user->chans[i].uc_modes & UCMODE_VOICE) > 0) + { + return STATUS_VOICE; + } + return STATUS_NORMAL; + } + } +} + + +/* compile a userlist of a channel into a string, each nick seperated by + * spaces and op, voice etc status shown as @ and + */ + +void userlist(userrec *user,chanrec *c) +{ + sprintf(list,"353 %s = %s :", user->nick, c->name); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (has_channel(i->second,c)) + { + if (isnick(i->second->nick)) + { + if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i'))) + { + /* user is +i, and source not on the channel, does not show + * nick in NAMES list */ + continue; + } + strcat(list,cmode(i->second,c)); + strcat(list,i->second->nick); + strcat(list," "); + if (strlen(list)>(480-NICKMAX)) + { + /* list overflowed into + * multiple numerics */ + WriteServ(user->fd,list); + sprintf(list,"353 %s = %s :", user->nick, c->name); + } + } + } + } + /* if whats left in the list isnt empty, send it */ + if (list[strlen(list)-1] != ':') + { + WriteServ(user->fd,list); + } +} + +/* return a count of the users on a specific channel accounting for + * invisible users who won't increase the count. e.g. for /LIST */ + +int usercount_i(chanrec *c) +{ + int i = 0; + int count = 0; + + strcpy(list,""); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (has_channel(i->second,c)) + { + if (isnick(i->second->nick)) + { + if ((!has_channel(i->second,c)) && (strchr(i->second->modes,'i'))) + { + /* user is +i, and source not on the channel, does not show + * nick in NAMES list */ + continue; + } + count++; + } + } + } + debug("usercount_i: %s %d",c->name,count); + return count; +} + + +int usercount(chanrec *c) +{ + int i = 0; + int count = 0; + + strcpy(list,""); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (has_channel(i->second,c)) + { + if (isnick(i->second->nick)) + { + count++; + } + } + } + debug("usercount: %s %d",c->name,count); + return count; +} + + +/* add a channel to a user, creating the record for it if needed and linking + * it to the user record */ + +chanrec* add_channel(userrec *user, char* cname, char* key) +{ + int i = 0; + chanrec* Ptr; + int created = 0; + + if ((!cname) || (!user)) + { + return NULL; + } + if (strlen(cname) > CHANMAX-1) + { + cname[CHANMAX-1] = '\0'; + } + + debug("add_channel: %s %s",user->nick,cname); + + if ((has_channel(user,FindChan(cname))) && (FindChan(cname))) + { + return NULL; // already on the channel! + } + + if (!FindChan(cname)) + { + /* create a new one */ + debug("add_channel: creating: %s",cname); + { + chanlist[cname] = new chanrec(); + + strcpy(chanlist[cname]->name, cname); + chanlist[cname]->topiclock = 1; + chanlist[cname]->noexternal = 1; + chanlist[cname]->created = time(NULL); + strcpy(chanlist[cname]->topic, ""); + strncpy(chanlist[cname]->setby, user->nick,NICKMAX); + chanlist[cname]->topicset = 0; + Ptr = chanlist[cname]; + debug("add_channel: created: %s",cname); + /* set created to 2 to indicate user + * is the first in the channel + * and should be given ops */ + created = 2; + } + } + else + { + /* channel exists, just fish out a pointer to its struct */ + Ptr = FindChan(cname); + if (Ptr) + { + debug("add_channel: joining to: %s",Ptr->name); + if (strcmp(Ptr->key,"")) + { + debug("add_channel: %s has key %s",Ptr->name,Ptr->key); + if (!key) + { + debug("add_channel: no key given in JOIN"); + WriteServ(user->fd,"475 %s %s :Cannot join channel (Requires key)",user->nick, Ptr->name); + return NULL; + } + else + { + debug("key at %p is %s",key,key); + if (strcasecmp(key,Ptr->key)) + { + debug("add_channel: bad key given in JOIN"); + WriteServ(user->fd,"475 %s %s :Cannot join channel (Incorrect key)",user->nick, Ptr->name); + return NULL; + } + } + } + + if (Ptr->inviteonly) + { + if (user->IsInvited(Ptr->name)) + { + /* user was invited to channel */ + /* there may be an optional channel NOTICE here */ + } + else + { + WriteServ(user->fd,"473 %s %s :Cannot join channel (Invite only)",user->nick, Ptr->name); + return NULL; + } + } + + if (Ptr->limit) + { + if (usercount(Ptr) == Ptr->limit) + { + WriteServ(user->fd,"471 %s %s :Cannot join channel (Channel is full)",user->nick, Ptr->name); + return NULL; + } + } + + /* check user against the channel banlist */ + for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++) + { + if (match(user->GetFullHost(),i->data)) + { + WriteServ(user->fd,"474 %s %s :Cannot join channel (You're banned)",user->nick, Ptr->name); + return NULL; + } + } + + user->RemoveInvite(Ptr->name); + + } + created = 1; + } + + + for (i =0; i != MAXCHANS; i++) + { + if (user->chans[i].channel == NULL) + { + if (created == 2) + { + /* first user in is given ops */ + user->chans[i].uc_modes = UCMODE_OP; + } + else + { + user->chans[i].uc_modes = 0; + } + user->chans[i].channel = Ptr; + WriteChannel(Ptr,user,"JOIN :%s",Ptr->name); + if (Ptr->topicset) + { + WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic); + WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset); + } + userlist(user,Ptr); + WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, Ptr->name); + WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name,chanmodes(Ptr)); + WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created); + FOREACH_MOD OnUserJoin(user,Ptr); + return Ptr; + } + } + debug("add_channel: user channel max exceeded: %s %s",user->nick,cname); + WriteServ(user->fd,"405 %s %s :You are on too many channels",user->nick, cname); + return NULL; +} + +/* remove a channel from a users record, and remove the record from memory + * if the channel has become empty */ + +chanrec* del_channel(userrec *user, char* cname, char* reason) +{ + int i = 0; + chanrec* Ptr; + int created = 0; + + if ((!cname) || (!user)) + { + return NULL; + } + + Ptr = FindChan(cname); + + if (!Ptr) + { + return NULL; + } + + FOREACH_MOD OnUserPart(user,Ptr); + debug("del_channel: removing: %s %s",user->nick,Ptr->name); + + for (i =0; i != MAXCHANS; i++) + { + /* zap it from the channel list of the user */ + if (user->chans[i].channel == Ptr) + { + if (reason) + { + WriteChannel(Ptr,user,"PART %s :%s",Ptr->name, reason); + } + else + { + WriteChannel(Ptr,user,"PART :%s",Ptr->name); + } + user->chans[i].uc_modes = 0; + user->chans[i].channel = NULL; + debug("del_channel: unlinked: %s %s",user->nick,Ptr->name); + break; + } + } + + /* if there are no users left on the channel */ + if (!usercount(Ptr)) + { + chan_hash::iterator iter = chanlist.find(Ptr->name); + + debug("del_channel: destroying channel: %s",Ptr->name); + + /* kill the record */ + if (iter != chanlist.end()) + { + debug("del_channel: destroyed: %s",Ptr->name); + delete iter->second; + chanlist.erase(iter); + } + } +} + + +void kick_channel(userrec *src,userrec *user, chanrec *Ptr, char* reason) +{ + int i = 0; + int created = 0; + + if ((!Ptr) || (!user) || (!src)) + { + return; + } + + debug("kick_channel: removing: %s %s %s",user->nick,Ptr->name,src->nick); + + if (!has_channel(user,Ptr)) + { + WriteServ(src->fd,"441 %s %s %s :They are not on that channel",src->nick, user->nick, Ptr->name); + return; + } + if ((cstatus(src,Ptr) < STATUS_HOP) || (cstatus(src,Ptr) < cstatus(user,Ptr))) + { + if (cstatus(src,Ptr) == STATUS_HOP) + { + WriteServ(src->fd,"482 %s %s :You must be a channel operator",src->nick, Ptr->name); + } + else + { + WriteServ(src->fd,"482 %s %s :You must be at least a half-operator",src->nick, Ptr->name); + } + + return; + } + + for (i =0; i != MAXCHANS; i++) + { + /* zap it from the channel list of the user */ + if (user->chans[i].channel == Ptr) + { + WriteChannel(Ptr,src,"KICK %s %s :%s",Ptr->name, user->nick, reason); + user->chans[i].uc_modes = 0; + user->chans[i].channel = NULL; + debug("del_channel: unlinked: %s %s",user->nick,Ptr->name); + break; + } + } + + /* if there are no users left on the channel */ + if (!usercount(Ptr)) + { + chan_hash::iterator iter = chanlist.find(Ptr->name); + + debug("del_channel: destroying channel: %s",Ptr->name); + + /* kill the record */ + if (iter != chanlist.end()) + { + debug("del_channel: destroyed: %s",Ptr->name); + delete iter->second; + chanlist.erase(iter); + } + } +} + + +/* returns 1 if user u has channel c in their record, 0 if not */ + +int has_channel(userrec *u, chanrec *c) +{ + int i = 0; + + if (!u) + { + return 0; + } + for (i =0; i != MAXCHANS; i++) + { + if (u->chans[i].channel == c) + { + return 1; + } + } + return 0; +} + +int give_ops(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status != STATUS_OP) + { + WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name); + return 0; + } + else + { + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + d = Find(dest); + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if (d->chans[i].uc_modes & UCMODE_OP) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_OP; + debug("gave ops: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +int give_hops(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status != STATUS_OP) + { + WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name); + return 0; + } + else + { + d = Find(dest); + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if (d->chans[i].uc_modes & UCMODE_HOP) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_HOP; + debug("gave h-ops: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +int give_voice(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status < STATUS_HOP) + { + WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name); + return 0; + } + else + { + d = Find(dest); + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if (d->chans[i].uc_modes & UCMODE_VOICE) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes = d->chans[i].uc_modes | UCMODE_VOICE; + debug("gave voice: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +int take_ops(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status != STATUS_OP) + { + WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name); + return 0; + } + else + { + d = Find(dest); + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if ((d->chans[i].uc_modes & UCMODE_OP) == 0) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes ^= UCMODE_OP; + debug("took ops: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +int take_hops(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status != STATUS_OP) + { + WriteServ(user->fd,"482 %s %s :You're not a channel operator",user->nick, chan->name); + return 0; + } + else + { + d = Find(dest); + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if ((d->chans[i].uc_modes & UCMODE_HOP) == 0) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes ^= UCMODE_HOP; + debug("took h-ops: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +int take_voice(userrec *user,char *dest,chanrec *chan,int status) +{ + userrec *d; + int i; + + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + if (status < STATUS_HOP) + { + WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, chan->name); + return 0; + } + else + { + d = Find(dest); + if (!isnick(dest)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + if (!d) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, dest); + return 0; + } + else + { + for (i = 0; i != MAXCHANS; i++) + { + if ((d->chans[i].channel == chan) && (chan != NULL)) + { + if ((d->chans[i].uc_modes & UCMODE_VOICE) == 0) + { + /* mode already set on user, dont allow multiple */ + return 0; + } + d->chans[i].uc_modes ^= UCMODE_VOICE; + debug("took voice: %s %s",d->chans[i].channel->name,d->nick); + } + } + } + } + return 1; +} + +void TidyBan(char *ban) +{ + char temp[MAXBUF],NICK[MAXBUF],IDENT[MAXBUF],HOST[MAXBUF]; + + strcpy(temp,ban); + + char* pos_of_pling = strchr(temp,'!'); + char* pos_of_at = strchr(temp,'@'); + + pos_of_pling[0] = '\0'; + pos_of_at[0] = '\0'; + pos_of_pling++; + pos_of_at++; + + strncpy(NICK,temp,NICKMAX); + strncpy(IDENT,pos_of_pling,IDENTMAX+1); + strncpy(HOST,pos_of_at,160); + + sprintf(ban,"%s!%s@%s",NICK,IDENT,HOST); +} + +int add_ban(userrec *user,char *dest,chanrec *chan,int status) +{ + BanItem b; + if ((!user) || (!dest) || (!chan)) + return 0; + if (strchr(dest,'!')==0) + return 0; + if (strchr(dest,'@')==0) + return 0; + for (int i = 0; i < strlen(dest); i++) + if (dest[i] < 32) + return 0; + for (int i = 0; i < strlen(dest); i++) + if (dest[i] > 126) + return 0; + int c = 0; + for (int i = 0; i < strlen(dest); i++) + if (dest[i] == '!') + c++; + if (c>1) + return 0; + c = 0; + for (int i = 0; i < strlen(dest); i++) + if (dest[i] == '@') + c++; + if (c>1) + return 0; + debug("add_ban: %s %s",chan->name,user->nick); + + TidyBan(dest); + for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) + { + if (!strcasecmp(i->data,dest)) + { + // dont allow a user to set the same ban twice + return 0; + } + } + + b.set_time = time(NULL); + strncpy(b.data,dest,MAXBUF); + strncpy(b.set_by,user->nick,NICKMAX); + chan->bans.push_back(b); + return 1; +} + +int take_ban(userrec *user,char *dest,chanrec *chan,int status) +{ + if ((!user) || (!dest) || (!chan)) + { + return 0; + } + + debug("del_ban: %s %s",chan->name,user->nick); + for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) + { + if (!strcasecmp(i->data,dest)) + { + chan->bans.erase(i); + return 1; + } + } + return 0; +} + +void process_modes(char **parameters,userrec* user,chanrec *chan,int status, int pcnt) +{ + char modelist[MAXBUF]; + char outlist[MAXBUF]; + char outstr[MAXBUF]; + char outpars[32][MAXBUF]; + int param = 2; + int pc = 0; + int ptr = 0; + int mdir = 1; + int r = 0; + bool k_set = false, l_set = false; + + if (pcnt < 2) + { + return; + } + + debug("process_modes: start"); + + strcpy(modelist,parameters[1]); /* mode list, e.g. +oo-o */ + /* parameters[2] onwards are parameters for + * modes that require them :) */ + strcpy(outlist,"+"); + mdir = 1; + + debug("process_modes: modelist: %s",modelist); + + for (ptr = 0; ptr < strlen(modelist); ptr++) + { + r = 0; + + { + debug("process_modes: modechar: %c",modelist[ptr]); + switch (modelist[ptr]) + { + case '-': + if (mdir != 0) + { + if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-')) + { + outlist[strlen(outlist)-1] = '-'; + } + else + { + strcat(outlist,"-"); + } + } + mdir = 0; + + break; + + case '+': + if (mdir != 1) + { + if ((outlist[strlen(outlist)-1] == '+') || (outlist[strlen(outlist)-1] == '-')) + { + outlist[strlen(outlist)-1] = '+'; + } + else + { + strcat(outlist,"+"); + } + } + mdir = 1; + break; + + case 'o': + if ((param >= pcnt)) break; + if (mdir == 1) + { + r = give_ops(user,parameters[param++],chan,status); + } + else + { + r = take_ops(user,parameters[param++],chan,status); + } + if (r) + { + strcat(outlist,"o"); + strcpy(outpars[pc++],parameters[param-1]); + } + break; + + case 'h': + if ((param >= pcnt)) break; + if (mdir == 1) + { + r = give_hops(user,parameters[param++],chan,status); + } + else + { + r = take_hops(user,parameters[param++],chan,status); + } + if (r) + { + strcat(outlist,"h"); + strcpy(outpars[pc++],parameters[param-1]); + } + break; + + + case 'v': + if ((param >= pcnt)) break; + if (mdir == 1) + { + r = give_voice(user,parameters[param++],chan,status); + } + else + { + r = take_voice(user,parameters[param++],chan,status); + } + if (r) + { + strcat(outlist,"v"); + strcpy(outpars[pc++],parameters[param-1]); + } + break; + + case 'b': + if ((param >= pcnt)) break; + if (mdir == 1) + { + r = add_ban(user,parameters[param++],chan,status); + } + else + { + r = take_ban(user,parameters[param++],chan,status); + } + if (r) + { + strcat(outlist,"b"); + strcpy(outpars[pc++],parameters[param-1]); + } + break; + + case 'k': + if ((param >= pcnt)) + break; + + if (mdir == 1) + { + if (k_set) + break; + + if (!strcmp(chan->key,"")) + { + strcat(outlist,"k"); + strcpy(outpars[pc++],parameters[param++]); + strcpy(chan->key,parameters[param-1]); + k_set = true; + } + } + else + { + /* only allow -k if correct key given */ + if (strcmp(chan->key,"")) + { + strcat(outlist,"k"); + strcpy(chan->key,""); + } + } + break; + + case 'l': + if (mdir == 0) + { + if (chan->limit) + { + strcat(outlist,"l"); + chan->limit = 0; + } + } + + if ((param >= pcnt)) break; + if (mdir == 1) + { + if (l_set) + break; + + bool invalid = false; + for (int i = 0; i < strlen(parameters[param]); i++) + { + if ((parameters[param][i] < '0') || (parameters[param][i] > '9')) + { + invalid = true; + } + } + if (atoi(parameters[param]) < 1) + { + invalid = true; + } + + if (invalid) + break; + + chan->limit = atoi(parameters[param]); + if (chan->limit) + { + strcat(outlist,"l"); + strcpy(outpars[pc++],parameters[param++]); + l_set = true; + } + } + break; + + case 'i': + if (chan->inviteonly != mdir) + { + strcat(outlist,"i"); + } + chan->inviteonly = mdir; + break; + + case 't': + if (chan->topiclock != mdir) + { + strcat(outlist,"t"); + } + chan->topiclock = mdir; + break; + + case 'n': + if (chan->noexternal != mdir) + { + strcat(outlist,"n"); + } + chan->noexternal = mdir; + break; + + case 'm': + if (chan->moderated != mdir) + { + strcat(outlist,"m"); + } + chan->moderated = mdir; + break; + + case 's': + if (chan->secret != mdir) + { + strcat(outlist,"s"); + if (chan->c_private) + { + chan->c_private = 0; + if (mdir) + { + strcat(outlist,"-p+"); + } + else + { + strcat(outlist,"+p-"); + } + } + } + chan->secret = mdir; + break; + + case 'p': + if (chan->c_private != mdir) + { + strcat(outlist,"p"); + if (chan->secret) + { + chan->secret = 0; + if (mdir) + { + strcat(outlist,"-s+"); + } + else + { + strcat(outlist,"+s-"); + } + } + } + chan->c_private = mdir; + break; + + } + } + } + + /* this ensures only the *valid* modes are sent out onto the network */ + while ((outlist[strlen(outlist)-1] == '-') || (outlist[strlen(outlist)-1] == '+')) + { + outlist[strlen(outlist)-1] = '\0'; + } + if (strcmp(outlist,"")) + { + strcpy(outstr,outlist); + for (ptr = 0; ptr < pc; ptr++) + { + strcat(outstr," "); + strcat(outstr,outpars[ptr]); + } + WriteChannel(chan,user,"MODE %s %s",chan->name,outstr); + } +} + +void handle_mode(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + userrec* dest; + int can_change,i; + int direction = 1; + char outpars[MAXBUF]; + + dest = Find(parameters[0]); + + if ((dest) && (pcnt == 1)) + { + WriteServ(user->fd,"221 %s :+%s",user->nick,user->modes); + return; + } + if ((dest) && (pcnt > 1)) + { + can_change = 0; + if (user != dest) + { + if (strchr(user->modes,'o')) + { + can_change = 1; + } + } + else + { + can_change = 1; + } + if (!can_change) + { + WriteServ(user->fd,"482 %s :Can't change mode for other users",user->nick); + return; + } + + strcpy(outpars,"+"); + direction = 1; + + if ((parameters[1][0] != '+') && (parameters[1][0] != '-')) + return; + + for (i = 0; i < strlen(parameters[1]); i++) + { + if (parameters[1][i] == '+') + { + if (direction != 1) + { + if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-')) + { + outpars[strlen(outpars)-1] = '+'; + } + else + { + strcat(outpars,"+"); + } + } + direction = 1; + } + else + if (parameters[1][i] == '-') + { + if (direction != 0) + { + if ((outpars[strlen(outpars)-1] == '+') || (outpars[strlen(outpars)-1] == '-')) + { + outpars[strlen(outpars)-1] = '-'; + } + else + { + strcat(outpars,"-"); + } + } + direction = 0; + } + else + { + can_change = 0; + if (strchr(user->modes,'o')) + { + can_change = 1; + } + else + { + if ((parameters[1][i] == 'i') || (parameters[1][i] == 'w') || (parameters[1][i] == 's')) + { + can_change = 1; + } + } + if (can_change) + { + if (direction == 1) + { + if (!strchr(dest->modes,parameters[1][i])) + { + dest->modes[strlen(dest->modes)+1]='\0'; + dest->modes[strlen(dest->modes)] = parameters[1][i]; + outpars[strlen(outpars)+1]='\0'; + outpars[strlen(outpars)] = parameters[1][i]; + } + } + else + { + int q = 0; + char temp[MAXBUF]; + char moo[MAXBUF]; + + outpars[strlen(outpars)+1]='\0'; + outpars[strlen(outpars)] = parameters[1][i]; + + strcpy(temp,""); + for (q = 0; q < strlen(user->modes); q++) + { + if (user->modes[q] != parameters[1][i]) + { + moo[0] = user->modes[q]; + moo[1] = '\0'; + strcat(temp,moo); + } + } + strcpy(user->modes,temp); + } + } + } + } + if (strlen(outpars)) + { + char b[MAXBUF]; + strcpy(b,""); + int z = 0; + int i = 0; + while (i < strlen (outpars)) + { + b[z++] = outpars[i++]; + b[z] = '\0'; + if (inick, b); + } + return; + } + + Ptr = FindChan(parameters[0]); + if (Ptr) + { + if (pcnt == 1) + { + /* just /modes #channel */ + WriteServ(user->fd,"324 %s %s +%s",user->nick, Ptr->name, chanmodes(Ptr)); + WriteServ(user->fd,"329 %s %s %d", user->nick, Ptr->name, Ptr->created); + return; + } + else + if (pcnt == 2) + { + if ((!strcmp(parameters[1],"+b")) || (!strcmp(parameters[1],"b"))) + { + + for (BanList::iterator i = Ptr->bans.begin(); i != Ptr->bans.end(); i++) + { + WriteServ(user->fd,"367 %s %s %s %s %d",user->nick, Ptr->name, i->data, i->set_by, i->set_time); + } + WriteServ(user->fd,"368 %s %s :End of channel ban list",user->nick, Ptr->name); + } + } + + if ((cstatus(user,Ptr) < STATUS_HOP) && (Ptr)) + { + WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, Ptr->name); + return; + } + + process_modes(parameters,user,Ptr,cstatus(user,Ptr),pcnt); + } + else + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + +/* This function pokes and hacks at a parameter list like the following: + * + * PART #winbot, #darkgalaxy :m00! + * + * to turn it into a series of individual calls like this: + * + * PART #winbot :m00! + * PART #darkgalaxy :m00! + * + * The seperate calls are sent to a callback function provided by the caller + * (the caller will usually call itself recursively). The callback function + * must be a command handler. Calling this function on a line with no list causes + * no action to be taken. You must provide a starting and ending parameter number + * where the range of the list can be found, useful if you have a terminating + * parameter as above which is actually not part of the list, or parameters + * before the actual list as well. This code is used by many functions which + * can function as "one to list" (see the RFC) */ + +int loop_call(handlerfunc fn, char **parameters, int pcnt, userrec *u, int start, int end, int joins) +{ + char plist[MAXBUF]; + char *param; + char *pars[32]; + char blog[32][MAXBUF]; + char blog2[32][MAXBUF]; + int i = 0, j = 0, q = 0, total = 0, t = 0, t2 = 0, total2 = 0; + char keystr[MAXBUF]; + char moo[MAXBUF]; + + for (i = 0; i <32; i++) + strcpy(blog[i],""); + + for (i = 0; i <32; i++) + strcpy(blog2[i],""); + + strcpy(moo,""); + for (i = 0; i <10; i++) + { + if (!parameters[i]) + { + parameters[i] = moo; + } + } + if (joins) + { + if (pcnt > 1) /* we have a key to copy */ + { + strcpy(keystr,parameters[1]); + } + } + + if (!parameters[start]) + { + return 0; + } + if (!strchr(parameters[start],',')) + { + return 0; + } + strcpy(plist,""); + for (i = start; i <= end; i++) + { + if (parameters[i]) + { + strcat(plist,parameters[i]); + } + } + + j = 0; + param = plist; + + t = strlen(plist); + for (i = 0; i < t; i++) + { + if (plist[i] == ',') + { + plist[i] = '\0'; + strcpy(blog[j++],param); + param = plist+i+1; + } + } + strcpy(blog[j++],param); + total = j; + + if ((joins) && (keystr) && (total>0)) // more than one channel and is joining + { + strcat(keystr,","); + } + + if ((joins) && (keystr)) + { + if (strchr(keystr,',')) + { + j = 0; + param = keystr; + t2 = strlen(keystr); + for (i = 0; i < t2; i++) + { + if (keystr[i] == ',') + { + keystr[i] = '\0'; + strcpy(blog2[j++],param); + param = keystr+i+1; + } + } + strcpy(blog2[j++],param); + total2 = j; + } + } + + for (j = 0; j < total; j++) + { + if (blog[j]) + { + pars[0] = blog[j]; + } + for (q = end; q < pcnt-1; q++) + { + if (parameters[q+1]) + { + pars[q-end+1] = parameters[q+1]; + } + } + if ((joins) && (parameters[1])) + { + if (pcnt > 1) + { + pars[1] = blog2[j]; + } + else + { + pars[1] = NULL; + } + } + /* repeatedly call the function with the hacked parameter list */ + if ((joins) && (pcnt > 1)) + { + if (pars[1]) + { + // pars[1] already set up and containing key from blog2[j] + fn(pars,2,u); + } + else + { + pars[1] = parameters[1]; + fn(pars,2,u); + } + } + else + { + fn(pars,pcnt-(end-start),u); + } + } + + return 1; +} + +void handle_join(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + int i = 0; + + if (loop_call(handle_join,parameters,pcnt,user,0,0,1)) + return; + if (parameters[0][0] == '#') + { + Ptr = add_channel(user,parameters[0],parameters[1]); + } +} + + +void handle_part(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + + if (pcnt > 1) + { + if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-2,0)) + return; + del_channel(user,parameters[0],parameters[1]); + } + else + { + if (loop_call(handle_part,parameters,pcnt,user,0,pcnt-1,0)) + return; + del_channel(user,parameters[0],NULL); + } +} + +void handle_kick(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr = FindChan(parameters[0]); + userrec* u = Find(parameters[1]); + + if ((!u) || (!Ptr)) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + return; + } + + if (!has_channel(u,Ptr)) + { + WriteServ(user->fd,"442 %s %s :You're not on that channel!",user->nick, parameters[0]); + return; + } + + if (pcnt > 2) + { + kick_channel(user,u,Ptr,parameters[2]); + } + else + { + kick_channel(user,u,Ptr,user->nick); + } +} + + +void handle_die(char **parameters, int pcnt, userrec *user) +{ + debug("die: %s",user->nick); + if (!strcmp(parameters[0],diepass)) + { + WriteOpers("*** DIE command from %s!%s@%s, terminating...",user->nick,user->ident,user->host); + sleep(DieDelay); + Exit(ERROR); + } + else + { + WriteOpers("*** Failed DIE Command from %s!%s@%s.",user->nick,user->ident,user->host); + } +} + +void handle_restart(char **parameters, int pcnt, userrec *user) +{ + debug("restart: %s",user->nick); + if (!strcmp(parameters[0],restartpass)) + { + WriteOpers("*** RESTART command from %s!%s@%s, Pretending to restart till this is finished :D",user->nick,user->ident,user->host); + sleep(DieDelay); + Exit(ERROR); + /* Will finish this later when i can be arsed :) */ + } + else + { + WriteOpers("*** Failed RESTART Command from %s!%s@%s.",user->nick,user->ident,user->host); + } +} + + +void kill_link(userrec *user,char* reason) +{ + user_hash::iterator iter = clientlist.find(user->nick); + + debug("kill_link: %s '%s'",user->nick,reason); + Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason); + fdatasync(user->fd); + WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason); + FOREACH_MOD OnUserQuit(user); + debug("closing fd %d",user->fd); + /* bugfix, cant close() a nonblocking socket (sux!) */ + WriteCommonExcept(user,"QUIT :%s",reason); + Blocking(user->fd); + close(user->fd); + NonBlocking(user->fd); + + if (iter != clientlist.end()) + { + debug("deleting user hash value %p",iter->second); + delete iter->second; + clientlist.erase(iter); + } + + purge_empty_chans(); +} + + +void handle_kill(char **parameters, int pcnt, userrec *user) +{ + userrec *u = Find(parameters[0]); + char killreason[MAXBUF]; + + debug("kill: %s %s",parameters[0],parameters[1]); + if (u) + { + WriteOpers("*** Local Kill by %s: %s!%s@%s (%s)",user->nick,u->nick,u->ident,u->host,parameters[1]); + sprintf(killreason,"Killed (%s (%s))",user->nick,parameters[1]); + kill_link(u,killreason); + } + else + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + +void handle_summon(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"445 %s :SUMMON has been disabled (depreciated command)",user->nick); +} + +void handle_users(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"445 %s :USERS has been disabled (depreciated command)",user->nick); +} + + +// looks up a users password for their connection class (/ tags) + +char* Passwd(userrec *user) +{ + for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++) + { + if (match(user->host,i->host) && (i->type == CC_ALLOW)) + { + return i->pass; + } + } + return ""; +} + +bool IsDenied(userrec *user) +{ + for (ClassVector::iterator i = Classes.begin(); i != Classes.end(); i++) + { + if (match(user->host,i->host) && (i->type == CC_DENY)) + { + return true; + } + } + return false; +} + + +void handle_pass(char **parameters, int pcnt, userrec *user) +{ + if (!strcasecmp(parameters[0],Passwd(user))) + { + user->haspassed = true; + } +} + +void handle_invite(char **parameters, int pcnt, userrec *user) +{ + userrec* u = Find(parameters[0]); + chanrec* c = FindChan(parameters[1]); + + if ((!c) || (!u)) + { + if (!c) + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[1]); + } + else + { + if (c->inviteonly) + { + WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, parameters[0]); + } + } + + return; + } + + if (c->inviteonly) + { + if (cstatus(user,c) < STATUS_HOP) + { + WriteServ(user->fd,"482 %s %s :You must be at least a half-operator",user->nick, c->name); + return; + } + + u->InviteTo(c->name); + WriteFrom(u->fd,user,"INVITE %s :%s",u->nick,c->name); + WriteServ(user->fd,"341 %s %s %s",user->nick,u->nick,c->name); + } +} + +void handle_topic(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + + if (pcnt == 1) + { + if (strlen(parameters[0]) <= CHANMAX) + { + Ptr = FindChan(parameters[0]); + if (Ptr) + { + if (Ptr->topicset) + { + WriteServ(user->fd,"332 %s %s :%s", user->nick, Ptr->name, Ptr->topic); + WriteServ(user->fd,"333 %s %s %s %d", user->nick, Ptr->name, Ptr->setby, Ptr->topicset); + } + else + { + WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name); + } + } + else + { + WriteServ(user->fd,"331 %s %s :No topic is set.", user->nick, Ptr->name); + } + } + } + else if (pcnt>1) + { + if (loop_call(handle_topic,parameters,pcnt,user,0,pcnt-2,0)) + return; + if (strlen(parameters[0]) <= CHANMAX) + { + Ptr = FindChan(parameters[0]); + if (Ptr) + { + if ((Ptr->topiclock) && (cstatus(user,Ptr)fd,"482 %s %s :You must be at least a half-operator", user->nick, Ptr->name); + return; + } + strcpy(Ptr->topic,parameters[1]); + strcpy(Ptr->setby,user->nick); + Ptr->topicset = time(NULL); + WriteChannel(Ptr,user,"TOPIC %s :%s",Ptr->name, Ptr->topic); + } + else + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } + } + } +} + +/* sends out an error notice to all connected clients (not to be used + * lightly!) */ + +void send_error(char *s) +{ + debug("send_error: %s",s); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + WriteServ(i->second->fd,"NOTICE %s :%s",i->second->nick,s); + } +} + +void Error(int status) +{ + signal (SIGALRM, SIG_IGN); + signal (SIGPIPE, SIG_IGN); + signal (SIGTERM, SIG_IGN); + signal (SIGABRT, SIG_IGN); + signal (SIGSEGV, SIG_IGN); + signal (SIGURG, SIG_IGN); + signal (SIGKILL, SIG_IGN); + debug("*** fell down a pothole in the road to perfection ***"); + send_error("Error! Segmentation fault! save meeeeeeeeeeeeee *splat!*"); + exit(status); +} + +int main (int argc, char *argv[]) +{ + Start(); + debug("*** InspIRCd starting up!"); + if (!CheckConfig()) + { + debug("main: no config"); + printf("ERROR: Your config file is missing, this IRCd will self destruct in 10 seconds!\n"); + Exit(ERROR); + } + if (InspIRCd() == ERROR) + { + debug("main: daemon function bailed"); + printf("ERROR: could not initialise. Shutting down.\n"); + Exit(ERROR); + } + Exit(TRUE); + return 0; +} + +template inline string ConvToStr(const T &in) +{ + stringstream tmp; + if (!(tmp << in)) return string(); + return tmp.str(); +} + +/* re-allocates a nick in the user_hash after they change nicknames, + * returns a pointer to the new user as it may have moved */ + +userrec* ReHashNick(char* Old, char* New) +{ + user_hash::iterator newnick; + user_hash::iterator oldnick = clientlist.find(Old); + + debug("ReHashNick: %s %s",Old,New); + + if (!strcasecmp(Old,New)) + { + debug("old nick is new nick, skipping"); + return oldnick->second; + } + + if (oldnick == clientlist.end()) return NULL; /* doesnt exist */ + + debug("ReHashNick: Found hashed nick %s",Old); + + clientlist[New] = new userrec(); + clientlist[New] = oldnick->second; + /*delete oldnick->second; */ + clientlist.erase(oldnick); + + debug("ReHashNick: Nick rehashed as %s",New); + + return clientlist[New]; +} + + +/* add a client connection to the sockets list */ +void AddClient(int socket, char* host, int port, bool iscached) +{ + int i; + int blocking = 1; + char resolved[MAXBUF]; + string tempnick; + char tn2[MAXBUF]; + user_hash::iterator iter; + + tempnick = ConvToStr(socket) + "-unknown"; + sprintf(tn2,"%d-unknown",socket); + + iter = clientlist.find(tempnick); + + if (iter != clientlist.end()) return; + + /* + * It is OK to access the value here this way since we know + * it exists, we just created it above. + * + * At NO other time should you access a value in a map or a + * hash_map this way. + */ + clientlist[tempnick] = new userrec(); + + NonBlocking(socket); + debug("AddClient: %d %s %d",socket,host,port); + + + clientlist[tempnick]->fd = socket; + strncpy(clientlist[tempnick]->nick, tn2,NICKMAX); + strncpy(clientlist[tempnick]->host, host,160); + strncpy(clientlist[tempnick]->dhost, host,160); + strncpy(clientlist[tempnick]->server, ServerName,256); + clientlist[tempnick]->registered = 0; + clientlist[tempnick]->signon = time(NULL); + clientlist[tempnick]->nping = time(NULL)+240; + clientlist[tempnick]->lastping = 1; + clientlist[tempnick]->port = port; + + if (iscached) + { + WriteServ(socket,"NOTICE Auth :Found your hostname (cached)..."); + } + else + { + WriteServ(socket,"NOTICE Auth :Looking up your hostname..."); + } + + if (clientlist.size() == MAXCLIENTS) + kill_link(clientlist[tempnick],"No more connections allowed in this class"); +} + +void handle_names(char **parameters, int pcnt, userrec *user) +{ + chanrec* c; + + if (loop_call(handle_names,parameters,pcnt,user,0,pcnt-1,0)) + return; + c = FindChan(parameters[0]); + if (c) + { + /*WriteServ(user->fd,"353 %s = %s :%s", user->nick, c->name,*/ + userlist(user,c); + WriteServ(user->fd,"366 %s %s :End of /NAMES list.", user->nick, c->name); + } + else + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + + +void handle_privmsg(char **parameters, int pcnt, userrec *user) +{ + userrec *dest; + chanrec *chan; + + if (loop_call(handle_privmsg,parameters,pcnt,user,0,pcnt-2,0)) + return; + if (parameters[0][0] == '#') + { + chan = FindChan(parameters[0]); + if (chan) + { + if ((chan->noexternal) && (!has_channel(user,chan))) + { + WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name); + return; + } + if ((chan->moderated) && (cstatus(user,chan)fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name); + return; + } + ChanExceptSender(chan, user, "PRIVMSG %s :%s", chan->name, parameters[1]); + } + else + { + /* no such nick/channel */ + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } + return; + } + + dest = Find(parameters[0]); + if (dest) + { + if (strcmp(dest->awaymsg,"")) + { + /* auto respond with aweh msg */ + WriteServ(user->fd,"301 %s %s :%s",user->nick,dest->nick,dest->awaymsg); + } + WriteTo(user, dest, "PRIVMSG %s :%s", dest->nick, parameters[1]); + } + else + { + /* no such nick/channel */ + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + +void handle_notice(char **parameters, int pcnt, userrec *user) +{ + userrec *dest; + chanrec *chan; + + if (loop_call(handle_notice,parameters,pcnt,user,0,pcnt-2,0)) + return; + if (parameters[0][0] == '#') + { + chan = FindChan(parameters[0]); + if (chan) + { + if ((chan->noexternal) && (!has_channel(user,chan))) + { + WriteServ(user->fd,"404 %s %s :Cannot send to channel (no external messages)", user->nick, chan->name); + return; + } + if ((chan->moderated) && (cstatus(user,chan)fd,"404 %s %s :Cannot send to channel (+m)", user->nick, chan->name); + return; + } + WriteChannel(chan, user, "NOTICE %s :%s", chan->name, parameters[1]); + } + else + { + /* no such nick/channel */ + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } + return; + } + + dest = Find(parameters[0]); + if (dest) + { + WriteTo(user, dest, "NOTICE %s :%s", dest->nick, parameters[1]); + } + else + { + /* no such nick/channel */ + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + +char lst[MAXBUF]; + +char* chlist(userrec *user) +{ + int i = 0; + char cmp[MAXBUF]; + + debug("chlist: %s",user->nick); + strcpy(lst,""); + if (!user) + { + return lst; + } + for (i = 0; i != MAXCHANS; i++) + { + if (user->chans[i].channel != NULL) + { + if (user->chans[i].channel->name) + { + strcpy(cmp,user->chans[i].channel->name); + strcat(cmp," "); + if (!strstr(lst,cmp)) + { + if ((!user->chans[i].channel->c_private) && (!user->chans[i].channel->secret)) + { + strcat(lst,cmode(user,user->chans[i].channel)); + strcat(lst,user->chans[i].channel->name); + strcat(lst," "); + } + } + } + } + } + return lst; +} + +void handle_info(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"371 %s :The Inspire IRCd Project Has been brought to you by the following people..",user->nick); + WriteServ(user->fd,"371 %s :Craig Edwards, Craig McLure, and Others..",user->nick); + WriteServ(user->fd,"371 %s :Will finish this later when i can be arsed :p",user->nick); + WriteServ(user->fd,"374 %s :End of /INFO list",user->nick); +} + +void handle_time(char **parameters, int pcnt, userrec *user) +{ + time_t rawtime; + struct tm * timeinfo; + + time ( &rawtime ); + timeinfo = localtime ( &rawtime ); + WriteServ(user->fd,"391 %s %s :%s",user->nick,ServerName, asctime (timeinfo) ); + +} + +void handle_whois(char **parameters, int pcnt, userrec *user) +{ + userrec *dest; + char *t; + + if (loop_call(handle_whois,parameters,pcnt,user,0,pcnt-1,0)) + return; + dest = Find(parameters[0]); + if (dest) + { + WriteServ(user->fd,"311 %s %s %s %s * :%s",user->nick, dest->nick, dest->ident, dest->dhost, dest->fullname); + if ((user == dest) || (strchr(user->modes,'o'))) + { + WriteServ(user->fd,"378 %s %s :is connecting from *@%s",user->nick, dest->nick, dest->host); + } + if (strcmp(chlist(dest),"")) + { + WriteServ(user->fd,"319 %s %s :%s",user->nick, dest->nick, chlist(dest)); + } + WriteServ(user->fd,"312 %s %s %s :%s",user->nick, dest->nick, dest->server, ServerDesc); + if (strcmp(dest->awaymsg,"")) + { + WriteServ(user->fd,"301 %s %s :%s",user->nick, dest->nick, dest->awaymsg); + } + if (strchr(dest->modes,'o')) + { + WriteServ(user->fd,"313 %s %s :is an IRC operator",user->nick, dest->nick); + } + //WriteServ(user->fd,"310 %s %s :is available for help.",user->nick, dest->nick); + WriteServ(user->fd,"317 %s %s %d %d :seconds idle, signon time",user->nick, dest->nick, abs((dest->idle_lastmsg)-time(NULL)), dest->signon); + + WriteServ(user->fd,"318 %s %s :End of /WHOIS list.",user->nick, dest->nick); + } + else + { + /* no such nick/channel */ + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } +} + +void handle_quit(char **parameters, int pcnt, userrec *user) +{ + user_hash::iterator iter = clientlist.find(user->nick); + + /* theres more to do here, but for now just close the socket */ + if (pcnt == 1) + { + if (parameters[0][0] == ':') + { + *parameters[0]++; + } + Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,parameters[0]); + WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,parameters[0]); + WriteCommonExcept(user,"QUIT :%s%s",PrefixQuit,parameters[0]); + } + else + { + Write(user->fd,"ERROR :Closing link (%s@%s) [QUIT]",user->ident,user->host); + WriteOpers("*** Client exiting: %s!%s@%s [Client exited]",user->nick,user->ident,user->host); + WriteCommonExcept(user,"QUIT :Client exited"); + } + + FOREACH_MOD OnUserQuit(user); + + /* confucious say, he who close nonblocking socket, get nothing! */ + Blocking(user->fd); + close(user->fd); + NonBlocking(user->fd); + + if (iter != clientlist.end()) + { + debug("deleting user hash value"); + delete iter->second; + clientlist.erase(iter); + } + + purge_empty_chans(); +} + +void handle_who(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + + /* theres more to do here, but for now just close the socket */ + if (pcnt == 1) + { + if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*"))) + { + Ptr = user->chans[0].channel; + printf(user->chans[0].channel->name); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((common_channels(user,i->second)) && (isnick(i->second->nick))) + { + WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname); + } + } + WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name); + return; + } + if (parameters[0][0] = '#') + { + Ptr = FindChan(parameters[0]); + if (Ptr) + { + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((has_channel(i->second,Ptr)) && (isnick(i->second->nick))) + { + WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname); + } + } + WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name); + } + else + { + WriteServ(user->fd,"401 %s %s :No suck nick/channel",user->nick, parameters[0]); + } + } + } + if (pcnt == 2) + { + if ((!strcmp(parameters[0],"0")) || (!strcmp(parameters[0],"*")) && (!strcmp(parameters[1],"o"))) + { + Ptr = user->chans[0].channel; + printf(user->chans[0].channel->name); + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((common_channels(user,i->second)) && (isnick(i->second->nick))) + { + if (strchr(i->second->modes,'o')) + { + WriteServ(user->fd,"352 %s %s %s %s %s %s Hr@ :0 %s",user->nick, Ptr->name, i->second->ident, i->second->dhost, ServerName, i->second->nick, i->second->fullname); + } + } + } + WriteServ(user->fd,"315 %s %s :End of /WHO list.",user->nick, Ptr->name); + return; + } + } +} + +void handle_wallops(char **parameters, int pcnt, userrec *user) +{ + WriteWallOps(user,"%s",parameters[0]); +} + +void handle_list(char **parameters, int pcnt, userrec *user) +{ + chanrec* Ptr; + + WriteServ(user->fd,"321 %s Channel :Users Name",user->nick); + for (chan_hash::const_iterator i = chanlist.begin(); i != chanlist.end(); i++) + { + if ((!i->second->c_private) && (!i->second->secret)) + { + WriteServ(user->fd,"322 %s %s %d :[+%s] %s",user->nick,i->second->name,usercount_i(i->second),chanmodes(i->second),i->second->topic); + } + } + WriteServ(user->fd,"323 %s :End of channel list.",user->nick); +} + + +void handle_rehash(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"382 %s %s :Rehashing",user->nick,CONFIG_FILE); + ReadConfig(); + WriteOpers("%s is rehashing config file %s",user->nick,CONFIG_FILE); +} + + +int usercnt(void) +{ + return clientlist.size(); +} + +int usercount_invisible(void) +{ + int c = 0; + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'i'))) c++; + } + return c; +} + +int usercount_opers(void) +{ + int c = 0; + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((i->second->fd) && (isnick(i->second->nick)) && (strchr(i->second->modes,'o'))) c++; + } + return c; +} + +int usercount_unknown(void) +{ + int c = 0; + + for (user_hash::const_iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if ((i->second->fd) && (i->second->registered != 7)) + c++; + } + return c; +} + +int chancount(void) +{ + return chanlist.size(); +} + +int servercount(void) +{ + return 1; +} + +void handle_lusers(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"251 %s :There are %d users and %d invisible on %d servers",user->nick,usercnt()-usercount_invisible(),usercount_invisible(),servercount()); + WriteServ(user->fd,"252 %s %d :operator(s) online",user->nick,usercount_opers()); + WriteServ(user->fd,"253 %s %d :unknown connections",user->nick,usercount_unknown()); + WriteServ(user->fd,"254 %s %d :channels formed",user->nick,chancount()); + WriteServ(user->fd,"254 %s :I have %d clients and 0 servers",user->nick,usercnt()); +} + +void handle_admin(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"256 %s :Administrative info for %s",user->nick,ServerName); + WriteServ(user->fd,"257 %s :Name - %s",user->nick,AdminName); + WriteServ(user->fd,"258 %s :Nickname - %s",user->nick,AdminNick); + WriteServ(user->fd,"258 %s :E-Mail - %s",user->nick,AdminEmail); +} + +void ShowMOTD(userrec *user) +{ + if (!MOTD.size()) + { + WriteServ(user->fd,"422 %s :Message of the day file is missing.",user->nick); + return; + } + WriteServ(user->fd,"375 %s :- %s message of the day",user->nick,ServerName); + for (int i = 0; i != MOTD.size(); i++) + { + WriteServ(user->fd,"372 %s :- %s",user->nick,MOTD[i].c_str()); + } + WriteServ(user->fd,"376 %s :End of %s message of the day.",user->nick,ServerName); +} + +void ShowRULES(userrec *user) +{ + if (!RULES.size()) + { + WriteServ(user->fd,"NOTICE %s :Rules file is missing.",user->nick); + return; + } + WriteServ(user->fd,"NOTICE %s :%s rules",user->nick,ServerName); + for (int i = 0; i != RULES.size(); i++) + { + WriteServ(user->fd,"NOTICE %s :%s",user->nick,RULES[i].c_str()); + } + WriteServ(user->fd,"NOTICE %s :End of %s rules.",user->nick,ServerName); +} + +/* shows the message of the day, and any other on-logon stuff */ +void ConnectUser(userrec *user) +{ + user->registered = 7; + user->idle_lastmsg = time(NULL); + debug("ConnectUser: %s",user->nick); + + if (strcmp(Passwd(user),"") && (!user->haspassed)) + { + Write(user->fd,"ERROR :Closing link: Invalid password"); + fdatasync(user->fd); + kill_link(user,"Invalid password"); + return; + } + if (IsDenied(user)) + { + Write(user->fd,"ERROR :Closing link: Unauthorized connection"); + fdatasync(user->fd); + kill_link(user,"Unauthorised connection"); + } + + WriteServ(user->fd,"NOTICE Auth :Welcome to \002%s\002!",Network); + WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Network,user->nick,user->ident,user->host); + WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,ServerName,VERSION); + WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__); + WriteServ(user->fd,"004 %s :%s %s iowghraAsORVSxNCWqBzvdHtGI lvhopsmntikrRcaqOALQbSeKVfHGCuzN",user->nick,ServerName,VERSION); + WriteServ(user->fd,"005 %s :MAP KNOCK SAFELIST HCN MAXCHANNELS=20 MAXBANS=60 NICKLEN=30 TOPICLEN=307 KICKLEN=307 MAXTARGETS=20 AWAYLEN=307 :are supported by this server",user->nick); + WriteServ(user->fd,"005 %s :WALLCHOPS WATCH=128 SILENCE=5 MODES=13 CHANTYPES=# PREFIX=(ohv)@%c+ CHANMODES=ohvbeqa,kfL,l,psmntirRcOAQKVHGCuzN NETWORK=%s :are supported by this server",user->nick,'%',Network); + ShowMOTD(user); + FOREACH_MOD OnUserConnect(user); + WriteOpers("*** Client connecting on port %d: %s!%s@%s",user->port,user->nick,user->ident,user->host); +} + +void handle_version(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"351 %s :%s %s :%s",user->nick,VERSION,ServerName,SYSTEM); +} + +void handle_ping(char **parameters, int pcnt, userrec *user) +{ + WriteServ(user->fd,"PONG %s :%s",ServerName,parameters[0]); +} + +void handle_pong(char **parameters, int pcnt, userrec *user) +{ + // set the user as alive so they survive to next ping + user->lastping = 1; +} + +void handle_motd(char **parameters, int pcnt, userrec *user) +{ + ShowMOTD(user); +} + +void handle_rules(char **parameters, int pcnt, userrec *user) +{ + ShowRULES(user); +} + +void handle_user(char **parameters, int pcnt, userrec *user) +{ + if (user->registered < 3) + { + WriteServ(user->fd,"NOTICE Auth :No ident response, ident prefixed with ~"); + strcpy(user->ident,"~"); /* we arent checking ident... but these days why bother anyway? */ + strncat(user->ident,parameters[0],IDENTMAX); + strncpy(user->fullname,parameters[3],128); + user->registered = (user->registered | 1); + } + else + { + WriteServ(user->fd,"462 %s :You may not reregister",user->nick); + return; + } + /* parameters 2 and 3 are local and remote hosts, ignored when sent by client connection */ + if (user->registered == 3) + { + /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ + ConnectUser(user); + } +} + +void handle_userhost(char **parameters, int pcnt, userrec *user) +{ + char Return[MAXBUF],junk[MAXBUF]; + sprintf(Return,"302 %s :",user->nick); + for (int i = 0; i < pcnt; i++) + { + userrec *u = Find(parameters[i]); + if (u) + { + if (strchr(u->modes,'o')) + { + sprintf(junk,"%s*=+%s@%s ",u->nick,u->ident,u->host); + strcat(Return,junk); + } + else + { + sprintf(junk,"%s=+%s@%s ",u->nick,u->ident,u->host); + strcat(Return,junk); + } + } + } + WriteServ(user->fd,Return); +} + + +void handle_ison(char **parameters, int pcnt, userrec *user) +{ + char Return[MAXBUF]; + sprintf(Return,"303 %s :",user->nick); + for (int i = 0; i < pcnt; i++) + { + userrec *u = Find(parameters[i]); + if (u) + { + strcat(Return,u->nick); + strcat(Return," "); + } + } + WriteServ(user->fd,Return); +} + + +void handle_away(char **parameters, int pcnt, userrec *user) +{ + if (pcnt) + { + strcpy(user->awaymsg,parameters[0]); + WriteServ(user->fd,"306 %s :You have been marked as being away",user->nick); + } + else + { + strcpy(user->awaymsg,""); + WriteServ(user->fd,"305 %s :You are no longer marked as being away",user->nick); + } +} + + +void handle_trace(char **parameters, int pcnt, userrec *user) +{ + for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (i->second) + { + if (isnick(i->second->nick)) + { + if (strchr(i->second->modes,'o')) + { + WriteServ(user->fd,"205 %s :Oper 0 %s",user->nick,i->second->nick); + } + else + { + WriteServ(user->fd,"204 %s :User 0 %s",user->nick,i->second->nick); + } + } + else + { + WriteServ(user->fd,"203 %s :???? 0 [%s]",user->nick,i->second->host); + } + } + } +} + +void handle_stats(char **parameters, int pcnt, userrec *user) +{ + if (pcnt != 1) + { + return; + } + if (strlen(parameters[0])>1) + { + /* make the stats query 1 character long */ + parameters[0][1] = '\0'; + } + + /* stats m (list number of times each command has been used, plus bytecount) */ + if (!strcasecmp(parameters[0],"m")) + { + for (int i = 0; i < cmdlist.size(); i++) + { + if (cmdlist[i].handler_function) + { + if (cmdlist[i].use_count) + { + /* RPL_STATSCOMMANDS */ + WriteServ(user->fd,"212 %s %s %d %d",user->nick,cmdlist[i].command,cmdlist[i].use_count,cmdlist[i].total_bytes); + } + } + } + + } + + /* stats z (debug and memory info) */ + if (!strcasecmp(parameters[0],"z")) + { + WriteServ(user->fd,"249 %s :Users(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,clientlist.size(),clientlist.size()*sizeof(userrec),clientlist.bucket_count()); + WriteServ(user->fd,"249 %s :Channels(HASH_MAP) %d (%d bytes, %d buckets)",user->nick,chanlist.size(),chanlist.size()*sizeof(chanrec),chanlist.bucket_count()); + WriteServ(user->fd,"249 %s :Commands(VECTOR) %d (%d bytes)",user->nick,cmdlist.size(),cmdlist.size()*sizeof(command_t)); + WriteServ(user->fd,"249 %s :MOTD(VECTOR) %d, RULES(VECTOR) %d",user->nick,MOTD.size(),RULES.size()); + WriteServ(user->fd,"249 %s :address_cache(HASH_MAP) %d (%d buckets)",user->nick,IP.size(),IP.bucket_count()); + WriteServ(user->fd,"249 %s :Modules(VECTOR) %d (%d)",user->nick,modules.size(),modules.size()*sizeof(Module)); + WriteServ(user->fd,"249 %s :ClassFactories(VECTOR) %d (%d)",user->nick,factory.size(),factory.size()*sizeof(ircd_module)); + WriteServ(user->fd,"249 %s :Ports(STATIC_ARRAY) %d",user->nick,boundPortCount); + } + + /* stats o */ + if (!strcasecmp(parameters[0],"o")) + { + for (int i = 0; i < ConfValueEnum("oper"); i++) + { + char LoginName[MAXBUF]; + char HostName[MAXBUF]; + char OperType[MAXBUF]; + ConfValue("oper","name",i,LoginName); + ConfValue("oper","host",i,HostName); + ConfValue("oper","type",i,OperType); + WriteServ(user->fd,"243 %s O %s * %s %s 0",user->nick,HostName,LoginName,OperType); + } + } + + /* stats l (show user I/O stats) */ + if (!strcasecmp(parameters[0],"l")) + { + WriteServ(user->fd,"211 %s :server:port nick bytes_in cmds_in bytes_out cmds_out",user->nick); + for (user_hash::iterator i = clientlist.begin(); i != clientlist.end(); i++) + { + if (isnick(i->second->nick)) + { + WriteServ(user->fd,"211 %s :%s:%d %s %d %d %d %d",user->nick,ServerName,i->second->port,i->second->nick,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out); + } + else + { + WriteServ(user->fd,"211 %s :%s:%d (unknown@%d) %d %d %d %d",user->nick,ServerName,i->second->port,i->second->fd,i->second->bytes_in,i->second->cmds_in,i->second->bytes_out,i->second->cmds_out); + } + + } + } + + /* stats u (show server uptime) */ + if (!strcasecmp(parameters[0],"u")) + { + time_t current_time = 0; + current_time = time(NULL); + time_t server_uptime = current_time - startup_time; + struct tm* stime; + stime = gmtime(&server_uptime); + /* i dont know who the hell would have an ircd running for over a year nonstop, but + * Craig suggested this, and it seemed a good idea so in it went */ + if (stime->tm_year > 70) + { + WriteServ(user->fd,"242 %s :Server up %d years, %d days, %.2d:%.2d:%.2d",user->nick,(stime->tm_year-70),stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); + } + else + { + WriteServ(user->fd,"242 %s :Server up %d days, %.2d:%.2d:%.2d",user->nick,stime->tm_yday,stime->tm_hour,stime->tm_min,stime->tm_sec); + } + } + + WriteServ(user->fd,"219 %s %s :End of /STATS report",user->nick,parameters[0]); + WriteOpers("*** Notice: Stats '%s' requested by %s (%s@%s)",parameters[0],user->nick,user->ident,user->host); + +} + +void handle_oper(char **parameters, int pcnt, userrec *user) +{ + char LoginName[MAXBUF]; + char Password[MAXBUF]; + char OperType[MAXBUF]; + char TypeName[MAXBUF]; + char Hostname[MAXBUF]; + int i,j; + + for (i = 0; i < ConfValueEnum("oper"); i++) + { + ConfValue("oper","name",i,LoginName); + ConfValue("oper","password",i,Password); + if ((!strcmp(LoginName,parameters[0])) && (!strcmp(Password,parameters[1]))) + { + /* correct oper credentials */ + ConfValue("oper","type",i,OperType); + WriteOpers("*** %s (%s@%s) is now an IRC operator of type %s",user->nick,user->ident,user->host,OperType); + WriteServ(user->fd,"381 %s :You are now an IRC operator of type %s",user->nick,OperType); + WriteServ(user->fd,"MODE %s :+o",user->nick); + for (j =0; j < ConfValueEnum("type"); j++) + { + ConfValue("type","name",j,TypeName); + if (!strcmp(TypeName,OperType)) + { + /* found this oper's opertype */ + ConfValue("type","host",j,Hostname); + strncpy(user->dhost,Hostname,256); + } + } + if (!strchr(user->modes,'o')) + { + strcat(user->modes,"o"); + } + return; + } + } + /* no such oper */ + WriteServ(user->fd,"491 %s :Invalid oper credentials",user->nick); + WriteOpers("*** WARNING! Failed oper attempt by %s!%s@%s!",user->nick,user->ident,user->host); +} + +void handle_nick(char **parameters, int pcnt, userrec *user) +{ + if (pcnt < 1) + { + debug("not enough params for handle_nick"); + return; + } + if (!parameters[0]) + { + debug("invalid parameter passed to handle_nick"); + return; + } + if (!strlen(parameters[0])) + { + debug("zero length new nick passed to handle_nick"); + return; + } + if (!user) + { + debug("invalid user passed to handle_nick"); + return; + } + if (!user->nick) + { + debug("invalid old nick passed to handle_nick"); + return; + } + if (!strcasecmp(user->nick,parameters[0])) + { + debug("old nick is new nick, skipping"); + return; + } + else + { + if (strlen(parameters[0]) > 1) + { + if (parameters[0][0] == ':') + { + *parameters[0]++; + } + } + if ((Find(parameters[0])) && (Find(parameters[0]) != user)) + { + WriteServ(user->fd,"433 %s %s :Nickname is already in use.",user->nick,parameters[0]); + return; + } + } + if (isnick(parameters[0]) == 0) + { + WriteServ(user->fd,"432 %s %s :Erroneous Nickname",user->nick,parameters[0]); + return; + } + + if (user->registered == 7) + { + WriteCommon(user,"NICK %s",parameters[0]); + } + + /* change the nick of the user in the users_hash */ + user = ReHashNick(user->nick, parameters[0]); + /* actually change the nick within the record */ + if (!user) return; + if (!user->nick) return; + + strncpy(user->nick, parameters[0],NICKMAX); + + debug("new nick set: %s",user->nick); + + if (user->registered < 3) + user->registered = (user->registered | 2); + if (user->registered == 3) + { + /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ + ConnectUser(user); + } + debug("exit nickchange: %s",user->nick); +} + +int process_parameters(char **command_p,char *parameters) +{ + int i = 0; + int j = 0; + int q = 0; + q = strlen(parameters); + if (!q) + { + /* no parameters, command_p invalid! */ + return 0; + } + if (parameters[0] == ':') + { + command_p[0] = parameters+1; + return 1; + } + if (q) + { + if ((strchr(parameters,' ')==NULL) || (parameters[0] == ':')) + { + /* only one parameter */ + command_p[0] = parameters; + if (parameters[0] == ':') + { + if (strchr(parameters,' ') != NULL) + { + command_p[0]++; + } + } + return 1; + } + } + command_p[j++] = parameters; + for (i = 0; i <= q; i++) + { + if (parameters[i] == ' ') + { + command_p[j++] = parameters+i+1; + parameters[i] = '\0'; + if (command_p[j-1][0] == ':') + { + *command_p[j-1]++; /* remove dodgy ":" */ + break; + /* parameter like this marks end of the sequence */ + } + } + } + return j; /* returns total number of items in the list */ +} + +void process_command(userrec *user, char* cmd) +{ + char *parameters; + char *command; + char *command_p[127]; + char p[MAXBUF], temp[MAXBUF]; + int i, j, items, cmd_found; + + for (int i = 0; i < 127; i++) + command_p[i] = NULL; + + if (!user) + { + return; + } + if (!cmd) + { + return; + } + if (!strcmp(cmd,"")) + { + return; + } + strcpy(temp,cmd); + if (!strchr(cmd,' ')) + { + /* no parameters, lets skip the formalities and not chop up + * the string */ + items = 0; + command_p[0] = NULL; + parameters = NULL; + for (int i = 0; i <= strlen(cmd); i++) + { + cmd[i] = toupper(cmd[i]); + } + } + else + { + strcpy(cmd,""); + j = 0; + /* strip out extraneous linefeeds through mirc's crappy pasting (thanks Craig) */ + for (i = 0; i < strlen(temp); i++) + { + if ((temp[i] != 10) && (temp[i] != 13) && (temp[i] != 0) && (temp[i] != 7)) + { + cmd[j++] = temp[i]; + cmd[j] = 0; + } + } + /* split the full string into a command plus parameters */ + parameters = p; + strcpy(p," "); + command = cmd; + if (strchr(cmd,' ')) + { + for (i = 0; i <= strlen(cmd); i++) + { + /* capitalise the command ONLY, leave params intact */ + cmd[i] = toupper(cmd[i]); + /* are we nearly there yet?! :P */ + if (cmd[i] == ' ') + { + command = cmd; + parameters = cmd+i+1; + cmd[i] = '\0'; + break; + } + } + } + else + { + for (i = 0; i <= strlen(cmd); i++) + { + cmd[i] = toupper(cmd[i]); + } + } + + } + + cmd_found = 0; + + for (i = 0; i != cmdlist.size(); i++) + { + if (strcmp(cmdlist[i].command,"")) + { + if (!strcmp(command, cmdlist[i].command)) + { + if (parameters) + { + if (strcmp(parameters,"")) + { + items = process_parameters(command_p,parameters); + } + else + { + items = 0; + command_p[0] = NULL; + } + } + else + { + items = 0; + command_p[0] = NULL; + } + + if (user) + { + user->idle_lastmsg = time(NULL); + /* activity resets the ping pending timer */ + user->nping = time(NULL) + 120; + if ((items) < cmdlist[i].min_params) + { + debug("process_command: not enough parameters: %s %s",user->nick,command); + WriteServ(user->fd,"461 %s %s :Not enough parameters",user->nick,command); + return; + } + if ((!strchr(user->modes,cmdlist[i].flags_needed)) && (cmdlist[i].flags_needed)) + { + debug("process_command: permission denied: %s %s",user->nick,command); + WriteServ(user->fd,"481 %s :Permission Denied- You do not have the required operator privilages",user->nick); + cmd_found = 1; + return; + } + /* if the command isnt USER, PASS, or NICK, and nick is empty, + * deny command! */ + if ((strcmp(command,"USER")) && (strcmp(command,"NICK")) && (strcmp(command,"PASS"))) + { + if ((!isnick(user->nick)) || (user->registered != 7)) + { + debug("process_command: not registered: %s %s",user->nick,command); + WriteServ(user->fd,"451 %s :You have not registered",command); + return; + } + } + if ((user->registered == 7) || (!strcmp(command,"USER")) || (!strcmp(command,"NICK")) || (!strcmp(command,"PASS"))) + { + debug("process_command: handler: %s %s %d",user->nick,command,items); + if (cmdlist[i].handler_function) + { + /* ikky /stats counters */ + if (temp) + { + if (user) + { + user->bytes_in += strlen(temp); + user->cmds_in++; + } + cmdlist[i].use_count++; + cmdlist[i].total_bytes+=strlen(temp); + } + + /* WARNING: nothing may come after the + * command handler call, as the handler + * may free the user structure! */ + + cmdlist[i].handler_function(command_p,items,user); + } + return; + } + else + { + debug("process_command: not registered: %s %s",user->nick,command); + WriteServ(user->fd,"451 %s :You have not registered",command); + return; + } + } + cmd_found = 1; + } + } + } + if ((!cmd_found) && (user)) + { + debug("process_command: not in table: %s %s",user->nick,command); + WriteServ(user->fd,"421 %s %s :Unknown command",user->nick,command); + } +} + + +void createcommand(char* cmd, handlerfunc f, char flags, int minparams) +{ + command_t comm; + /* create the command and push it onto the table */ + strcpy(comm.command,cmd); + comm.handler_function = f; + comm.flags_needed = flags; + comm.min_params = minparams; + comm.use_count = 0; + comm.total_bytes = 0; + cmdlist.push_back(comm); +} + +void SetupCommandTable(void) +{ + createcommand("USER",handle_user,0,4); + createcommand("NICK",handle_nick,0,1); + createcommand("QUIT",handle_quit,0,1); + createcommand("VERSION",handle_version,0,0); + createcommand("PING",handle_ping,0,1); + createcommand("PONG",handle_pong,0,1); + createcommand("ADMIN",handle_admin,0,0); + createcommand("PRIVMSG",handle_privmsg,0,2); + createcommand("INFO",handle_info,0,0); + createcommand("TIME",handle_time,0,0); + createcommand("WHOIS",handle_whois,0,1); + createcommand("WALLOPS",handle_wallops,'o',1); + createcommand("NOTICE",handle_notice,0,2); + createcommand("JOIN",handle_join,0,1); + createcommand("NAMES",handle_names,0,1); + createcommand("PART",handle_part,0,1); + createcommand("KICK",handle_kick,0,2); + createcommand("MODE",handle_mode,0,1); + createcommand("TOPIC",handle_topic,0,1); + createcommand("WHO",handle_who,0,1); + createcommand("MOTD",handle_motd,0,0); + createcommand("RULES",handle_join,0,0); + createcommand("OPER",handle_oper,0,2); + createcommand("LIST",handle_list,0,0); + createcommand("DIE",handle_die,'o',1); + createcommand("RESTART",handle_restart,'o',1); + createcommand("KILL",handle_kill,'o',2); + createcommand("REHASH",handle_rehash,'o',0); + createcommand("LUSERS",handle_lusers,0,0); + createcommand("STATS",handle_stats,0,1); + createcommand("USERHOST",handle_userhost,0,1); + createcommand("AWAY",handle_away,0,0); + createcommand("ISON",handle_ison,0,0); + createcommand("SUMMON",handle_summon,0,0); + createcommand("USERS",handle_users,0,0); + createcommand("INVITE",handle_invite,0,2); + createcommand("PASS",handle_pass,0,1); + createcommand("TRACE",handle_trace,'o',0); +} + +void process_buffer(userrec *user) +{ + char cmd[MAXBUF]; + int i; + if (!user->inbuf) + { + return; + } + if (!strcmp(user->inbuf,"")) + { + return; + } + strncpy(cmd,user->inbuf,MAXBUF); + if (!strcmp(cmd,"")) + { + return; + } + if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10)) + { + cmd[strlen(cmd)-1] = '\0'; + } + if ((cmd[strlen(cmd)-1] == 13) || (cmd[strlen(cmd)-1] == 10)) + { + cmd[strlen(cmd)-1] = '\0'; + } + strcpy(user->inbuf,""); + if (!strcmp(cmd,"")) + { + return; + } + debug("InspIRCd: processing: %s %s",user->nick,cmd); + process_command(user,cmd); +} + +int InspIRCd(void) +{ + struct sockaddr_in client, server; + int portCount = 0, ports[MAXSOCKS]; + char addrs[MAXBUF][255]; + int openSockfd[MAXSOCKS], incomingSockfd, result = TRUE; + socklen_t length; + int count = 0, scanDetectTrigger = TRUE, showBanner = FALSE; + int selectResult = 0; + char *temp, configToken[MAXBUF], stuff[MAXBUF], Addr[MAXBUF]; + char resolvedHost[MAXBUF]; + fd_set selectFds; + struct timeval tv; + int count2; + + debug("InspIRCd: startup: begin"); + debug("$Id$"); + if ((geteuid()) && (getuid()) == 0) + { + printf("WARNING!!! You are running an irc server as ROOT!!! DO NOT DO THIS!!!\n\n"); + Exit(ERROR); + debug("InspIRCd: startup: not starting with UID 0!"); + } + SetupCommandTable(); + debug("InspIRCd: startup: default command table set up"); + + ReadConfig(); + if (strcmp(DieValue,"")) + { + printf("WARNING: %s\n\n",DieValue); + exit(0); + } + debug("InspIRCd: startup: read config"); + + for (count = 0; count < ConfValueEnum("bind"); count++) + { + ConfValue("bind","port",count,configToken); + ConfValue("bind","address",count,Addr); + ports[count] = atoi(configToken); + strcpy(addrs[count],Addr); + debug("InspIRCd: startup: read binding %s:%d from config",addrs[count],ports[count]); + } + portCount = ConfValueEnum("bind"); + debug("InspIRCd: startup: read %d total ports",portCount); + + debug("InspIRCd: startup: InspIRCd is now running!"); + + printf("\n"); + for (count = 0; count < ConfValueEnum("module"); count++) + { + char modfile[MAXBUF]; + ConfValue("module","name",count,configToken); + sprintf(modfile,"%s/%s",MOD_PATH,configToken); + printf("Loading module... \033[1;37m%s\033[0;37m\n",modfile); + debug("InspIRCd: startup: Loading module: %s",modfile); + + factory[count] = new ircd_module(modfile); + if (factory[count]->LastError()) + { + debug("Unable to load %s: %s",modfile,factory[count]->LastError()); + sprintf("Unable to load %s: %s\nExiting...\n",modfile,factory[count]->LastError()); + Exit(ERROR); + } + if (factory[count]->factory) + { + modules[count] = factory[count]->factory->CreateModule(); + /* save the module and the module's classfactory, if + * this isnt done, random crashes can occur :/ */ + } + else + { + debug("Unable to load %s",modfile); + sprintf("Unable to load %s\nExiting...\n",modfile); + Exit(ERROR); + } + } + MODCOUNT = count - 1; + debug("Total loaded modules: %d",MODCOUNT+1); + + printf("\nInspIRCd is now running!\n"); + + startup_time = time(NULL); + + if (DaemonSeed() == ERROR) + { + debug("InspIRCd: startup: can't daemonise"); + printf("ERROR: could not go into daemon mode. Shutting down.\n"); + Exit(ERROR); + } + + + /* setup select call */ + FD_ZERO(&selectFds); + debug("InspIRCd: startup: zero selects"); + + for (count = 0; count < portCount; count++) + { + if ((openSockfd[boundPortCount] = OpenTCPSocket()) == ERROR) + { + debug("InspIRCd: startup: bad fd %d",openSockfd[boundPortCount]); + return(ERROR); + } + if (BindSocket(openSockfd[boundPortCount],client,server,ports[count],addrs[count]) == ERROR) + { + debug("InspIRCd: startup: failed to bind port %d",ports[count]); + } + else /* well we at least bound to one socket so we'll continue */ + { + boundPortCount++; + } + } + + debug("InspIRCd: startup: total bound ports %d",boundPortCount); + + /* if we didn't bind to anything then abort */ + if (boundPortCount == 0) + { + debug("InspIRCd: startup: no ports bound, bailing!"); + return (ERROR); + } + + length = sizeof (client); + int flip_flop = 0; + + /* main loop for multiplexing/resetting */ + for (;;) + { + /* set up select call */ + for (count = 0; count < boundPortCount; count++) + { + FD_SET (openSockfd[count], &selectFds); + } + + /* added timeout! select was waiting forever... wank... :/ */ + tv.tv_usec = 0; + + flip_flop++; + if (flip_flop > 20) + { + tv.tv_usec = 1; + flip_flop = 0; + } + + tv.tv_sec = 0; + selectResult = select(MAXSOCKS, &selectFds, NULL, NULL, &tv); + + for (user_hash::iterator count2 = clientlist.begin(); count2 != clientlist.end(); count2++) + { + char data[MAXBUF]; + + if (!count2->second) break; + + if (count2->second) + if (count2->second->fd) + { + if (((time(NULL)) > count2->second->nping) && (isnick(count2->second->nick)) && (count2->second->registered == 7)) + { + if (!count2->second->lastping) + { + debug("InspIRCd: ping timeout: %s",count2->second->nick); + kill_link(count2->second,"Ping timeout"); + break; + } + Write(count2->second->fd,"PING :%s",ServerName); + debug("InspIRCd: pinging: %s",count2->second->nick); + count2->second->lastping = 0; + count2->second->nping = time(NULL)+120; + } + + result = read(count2->second->fd, data, 1); + // result EAGAIN means nothing read + if (result == EAGAIN) + { + } + else + if (result == 0) + { + debug("InspIRCd: Exited: %s",count2->second->nick); + kill_link(count2->second,"Client exited"); + } + else if (result > 0) + { + strncat(count2->second->inbuf, data, result); + if (strchr(count2->second->inbuf, '\n') || strchr(count2->second->inbuf, '\r')) + { + /* at least one complete line is waiting to be processed */ + if (!count2->second->fd) + break; + else + { + process_buffer(count2->second); + break; + } + } + } + } + } + + /* select is reporting a waiting socket. Poll them all to find out which */ + if (selectResult > 0) + { + char target[MAXBUF], resolved[MAXBUF]; + for (count = 0; count < boundPortCount; count++) + { + if (FD_ISSET (openSockfd[count], &selectFds)) + { + incomingSockfd = accept (openSockfd[count], (struct sockaddr *) &client, &length); + + address_cache::iterator iter = IP.find(client.sin_addr); + bool iscached = false; + if (iter == IP.end()) + { + /* ip isn't in cache, add it */ + strncpy (target, (char *) inet_ntoa (client.sin_addr), MAXBUF); + if(CleanAndResolve(resolved, target) != TRUE) + { + strncpy(resolved,target,MAXBUF); + } + /* hostname now in 'target' */ + IP[client.sin_addr] = new string(resolved); + /* hostname in cache */ + } + else + { + /* found ip (cached) */ + strncpy(resolved, iter->second->c_str(), MAXBUF); + iscached = true; + } + + if (incomingSockfd < 0) + { + WriteOpers("*** WARNING: Accept failed on port %d (%s)", ports[count],target); + debug("InspIRCd: accept failed: %d",ports[count]); + break; + } + AddClient(incomingSockfd, resolved, ports[count], iscached); + debug("InspIRCd: adding client on port %d fd=%d",ports[count],incomingSockfd); + break; + } + + } + } + } + + /* not reached */ + close (incomingSockfd); +} + diff --git a/src/inspircd_io.cpp b/src/inspircd_io.cpp new file mode 100644 index 000000000..474f48fe1 --- /dev/null +++ b/src/inspircd_io.cpp @@ -0,0 +1,371 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * Inspire is copyright (C) 2002-2003 ChatSpike-Dev. + * E-mail: + * + * + * + * Written by Craig Edwards, Craig McLure, and others. + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + + $Log$ + Revision 1.1 2003/01/23 19:45:58 brain + Initial revision + + Revision 1.12 2003/01/22 20:49:16 brain + Added FileReader file-caching class + Changed m_randquote to use FileReader class + + Revision 1.11 2003/01/21 20:31:24 brain + Modified to add documentation + Added ConfigReader class for modules + + Revision 1.10 2003/01/16 20:11:55 brain + fixed some ugly pointer bugs (thanks dblack and a|KK|y!) + + Revision 1.9 2003/01/09 13:05:58 brain + + Fixed socket lingering problems (is BSD compatible) + + Revision 1.8 2003/01/07 19:57:56 brain + + Dynamix module support, preliminary release + + Revision 1.7 2003/01/06 23:38:29 brain + + just playing with header tags + + + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "inspircd_io.h" +#include "inspircd_util.h" + +void WriteOpers(char* text, ...); + +void Exit (int status) +{ + send_error("Server shutdown."); + exit (status); +} + +void Killed(int status) +{ + send_error("Server terminated."); + exit(status); +} + +void Rehash(int status) +{ + ReadConfig(); + WriteOpers("Rehashing config file %s due to SIGHUP",CONFIG_FILE); +} + + + +void Start (void) +{ + printf("\033[1;37mInspire Internet Relay Chat Server, compiled " __DATE__ " at " __TIME__ "\n"); + printf("(C) ChatSpike Development team.\033[0;37m\n\n"); + printf("\033[1;37mDevelopers:\033[0;37m Brain, FrostyCoolSlug, Raider, RD\n"); + printf("\033[1;37mDocumentation:\033[0;37m FrostyCoolSlug\n"); + printf("\033[1;37mTesters:\033[0;37m MrBOFH, piggles, Lord_Zathras, typobox43, CC\n"); + printf("\033[1;37mName concept:\033[0;37m Lord_Zathras\n\n"); +} + + +int DaemonSeed (void) +{ + int childpid; + signal (SIGALRM, SIG_IGN); + signal (SIGHUP, Rehash); + signal (SIGPIPE, SIG_IGN); + signal (SIGTERM, Exit); + signal (SIGABRT, Exit); + signal (SIGSEGV, Error); + signal (SIGURG, Exit); + signal (SIGKILL, Exit); + if ((childpid = fork ()) < 0) + return (ERROR); + else if (childpid > 0) + exit (0); + setsid (); + umask (077); + /* close stdout, stdin, stderr */ + close(0); + close(1); + close(2); + return (TRUE); +} + + + + +/* Make sure the config file is available */ +int CheckConfig (void) +{ + FILE *input; + + if ((input = fopen (CONFIG_FILE, "r")) == NULL) + { + printf("ERROR: Cannot open config file: %s\nExiting...\n",CONFIG_FILE); + return(FALSE); + } + else + fclose (input); + +return(TRUE); +} + +/* Counts the number of tags of a certain type within the config file, e.g. to enumerate opers */ + +int EnumConf(const char* filename, const char* tag) +{ + FILE *config; + int ptr = 0; + char buffer[MAXBUF], c_tag[MAXBUF], c; + int in_token, in_quotes, tptr, j, idx = 0; + char* key; + + if ((config = fopen (filename, "r")) == NULL) + { + return 0; + } + else + { + ptr = 0; + in_token = 0; + in_quotes = 0; + while (!feof(config)) + { + c = fgetc(config); + if ((c == '<') && (!in_quotes)) + { + tptr = 0; + in_token = 1; + do { + c = fgetc(config); + if (c != ' ') + { + c_tag[tptr++] = c; + c_tag[tptr] = '\0'; + } + } while (c != ' '); + } + if (c == '"') + { + in_quotes = (!in_quotes); + } + if ((c == '>') && (!in_quotes)) + { + in_token = 0; + if (!strcmp(c_tag,tag)) + { + /* correct tag, but wrong index */ + idx++; + } + c_tag[0] = '\0'; + buffer[0] = '\0'; + ptr = 0; + tptr = 0; + } + if (c != '>') + { + if ((in_token) && (c != '\n') && (c != '\r')) + { + buffer[ptr++] = c; + buffer[ptr] = '\0'; + } + } + } + } + fclose(config); + return idx; +} + + + +int ConfValueEnum(char* tag) +{ + EnumConf(CONFIG_FILE,tag); +} + + + +/* Retrieves a value from the config file. If there is more than one value of the specified + * key and section (e.g. for opers etc) then the index value specifies which to retreive, e.g. + * + * ConfValue("oper","name",2,result); + */ + +int ReadConf(const char* filename, const char* tag, const char* var, int index, char *result) +{ + FILE *config; + int ptr = 0; + char buffer[MAXBUF], c_tag[MAXBUF], c; + int in_token, in_quotes, tptr, j, idx = 0; + char* key; + + if ((config = fopen (filename, "r")) == NULL) + { + return 0; + } + else + { + ptr = 0; + in_token = 0; + in_quotes = 0; + while (!feof(config)) + { + c = fgetc(config); + if ((c == '<') && (!in_quotes)) + { + tptr = 0; + in_token = 1; + do { + c = fgetc(config); + if (c != ' ') + { + c_tag[tptr++] = c; + c_tag[tptr] = '\0'; + } + } while (c != ' '); + } + if (c == '"') + { + in_quotes = (!in_quotes); + } + if ((c == '>') && (!in_quotes)) + { + in_token = 0; + if (idx == index) + { + if (!strcmp(c_tag,tag)) + { + if ((buffer) && (c_tag) && (var)) + { + key = strstr(buffer,var); + if (!key) + { + /* value not found in tag */ + fclose(config); + return 0; + } + else + { + key+=strlen(var); + while (key[0] !='"') + { + if (!strlen(key)) + { + /* missing quote */ + return 0; + } + key++; + } + key++; + for (j = 0; j < strlen(key); j++) + { + if (key[j] == '"') + { + key[j] = '\0'; + } + } + fclose(config); + strcpy(result,key); + return 1; + } + } + } + } + if (!strcmp(c_tag,tag)) + { + /* correct tag, but wrong index */ + idx++; + } + c_tag[0] = '\0'; + buffer[0] = '\0'; + ptr = 0; + tptr = 0; + } + if (c != '>') + { + if ((in_token) && (c != '\n') && (c != '\r')) + { + buffer[ptr++] = c; + buffer[ptr] = '\0'; + } + } + } + } + fclose(config); + return 0; +} + + + +int ConfValue(char* tag, char* var, int index, char *result) +{ + ReadConf(CONFIG_FILE, tag, var, index, result); +} + + + +/* This will bind a socket to a port. It works for UDP/TCP */ +int BindSocket (int sockfd, struct sockaddr_in client, struct sockaddr_in server, int port, char* addr) +{ + bzero((char *)&server,sizeof(server)); + struct in_addr addy; + inet_aton(addr,&addy); + + server.sin_family = AF_INET; + if (!strcmp(addr,"")) + { + server.sin_addr.s_addr = htonl(INADDR_ANY); + } + else + { + server.sin_addr = addy; + } + + server.sin_port = htons(port); + + if (bind(sockfd,(struct sockaddr*)&server,sizeof(server))<0) + { + return(ERROR); + } + else + { + listen(sockfd,5); + return(TRUE); + } +} + + +/* Open a TCP Socket */ +int OpenTCPSocket (void) +{ + int sockfd; + int on = 0; + struct linger linger = { 0 }; + + if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) + return (ERROR); + else + { + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); + /* This is BSD compatible, setting l_onoff to 0 is *NOT* http://web.irc.org/mla/ircd-dev/msg02259.html */ + linger.l_onoff = 1; + linger.l_linger = 0; + setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&linger,sizeof(linger)); + return (sockfd); + } +} + diff --git a/src/inspircd_util.cpp b/src/inspircd_util.cpp new file mode 100644 index 000000000..756a61d23 --- /dev/null +++ b/src/inspircd_util.cpp @@ -0,0 +1,77 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.2 2003/01/15 22:49:18 brain +Added log macros + + +*/ + +#include "inspircd.h" +#include "inspircd_io.h" +#include "inspircd_util.h" + +char *SafeStrncpy (char *dest, const char *src, size_t size) +{ + if (!dest) + { + dest = NULL; + return (NULL); + } + else if (size < 1) + { + dest = NULL; + return (NULL); + } + + memset (dest, '\0', size); + strncpy (dest, src, size - 1); + + return (dest); +} + + +char *CleanIpAddr (char *cleanAddr, const char *dirtyAddr) +{ + int count = 0, maxdot = 0, maxoctet = 0; + + memset (cleanAddr, '\0', MAXBUF); + if(dirtyAddr == NULL) + return(cleanAddr); + + for (count = 0; count < MAXBUF - 1; count++) + { + if (isdigit (dirtyAddr[count])) + { + if (++maxoctet > 3) + { + cleanAddr[count] = '\0'; + break; + } + cleanAddr[count] = dirtyAddr[count]; + } + else if (dirtyAddr[count] == '.') + { + if (++maxdot > 3) + { + cleanAddr[count] = '\0'; + break; + } + maxoctet = 0; + cleanAddr[count] = dirtyAddr[count]; + } + else + { + cleanAddr[count] = '\0'; + break; + } + } + + return (cleanAddr); +} + + + diff --git a/src/modules.cpp b/src/modules.cpp new file mode 100644 index 000000000..36dbd2933 --- /dev/null +++ b/src/modules.cpp @@ -0,0 +1,232 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.7 2003/01/22 20:49:16 brain +Added FileReader file-caching class +Changed m_randquote to use FileReader class + +Revision 1.6 2003/01/21 20:31:24 brain +Modified to add documentation +Added ConfigReader class for modules + +Revision 1.5 2003/01/13 22:30:50 brain +Added Admin class (holds /admin info for modules) +Added methods to Server class + + +*/ + + + +#include +#include +#include "globals.h" +#include "modules.h" +#include "inspircd_io.h" + +// version is a simple class for holding a modules version number + +Version::Version(int major, int minor, int revision, int build) : Major(major), Minor(minor), Revision(revision), Build(build) { }; + +// admin is a simple class for holding a server's administrative info + +Admin::Admin(string name, string email, string nick) : Name(name), Email(email), Nick(nick) { }; + +// +// Announce to the world that the Module base +// class has been created or destroyed +// + +Module::Module() { } +Module::~Module() { } +void Module::OnUserConnect(userrec* user) { } +void Module::OnUserQuit(userrec* user) { } +void Module::OnUserJoin(userrec* user, chanrec* channel) { } +void Module::OnUserPart(userrec* user, chanrec* channel) { } +Version Module::GetVersion() { return Version(1,0,0,0); } + +// server is a wrapper class that provides methods to all of the C-style +// exports in the core +// + +Server::Server() +{ +} + +Server::~Server() +{ +} + +void Server::SendOpers(string s) +{ + WriteOpers("%s",s.c_str()); +} + +void Server::Debug(string s) +{ + debug("%s",s.c_str()); +} + +void Server::Send(int Socket, string s) +{ + Write(Socket,"%s",s.c_str()); +} + +void Server::SendServ(int Socket, string s) +{ + WriteServ(Socket,"%s",s.c_str()); +} + +void Server::SendFrom(int Socket, userrec* User, string s) +{ + WriteFrom(Socket,User,"%s",s.c_str()); +} + +void Server::SendTo(userrec* Source, userrec* Dest, string s) +{ + WriteTo(Source,Dest,"%s",s.c_str()); +} + +void Server::SendChannel(userrec* User, chanrec* Channel, string s,bool IncludeSender) +{ + if (IncludeSender) + { + WriteChannel(Channel,User,"%s",s.c_str()); + } + else + { + ChanExceptSender(Channel,User,"%s",s.c_str()); + } +} + +bool Server::CommonChannels(userrec* u1, userrec* u2) +{ + return (common_channels(u1,u2) != 0); +} + +void Server::SendCommon(userrec* User, string text,bool IncludeSender) +{ + if (IncludeSender) + { + WriteCommon(User,"%s",text.c_str()); + } + else + { + WriteCommonExcept(User,"%s",text.c_str()); + } +} + +void Server::SendWallops(userrec* User, string text) +{ + WriteWallOps(User,"%s",text.c_str()); +} + +bool Server::IsNick(string nick) +{ + return (isnick(nick.c_str()) != 0); +} + +userrec* Server::FindNick(string nick) +{ + return Find(nick); +} + +chanrec* Server::FindChannel(string channel) +{ + return FindChan(channel.c_str()); +} + +string Server::ChanMode(userrec* User, chanrec* Chan) +{ + string mode = cmode(User,Chan); + return mode; +} + +string Server::GetServerName() +{ + return getservername(); +} + +string Server::GetNetworkName() +{ + return getnetworkname(); +} + +Admin Server::GetAdmin() +{ + return Admin(getadminname(),getadminemail(),getadminnick()); +} + + +ConfigReader::ConfigReader() +{ + fname = CONFIG_FILE; +} + + +ConfigReader::~ConfigReader() +{ +} + + +ConfigReader::ConfigReader(string filename) : fname(filename) { }; + +string ConfigReader::ReadValue(string tag, string name, int index) +{ + char val[MAXBUF]; + ReadConf(fname.c_str(),tag.c_str(),name.c_str(),index,val); + string s = val; + return s; +} + + +int ConfigReader::Enumerate(string tag) +{ + return EnumConf(fname.c_str(),tag.c_str()); +} + + +bool ConfigReader::Verify() +{ + return true; +} + + +FileReader::FileReader(string filename) +{ + file_cache c; + readfile(c,filename.c_str()); + this->fc = c; +} + +FileReader::FileReader() +{ +} + +void FileReader::LoadFile(string filename) +{ + file_cache c; + readfile(c,filename.c_str()); + this->fc = c; +} + +FileReader::~FileReader() +{ +} + +string FileReader::GetLine(int x) +{ + if ((x<0) || (x>fc.size())) + return ""; + return fc[x]; +} + +int FileReader::FileSize() +{ + return fc.size(); +} + + diff --git a/src/modules/.make b/src/modules/.make new file mode 100644 index 000000000..0f68a9fad --- /dev/null +++ b/src/modules/.make @@ -0,0 +1,3 @@ +g++ -I../../include -fPIC -frtti -O3 -shared -o m_cloaking.so m_cloaking.cpp +g++ -I../../include -fPIC -frtti -O3 -shared -o m_foobar.so m_foobar.cpp +g++ -I../../include -fPIC -frtti -O3 -shared -o m_randquote.so m_randquote.cpp diff --git a/src/modules/m_cloaking.cpp b/src/modules/m_cloaking.cpp new file mode 100644 index 000000000..91ab49054 --- /dev/null +++ b/src/modules/m_cloaking.cpp @@ -0,0 +1,73 @@ +#include + +#include "users.h" +#include "channels.h" +#include "modules.h" + +/* $ModDesc: Provides masking of user hostnames */ + +class ModuleCloaking : public Module +{ + private: + + Server *Srv; + + public: + ModuleCloaking() + { + Srv = new Server; + } + + virtual ~ModuleCloaking() + { + delete Srv; + } + + virtual Version GetVersion() + { + return Version(1,0,0,0); + } + + virtual void OnUserConnect(userrec* user) + { + if (strstr(user->dhost,".")) + { + string a = strstr(user->dhost,"."); + char ra[64]; + long seed,s2; + memcpy(&seed,user->dhost,sizeof(long)); + memcpy(&s2,a.c_str(),sizeof(long)); + sprintf(ra,"%.8X",seed*s2*strlen(user->host)); + string b = Srv->GetNetworkName() + "-" + ra + a; + Srv->Debug("cloak: allocated "+b); + strcpy(user->dhost,b.c_str()); + } + } + +}; + + +class ModuleCloakingFactory : public ModuleFactory +{ + public: + ModuleCloakingFactory() + { + } + + ~ModuleCloakingFactory() + { + } + + virtual Module * CreateModule() + { + return new ModuleCloaking; + } + +}; + + +extern "C" void * init_module( void ) +{ + return new ModuleCloakingFactory; +} + diff --git a/src/modules/m_foobar.cpp b/src/modules/m_foobar.cpp new file mode 100644 index 000000000..9aed188d8 --- /dev/null +++ b/src/modules/m_foobar.cpp @@ -0,0 +1,113 @@ +#include "users.h" +#include "channels.h" +#include "modules.h" + +/* $ModDesc: A dummy module for testing */ + +// Class ModuleFoobar inherits from Module +// It just outputs simple debug strings to show its methods are working. + +class ModuleFoobar : public Module +{ + private: + + // It is recommended that your class makes use of one or more Server + // objects. A server object is a class which contains methods which + // encapsulate the exports from the core of the ircd. + // such methods include Debug, SendChannel, etc. + + Server *Srv; + public: + ModuleFoobar() + { + // The constructor just creates an instance of the server class + + Srv = new Server; + } + + virtual ~ModuleFoobar() + { + // destructor deletes the instance of the server class + + delete Srv; + } + + virtual Version GetVersion() + { + // this method instantiates a class of type Version, and returns + // the modules version information using it. + + return Version(1,0,0,0); + } + + virtual void OnUserConnect(userrec* user) + { + // method called when a user connects + + string b = user->nick; + Srv->Debug("Foobar: User connecting: " + b); + } + + virtual void OnUserQuit(userrec* user) + { + // method called when a user disconnects + + string b = user->nick; + Srv->Debug("Foobar: User quitting: " + b); + } + + virtual void OnUserJoin(userrec* user, chanrec* channel) + { + // method called when a user joins a channel + + string c = channel->name; + string b = user->nick; + Srv->Debug("Foobar: User " + b + " joined " + c); + } + + virtual void OnUserPart(userrec* user, chanrec* channel) + { + // method called when a user parts a channel + + string c = channel->name; + string b = user->nick; + Srv->Debug("Foobar: User " + b + " parted " + c); + } + +}; + + +// +// The ModuleFoobarFactory class inherits from ModuleFactory +// and creates a ModuleFoobar object when requested. +// + +class ModuleFoobarFactory : public ModuleFactory +{ + public: + ModuleFoobarFactory() + { + } + + ~ModuleFoobarFactory() + { + } + + virtual Module * CreateModule() + { + return new ModuleFoobar; + } + +}; + + +// +// The "C" linkage factory0() function creates the ModuleFoobarFactory +// class for this library +// + +extern "C" void * init_module( void ) +{ + return new ModuleFoobarFactory; +} + diff --git a/src/modules/m_randquote.cpp b/src/modules/m_randquote.cpp new file mode 100644 index 000000000..aebf7c0ad --- /dev/null +++ b/src/modules/m_randquote.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +#include "users.h" +#include "channels.h" +#include "modules.h" + + +/* $ModDesc: Provides random Quotes on Connect. */ + +class ModuleRandQuote : public Module +{ + private: + + Server *Srv; + ConfigReader *conf; + FileReader *quotes; + + string q_file; + string prefix; + string suffix; + + public: + ModuleRandQuote() + { + Srv = new Server; + conf = new ConfigReader; + + q_file = conf->ReadValue("randquote","file",0); + prefix = conf->ReadValue("randquote","prefix",0); + suffix = conf->ReadValue("randquote","suffix",0); + + quotes = new FileReader(q_file); + } + + virtual ~ModuleRandQuote() + { + delete Srv; + delete conf; + delete quotes; + } + + virtual Version GetVersion() + { + return Version(1,0,0,0); + } + + virtual void OnUserConnect(userrec* user) + { + string str; + int fsize; + char buf[MAXBUF]; + + fsize = quotes->FileSize(); + srand(time(NULL)); + str = quotes->GetLine(rand() % fsize); + + sprintf(buf,"NOTICE %s :%s%s%s",user->nick,prefix.c_str(),str.c_str(),suffix.c_str()); + Srv->SendServ(user->fd, buf); + return; + } +}; + + +class ModuleRandQuoteFactory : public ModuleFactory +{ + public: + ModuleRandQuoteFactory() + { + } + + ~ModuleRandQuoteFactory() + { + } + + virtual Module * CreateModule() + { + return new ModuleRandQuote; + } + +}; + + +extern "C" void * init_module( void ) +{ + return new ModuleRandQuoteFactory; +} + diff --git a/src/users.cpp b/src/users.cpp new file mode 100644 index 000000000..a6ced8231 --- /dev/null +++ b/src/users.cpp @@ -0,0 +1,92 @@ +/* + +$Log$ +Revision 1.1 2003/01/23 19:45:58 brain +Initial revision + +Revision 1.3 2003/01/17 13:21:38 brain +Added CONNECT ALLOW and CONNECT DENY config tags +Added PASS command + +Revision 1.2 2003/01/17 10:37:55 brain +Added /INVITE command and relevent structures + +Revision 1.1 2003/01/16 01:10:04 brain +forgot to add this + + +*/ + +#include "inspircd_config.h" +#include "channels.h" +#include "users.h" +#include "inspircd.h" +#include + +userrec::userrec() +{ + // the PROPER way to do it, AVOID bzero at *ALL* costs + strcpy(nick,""); + ip = 0; + strcpy(ident,""); + strcpy(host,""); + strcpy(dhost,""); + strcpy(fullname,""); + strcpy(modes,""); + strcpy(inbuf,""); + strcpy(server,""); + strcpy(awaymsg,""); + fd = lastping = signon = idle_lastmsg = nping = registered = 0; + port = bytes_in = bytes_out = cmds_in = cmds_out = 0; + haspassed = false; + strcpy(result,""); + for (int i = 0; i < MAXCHANS; i++) + { + chans[i].channel = NULL; + } + invites.clear(); +} + + +char* userrec::GetFullHost() +{ + sprintf(result,"%s!%s@%s",nick,ident,dhost); + return result; +} + + +char* userrec::GetFullRealHost() +{ + sprintf(result,"%s!%s@%s",nick,ident,host); + return result; +} + +bool userrec::IsInvited(char* channel) +{ + for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) + { + if (!strcasecmp(i->channel,channel)) + { + return true; + } + } +} + +void userrec::InviteTo(char* channel) +{ + Invited i; + strcpy(i.channel,channel); + invites.push_back(i); +} + +void userrec::RemoveInvite(char* channel) +{ + for (InvitedList::iterator i = invites.begin(); i != invites.end(); i++) + { + if (!strcasecmp(i->channel,channel)) + { + invites.erase(i); + return; + } + } +} diff --git a/src/version.sh b/src/version.sh new file mode 100755 index 000000000..14b08aa61 --- /dev/null +++ b/src/version.sh @@ -0,0 +1,2 @@ +#!sh +echo "InspIRCd-1.0[Alpha9]" diff --git a/src/wildcard.cpp b/src/wildcard.cpp new file mode 100644 index 000000000..900f314ea --- /dev/null +++ b/src/wildcard.cpp @@ -0,0 +1,90 @@ +#include +#include "inspircd_config.h" +#include "inspircd.h" + +void Delete(char* str,int pos) +{ + char moo[MAXBUF]; + strcpy(moo,str); + moo[pos] = '\0'; + strcpy(str,moo); + strcat(str,moo+pos+1); +} + +void Insert(char* substr,char* str,int pos) +{ + string a = str; + a.insert(pos,substr); + strcpy(str,a.c_str()); +} + + +int MWC = 0; + +bool match2(char* literal,char* mask) +{ + +char OldM[MAXBUF]; +int I,I2; + +if (MWC) + return true; + +if ((strstr(mask,"*")==0) && (strlen(literal) != strlen(mask))) + return 0; + I=0; + I2=0; + while (I < strlen(mask)) + { + if (I2 >= strlen(literal)) + return 0; + + if ((mask[I]=='*') && (MWC==0)) + { + strcpy(OldM,mask); + + Delete(mask,I); + + while (strlen(mask)<255) + { + match2(literal,mask); + if (MWC==2) + return 1; + + Insert("?",mask,I); + } + strcpy(mask,OldM); + Delete(mask,I); + Insert("?",mask,I); + } + if (mask[I]=='?') + { + I++; + I2++; + continue; + } + if (mask[I] != literal[I2]) + return 0; + if (MWC) + return 1; + I++; + I2++; + } + if (strlen(literal)==strlen(mask)) + MWC=2; + +} + +bool match(char* literal, char* mask) +{ + char L[10240]; + char M[10240]; + MWC = 0; + strncpy(L,literal,10240); + strncpy(M,mask,10240); + strlower(L); + strlower(M); + match2(L,M); + return (MWC == 2); +} + -- 2.39.5