diff -BNru iroffer1.2b13/ChangeLog iroffer1.2b13+cpitchfor9/ChangeLog
--- iroffer1.2b13/ChangeLog	Thu Jan  1 01:00:00 1970
+++ iroffer1.2b13+cpitchfor9/ChangeLog	Wed Mar  6 01:48:54 2002
@@ -0,0 +1,126 @@
+cpitchfor9:	Wed Mar  6 01:47:46 GMT 2002	cpitchford
+	*	Updated admin.c u_psend so it will set the nolisttime to
+		zero before calling u_xdl otherwise it is not possible to
+		force a list to be sent to all the channels
+	*	Updated admin.c to include say admin command to talk to
+		a user or a channel
+
+cpitchfor8:	Wed Feb 27 03:00:30 GMT 2002	cpitchford
+	*	Moved the "timed advert" code from iroffer.c into
+		sendAdvert() in admin.c since it is required elsewhere now
+	*	Added fullignore() function to admin.c which will ignore
+		user/hostname if the fullignoretime is set
+	*	Added fullignore support to misc.c and admin.c
+		takes mins as an argument. Enfoced by fullignore
+	*	added calls to fullignore to queue full notices in iroffer.c
+	*	added adsend function to send adverts to channel or all
+		channels using sendAdvert
+	*	Added Adverts to admin.c to enable control over auto-advert
+		sends
+	*	Added noaverts configfile directive to misc.c
+	*	Fixed bug in getEngineerval() in utilities.c whereby
+		last char is ignored in quantifier array.
+
+cpitchfor7:	Tue Feb 12 22:56:54 GMT 2002	cpitchford
+	*	Fixed bug with advert rehash causing it to only use last
+		advert line in config file.
+
+
+cpitchfor6:	Tue Feb 12 02:01:35 GMT 2002	cpitchford
+	*	%l has been added to the list of tags for the advert
+		directive. It will be replaced with the minimum speed
+
+	*	Added "on" option to NOLIST admin command.. "on" will enable
+		NOLIST indefinitely until NOLIST is called again
+		with either zero or a number of minutes
+
+	*	Added "nolist" config file directives, which will disable
+		listing indefinitely or until nolist admin command is
+		issued to cancel nolist. It also takes an optional 
+		parameter of "-q" to drop list requests silently
+		or of m where it will auto-ban any user for m minutes
+		should they make a list request to the bot, in the same
+		way as the NOLIST admin command
+
+	*	Fixed a BUG in admin.c: void getconfig_set. If line
+		in the configuration file has no parameters (e.g. 
+		"nolist" the "var" and "var2" variables faced a buffer
+		overrun situation, as they are assigned after the
+		terminating NULL character and hence a configfile
+		with a single word on it could potentially lead to
+		a buffer overrun and a SEGV death. This is a bug in
+		iroffer, this patch fixes it.
+
+	*	Added configuration directives "speedwarnings" and 
+		"nospeedwarnings". These two directives turn off the
+		warnings notices sent to users when they reach bandwidth
+		limits
+
+	*	Added SPDWRN admin command with parameter + or - This
+		command turns off the notifications that are sent to a user
+		when they reach bandwidth limits
+
+
+cpitchfor5:		cpitchfor
+	*	%i was added to the humiliate list of replace tags. This
+		will be replaced in the string with the number of
+		minutes the user has been ignored for.
+
+
+cpitchfor4:		cpitchfor
+	*	Humiliate config file directive and admin command was
+		added. Like advert it takes a printf style string
+		in which %u is replaced with the username of a user
+		who has just been auto-banned.
+
+	*	"public" and "nopublic" config file directives were
+		added to allow the ability to control how the bot
+		responds to public triggers
+
+	*	the ignore admin command now accepts network ranges
+		in the form of strings starting with "*"
+		A hostname is checked to see if it ends with a network
+		range (excluding the prefixing *) to determine
+		a match
+	*	!strcmp was replaced with isbanned to determine
+		if a hostname matched an ignore entry to ensure
+		network ranges are catered for
+
+
+cpitchfor3:		cpitchfor
+	*	When a user was banned public triggers failed. This was
+		fixed
+
+	*	advert lines were silently unlinked and therefore caused
+		memory leaks. (Thanks to FarFetch'd for fix)
+
+	*	Files were not closed after finished reading. This is
+		an actual bug in iroffer. This patch fixes it.
+		(Thanks to FarFetch'd for fix)
+
+
+cpitchfor2:		cpitchfor
+	*	PUBLIC admin command added to toggle whether the bot will
+		respond to public messages, and public triggers (/CTCP)
+		using the admin command PUBLIC <+|->
+
+
+cpitchfor1:		cpitchfor
+	*	Altered NOLIST function to admin commands.
+		NOLIST now accepts two parameters. first still specifies
+		how long list is disabled, second new parameter specifies
+		that the list requests should be silently dropped "-q"
+		or the number of minutes to ignore a user after making
+		a list request. Quiet and banning NOLIST commands will
+		also drop the list command without queuing it for
+		processing.
+
+	* 	Added config file directive for custom adverts
+		Advert when used (multiple times also) will define
+		a printf like template for the advert sent out to 
+		channels with the -advert option enabled.
+		The advert is created from the advert lines in the config
+		file in the order they appear.
+		% was chosen as the escape character. The flag letter
+		was taken from the /ctcp status option as mentioned
+		on the iroffer documentation
diff -BNru iroffer1.2b13/README.cpitchfor-patch iroffer1.2b13+cpitchfor9/README.cpitchfor-patch
--- iroffer1.2b13/README.cpitchfor-patch	Thu Jan  1 01:00:00 1970
+++ iroffer1.2b13+cpitchfor9/README.cpitchfor-patch	Wed Mar  6 01:48:54 2002
@@ -0,0 +1,241 @@
+cpitchfor6   2002/02/12				<iroffer@itmakesmemad.com>
+http://iroffer.itmakesmemad.com/
+
+This patch adds a bunch of new features to iroffer. All have been requested
+by faithful people on a channel I frequent. See here for a summary:
+
+XDCC LIST handler:
+------------------
+This is an update to the admin command "NOLIST" and the config file
+directive nolist.
+
+The admin command "NOLIST" can be sent to the bot to control how it will
+react to a xdcc list request:
+
+NOLIST [ <on|m> [-q|n] ]
+
+	NOLIST with no paramters will turn listing back on.
+
+	The first parameter can be "on" or a number.
+		"on":	Turn listing off until it is enabled again
+			with the NOLIST command
+
+		n:	Turn listing off for n minutes
+
+		0:	Turn listing back on
+
+	The second optional parameter can be -q or a number
+		-q:	When a xdcc list request is received quietly
+			drop the request. Do not inform the requesting
+			user that lists have been disabled
+
+		m:	Ban any user that xdcc list requests this bot
+			for m minutes
+
+			if no second paramter is provided, the bot
+			will msg the requesting user to tell them
+			the bot is not accepting list requests.
+			
+
+NOLIST 10		# Will turn off list response for 10 minutes
+
+NOLIST 10 -q		# will turn off list responce for 10 minutes and
+			  drop list requests silently. The user will not
+			  get any response from the server at all. -q quiet
+
+NOLIST 10 100		# Will turn off list response for 10 minutes and
+			  auto ban any user who sends a list request for
+			  100 minutes
+
+NOLIST on 1000		# Will turn off listing and ban any requesting
+			  user for 1000 minutes
+
+The nolist directive has also been added to the configuration file
+
+nolist			# turns off listing
+
+nolist -q		# turns off listing and quietly drop list requests
+			  does NOT inform the user that lists have been
+			  disabled
+
+nolist 1000		# turns off listing and bans any user making a list
+			# request for 1000 minutes.
+
+
+
+Humiliate the user autobanned
+----------------------------
+You can set either as an admin command or in the config file a message to be
+sent to the channels the bot sits on in the event it should auto-ban a user
+
+humiliate I've just banned %u for %t for being naughty
+
+should cpitchfor send a xdcc list when nolist+ban is on the channel would
+see:
+
+<yourbot> I've just banned cpitchfor for 10 minutes for being naughty
+
+
+
+Custom Ads:
+-----------
+This is an additional flag to the channel directive in the configuration
+file:
+
+channel #mychannel -plist 30 -pformat summary -advert
+
+This instructs the bot that when sending an advert to the channel it should
+send a "custom" advert defined in the directive advert:
+
+
+advert This is the first line of the advert
+advert This is the second line of the advert
+advert 3rd line: SLOTS:[%a/%b]  QUEUE:[%c/%d]
+advert 4th line: Record Speed: %g  Total Offered: %x
+
+
+a % is a special character, much like in printf. It will be replaced with
+values as the advert is sent for example the above example would send
+
+<mybot> This is the first line of the advert
+<mybot> This is the second line of the advert
+<mybot> 3rd line: SLOTS:[4/10]  QUEUE:[0/0]
+<mybot> 4th line: Record Speed: 1245.3K/s  Total Offered: 3223.3 MB
+
+If a channel has a "-advert" flag but there are no "advert" lines defined in
+the config file, the bot will not advertise in that channel
+
+The conversions are as follows:
+
+%a	number of slots in use 
+%b	total slots 
+%c	number in main queue 
+%d	size of main queue 
+%e	number in pack queue 
+%f	size of pack queue 
+%g	pack speed record (K/sec) 
+%h	number of lines in send to server queue 
+%i	amount of data sent to network in past 120 seconds (K) 
+%j	average bandwidth of past 120 seconds (K/sec) 
+%k	record average bandwidth (K/sec) 
+%l	minimum bandwith required
+%w	number of packs offered 
+%x	total size of offered packs (MB) 
+%y	total completed transfers
+%z	total transfered (MB)
+%%	a single "%"
+
+Advert Control:
+---------------
+
+You can now disable adverts either permanently or for a number of minutes.
+Use the admin command "ADVERTS" to control the auto-adverts:
+
+ADVERTS 0
+	Enable auto advert posting to channels
+
+ADVERTS off
+	Disable adverts permanently
+
+ADVERTS 20
+	Disable adverts for at least the next 20 minutes
+
+You can also disable adverts (to be reenabled as above) from the config
+file. Use "noadverts" to disable them.
+
+Advertise NOW!
+--------------
+
+A new admin command has been added to force an advert to be sent to a
+single or all of the channels the bot is on
+
+
+ADSEND #mychannel
+	will force an advert to be sent to #mychannel
+
+ADSEND
+	will force an advert to be sent to ALl the channels the bot is on
+
+
+Public Triggers:
+----------------
+iroffer will respond to public triggers such as "xdcc list" or /ctcp
+#channel ping. The admin command "public" can control this functionality
+
+public -
+	will turn off the ability to respond to any public trigger
+
+public +
+	will turn it back on again
+
+you can set the default in you config file with either
+
+public	
+	# react to public triggers
+
+nopublic
+	# dont react to public triggers
+
+
+
+Baning Network ranges:
+----------------------
+ignore 10 cptf-adsl.demon.co.uk
+	will ignore all connections from cptf-adsl.demon.co.uk
+
+ignore 10 *.demon.co.uk
+	will ignore all connections from ANY host ending in .demon.co.uk
+
+
+
+Bandwidth Warning Notices
+-------------------------
+
+When a user is downloading a pack with bandwidth limits (or from a bot with 
+bandwidth limits) iroffer will send the user a warning regarding bandwidth
+limits and how much bandwidth they are using. This can now be controlled
+with these functions:
+
+SPDWRN Admin command
+
+	SPDWRN +	Enable bandwidth warning notices
+	SPDWRN -	Disable bandwidth warning notices
+
+Configuration file directives:
+
+speedwarnings		Enable bandwidth warning notices
+nospeedwarnings		Disable bandwidth warning notices
+
+Queue Auto-ignoring:
+--------------------
+
+When the queue is full and a user makes a send request, the bot will inform
+them that the queue is full and that they should try again later. Now you
+can auto-ignore these people (ideally for a SHORT time, lets not be mean
+here!). The admin command "fullignore" controls this:
+
+FULLIGNORE 1
+	Will automatically ignore any user for one minute should they
+	make a request when the queue is full. It will NOT send them any
+	queue-full notification.
+
+FULLIGNORE
+	Reenabled notifications. No users will be ignored, they will instead
+	receive a queue-full warning
+
+You can control this in the configuration file with "fullignore"
+
+fullignore 10
+	#	auto-ignore for 10 minutes on queue full request
+
+Speak To People And Channels:
+-----------------------------
+
+Now you can say things to people and to the channel with the admin command
+say. For example:
+
+say #yourchan Hello everybody
+	send a message to #yourchan
+
+say bob Hello bob
+	send a private message to bob
diff -BNru iroffer1.2b13/sample.config iroffer1.2b13+cpitchfor9/sample.config
--- iroffer1.2b13/sample.config	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/sample.config	Wed Mar  6 01:48:54 2002
@@ -109,13 +109,15 @@
 ###                         - channels (upto 50) -                         ###
 ### channel format:                                                        ###
 ### "channel <channel> [-plist <time>]                                     ###
-###    [-pformat <full|minimal|summary>] [-key <key>] "                    ###
+###    [-pformat <full|minimal|summary>] [-key <key>] [-advert] "          ###
 ### plist: time is number of minutes between plists.                       ###
 ### pformat: full is normal and default if pformat is not used             ###
 ###          minimal is similar to full but removes some lines             ###
 ###          summary displays only a 2 line summary                        ###
 ### key:     for +k channels, the key specified is used when joining       ###
 ### using same or multiples of the same number plist time is recomended    ###
+### advert: This channel will received a customised advert in the format
+###          defined by the advert directive
 channel #chan01
 channel #chan02 -plist 14
 channel #chan03 -plist 28 -pformat minimal
@@ -123,6 +125,82 @@
 
 
 ##############################################################################
+###                               - advert -                               ###
+### advert format:                                                         ###
+### "advert line 1 format"                                                 ###
+### "advert line 2 format"                                                 ###
+### "advert line n format"                                                 ###
+### The advert lines will be combined to form you channel advert           ###
+### Certain characters will be replaced by values:                         ###
+###    %a      number of slots in use                                      ###
+###    %b      total slots                                                 ###
+###    %c      number in main queue                                        ###
+###    %d      size of main queue                                          ###
+###    %e      number in pack queue                                        ###
+###    %f      size of pack queue                                          ###
+###    %g      pack speed record (K/sec)                                   ###
+###    %h      number of lines in send to server queue                     ###
+###    %i      amount of data sent to network in past 120 seconds (K)      ###
+###    %j      average bandwidth of past 120 seconds (K/sec)               ###
+###    %k      record average bandwidth (K/sec)                            ###
+###    %l      required minimum download bandwidth                         ###
+###    %w      number of packs offered                                     ###
+###    %x      total size of offered packs (MB)                            ###
+###    %y      total completed transfers                                   ###
+###    %z      total transfered (MB)                                       ###
+###    %%      a single "%"                                                ###
+
+
+advert my special bot Slots [%a/%b]
+advert queue [%c/%b] %x offered in %w packs
+
+##############################################################################
+###                              - noadverts -                             ###
+###                                                                        ###
+### This will disable the automatic adverts sent to the channels specified ###
+### in the channel directive above.                                        ###
+
+#noadverts
+
+
+##############################################################################
+###                              - nolist -                                ###
+### nolist format:                                                         ###
+### [-q|n]                                                                 ###
+### This function will control how the bot responds to list commands       ###
+### No parameters means the bot will not serve lists, instead it will      ###
+### inform the user lists are disabled                                     ###
+### -q will quietly drop any list request without processing them. The     ###
+### user will not see a response                                           ###
+### n, being a number, will ban any user making a list request to the bot  ###
+### for n minutes                                                          ###
+
+nolist -q
+
+
+
+##############################################################################
+###                             - humiliate -                              ###
+### humiliate format:                                                      ###
+### [message]                                                              ###
+### When a user is autobanned, this message will be sent to the channels   ###
+### as with the advert directive, %u will be replaced with the nick of     ###
+### the person being banned and %i will be replaced with the time before   ###
+### the ban is lifted                                                      ###
+
+humiliate %u has been banned for %i
+
+##############################################################################
+###                              - public -                                ###
+### public|nopublic:                                                       ###
+### sets the default reaction to public triggers. public means the bot     ###
+### responed to public triggers and nopublic means the bot will not        ###
+
+nopublic
+
+
+
+##############################################################################
 ###                          - user information -                          ###
 user_nick nickDCC
 user_realname NAME
@@ -185,6 +263,17 @@
 slotsmaxqueue 10
 
 ##############################################################################
+###                       - full queue autoignore -                        ###
+### This directive will allow you to specify the number of minutes to      ###
+### ignore a person should they make a request when the queue is full      ###
+### Not intended to be mean, this function will help again release         ###
+### hammering                                                              ###
+
+# Ignore user for 2 minutes if queue is full and they make requests
+fullignore 3
+
+
+##############################################################################
 ###                      - max transfers per person -                      ###
 ### maximum transfers per person at a time                                 ###
 maxtransfersperperson 1
@@ -213,8 +302,8 @@
 ### if yes, xdcc list and/or xdcc send will be restricted to users who are ###
 ### on a known channel. If a user is not on one of the known channels they ###
 ### will not be able to list and/or get packs                              ###
-restrictlist no
-restrictsend no
+restrictlist yes
+restrictsend yes
 
 
 ##############################################################################
diff -BNru iroffer1.2b13/src/admin.c iroffer1.2b13+cpitchfor9/src/admin.c
--- iroffer1.2b13/src/admin.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/admin.c	Wed Mar  6 01:48:54 2002
@@ -73,6 +73,14 @@
 static void u_crash(const userinput * const u);
 static void u_chanl(const userinput * const u);
 
+static void u_public(const userinput * const u);
+static void u_humiliate(const userinput * const u);
+static void u_spdwrn(const userinput * const u);
+static void u_adsend(const userinput * const u);
+static void u_fullignore(const userinput * const u);
+static void u_adverts(const userinput * const u);
+static void u_say(const userinput * const u);
+
 
 /* local info */
 static const userinput_parse_t userinput_parse[] = {
@@ -93,9 +101,10 @@
 {2,method_allow_all,u_nomin,    "NOMIN","n","Disables Minspeed For Transfer ID n"},
 {2,method_allow_all,u_nomax,    "NOMAX","n","Disables Maxspeed For Transfer ID n"},
 {2,method_allow_all,u_send,     "SEND","nick n","Sends Pack n to nick"},
+{2,method_allow_all,u_adsend,    "ADSEND", "[channel] send an advert to all the to a specific channel all channels"},
 {2,method_allow_all,u_psend,    "PSEND","<channel>","Sends XDCC LIST to <channel>"},
 {2,method_allow_all,u_qsend,    "QSEND",NULL,"Sends Out The First Queued Pack"},
-
+{2,method_allow_all,u_spdwrn,      "SPDWRN","<+|->","Turn on (+) or off (-) the notices sent to users when bandwidth limits are reached"},
 {3,method_allow_all,u_info,     "INFO","n","Show Info for Pack n"},
 {3,method_allow_all,u_remove,   "REMOVE","n","Removes Pack n"},
 {3,method_allow_all,u_renumber, "RENUMBER","x y","Moves Pack x to y"},
@@ -109,15 +118,18 @@
 
 {4,method_allow_all,u_mesg,     "MESG","<message>","Sends msg to all users who are transferring"},
 {4,method_allow_all,u_mesq,     "MESQ","<message>","Sends msg to all users in a queue"},
-{4,method_allow_all,u_ignore,   "IGNORE","n <host>","Ignore <host> (hostname) for n minutes"},
+{4,method_allow_all,u_ignore,   "IGNORE","n [<host>| *<hostmask>]","Ignore <host> (hostname) or any hostname ending in hostmask for n minutes"},
 {4,method_allow_all,u_nosave,   "NOSAVE","n","Disables XDCC AutoSave for next n minutes"},
 {4,method_allow_all,u_nosend,   "NOSEND","n","Disables XDCC Send for next n minutes"},
-{4,method_allow_all,u_nolist,   "NOLIST","n","Disables XDCC List and Plist for next n mins"},
+{4,method_allow_all,u_adverts,  "ADVERTS","<off|n>","Disables adverts for an optional time"},
+{4,method_allow_all,u_nolist,   "NOLIST","n [-q|m]","Disables XDCC List and Plist for next n mins and optionally makes output quiet (-q) or bans any user requesting a list for m minutes"},
+{4,method_allow_all,u_fullignore,   "FULLIGNORE","n","Will automatically ignore any user who makes a send request when the queues are full. Their request is silently dropped"},
 {4,method_allow_all,u_msgread,  "MSGREAD",NULL,"Show MSG log"},
 {4,method_allow_all,u_msgdel,   "MSGDEL",NULL,"Delete MSG log"},
 {4,method_allow_all,u_rmul,     "RMUL","<file>","Delete a file in the Upload Dir"},
 {4,method_allow_all,u_raw,      "RAW","<command>","Send <command> to server (RAW IRC)"},
-
+{4,method_allow_all,u_say,      "SAY","<#channel|nick> <text...>","Say text in a channel or to a person"},
+{4,method_allow_all,u_humiliate,      "HUMILIATE","[message]","Will announce this message (%u is replaced with nick and %t is replaced with the ban time) to all channels when user is autobanned by listing server"},
 {5,method_allow_all,u_servers,  "SERVERS",NULL,"Shows the server list"},
 {5,method_allow_all,u_jump,     "JUMP","<num>","Switches to a random server or server <num>"},
 {5,method_allow_all,u_status,   "STATUS",NULL,"Show Useful Information"},
@@ -130,6 +142,7 @@
 {5,method_msg,      u_chatme,   "CHATME",NULL,"Sends you a DCC Chat Request"},
 {5,method_stdin,    u_debug,    "DEBUG","n","Set Debugging to n [0,1,2]"},
 {5,method_allow_all,u_shutdown, "SHUTDOWN","<act>","Shutdown iroffer, <act> is \"now\", \"delayed\", or \"cancel\""},
+{5,method_allow_all,u_public,      "PUBLIC","<+|->","Turn on (+) or off (-) the ability to resond to public triggers"},
 
 {6,method_stdin,    u_crash, "CRASH",NULL,"Cause a segmentation fault"},
 };
@@ -291,6 +304,7 @@
       privmsg(u->snick,"%s",a);
       break;
    case method_xdl_channel_sum:
+   case method_xdl_channel_cust:
       privmsg(u->snick,"%s",a);
       break;
    case method_allow_all:
@@ -320,14 +334,19 @@
    
    if (!found)
       u_respond(u,"*** User Command Not Recognized, try \"HELP\"");
-   
-   if (found && u->method==method_stdin)
+   else
+     switch (u->method)
+       {
+       case method_stdin:
       ioutput(0,OUT_S|OUT_L|OUT_D,"0;35","ADMIN %s Requested (stdin)",u->cmd);
-   if (found && u->method==method_dcc)
+	 break;
+       case method_dcc:
       ioutput(0,OUT_S|OUT_L|OUT_D,"0;35","ADMIN %s Requested (DCC Chat)",u->cmd);
-   if (found && u->method==method_msg)
+	 break;
+       case method_msg:
       ioutput(0,OUT_S|OUT_L|OUT_D,"0;35","ADMIN %s Requested (MSG: %s)",u->cmd,u->snick);
-   
+	 break;
+       }
    u_fillwith_clean(u);
    
    }
@@ -350,10 +369,10 @@
       u_respond(u,"Usage: \"HELP <section>\"");
       u_respond(u,"Help Sections Available:");
       u_respond(u,"  Info     - help, xdl, xds, dcl, dcld, trinfo, qul, ignl, listul, chanl");
-      u_respond(u,"  Transfer - close, rmq, rpq, nomin, nomax, send, psend, qsend");
+      u_respond(u,"  Transfer - close, rmq, rpq, nomin, nomax, send, adsend, psend, qsend, spdwrn");
       u_respond(u,"  Pack     - info, remove, renumber, add, adddir, chfile, chdesc, chnote, chmins, chmaxs");
-      u_respond(u,"  Misc     - mesg, mesq, ignore, nosave, nosend, nolist, msgread, msgdel, rmul, raw");
-      u_respond(u,"  Bot      - servers, jump, status, rehash, botinfo, memstat, clearrecords, redraw, quit, chatme, debug, shutdown");
+      u_respond(u,"  Misc     - mesg, mesq, ignore, nosave, nosend, adverts, nolist, fullignore msgread, msgdel, rmul, raw, say, public, humiliate");
+      u_respond(u,"  Bot      - servers, jump, status, rehash, botinfo, memstat, clearrecords, redraw, quit, chatme, debug, shutdown, public");
       u_respond(u,"For additional help, see the complete documentation at http://iroffer.org/");
       return;
       }
@@ -394,9 +413,9 @@
    }
 
 static void u_xdl(const userinput * const u) {
-   char *tempstr,*tempstr2,*tempstr3;
+   char *tempstr,*tempstr2,*tempstr3, *cptr, *nptr;
    const char *spaces[] = { ""," ","  ","   ","    ","     ","      " };
-   int a,i,p,m,m1,s;
+   int a,i,p,m,m1,s,spaceleft,x;
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
    
@@ -416,6 +435,136 @@
    tempstr2 = mycalloc(maxtextlength,"u_xdl");
    tempstr3 = mycalloc(maxtextlengthshort,"u_xdl");
 
+   if (u->method==method_xdl_channel_cust)
+     {
+       /* We are in a loop to display the formated stuff from the advert definition string */
+       for (a=0;a<MAXADVERTS && gdata.advert[a]!=NULL;a++)
+	 {
+	   memset(tempstr,0,maxtextlength);
+	   i=0;
+	   cptr=gdata.advert[a];
+	   nptr=tempstr;
+	   /* All strings will be null terminated.
+	      We must ensure we do no outstretch ourselves and write more than maxtextlength
+	      to the tempstring
+	   */
+	   spaceleft=maxtextlength-2;
+	   while (spaceleft>0)
+	     switch (*cptr)
+	       {
+	       case 0:
+		 spaceleft=0;
+		 break;
+	       case '%':
+		 cptr++;tempstr2[0]=0;
+		 switch(capchar(*(cptr++)))
+		   {
+		   case 'A': /* Number of slots in use */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.slotsfull);
+		     break;
+		   case 'B': /* Totle slots */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.slotsmax);
+		     break;
+		   case 'C': /* Number in queue */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.inqueue);		     
+		     break;
+		   case 'D': /* Size of queue */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.queuesize);
+		     break;
+		   case 'E': /* number in packs queue */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.inslotsmaxqueue);
+		     break;
+		   case 'F': /* size of pack queue */
+		     isnprintf(tempstr2, maxtextlength-1, "%i", gdata.slotsmaxqueue);
+		     break;
+		   case 'G': /* pack speed record */
+		     isnprintf(tempstr2,maxtextlength-1, "%1.1fK/s", gdata.record);
+		     break;
+		   case 'H': /* number of lines in send to server queue*/
+		     {
+		       int srvq;
+		       for (srvq=0; gdata.serverq[srvq] && srvq<MAXSENDQ; srvq++);
+		       isnprintf(tempstr2, maxtextlength-1, "%i", srvq);
+		     }
+		     break;
+		   case 'I': /* ammount of data send to network in last 120 seconds*/
+		     {
+		       int count=0;
+		       for (i=0; i<120; i++)
+			 count += gdata.xdccsent[i];
+		       isnprintf(tempstr2, maxtextlength-1, "%i", count/1024);
+		     }
+		     break;
+		   case 'J': /* Average bandwidth in last 120 seconds */
+		     {
+		       int count=0;
+		       for (i=0; i<120; i++)
+			 count += gdata.xdccsent[i];
+		       isnprintf(tempstr2, maxtextlength-1, "%1.1fK/s", ((float)count)/120.0/1024.0);
+		     }
+		     break;
+		   case 'K': /* record average bandwidth */
+		     isnprintf(tempstr2,maxtextlength-1, "%1.1fK/s", gdata.sentrecord);
+		     break;
+		   case 'L': /* minimum required bandwidth */
+		     isnprintf(tempstr2,maxtextlength,"%1.1fK/s",gdata.overallminspeed);
+		     break;
+		   case 'W': /* packs offered */
+		     isnprintf(tempstr2,maxtextlength,"%i",gdata.numpacks);
+		     break;
+		   case 'X': /* total size of packs offered */
+		     {
+		       float ocount = 0;
+		       for (i=0; i<MAXXDCCS; i++)
+			 if (gdata.xdccs[i])
+			   ocount += (float)gdata.xdccs[i]->size;
+		       isnprintf(tempstr2,maxtextlength-1,"%1.1f MB",ocount/1024.0/1024.0);
+		     }
+		     break;
+		   case 'Y': /* total completed transfers */
+		     {
+		       int gcount=0;
+		       for (i=0; i<MAXXDCCS; i++)
+			 if (gdata.xdccs[i])
+			   gcount += gdata.xdccs[i]->gets;
+		       isnprintf(tempstr2, maxtextlength-1,"%i",gcount);
+		     }
+		     break;
+		   case 'Z': /* total transfered MB*/
+		     {
+		       char postfix;
+		       float totsent=getEngineerval(gdata.totalsent/1024.0/1024.0,
+						    "MGT\0",
+						    &postfix);
+		       
+		       isnprintf(tempstr2,maxtextlength-1,"%1.2f %cB",totsent,postfix);
+		     }
+		     break;
+		   default:
+		     cptr--;
+		   case '%':
+		     tempstr2[0]='%';
+		     tempstr2[1]=0;
+		     break;
+		   }
+		 isnprintf(nptr,spaceleft,"%s",tempstr2);
+		 spaceleft-=x=strlen(tempstr2);
+		 nptr+=x;
+		 break;		 
+	       default:
+		 spaceleft--;
+		 *(nptr++)=*(cptr++);
+	       }
+	   /*	   if (tempstr[0]!=0)*/
+	     u_respond(u,tempstr);
+	 }
+      mydelete(tempstr);
+      mydelete(tempstr2);
+      mydelete(tempstr3);
+      return;
+     }
+   
+
    if (u->method==method_xdl_channel_min) m = 1; else m = 0;
    if (u->method==method_xdl_channel_sum) m1 = 1; else m1 = 0;
    
