diff -BNru iroffer1.2b13/ChangeLog iroffer1.2b13+cpitchfor11/ChangeLog
--- iroffer1.2b13/ChangeLog	Thu Jan  1 01:00:00 1970
+++ iroffer1.2b13+cpitchfor11/ChangeLog	Wed Apr  3 20:40:23 2002
@@ -0,0 +1,168 @@
+cpitchfor11:	Wed Apr  3 20:37:38 BST 2002	cpitchford
+	*	Updated misc.c admin.c: Changed Humiliate directive
+		Now it must have the paramter nolist or badpack to specify
+		which humiliate it refers to.
+	*	Updated utilities.c: Added simpleformat function
+		takes a list of paramters and works like snprintf replacing
+		defined tags (ie %g) with numbers, strings, numbers followed
+		by a word with auto plural (%m means 1 minute or 2 minutes)
+		or a quantity that is reduced with engineering values
+		1024 B goes to 1KB. This will replace the humiliate code
+		and the custom advert code
+	*	Updated utilities.c global.c defines.c: Added badpack
+		structure to gdata. It contains the list of people who
+		requested an invalid pack in a sliding window mechanism. If
+		the total in the first slot plus total in second slot are
+		greater than the limit, they are banned. Each half interval,
+		the first slot is moved to the second and then blanked.  A
+		function badpackadd will attempt to add a host to the list
+		and return true if they have reached their limit (ie to be
+		banned) and badpackrotate will "rotate" the list as
+		necessary or by force
+	*	Updated admin.c: Implemented BADPACK, BDPKLMT admin commands
+		to control the badpack ban on invalid request function. 
+		BADPACK controls how long the monitoring is enabled for and
+		how long the users will be banned, BDPKLMT controls the limits (ie how many invalid
+		requests are required in what time before a ban is made)
+	*	Updated misc.c: Implemented badpack configfile param
+		to default the badpack control, much like the nolist
+		directive
+
+cpitchfor10:	Thu Mar 21 23:33:22 GMT 2002	cpitchford	
+	*	Updated misc.c, defines.h, globals.h: added prejoin config	
+		file option to send a RAW command before joining any
+		channels. This will allow nicksrv commands to be sent for
+		IRC services such as those on DALNet. Thanks to
+		coombes_mark@hotmail.com for suggestion and DALNet help
+	*	bugfixed misc.c: config file parsing would allow
+		gdata.server[MAXSRVS] to be defined in the event there were
+		MAXSRVS+1 servers defined in the config file. This has been
+		limited and an error returned.
+	*	bugfixed misc.c: same as above but for gdata.advert
+
+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+cpitchfor11/README.cpitchfor-patch
--- iroffer1.2b13/README.cpitchfor-patch	Thu Jan  1 01:00:00 1970
+++ iroffer1.2b13+cpitchfor11/README.cpitchfor-patch	Wed Apr  3 20:40:23 2002
@@ -0,0 +1,295 @@
+cpitchfor10   2002/03/20				<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.
+
+
+Bad Pack auto ban
+-----------------
+
+Now you can ban a user if they request a pack that isn't offered on your bot
+To make it slightly fairer, you can change the limits so that they are only
+banned if they make these requests repeatidly, use the admin commands
+BADPACK and BDPKLMT to change these values as follows:
+
+BADPACK on 10
+			# Turn on the BADPACK autoban and ban a user for
+			  10 minutes
+
+BADPACK	0
+			# Turn off BADPACK autobaning
+
+BADPACK 30 5
+			# For the next 30 minutes, turn on BADPACK
+			  autobanning and ban users for 5 minutes
+
+BDPKLMT 5 10
+			# When autobaning is enabled (see above) ban a user
+			  if they request 5 invalid packs in 10 minutes
+
+BDPKLMT 2 60		# When autobannign is enabled ban a user if they
+			  request 2 invalid packs in 60 minutes (harsh!)
+
+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
+You can specify nolist or badpack to specify when the message should be used
+
+humiliate nolist 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
+
+humiliate badpack I've just banned %u for %t for requesting %p in %m
+
+would mean that should cpitchfor repeatidly request invalid packs
+
+<yourbot>: I've just banned cpitchfor for 60 minutes for requesting 2 invalid
+           packs in 60 minutes
+
+
+%u is replaced with the username (nick)
+%t is replaced with the ban time
+for badpack also:
+%p is replaced with the number of invalid packs requested
+%m is replaced with the time in which these packs were requested
+
+
+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
+
+Pre join RAW commands:
+----------------------
+
+Some services on networks (ie DALNet) require raw commands to be sent to the
+server before joining a channel (ie to register a nick with a password)
+The prejoin config file parameter allows you to specify multiple raw
+commands that will be sent prior to the bot joining a channel. It will also
+be sent in the event a bot changes server or is disconnected and reconnects.
+
+This can also be used to msg a nick when the bot comes up.. ie
+
+prejoin PRIVMSG cpitchfor : I've just joined a server and I'm serving!
+prejoin nickserv mybot mypassword
+
diff -BNru iroffer1.2b13/sample.config iroffer1.2b13+cpitchfor11/sample.config
--- iroffer1.2b13/sample.config	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/sample.config	Wed Apr  3 20:40:23 2002
@@ -106,16 +106,36 @@
 server irc.east.gblx.net 6667
 
 ##############################################################################