@@ -1060,6 +1209,7 @@
 
 static void u_psend(const userinput * const u) {
    char *tempstr;
+   long nolisting;
    userinput manplist;
   
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
@@ -1071,8 +1221,10 @@
    
    u_fillwith_msg(&manplist,u->arg1,"A A A A A xdl");
    manplist.method = method_xdl_channel;
+   nolisting=gdata.nolisting;
+   gdata.nolisting=0;
    u_parseit(&manplist);
-   
+   gdata.nolisting=nolisting;
    tempstr = mycalloc(maxtextlength,"u_psend");
    isnprintf(tempstr,maxtextlength-2,"Sending PLIST to %s",u->arg1);
    mydelete(tempstr);
@@ -1545,7 +1697,7 @@
    /* other variables */
    char *templine = mycalloc(maxtextlength,"u_rehash_templine");
    char *tempc = mycalloc(2,"u_rehash_tempc");
-   int h,i,j,k,found,filedescriptor,needtojump;
+   int h,i,j,k,found,filedescriptor=-1,needtojump;
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
    
@@ -1558,10 +1710,15 @@
       mydelete(gdata.server[i]);
    for (i=0; i<MAXCHNLS; i++)
       gdata.t_channel[i] = gdata.r_channel[i] = NULL;
-   
+   for (i=0; i<MAXADVERTS && gdata.advert[i]; i++)
+     {
+       mydelete (gdata.advert[i]);
+       gdata.advert[i]=NULL;
+     }
+   gdata.nospeedwarnings=0;
+   gdata.fullignoretime=0;
    gdata.r_overallminspeed = gdata.overallminspeed;
    gdata.r_transfermaxspeed = gdata.transfermaxspeed;
-   
    mydelete(gdata.logfile);
    gdata.logrotate = gdata.logstats = 0;
    mydelete(gdata.ignorefile);
@@ -1594,7 +1751,6 @@
    gdata.uploadallowed = gdata.uploadmaxsize = 0;
    mydelete(gdata.uploaddir);
    gdata.restrictlist = gdata.restrictsend = 0;
-   
    mydelete(gdata.loginname);
    set_loginname();
    
@@ -1631,7 +1787,7 @@
             }
          }
       }