+###                         - prejoin (upto 20) -                          ###
+###                                                                        ###
+### prejoin format:                                                        ###
+###  "prejoin RAW COMMAND"                                                 ###
+### the RAW command will be sent to the server before it joins any         ###
+### channels. This can be used to msg a nick or use DALNet nickserv        ###
+### services. Multiple commands can be specified on multiple lines.        ###
+### It SHOULD BE USED WITH CARE!!!!!!                                      ###
+###                                                                        ###
+
+# Send msg to cpitchfor when the server join
+#prejoin PRIVMSG cpitchfor : I have joined and I'm ready to serve again!
+
+# DALNet nick services!
+#prejoin NICKSERV mybot mysecretpasswrd
+
+
+##############################################################################
 ###                         - 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 +143,96 @@
 
 
 ##############################################################################
+###                               - 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
+
+##############################################################################
+###                              - badpack -
+### badpack format:
+### <maxattempts> <during> <bantime>
+### This function makes the bot ban users that request <maxattempts>       ###
+### invalid packs within <during> minutes. The ban lasts <bantime> minutes ###
+### The user will be warned each time they make an invalid pack request    ###
+
+# if a user requests more than 5 invalid packs in an hour, ban for 300 mins
+badpack 5 60 300
+
+
+##############################################################################
+###                             - humiliate -                              ###
+### humiliate format:                                                      ###
+### <nolist|badpack> [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 %t will be replaced with the time before   ###
+### the ban is lifted. nolist and badpack define where the message will be ###
+### used. In the case of badpack %p is replaced with the number of invalid ###
+### packs requested and %m is the duration in which they were requested    ###
+
+humiliate nolist %u has been banned for %t for listing
+humiliate badpack %u has been banned for %t for requesting %p within %m
+
+
+##############################################################################
+###                              - 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 +295,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 +334,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+cpitchfor11/src/admin.c
--- iroffer1.2b13/src/admin.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/admin.c	Wed Apr  3 20:40:23 2002
@@ -73,6 +73,16 @@
 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);
+
+static void u_badpack(const userinput * const u);
+static void u_bdpklmt(const userinput * const u);
 
 /* local info */
 static const userinput_parse_t userinput_parse[] = {
@@ -93,9 +103,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 +120,20 @@
 
 {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_badpack,  "BADPACK","[on|n] [m]","Enables autobanning (for n minutes) for m minutes if they request an invalid pack"},
+{4,method_allow_all,u_bdpklmt, "BDPKLMT","n m","Used with BADPACK. Autoban user if they request invalid packs n times in 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","<nolist|badpack> [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 +146,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 +308,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 +338,27 @@
    
    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);
    
+       case method_xdl_channel:
+       case method_xdl_user:
+       case method_out_all:
+       case method_xdl_channel_min:
+       case method_xdl_channel_sum:
+       case method_xdl_channel_cust:
+       case method_allow_all:
+	 break;
+       }
    u_fillwith_clean(u);
    
    }