-   
+   close(filedescriptor);
    /* see what needs to be redone */
    
    u_respond(u,"Reconfiguring...");
@@ -1857,7 +2013,9 @@
       if (gdata.channels[i]->plisttime) {
          isnprintf(tempstr2,maxtextlength-2,"%s, plist every %2i min (%s)",tempstr,
                   gdata.channels[i]->plisttime,
-                  gdata.channels[i]->flags & CHAN_MINIMAL ? "minimal" : (gdata.channels[i]->flags & CHAN_SUMMARY ? "summary" : "full"));
+                  gdata.channels[i]->flags & CHAN_MINIMAL ? "minimal" : 
+		   (gdata.channels[i]->flags & CHAN_SUMMARY ? "summary" : 
+		    (gdata.channels[i]->flags & CHAN_CUSTOM ? "custom" : "full")));
          strncpy(tempstr,tempstr2,maxtextlength-1);
          }
       
@@ -1974,9 +2132,54 @@
    mydelete(tempstr);
    }
 
+int fullignore (const char* nick,const char* hostname)
+{
+  if (gdata.fullignoretime>0 && hostname)
+    {
+      ignoreuser(hostname,gdata.fullignoretime);
+      ioutput(0,OUT_S|OUT_L|OUT_D,"0;33","XDCC SEND QUEUEFULL AUTOIGNORE: %s (%s)",nick,hostname);
+      return 0;
+    }
+  return -1;
+}
+ 
+  
+void ignoreuser(const char* hostname, int bantime)
+{
+  /* Ban a host for bantime minutes */
+  int i, found;
+  if (!hostname)
+    return;
+  
+   for (found=i=0; (i<MAXIGNL && gdata.ignorelist[i] && !found); i++)
+      if (isbanned(i,hostname)) found++;
+   
+   if (i == MAXIGNL) {
+      outerror(1,"Out of ignore slots!, This shouldn't happen");
+      return;
+      }
+   if (!found) {
+
+      gdata.ignorelist[i] = mycalloc(sizeof(igninfo),"u_ignore_ignorelist[i]");
+      strncpy(gdata.ignorelist[i]->hostname,hostname,maxtextlength-1);
+      gdata.ignorelist[i]->flags &= ~IGN_FIRSTIGNORE;
+      gdata.ignorelist[i]->lastcontact = gdata.curtime;
+      }
+   else
+   	i--;
+      gdata.ignorelist[i]->flags |= IGN_IGNORING;   
+      gdata.ignorelist[i]->flags &= ~IGN_MANUAL & ~IGN_RANGE;
+   gdata.ignorelist[i]->bucket = (bantime*60)/IGN_TL;
+   ioutput(0,OUT_S|OUT_L|OUT_D,"0;33","IGNORE banned: %s (%i)",hostname,bantime);
+   write_ignorefile();
+}
+
+
+
 static void u_ignore(const userinput * const u) {
-   int i, num=0, found;
+   int i, num=0, found, mask;
    char *tempstr;
+   char* cptr;
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
    
@@ -1986,14 +2189,16 @@
       u_respond(u,"Try specifying an amount of time to ignore");        
       return;
       }