@@ -350,10 +381,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, badpack, bdpklmt, 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 +425,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 +447,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 +1221,7 @@
 
 static void u_psend(const userinput * const u) {
    char *tempstr;
+   long nolisting;
    userinput manplist;
   
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
@@ -1071,8 +1233,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 +1709,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 +1722,20 @@
       mydelete(gdata.server[i]);
    for (i=0; i<MAXCHNLS; i++)
       gdata.t_channel[i] = gdata.r_channel[i] = NULL;
-   
+   for (i=0; i<MAXPREJOIN && gdata.prejoin[i]; i++)
+     {
+       mydelete (gdata.prejoin[i]);
+       gdata.prejoin[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 +1768,6 @@
    gdata.uploadallowed = gdata.uploadmaxsize = 0;
    mydelete(gdata.uploaddir);
    gdata.restrictlist = gdata.restrictsend = 0;
-   
    mydelete(gdata.loginname);
    set_loginname();
    
@@ -1631,7 +1804,7 @@
             }
          }
       }
-   
+   close(filedescriptor);
    /* see what needs to be redone */
    
    u_respond(u,"Reconfiguring...");
@@ -1857,7 +2030,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 +2149,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 +2206,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 +2227,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 +2235,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,24 +2279,446 @@
    
    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);
+   }
+}
+
+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);
+	}
+      }
 
-static void u_nolist(const userinput * const u) {
+    }
+  
+  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);
    
    }
+
+
+static void u_badpack(const userinput * const u)
+{
+  int i=0;
+  int num = 0, num2=-1, x=maxtextlength-2,y;
+  char tempstr[maxtextlength];
+  char *tstr=tempstr;
+  tempstr[0]=0;
+  
+  updatecontext(__FILE__,__FUNCTION__,__LINE__);
+  
+  if (u->arg1){
+    if (!strcasecmp(u->arg1,"on"))
+      {
+	i=(-3ul)>>1;
+	num=-1;
+      }
+    else
+      x=gdata.curtime + 60*(num=atoi(u->arg1));
+  }
+  
+  if (num==0)
+    {
+      gdata.badpack.badpacktime=i;
+      isnprintf(tstr,x,
+		"*** BADPACK Banning disabled");
+      return;
+    }
+  
+  if ((!u->arg2) || ((num2=atoi(u->arg2))<1))
+    {
+      u_respond(u,"The ban time is invalid. It should be numerical and
+greater than 0");
+      return;
+    }
+  
+  gdata.nolistbantime=num2;
+  gdata.badpack.badpacktime=i;
+  
+  x-=y=isnprintf(tstr,x,
+		 "*** BADPACK Banning is enabled");
+  tstr+=y;
+  if (num>0)
+    {
+      x-=y=isnprintf(tstr,x,
+		     "for the next %i minute%s",num,(num==1)?"":"s");
+      tstr+=y;
+    }
+  isnprintf(tstr,x,". Any user requesting %i or more packs in %i
+minute%s will be banned for %i minute%s",
+	    gdata.badpack.maxattempts,
+	    gdata.badpack.interval,
+	    (gdata.badpack.interval==1)?"":"s",
+	    gdata.badpack.bantime,
+	    (gdata.badpack.bantime==1)?"":"s"
+	    );
+  u_respond(u,tempstr);
+  badpackrotate(1);
+}
+
+
+static void u_bdpklmt(const userinput * const u)
+{
+   int num = 0, num2=-1, x=maxtextlength-2;
+   char tempstr[maxtextlength];
+   char *tstr=tempstr;
+   tempstr[0]=0;
+   
+   updatecontext(__FILE__,__FUNCTION__,__LINE__);
+
+   if ((!u->arg2) || ((num2=atoi(u->arg2))<1) || ((num=atoi(u->arg1))<1))
+     {
+       u_respond(u,"Invalid parameters. Max attempts and interval should be
+numerical and greater than 0");
+       return;
+     }
+
+   gdata.badpack.maxattempts=num;
+   gdata.badpack.interval=num2;
+   isnprintf(tstr,x," BADPACK limits set. User will be banned if they
+request %i pack%s in %i minute%s",
+	     gdata.badpack.maxattempts,
+	     (gdata.badpack.maxattempts==1)?"":"s",
+	     gdata.badpack.interval,
+	     (gdata.badpack.interval==1)?"":"s"
+	     );
+   u_respond(u,tempstr);
+   
+}
+
+  
+
 
 
 static void u_renumber(const userinput * const u) {
diff -BNru iroffer1.2b13/src/defines.h iroffer1.2b13+cpitchfor11/src/defines.h
--- iroffer1.2b13/src/defines.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/defines.h	Wed Apr  3 20:40:23 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+cpitchfor11"
+#define  VERSIONDATE "April 3rd, 2002"
+#define  VERSIONDATEUTC 1017862685 /* "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,22 @@
 #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
+
+/* Maximum number of pre channel join raw commands */
+#define MAXPREJOIN      20
+
+/* Maximum number of hosts to monitor for invalid packs */
+#define MAXBADPACK      500
 
 /* type definistions: Screen, Log, DCC CHAT */
 #define OUT_S    1
diff -BNru iroffer1.2b13/src/globals.h iroffer1.2b13+cpitchfor11/src/globals.h
--- iroffer1.2b13/src/globals.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/globals.h	Wed Apr  3 20:40:23 2002
@@ -150,6 +150,34 @@
 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;
+  char* prejoin[MAXPREJOIN];
+  struct {
+    int rotate;
+    int interval;
+    int maxattempts;
+    int badpacktime;
+    int bantime;
+    char* humiliate;
+    struct {
+      char *hostmask;
+      int first;
+      int last;
+    } list[MAXBADPACK];
+  } badpack;
 
 } gdata_t;
 
diff -BNru iroffer1.2b13/src/headers.h iroffer1.2b13+cpitchfor11/src/headers.h
--- iroffer1.2b13/src/headers.h	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/headers.h	Wed Apr  3 20:40:23 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 {
@@ -238,6 +239,8 @@
 int strcmppart (const char *str, const char *match);
 int strcmpany (const char *str1, const char *match1);
 int strcmpend (const char *str, const char *match);
+int simpleformat(char* buffer, const int length, char* format,
+		 char* params, ...);
 char* getpart(const char *line, int howmany, const char *src);
 char* caps(char *text);
 char* nocaps(char *text);
@@ -255,6 +258,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 +291,10 @@
 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);
+double getEngineerval(const double value, const char *engfix, char *res);
+int badpackadd(const char* hostmask, int *count);
+void badpackrotate(int now);
 
 /* misc.cpp */
 void getconfig (void);
@@ -316,6 +324,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 +336,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 +381,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+cpitchfor11/src/iroffer.c
--- iroffer1.2b13/src/iroffer.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/iroffer.c	Wed Apr  3 20:40:23 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;
    
@@ -512,6 +511,9 @@
       /* time to rotate log ? */
       if (changehour && gdata.logrotate && gdata.logfile)
          isrotatelog();
+      if (changesec)
+	badpackrotate(0);
+      
 
       /*----- IGN_TL seconds ----- */
       if (changesec && (gdata.curtime - lastignoredec > IGN_TL)) {
@@ -629,72 +631,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 +1130,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 +1157,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 +1175,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 +1359,41 @@
    
    /*----- 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];
+			 simpleformat(tempmessage,maxtextlength,
+				      gdata.humiliate,
+				      "tp minute",gdata.nolistbantime,
+				      "us",nick,
+				      NULL);
+			 
+			 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 +1424,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();
@@ -1638,11 +1606,45 @@
       notice(nick,"*** You can only have %d transfer%s at a time",gdata.maxtransfersperperson,gdata.maxtransfersperperson!=1?"s":"");
       }
    else if (!man && (pack > gdata.numpacks || pack < 1)) {
+      int c=0;
       ioutput(2,OUT_S|OUT_L|OUT_D,"0;33"," (Bad Pack Number): ");
+      if (badpackadd(hostname,&c))
+	{ /* We need to ban this person */
+	  ignoreuser(hostname, gdata.badpack.bantime);
+	  ioutput(0,OUT_S|OUT_L|OUT_D,"0;33","XDCC BADPACK banned: %s (%s)",nick,hostname);
+	  if (gdata.badpack.humiliate)
+	    {
+	      char tempmessage[maxtextlength];
+	      simpleformat(tempmessage,maxtextlength,
+			   gdata.badpack.humiliate,
+			   "tp minute",gdata.badpack.bantime,
+			   "us",nick,
+			   "pp invalid pack",gdata.badpack.maxattempts,
+			   "mp minute",gdata.badpack.interval,
+			   NULL);
+	      ioutput(0,OUT_S|OUT_L|OUT_D,"0;33",
+		      "XDCC BANSEND to %s: %s",
+		      nick,tempmessage);		
+	      allchanmsg(tempmessage);
+	    }
+	}
+      else
+	{
+	  if (c==0)
       notice(nick,"*** Invalid Pack Number, Try Again");
+	  else
+	    {
+	      char cbuf[maxtextlength];
+	      char *cptr=cbuf;
+	      isnprintf(cptr,maxtextlength,"*** Invalid Pack Number, be more accurate or you may be banned %i/%i",c,gdata.badpack.maxattempts);
+	      notice (nick,cptr);
+	    }
       }
+   }
+   
    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 +1762,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 +1788,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+cpitchfor11/src/misc.c
--- iroffer1.2b13/src/misc.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/misc.c	Wed Apr  3 20:40:23 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;
@@ -160,9 +161,120 @@
       mydelete(var);
       }
    else if ( ! strcmp(type,"server")) {
-      for (i=0; gdata.server[i] && i<MAXSRVS; i++) ;
+      for (i=0;i<MAXSRVS && gdata.server[i]; i++) ;
+      if (i==MAXSRVS)
+	{
+	  ioutput(0,OUT_S|OUT_L|OUT_D,NULL," !!! Too many servers, ignoring %s in config file !!!",var);
+	}
+      else
       gdata.server[i] = var;
       }