-
-   if (!u->arg2 || strlen(u->arg2) < 4) {
+   cptr=u->arg2;
+   if (!cptr || strlen(cptr) < 4) {
       u_respond(u,"Try specifying a hostname longer than 4 characters");
       return;
       }
    
+   mask=(cptr[0]=='*')?IGN_RANGE:0;
+   
    for (found=i=0; (i<MAXIGNL && gdata.ignorelist[i] && !found); i++)
-      if (!strcmp(gdata.ignorelist[i]->hostname,u->arg2)) found++;
+     if (!strcmp(gdata.ignorelist[i]->hostname,cptr)) found++;
    
    if (i == MAXIGNL) {
       outerror(1,"Out of ignore slots!, This shouldn't happen");
@@ -2005,7 +2210,7 @@
    
    if (!found) {
       gdata.ignorelist[i] = mycalloc(sizeof(igninfo),"u_ignore_ignorelist[i]");
-      strncpy(gdata.ignorelist[i]->hostname,u->arg2,maxtextlength-1);
+      strncpy(gdata.ignorelist[i]->hostname,cptr,maxtextlength-1);
       gdata.ignorelist[i]->flags |= IGN_IGNORING;
       gdata.ignorelist[i]->flags &= ~IGN_FIRSTIGNORE;
       gdata.ignorelist[i]->lastcontact = gdata.curtime;
@@ -2013,11 +2218,12 @@
    else
       i--;
    gdata.ignorelist[i]->flags |= IGN_MANUAL;
+   gdata.ignorelist[i]->flags |= mask;
    gdata.ignorelist[i]->bucket = (num*60)/IGN_TL;
    
    isnprintf(tempstr,maxtextlength-2,
             "Ignore activated for *!*@%s which will last %i min",
-            u->arg2,num);
+            cptr,num);
    u_respond(u,tempstr);
    write_ignorefile();
 
@@ -2056,22 +2262,351 @@
    
    mydelete(tempstr);
    
-   }
+}
 