+   else if ( ! strcmp(type,"advert")) {
+     for (i=0; i<MAXADVERTS && gdata.advert[i]!=NULL;i++);
+     if ((i!=MAXADVERTS) && (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, "badpack")) {
+     /* badpack <attempts> <in mins>  <banfor> */
+     char *tptr;
+     int i,num[4];
+
+     for(i=1;i<4;i++)
+       {
+	 if ((tptr=getpart(var,i,"badpackstring")))
+	   {
+	     if ((num[i]=atoi(tptr))<1)
+	       {
+		 
+		 ioutput(0,OUT_S|OUT_L|OUT_D,NULL," !!! Invalid badpack paramter %i in config file: %s",i,var);
+		 mydelete (tptr);
+		 i=9;
+	       }
+	   }
+	 else
+	   {
+	     ioutput(0,OUT_S|OUT_L|OUT_D,NULL," !!! Missing badpack paramter in config file: %s",var);
+	     mydelete (tptr);
+	     i=9;
+	   }
+       }
+     if (i!=9)
+       {
+	 gdata.badpack.badpacktime=(-3ul)>>1;
+	 gdata.badpack.maxattempts=num[1];
+	 gdata.badpack.interval=num[2];
+	 gdata.badpack.bantime=num[3];
+	 badpackrotate(1);
+       }
+   }
+   else if ( ! strcmp(type,"humiliate")) {
+     char** ccptr=NULL;
+     char* cptr=NULL;
+     int i;
+     for (i=0;var[i]!=0;i++)
+       if (var[i]==' ')
+	 {
+	   cptr=&(var[i+1]);
+	   var[i]=0;
+	   break;
+	 }
+     
+     if ( ! strcasecmp(var,"nolist") )
+       ccptr=&gdata.humiliate;
+     else if ( ! strcasecmp (var , "badpack") )
+       ccptr=&gdata.badpack.humiliate;
+     else
+       {
+	 ioutput(0,OUT_S|OUT_L|OUT_D,NULL," !!! Bad syntax for humiliate %s in config file !!!",var);
+       }
+     if (ccptr)
+       {
+	 if (*ccptr)
+	   {
+	     mydelete (*ccptr);
+	     *ccptr=NULL;
+	   }
+	 strncpy(*ccptr=mycalloc(maxtextlength,"u_humiliate"),
+		 cptr, maxtextlength-2);
+       }
+   }
+   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,"prejoin")) {
+     for (i=0; i<MAXPREJOIN && gdata.prejoin[i]!=NULL;i++);
+     if ((i<MAXPREJOIN) && (gdata.prejoin[i]==NULL))
+       gdata.prejoin[i]=var;
+   }   
    else if ( ! strcmp(type,"channel")) {
       char *tptr = NULL, *tptr2 = NULL, *tname;
       int ok=1;
@@ -206,6 +318,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);
@@ -738,6 +855,10 @@
       isnprintf(tempstr,maxtextlength-2,"MODE %s %s",gdata.user_nick,gdata.user_modes);
       writeserver2(tempstr,1);
       }
+
+   for (i=0; i<MAXPREJOIN && gdata.prejoin[i]!=NULL;i++)
+     writeserver(gdata.prejoin[i]);
+     
    for (i=0; i<MAXCHNLS; i++)
       if (gdata.channels[i]) {
          joinchannel(gdata.channels[i]);
@@ -1611,6 +1732,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 +1759,7 @@
    }
 
 void initvars(void) {
+  int i;
   
    bzero((char *) gdata.serverq, MAXSENDQ * sizeof(char*) );
    bzero((char *) gdata.inamnt, 10 * sizeof(int) );
@@ -1693,7 +1821,20 @@
    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;
+   for (i=0;i<MAXPREJOIN;i++)
+     gdata.prejoin[i]=NULL;
+   gdata.badpack.interval=gdata.badpack.maxattempts=1;
+   gdata.badpack.badpacktime=gdata.badpack.bantime=0;
+   for (i=0;i<MAXBADPACK;i++)
+     gdata.badpack.list[i].hostmask=NULL;
    }
    
 void startupiroffer(void) {
@@ -2016,7 +2157,7 @@
    updatecontext(__FILE__,__FUNCTION__,__LINE__);
 
    if (gdata.exiting) return;
-   if (!gdata.maxb) return;
+   if (!gdata.maxb || gdata.nospeedwarnings) return;
    
    
    j = 0;
@@ -2046,7 +2187,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 +2281,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+cpitchfor11/src/utilities.c
--- iroffer1.2b13/src/utilities.c	Sat Nov 10 17:06:40 2001
+++ iroffer1.2b13+cpitchfor11/src/utilities.c	Wed Apr  3 20:40:23 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)
@@ -168,6 +173,126 @@
    return str;
    }
 