+static void u_humiliate (const userinput * const u)
+{
+  if (gdata.humiliate)
+    {
+      mydelete (gdata.humiliate);
+      gdata.humiliate=NULL;
+   }
+  if ((u->arg1) || (strlen(u->arg1e)>1))
+    {
+      strncpy(gdata.humiliate=mycalloc(maxtextlength,"u_humiliate"),
+	      u->arg1e, maxtextlength-2);
+    }
+}
 
-static void u_nolist(const userinput * const u) {
+int sendAdvert(const char* ch, int force)
+{
+  /* This is a relocation of the code in iroffer.c since we need it to 
+     implement the adsend admin function it seemed sensible to 
+     put it all in a common function with some modifications to find
+     the channels requested.. eek
+     This function is hideously ugly.
+  */
+  
+  char *tchanf = NULL, *tchanm = NULL, *tchans = NULL, *tchanc = NULL;
+  int max,i=0;
+  static userinput *pubplist;
+  if (!force && gdata.noadverts>gdata.curtime)
+    return -1;
+
+  if (!ch)
+      max=MAXCHNLS;
+  else
+    {
+      /* we have to find the channel specified by ch.. */
+      for (i=0; gdata.channels[i] && i<MAXCHNLS; i++)
+	if (!strcasecmp(ch,gdata.channels[i]->name))
+	  break;
+      if (i<MAXCHNLS && gdata.channels[i])
+	max=1+i;
+      else
+	return -1;
+    }
+
+  for (; gdata.channels[i] && i<max; i++)
+    if (force || (gdata.channels[i]->plisttime && !((gdata.curtime/60)%(gdata.channels[i]->plisttime)))) {
+      if (gdata.channels[i]->flags & CHAN_CUSTOM) {
+	if (tchanc) {
+	  strncat(tchanc,",",maxtextlength-strlen(tchanc)-1);
+	  strncat(tchanc,gdata.channels[i]->name,maxtextlength-strlen(tchanc)-1);
+	}
+	else {
+	  tchanc = mycalloc(maxtextlength,"mainloop_pubplist1m");
+	  strncpy(tchanc,gdata.channels[i]->name,maxtextlength-1);
+	}
+      }
+      else if (gdata.channels[i]->flags & CHAN_MINIMAL) {
+	if (tchanm) {
+	  strncat(tchanm,",",maxtextlength-strlen(tchanm)-1);
+	  strncat(tchanm,gdata.channels[i]->name,maxtextlength-strlen(tchanm)-1);
+	}
+	else {
+	  tchanm = mycalloc(maxtextlength,"mainloop_pubplist1m");
+	  strncpy(tchanm,gdata.channels[i]->name,maxtextlength-1);
+	}
+      }
+      else if (gdata.channels[i]->flags & CHAN_SUMMARY) {
+	if (tchans) {
+	  strncat(tchans,",",maxtextlength-strlen(tchans)-1);
+	  strncat(tchans,gdata.channels[i]->name,maxtextlength-strlen(tchans)-1);
+	}
+	else {
+	  tchans = mycalloc(maxtextlength,"mainloop_pubplist1s");
+	  strncpy(tchans,gdata.channels[i]->name,maxtextlength-1);
+	}
+      }
+      else {
+	if (tchanf) {
+	  strncat(tchanf,",",maxtextlength-strlen(tchanf)-1);
+	  strncat(tchanf,gdata.channels[i]->name,maxtextlength-strlen(tchanf)-1);
+	}
+	else {
+	  tchanf = mycalloc(maxtextlength,"mainloop_pubplist1f");
+	  strncpy(tchanf,gdata.channels[i]->name,maxtextlength-1);
+	}
+      }
+      
+    }
+  
+  if (tchans) {
+    pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2s");
+    u_fillwith_msg(pubplist,tchans,"A A A A A xdl");
+    pubplist->method = method_xdl_channel_sum;
+    u_parseit(pubplist);
+    mydelete(pubplist);
+    ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (summary)",tchans);
+    mydelete(tchans);
+  }
+  if (tchanf) {
+    pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2f");
+    u_fillwith_msg(pubplist,tchanf,"A A A A A xdl");
+    pubplist->method = method_xdl_channel;
+    u_parseit(pubplist);
+    mydelete(pubplist);
+    ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (full)",tchanf);
+    mydelete(tchanf);
+  }
+  if (tchanm) {
+    pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2m");
+    u_fillwith_msg(pubplist,tchanm,"A A A A A xdl");
+    pubplist->method = method_xdl_channel_min;
+    u_parseit(pubplist);
+    mydelete(pubplist);
+    ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (minimal)",tchanm);
+    mydelete(tchanm);
+  }
+  if (tchanc) {
+    ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (custom)",tchanc);
+    pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2m");
+    u_fillwith_msg(pubplist,tchanc,"A A A A A xdl");
+    pubplist->method = method_xdl_channel_cust;
+    u_parseit(pubplist);
+    mydelete(pubplist);
+    ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (custom)",tchanc);
+    mydelete(tchanc);
+  }
+  return 0;
+  
+}
+
+static void u_adsend(const userinput * const u)
+{
+  /* This function requests that an advert be sent to a channel
+     or all the channels
+  */
+  char temp[maxtextlength];
+  if ((u->arg1))
+    {
+      if (sendAdvert(u->arg1,1)==0)
+	isnprintf(temp,maxtextlength-2,
+		  "*** ADSEND sent advert to %s", u->arg1);
+      else
+	isnprintf(temp,maxtextlength-2,
+		  "*** ADSEND not currently on channel %s, no advert sent", u->arg1);
+      u_respond(u,temp);
+    }
+  else
+    {
+      sendAdvert(NULL,1);
+      u_respond(u,"*** ADSEND sent advert to all current channels");
+    }
+
+}
+
+static void u_fullignore(const userinput * const u)
+{
    int num = 0;
-   char *tempstr = mycalloc(maxtextlength,"u_nolist");
+  char tempstr[maxtextlength];
+  tempstr[0]=0;
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
    
-   if (u->arg1) num = atoi(u->arg1);
-   gdata.nolisting=gdata.curtime + 60*num - 1;
-   isnprintf(tempstr,maxtextlength-2,
-   "*** XDCC List and PLIST have been disabled for the next %i minute%s",num,num!=1?"s":"");
+  if (u->arg1)
+    gdata.fullignoretime=num=atoi(u->arg1);
+  else
+    gdata.fullignoretime=num=0;
+  
+  if (num==0)
+    isnprintf(tempstr,maxtextlength,
+	      "*** XDCC FULLQUEUE Requests will receive a warning. Users will not be banned");
+  else  
+    isnprintf(tempstr,maxtextlength,
+	      "*** XDCC FULLQUEUE Requests will result in a %i minute ignore",num);
+  u_respond(u,tempstr);
+}
+
+static void u_say(const userinput * const u)
+{
+  if (!u->arg1)
+    {
+      u_respond(u,"Try specifying a channel or nick");
+      return;
+    }
+  if (!u->arg2e)
+    {
+      u_respond(u,"Try specifying something to say");
+      return;
+    }
+  privmsg(u->arg1, "%s" , u->arg2e); 
+}
+static void u_adverts(const userinput * const u)
+{
+  int num = 0;
+  char tempstr[maxtextlength];
+  tempstr[0]=0;
+  
+  updatecontext(__FILE__,__FUNCTION__,__LINE__);
+  
+   if (u->arg1)
+     {
+       if (!strcasecmp(u->arg1,"off"))
+	 {
+	   gdata.noadverts=(-3ul)>>1;
+	   num=-1;
+	 }
+       else
+	 gdata.noadverts=gdata.curtime + 60*(num=atoi(u->arg1));
+     }
+   else
+     gdata.fullignoretime=num=0;
+  
+  if (num==0)
+    isnprintf(tempstr,maxtextlength,
+	      "*** ADVERTS are enabled and will be sent automatically");
+  else if (num==-1)
+    isnprintf(tempstr,maxtextlength,
+	      "*** ADVERTS have been disabled");
+  else
+    isnprintf(tempstr,maxtextlength,
+	      "*** ADVERTS have been disabled for the next %i minute%s",num,
+	      (num>1)?"s":"");
+  u_respond(u,tempstr);
+}
+
+
+static void u_spdwrn(const userinput * const u)
+{
+  char *x=u->arg1;
+  updatecontext(__FILE__,__FUNCTION__,__LINE__);
+  if ((!x) || (strlen(x)!=1))
+    x="\0";
+  switch (x[0])
+    {
+    case '-':
+      gdata.nospeedwarnings=1;
+      u_respond(u,"*** SPDWRN will not warn users about bandwidth limits");
+     break;
+    case '+':
+      gdata.nospeedwarnings=0;
+      u_respond(u,"*** SPDWRN will warn users about bandwidth limits");
+      break;
+    default:
+      {
+	char temp[maxtextlength];
+	char* t=&(temp[0]);
+	isnprintf(t,maxtextlength-2,
+		  "Speed warning notices are %s. Use - to turn off, + to turn on",(gdata.nospeedwarnings)?"disabled":"enabled");
+	u_respond(u,t);
+
+      }
+    }
+}
+
+
+static void u_public(const userinput * const u)
+{
+  char *x=u->arg1;
+  updatecontext(__FILE__,__FUNCTION__,__LINE__);
+  if ((!x) || (strlen(x)!=1))
+    x="\0";
+  switch (x[0])
+    {
+    case '-':
+      gdata.publictriggers=0;
+      u_respond(u,"*** PUBLIC will not respond to public triggers");
+     break;
+    case '+':
+      gdata.publictriggers=1;
+      u_respond(u,"*** PUBLIC public triggers will receive a response");
+      break;
+    default:
+      {
+        char temp[maxtextlength];
+        char* t=&(temp[0]);
+        isnprintf(t,maxtextlength-2,
+                  "Response to public triggers is %s. Use - to turn off, + to tu
+rn on",(gdata.publictriggers)?"on":"off");
+     u_respond(u,t);
+
+      }
+
+    }
+}
+static void u_nolist(const userinput * const u) {
+   int num = 0, num2=-1, x=maxtextlength-2,y;
+   int on=0;
+   char tempstr[maxtextlength];
+   char *tstr=tempstr;
+   tempstr[0]=0;
+   
+   updatecontext(__FILE__,__FUNCTION__,__LINE__);
+   
+   /* Can we assume that -1 is 1111 1111 1111 1111 1111 1111 1111 1111
+      on a 32 bit architechture using 2s-compliment???
+      If so then surely -1>>1 represents the biggest positive number
+      representable?
+      I certainly hope so, as it's important here :)
+   */
+
+   if (u->arg1){
+     if (!strcasecmp(u->arg1,"on"))
+       {
+	 gdata.nolisting=(-3ul)>>1;
+	 num=-1;
+	 on=1;
+       }
+     else
+       gdata.nolisting=gdata.curtime + 60*(num=atoi(u->arg1));
+
+     if (u->arg2)
+       num2=(strcasecmp(u->arg2,"-q")==0)?0:atoi(u->arg2);
+   }
+   gdata.nolistbantime=num2;
+
+
+
+   if (num==0)
+     isnprintf(tstr,x,
+	       "*** XDCC List and PLIST have been enabled");
+   else
+     {
+       x-=y=isnprintf(tstr,x,
+		      "*** XDCC List and PLIST have been disabled%s",
+		      ((num2==-1)?"":" silently")
+		      );
+       tstr+=y;
+
+       if (!on)
+	 {
+	   x-=y=isnprintf(tstr,x," for the next %i minute%s",num,num!=1?"s":"");
+	   tstr+=y;
+	 }
+
+       if (num2>0)
+	 {
+	   x-=y=isnprintf(tstr,x," and any user requesting a list will be banned for %i minute%s",
+			  num2,num2!=1?"s":"");
+	   tstr+=y;
+	 }
+     }
+   
+
    u_respond(u,tempstr);
    
-   mydelete(tempstr);
    
    }
 
diff -BNru iroffer1.2b13/src/defines.h iroffer1.2b13+cpitchfor9/src/defines.h
--- iroffer1.2b13/src/defines.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/defines.h	Wed Mar  6 01:48:54 2002
@@ -17,9 +17,9 @@
 #if !defined _IROFFER_DEFINES
 #define _IROFFER_DEFINES
 
-#define  VERSION "1.2b13"
-#define  VERSIONDATE "November 10th, 2001"
-#define  VERSIONDATEUTC 1005405514 /* "date +%s" */
+#define  VERSION "1.2b13+cpitchfor9"
+#define  VERSIONDATE "March 6st, 2002"
+#define  VERSIONDATEUTC 1015379317 /* "date +%s" */
 #define  RELEASE 1
 
 
@@ -98,7 +98,7 @@
 #define  SRVRTOUT  240
 
 /*       max number of people to keep track of in ignore list */
-#define  MAXIGNL  80
+#define  MAXIGNL  500
 /*       tollerance for ignore, seconds/request to decrement bucket */
 #define  IGN_TL    10
 /*       threshhold for ignore, number of requests in bucket */
@@ -141,11 +141,16 @@
 #define IGN_MANUAL      1
 #define IGN_IGNORING    2
 #define IGN_FIRSTIGNORE 4
+#define IGN_RANGE       8
 
 /* type definitions for channel_t flags */
 #define CHAN_ONCHAN     1
 #define CHAN_MINIMAL    2
 #define CHAN_SUMMARY    4
+#define CHAN_CUSTOM     8
+
+/* Maximum number of advert lines */
+#define MAXADVERTS      20
 
 /* type definistions: Screen, Log, DCC CHAT */
 #define OUT_S    1
diff -BNru iroffer1.2b13/src/globals.h iroffer1.2b13+cpitchfor9/src/globals.h
--- iroffer1.2b13/src/globals.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/globals.h	Wed Mar  6 01:48:54 2002
@@ -150,7 +150,20 @@
 upload *uploads[MAXUPLDS];
 
 meminfo_t meminfo[MAXMEMINFO];
+  /* The custom advert */
+  char* advert[MAXADVERTS];
 
+  /* Time to ban a user
+     -1: Disable, normal list operation response
+      0: Ignore all list requests silently
+    n>0: Ban a user for n minutes should they xdcc list this bot
+  */
+  int nolistbantime;
+  int publictriggers;
+  char* humiliate;
+  int nospeedwarnings;
+  int fullignoretime;
+  int noadverts;
 } gdata_t;
 
 
diff -BNru iroffer1.2b13/src/headers.h iroffer1.2b13+cpitchfor9/src/headers.h
--- iroffer1.2b13/src/headers.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/headers.h	Wed Mar  6 01:48:54 2002
@@ -162,7 +162,8 @@
    method_out_all         = 0x20,
    method_xdl_channel_min = 0x40,
    method_xdl_channel_sum = 0x80,
-   method_allow_all       = 0xFF
+   method_xdl_channel_cust= 0x100,
+   method_allow_all       = 0x1FF
    } userinput_method_e;
 
 typedef struct {
@@ -255,6 +256,7 @@
 unsigned long atoul (const char *str);
 unsigned long long atoull (const char *str);
 void ioutput(int beg, int dest, const char *color, const char *format, ...);
+void allchanmsg(const char *message);
 void privmsg(const char *nick, const char *format, ...);
 void notice(const char *nick, const char *format, ...);
 char* hostmasktoregex(char *str);
@@ -287,6 +289,8 @@
 int mysnprintf(char *str, size_t n, const char *format, ... );
 int myvsnprintf(char *str, size_t n, const char *format, va_list ap );
 #endif
+char capchar(const char c);
+float getEngineerval(const float value, const char *engfix, char *res);
 
 /* misc.cpp */
 void getconfig (void);
@@ -316,6 +320,7 @@
 char* getstatusline(char *str);
 char* getstatuslinenums(char *str);
 void sendxdlqueue(void);
+int addressedtome(const char *dest);
 int isthisforme (const char *dest, char *msg1);
 void initvars(void);
 void startupiroffer(void);
@@ -327,6 +332,7 @@
 void notifybandwidthtrans(void);
 void write_ignorefile(void);
 void read_ignorefile(void);
+int isbanned(const int i, const char* host);
 
 /* dccchat.cpp */
 int setupdccchatout(const char *nick);
@@ -371,8 +377,10 @@
 void u_fillwith_dcc(userinput * const u, char *line);
 void u_fillwith_msg(userinput * const u, char *n, const char *line);
 void u_fillwith_clean(userinput * const u);
-
+int sendAdvert(const char* ch, int force);
 void u_parseit(userinput * const u);
+int fullignore(const char* nick, const char* hostname);
+void ignoreuser(const char* hostname, int bantime);
 
 #endif
 
diff -BNru iroffer1.2b13/src/iroffer.c iroffer1.2b13+cpitchfor9/src/iroffer.c
--- iroffer1.2b13/src/iroffer.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/iroffer.c	Wed Mar  6 01:48:54 2002
@@ -88,7 +88,6 @@
    static int i,j,length,changesec,changemin,changehour,linecut,linecutd,count,efficency;
    static long lasttime, lastmin, lasthour, last4sec, last5sec, last20sec;
    static long lastxminautosave, last3min, last2min, lastignoredec, lastperiodicmsg;
-   static userinput *pubplist;
    static userinput *urehash;
    static int first_loop = 1;
    
@@ -629,72 +628,8 @@
       
       /*----- plist stuff ----- */
       if (gdata.serverstatus == 'C' && changemin && gdata.numpacks) {
-         if (!gdata.queuesize || gdata.inqueue < gdata.queuesize) {
-            char *tchanf = NULL, *tchanm = NULL, *tchans = NULL;
-            
-            for (i=0; gdata.channels[i] && i<MAXCHNLS; i++)
-               if (gdata.channels[i]->plisttime && !((gdata.curtime/60)%(gdata.channels[i]->plisttime))) {
-                  if (gdata.channels[i]->flags & CHAN_MINIMAL) {
-                     if (tchanm) {
-                        strncat(tchanm,",",maxtextlength-strlen(tchanm)-1);
-                        strncat(tchanm,gdata.channels[i]->name,maxtextlength-strlen(tchanm)-1);
-                        }
-                     else {
-                        tchanm = mycalloc(maxtextlength,"mainloop_pubplist1m");
-                        strncpy(tchanm,gdata.channels[i]->name,maxtextlength-1);
-                        }
-                     }
-                  else if (gdata.channels[i]->flags & CHAN_SUMMARY) {
-                     if (tchans) {
-                        strncat(tchans,",",maxtextlength-strlen(tchans)-1);
-                        strncat(tchans,gdata.channels[i]->name,maxtextlength-strlen(tchans)-1);
-                        }
-                     else {
-                        tchans = mycalloc(maxtextlength,"mainloop_pubplist1s");
-                        strncpy(tchans,gdata.channels[i]->name,maxtextlength-1);
-                        }
-                     }
-                  else {
-                     if (tchanf) {
-                        strncat(tchanf,",",maxtextlength-strlen(tchanf)-1);
-                        strncat(tchanf,gdata.channels[i]->name,maxtextlength-strlen(tchanf)-1);
-                        }
-                     else {
-                        tchanf = mycalloc(maxtextlength,"mainloop_pubplist1f");
-                        strncpy(tchanf,gdata.channels[i]->name,maxtextlength-1);
-                        }
-                     }
-                     
-                  }
-            if (tchans) {
-               ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (summary)",tchans);
-               pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2s");
-               u_fillwith_msg(pubplist,tchans,"A A A A A xdl");
-               pubplist->method = method_xdl_channel_sum;
-               u_parseit(pubplist);
-               mydelete(pubplist);
-               mydelete(tchans);
-               }
-            if (tchanf) {
-               ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (full)",tchanf);
-               pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2f");
-               u_fillwith_msg(pubplist,tchanf,"A A A A A xdl");
-               pubplist->method = method_xdl_channel;
-               u_parseit(pubplist);
-               mydelete(pubplist);
-               mydelete(tchanf);
-               }
-            if (tchanm) {
-               ioutput(0,OUT_S|OUT_D,NULL,"Plist sent to %s (minimal)",tchanm);
-               pubplist = mycalloc(sizeof(userinput),"mainloop_pubplist2m");
-               u_fillwith_msg(pubplist,tchanm,"A A A A A xdl");
-               pubplist->method = method_xdl_channel_min;
-               u_parseit(pubplist);
-               mydelete(pubplist);
-               mydelete(tchanm);
-               }
-            
-            }
+	if (!gdata.queuesize || gdata.inqueue < gdata.queuesize) 
+	  sendAdvert(NULL,0);
          else
             ioutput(0,OUT_S|OUT_D,NULL,"Plist skipped, we seem to be rather busy");
          }
@@ -1192,7 +1127,7 @@
       /* add/increment ignore list */
       j=0;
       for (i=0; i<MAXIGNL && gdata.ignorelist[i]; i++)
-         if (!strcmp(gdata.ignorelist[i]->hostname,hostname)) {
+         if (isbanned(i,hostname)) {
             /* already in list */
             j=1;
             gdata.ignorelist[i]->bucket++;
@@ -1219,14 +1154,14 @@
             gdata.ignorelist[i] = mycalloc(sizeof(igninfo),"privmsgparse_gdata.ignorelist[i]");
          strncpy(gdata.ignorelist[i]->hostname,hostname,maxtextlength-1);
          gdata.ignorelist[i]->bucket = 1;
-         gdata.ignorelist[i]->flags &= ~IGN_MANUAL & ~IGN_IGNORING & ~IGN_FIRSTIGNORE;
+         gdata.ignorelist[i]->flags &= ~IGN_RANGE & ~IGN_MANUAL & ~IGN_IGNORING & ~IGN_FIRSTIGNORE;
          gdata.ignorelist[i]->lastcontact = gdata.curtime;
          
          }
    
       /* see if we are ignoreing this person */
       for (i=0; i<MAXIGNL && gdata.ignorelist[i]; i++)
-         if (!strcmp(gdata.ignorelist[i]->hostname,hostname) && (gdata.ignorelist[i]->flags & IGN_IGNORING)) {
+         if (isbanned(i,hostname) && (gdata.ignorelist[i]->flags & IGN_IGNORING)) {
             if (gdata.ignorelist[i]->flags & IGN_FIRSTIGNORE) {
                 privmsg(nick,"Auto-ignore activated, ignoring *!*@%s until you calm down",hostname);
                 gdata.ignorelist[i]->flags &= ~IGN_FIRSTIGNORE;
@@ -1237,6 +1172,9 @@
 	    goto privmsgparse_cleanup; /* it's useful damnit! */
             }
       }
+   if (!gdata.publictriggers && !addressedtome(dest))
+     goto privmsgparse_cleanup;
+   
    
    /*----- CLIENTINFO ----- */
    if ( !gdata.ignore && (!strcmp(msg1,"\1CLIENTINFO")
@@ -1418,14 +1356,65 @@
    
    /*----- XDCC ----- */
    else if ( !gdata.ignore && (!strcmp(caps(msg1),"XDCC") || !strcmp(msg1,"\1XDCC") || !strcmp(caps(msg1),"CDCC") || !strcmp(msg1,"\1CDCC") )) {
-      gdata.inamnt[gdata.curtime%10]++;
       
+	 gdata.inamnt[gdata.curtime%10]++;
       caps(msg2);
       
       if (msg3 && msg3[strlen(msg3)-1] == '\1')
          msg3[strlen(msg3)-1] = '\0';
       
-      if ( msg2 && ( !strcmp(msg2,"LIST") || !strcmp(msg2,"LIST\1"))) {
+	 if ( msg2 && ( !strcmp(msg2,"LIST") || !strcmp(msg2,"LIST\1")))
+	   {
+	     if ((gdata.nolisting > gdata.curtime) && (gdata.nolistbantime!=-1))
+	       {
+		 if (gdata.nolistbantime>0)
+		   {
+		     /* We have someone to ban!! hurrah! */
+		     ignoreuser(hostname, gdata.nolistbantime);
+		     ioutput(0,OUT_S|OUT_L|OUT_D,"0;33","XDCC LIST banned: %s (%s)",nick,hostmask);
+
+		     if (gdata.humiliate)
+		       {
+			 char tempmessage[maxtextlength];
+			 char* cptr=gdata.humiliate;
+			 char* tptr=&(tempmessage[0]);
+			 int z,a;
+			 tempmessage[0]=tempmessage[maxtextlength-1]=0;
+			 for (z=maxtextlength-2;z>0 && *cptr!=0;z--)
+			   if (*cptr=='%')
+			     switch (*(cptr+1))
+			       {
+			       case 'U':
+			       case 'u':
+				 cptr+=2;
+				 strncpy(tptr,nick,z);
+				 a=strlen(tptr);
+				 tptr+=a;
+				 z-=a-1;
+				 break;
+			       case 'T':
+			       case 't':
+				 cptr+=2;
+				 a=isnprintf(tptr, z, "%i minute%s",
+					     gdata.nolistbantime,
+					     (gdata.nolistbantime==1)?"":"s"
+					     );
+				 tptr+=a;
+				 z-=a-1;
+			       }		       
+			   else
+			     *(tptr++)=*(cptr++);
+			 *tptr=0; 
+			 ioutput(0,OUT_S|OUT_L|OUT_D,"0;33",
+				 "XDCC BANSEND to %s: %s",
+				 nick,tempmessage);		
+			 allchanmsg(tempmessage);
+		       }
+		     
+		   }
+	       }
+	     else
+	       {
          if (!gdata.attop) gototop();
          
 	 if (gdata.restrictlist && !isinmemberlist(nick))
@@ -1456,7 +1445,7 @@
          ioutput(0,OUT_S|OUT_L|OUT_D,"0;33","XDCC LIST %s: (%s)",(j==1?"ignored":(j==2?"denied":"queued")),hostmask);
          
          }
-      else if(!strcmp(gdata.caps_nick,dest))
+	   } else if(!strcmp(gdata.caps_nick,dest))
 	{
          if ( msg2 && msg3 && (!strcmp(msg2,"SEND") || !strcmp(msg2,"GET"))) {
          if (!gdata.attop) gototop();
@@ -1643,6 +1632,7 @@
       }
    else if (!man && gdata.nonewcons > gdata.curtime ) {
       ioutput(2,OUT_S|OUT_L|OUT_D,"0;33"," (No New Cons): ");
+      if (fullignore(nick,hostname))
       notice(nick,"*** The Owner Has Requested That No New Connections Are Made In The Next %li Minute%s",(gdata.nonewcons-gdata.curtime+1)/60,((gdata.nonewcons-gdata.curtime+1)/60)!=1?"s":"");
       }   
    else if (!man && pack == gdata.slotsmaxpack && gdata.slotsmaxslots-gdata.slotsfull <= 0) {
@@ -1760,6 +1750,8 @@
             "%sQueue for pack %d of size %d is Full, Try Again Later",
             srvmsg,pack,gdata.slotsmaxqueue);
          strncpy(srvmsg,tempstr,maxtextlength-1);
+	 if (fullignore(nick,hostname)==0)
+	   srvmsg[0]=0;
          }
       else {
          ioutput(2,OUT_S|OUT_L|OUT_D,"0;33"," Queued (pack): ");
@@ -1784,6 +1776,8 @@
             "%sMain queue of size %d is Full, Try Again Later",
             srvmsg,gdata.queuesize);
          strncpy(srvmsg,tempstr,maxtextlength-1);
+	 if (fullignore(nick,hostname)==0)
+	   srvmsg[0]=0;
          }
       else {
          ioutput(2,OUT_S|OUT_L|OUT_D,"0;33"," Queued (slot): ");
diff -BNru iroffer1.2b13/src/misc.c iroffer1.2b13+cpitchfor9/src/misc.c
--- iroffer1.2b13/src/misc.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/misc.c	Wed Mar  6 01:48:54 2002
@@ -23,7 +23,7 @@
 void getconfig (void) {
    char *templine = mycalloc(maxtextlength,"getconfig_templine");
    char *tempc = mycalloc(2,"getconfig_tempc");
-   int h,i,filedescriptor;
+   int h,i,filedescriptor=-1;
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
 
@@ -53,7 +53,7 @@
             }
           }
        }
-   
+   close(filedescriptor);   
    printf("*** Checking for completeness of config file ...\n");
    
    if ( gdata.server[0] == NULL
@@ -103,7 +103,8 @@
       type[i] = line[i];
       }
    type[i] = '\0';
-   
+   if (line[i]==0)
+     i--;
    for (j=i+1; j<maxtextlength; j++) {
       if (line[j] == '\0')
          break;
@@ -163,6 +164,48 @@
       for (i=0; gdata.server[i] && i<MAXSRVS; i++) ;
       gdata.server[i] = var;
       }
+   else if ( ! strcmp(type,"advert")) {
+     for (i=0; i<MAXADVERTS && gdata.advert[i]!=NULL;i++);
+     if (gdata.advert[i]==NULL)
+       gdata.advert[i]=var;
+   }
+   else if ( ! strcmp(type,"nolist")) {
+     char* cptr;
+     gdata.nolisting=(-3ul)>>1;
+     if ((cptr=getpart(var,1,"getconfig_set_nolist")))
+	 gdata.nolistbantime=(!strcasecmp(cptr,"-q"))?0:atoi(cptr);
+     else
+       gdata.nolistbantime=-1;
+     mydelete (cptr);
+   }
+   else if ( ! strcmp(type,"noadverts")) {
+     gdata.noadverts=(-3ul)>>1;
+   }
+   else if ( ! strcmp(type,"public")) {
+     gdata.publictriggers=1;
+   }
+   else if ( ! strcmp(type,"speedwarnings")) {
+     gdata.nospeedwarnings=0;
+   }
+   else if ( ! strcmp(type,"nospeedwarnings")) {
+     gdata.nospeedwarnings=10;
+   }
+   else if ( ! strcmp(type,"nopublic")) {
+     gdata.publictriggers=0;
+   }
+   else if ( ! strcmp(type,"humiliate")) {
+     if (gdata.humiliate)
+       mydelete(gdata.humiliate);
+     gdata.humiliate=var;
+   }
+   else if ( ! strcmp(type,"fullignore")) {
+     char* cptr;
+     if ((cptr=getpart(var,1,"getconfig_set_fullignoretime")))
+       gdata.fullignoretime=atoi(cptr);
+     else
+       gdata.fullignoretime=0;
+     mydelete (cptr);
+   }
    else if ( ! strcmp(type,"channel")) {
       char *tptr = NULL, *tptr2 = NULL, *tname;
       int ok=1;
@@ -206,6 +249,11 @@
                strncpy(cptr->key,tptr2,maxtextlengthshort-1);
             else ok=0;
             }
+	 else if ((!strcmp(tptr,"-advert")) && (cptr->flags | CHAN_CUSTOM))
+	   {
+	     i++;
+	     cptr->flags |= CHAN_CUSTOM;
+	   }
          else ok=0;
          
          mydelete(tptr);
@@ -1611,6 +1659,12 @@
    mydelete(tempstr);
    }
 
+int addressedtome(const char *dest)
+{
+     if (!dest) { outerror(1,"addressedtome() got NULL value"); return 1; }
+     return (!strcmp(gdata.caps_nick,dest));
+}
+
 int isthisforme (const char *dest, char *msg1) {
    if (!msg1 || !dest) { outerror(1,"isthisforme() got NULL value"); return 1; }
    
@@ -1632,6 +1686,7 @@
    }
 
 void initvars(void) {
+  int i;
   
    bzero((char *) gdata.serverq, MAXSENDQ * sizeof(char*) );
    bzero((char *) gdata.inamnt, 10 * sizeof(int) );
@@ -1693,7 +1748,14 @@
    gdata.restrictlist = gdata.restrictsend = 0;
    
    gdata.startuptime = gdata.curtime = time(NULL);
-   
+   for (i=0;i<MAXADVERTS;i++)
+     gdata.advert[i]=NULL;
+   gdata.nolistbantime=-1;
+   gdata.publictriggers=1;
+   gdata.humiliate=NULL;
+   gdata.nospeedwarnings=0;
+   gdata.fullignoretime=0;
+   gdata.noadverts=0;
    }
    
 void startupiroffer(void) {
@@ -2016,7 +2078,7 @@
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
 
    if (gdata.exiting) return;
-   if (!gdata.maxb) return;
+   if (!gdata.maxb || gdata.nospeedwarnings) return;
    
    
    j = 0;
@@ -2046,7 +2108,7 @@
    
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
 
-   if (gdata.exiting) return;
+   if (gdata.exiting || gdata.nospeedwarnings) return;
    
    for (i=0; i<MAXTRANS; i++)
       if (gdata.trans[i] != NULL
@@ -2140,6 +2202,32 @@
    ioutput(3,OUT_S|OUT_D,NULL,"Done");
    }
 
+
+
+int isbanned(const int i, const char* host)
+{
+  /* This function check to see if the host is in the list either
+     directly or via a netmask */
+  int x,y;
+  char *hptr;
+
+  if (!gdata.ignorelist[i] || !host)
+    return 0;
+  hptr=gdata.ignorelist[i]->hostname;
+  if (gdata.ignorelist[i]->flags & IGN_RANGE)
+    {
+      /* Its a range so we have to check the host name matches */
+      x=strlen(++hptr);
+      y=strlen(host);
+      if (y<x)
+	return 0;
+      return (!strcmp(&(host[y-x]),hptr))?1:0;
+    }
+  return (!strcmp(hptr,host));
+}
+  
+      
+	  
 
 /* End of File */
 
diff -BNru iroffer1.2b13/src/utilities.c iroffer1.2b13+cpitchfor9/src/utilities.c
--- iroffer1.2b13/src/utilities.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor9/src/utilities.c	Wed Mar  6 01:48:54 2002
@@ -124,6 +124,11 @@
    return part;
    }
 
+char capchar(const char c)
+{
+  return (c>='a' && c<='z')?(c-32):c;
+}
+
 char* caps(char *text) {
    int i;
    if (text)
@@ -198,6 +203,20 @@
    return highest;
    }
 
+float getEngineerval(const float value, const char *engfix, char *res)
+{
+  float fval=value;
+  int x,y;
+  if ((engfix==NULL) || ((y=strlen(engfix))<1) || (res==NULL))
+    return 0;
+  y--;
+  for (x=0;x<y && fval>1024;x++, fval/=1024.0);
+  *res=engfix[x];
+  return fval;
+}
+
+
+
 void getos (void) {
 
    struct utsname u1;
@@ -591,6 +610,20 @@
       }
    
    }
+
+void allchanmsg(const char *message)
+{
+  int i;
+  char temp[maxtextlength];
+  temp[0]=0;
+  for (i=0; gdata.channels[i] && i<MAXCHNLS; i++)
+    {
+      if (temp[0]!=0)
+	strncat(temp,",",maxtextlength-strlen(temp)-1);
+      strncat(temp,gdata.channels[i]->name,maxtextlength-strlen(temp)-1);
+    }
+  privmsg (temp, "%s", message);
+}
 
 void privmsg(const char *nick, const char *format, ...) {
    char tempstr[maxtextlength];