+int simpleformat(char* buffer, const int length, char* format,
+		   char* params, ...) {
+  /* This function will take format and replace %x with the corresponding values in the following string ie
+
+(buffera, 200, "%x is an integer, %y is a string", "xi", 200, "ys", "BLARGH", NULL);
+  */
+  va_list args;
+  struct {
+    enum {SMPFMT_NULL, SMPFMT_INT, SMPFMT_STR, SMPFMT_PLR, SMPFMT_BYT} type;
+    struct {
+      double fl;
+      int number;
+      char *string;
+    } value;
+  } fmt[128];
+  int x,spaceleft=length-2, used=0;
+  char* cptr=params;
+  double flo;
+  
+  if (length<2)
+    return 0;
+  if (fmt==NULL)
+    return buffer[0]=0,0;
+  for (x=0;x<128;x++)
+    fmt[x].type=SMPFMT_NULL;
+  va_start(args, params);
+  cptr=params;
+  while (cptr!=NULL) {
+    x=cptr[0];
+    if (x<0 || x>127)
+      return 0;
+    switch (cptr[1])
+      {
+      case 'i':
+	fmt[x].type=SMPFMT_INT;
+	fmt[x].value.number=va_arg(args,int);
+	break;
+      case 's':
+	fmt[x].type=SMPFMT_STR;
+	fmt[x].value.string=va_arg(args,char*);
+	break;
+      case 'p':
+	fmt[x].type=SMPFMT_PLR;
+	fmt[x].value.number=va_arg(args,int);
+	fmt[x].value.string=cptr+2;
+	break;
+      case 'b':
+	flo=(double)(va_arg(args,double));
+	printf("setting %c: %f%s\n",x,flo,cptr+2);
+      	fmt[x].type=SMPFMT_BYT;
+	fmt[x].value.fl=flo;
+	printf("got.. %1.2f\n",fmt[x].value.fl);
+	fmt[x].value.string=cptr+2;
+	break;
+      default:
+	return 0;
+      }
+    cptr=va_arg(args,char*);
+  }
+  fmt[0].type=fmt['%'].type=SMPFMT_STR;
+  fmt[0].value.string=fmt['%'].value.string="%\0";
+  cptr=format;
+  while (spaceleft>0)
+    {
+      x=0;
+      switch(*cptr)
+	{
+	case 0:
+	  buffer[0]=0;
+	  spaceleft=0;
+	  break;
+	case '%':
+	  cptr++;
+	  /*switch ((*cptr>=0 && *cptr<128)?fmt[(int)*cptr].type:SMPFMT_NULL)*/
+	  switch (fmt[(int)*cptr].type)
+	    {
+	    case SMPFMT_STR:
+	      x=isnprintf(buffer,spaceleft+1,"%s",fmt[(int)*cptr].value.string);
+	      break;
+	    case SMPFMT_INT:
+	      x=isnprintf(buffer,spaceleft+1,"%i",fmt[(int)*cptr].value.number);
+	      break;
+	    case SMPFMT_PLR:
+	      x=isnprintf(buffer,spaceleft+1,"%i%s%s",fmt[(int)*cptr].value.number,
+			  fmt[(int)*cptr].value.string,(fmt[(int)*cptr].value.number==1)?"":"s");
+	      break;
+	    case SMPFMT_BYT:
+	      {
+		double f;
+		char c;
+		f=getEngineerval(fmt[(int)*cptr].value.fl," KMGTPE\0", &c);
+		x=isnprintf(buffer,spaceleft+1,"%1.2f %c%s",
+			    f,c,fmt[(int)*cptr].value.string);
+	      }
+	      break;
+	    case SMPFMT_NULL:
+	      x=isnprintf(buffer,spaceleft+1,"%%%c", *cptr);
+	      break;
+	    }
+	  cptr++;
+	  break;
+	default:
+	  x=1;
+	  buffer[0]=*cptr;
+	  buffer[1]=0;
+	  cptr++;
+	}
+      
+      buffer+=x;
+      used+=x;
+      spaceleft-=x;
+  }
+  return used;
+}
+ 		
+
+	      
+
+
+
 int highestsock (void) {
    int i,highest;
    highest = 0;
@@ -198,6 +323,21 @@
    return highest;
    }
 
+double getEngineerval(const double value, const char *engfix, char *res)
+{
+  double 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;
@@ -592,6 +732,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];
    char tempstr2[maxtextlength];
@@ -1290,6 +1444,116 @@
    }
 
 #endif
+
+
+void badpackrotate(int now)
+{
+  if (gdata.curtime>gdata.badpack.badpacktime)
+    {
+      int i;
+      for (i=0;i<MAXBADPACK && gdata.badpack.list[i].hostmask;i++)
+	{
+	  mydelete (gdata.badpack.list[i].hostmask);
+	  gdata.badpack.list[i].hostmask=NULL;
+	  gdata.badpack.list[i].first=gdata.badpack.list[i].last=0;
+	}
+    }
+  else if (now || gdata.curtime>gdata.badpack.rotate)
+    {
+      int i,j;
+      for (i=j=0;i<MAXBADPACK && gdata.badpack.list[i].hostmask ; i++)
+	if 
+	  (gdata.badpack.list[i].first==0)
+	  {
+	    /* We can delete this entry.. */
+	    mydelete (gdata.badpack.list[i].hostmask);
+	    gdata.badpack.list[i].hostmask=NULL;
+	  }
+      else
+	{
+	  /* We have to rotated the data, and shuffle in necessary */
+	  gdata.badpack.list[j].last=gdata.badpack.list[i].first;
+	  gdata.badpack.list[j].first=0;
+	  if (j!=i)
+	    {
+	      gdata.badpack.list[j].hostmask=gdata.badpack.list[i].hostmask;
+	      gdata.badpack.list[i].hostmask=NULL;
+	    }
+	  j++;
+	}
+      gdata.badpack.rotate=gdata.curtime+(30*gdata.badpack.interval);
+    }
+}
+
+
+
+
+void _badpackremove(int pos)
+{
+  if (pos>=0 && pos<MAXBADPACK)
+    {
+      int i;
+      mydelete(gdata.badpack.list[pos].hostmask);
+      gdata.badpack.list[pos].hostmask=NULL;
+      for (i=pos+1;i<MAXBADPACK &&gdata.badpack.list[i].hostmask; i++)
+	{
+	  gdata.badpack.list[pos].first=gdata.badpack.list[i].first;
+	  gdata.badpack.list[pos].last=gdata.badpack.list[i].last;
+	  gdata.badpack.list[pos].hostmask=gdata.badpack.list[i].hostmask;
+	  pos++;
+	}
+      if (i<MAXBADPACK)
+	{
+	  gdata.badpack.list[i].first=gdata.badpack.list[i].last=0;
+	  gdata.badpack.list[i].hostmask=NULL;
+	}
+    }
+}
+
+int badpackadd(const char* hostmask, int *count)
+{
+  if (!hostmask || gdata.curtime>gdata.badpack.badpacktime)
+    return 0;
+  else
+    {
+      int i;
+      *count=0;
+      /* Step one, find the host in the list. Case insensitive */
+      for (i=0;i<MAXBADPACK && gdata.badpack.list[i].hostmask;i++)
+	if (!strcasecmp(gdata.badpack.list[i].hostmask,hostmask))
+	  break;
+      if (i==MAXBADPACK)
+	/* we have searched and all slots are full, and do not match
+	   therefore we silently let this person abuse us.. :( by returning 
+	   false... we could instantly ban them by returning true though!
+	   but that would be evil :)
+	*/
+	return 0;
+      if (!gdata.badpack.list[i].hostmask)
+	{
+	  strcpy(
+		 gdata.badpack.list[i].hostmask=
+		 mycalloc(strlen(hostmask)+1,"badpackadd"),
+		 hostmask);
+	  gdata.badpack.list[i].first=0;
+	  gdata.badpack.list[i].last=0;
+	}
+      
+      /* Found at location i */
+      if ((*count=(
+	   gdata.badpack.list[i].last + 
+	   (++gdata.badpack.list[i].first))) >= gdata.badpack.maxattempts)
+	{
+	  _badpackremove(i);
+	  return -1;
+	}
+      else
+	return 0;
+    }
+  
+}
+
+
 
 /* End of File */
 
