/*

											$VER: MM_MegaStat 0.14 (28/8/98)

												  ©1997-8 Neil Williams

					now2@frost3.demon.co.uk, 2:442/107.0@fidonet, 39:136/1.0@amiganet
					neil@tkgbbs.freeserve.co.uk     http://www.tkgbbs.freeserve.co.uk
*/

parse arg args

options cache
options failat 99
options results

signal on break_c
signal on break_d
signal on break_e
signal on break_f
signal on halt
signal on ioerr
signal on syntax

address 'MAILMANAGER'

Main:

				call Init
				call Header
				call Parse_Args(strip(args))
				call Read_Cfg

				call Read_Messages

				if system.arg.postmsg = 1 then do
					 if multi=0 then do
						 call PostMsg
						 address command 'delete >NIL: 'system.tmpfile
						 end
					 else do
						 call Log()
						 call Log('POSTMSG will not work with multiple areas.')
						 call Log('The statistics are in the file 'system.tmpfile)
						 end
					 end
				else do
					 call Log()
					 call Log('The statistics are in the file 'system.tmpfile)
					 end

call Quit(0, 'All done.')
exit


break_c:; break_d:; break_e:; break_f:; halt:

				signal off break_c
				signal off break_d
				signal off break_e
				signal off break_f
				signal off halt

				return_code   =       5
				error_line    =       0
				error_msg     =       'Execution halted!!!'
				rc            =       0

signal Exit


Exit:

				select
								when return_code>=40 then error = 'INTERNAL-ERROR:'
								when return_code>=30 then error = 'IO-ERROR:'
								when return_code>=20 then error = 'ERROR:'
								when return_code>=10 then error = 'WARNING:'
								when return_code>=5  then error = 'INFO:'
								otherwise                 error = ''
				end

	call Log()
				call Log('***' strip(error error_msg) '***', '+')
				call Log(,'\')

				call setclip('MM_LogPre', system.mm.logpre)

exit return_code


Get_Arg: procedure Expose args system.

	arg keyword, mode, old

				uargs   = upper(args)
				p                       = find(uargs, keyword)

				if p=0  then
								do
												p = pos(' 'keyword'=', ' 'uargs)

												if p>0 then     args    = overlay(' ', args, p+length(keyword))

			p = find(upper(args), keyword)
								end

				system.cmdopt.keyword   = p>0

				select
								when mode=0     then
												if p>0 then
																do
																				ret             = 1
																				args    = delword(args, p, 1)
																end
												else ret        = old

								when mode=1 then
												if p>0 then
																do
																				left    = subword(args, 1, p-1)
																				rest    = subword(args, p+1)

																				if left(rest, 1)='"' then       parse var rest . '"'    ret '"' rest
																				else                                                                                    parse var rest                          ret                     rest

																				args    = strip(left strip(rest))
																end
												else ret        = old

								when mode=2 then
												do
																if left(args, 1)='"'    then    parse var args . '"'    ret '"' args
																else                                                                                            parse var args                          ret             args

																if strip(ret)=''                        then    ret = old
												end

								otherwise exit 99
				end

				args    = strip(args)
				ret             = strip(ret, 'b', '" ')

return ret


Get_Version: procedure

				parse arg mode

				parse value sourceline(3-mode) with . . ver .
				parse var ver tst 'ß' .

				if ~datatype(strip(tst, 'b', '/c '), 'N') then
								if ~mode then ver = Get_Version(1)
								else exit 99

return ver


Header:

				call Log(,'/')
				call Log('***' system.prg.id '***', '+')
				call Log(' 'system.prg.cr)
				call Log()

return


Init:

				system.                 = 0

				system.prg.ver          = Get_Version(0)
				system.prg.name         = 'MM_MegaStat'
				system.prg.id           = system.prg.name 'v'system.prg.ver
				system.prg.cfg          = 'MM:Config/'system.prg.name'.cfg'
				system.prg.cr           = '(C)1997-8 Neil Williams'
				system.tmpfile          = 'T:'system.prg.name'.tmp'
				system.mm.logpre        = getclip('MM_LogPre')
				system.prg.logpre       = system.mm.logpre'|'
				call setclip('MM_LogPre', system.prg.logpre)
				system.cmdopts          = ',AREA/A,START,POSTMSG/S,SINCELAST/S,TOTAL/K,EXPORT/S,SMALLHEADER/S,NOUSEHEADER/S,NOPOSTERSTATS/S,NORECEIVERSTATS/S,NOSUBJECTSTATS/S,NOQUOTERSTATS/S,NONODESTATS/S,NOTEARSTATS/S,NOTIMESTATS/S,NOMISCSTATS/S'
				system.prg.loglevel     = 3

				call Include_Lib('rexxsupport')
/*      call Include_Lib('rexxtricks')  */

				drop user.
				drop subject.

return


Include_Lib: procedure Expose system.

	 parse arg lib, prio
	 if right(upper(lib), 8)~='.LIBRARY' then lib = lib'.library'
	 if prio='' then prio       = 0

	 if ~show('l', lib) then
			if ~addlib(lib, prio, -30, 0) then call Quit(20, 'Could not open' lib'!!!')

return


IOerr:

				signal off ioerr

				return_code             = 20
				error_line    = sigl
				error_msg                       = 'IO-error' rc 'at line' sigl '['errortext(rc)']')
				rc                                              = 0
signal Exit


Log: procedure Expose system.

				parse arg text, pre, level

				if ~datatype(level, 'N') then level = system.prg.loglevel

				tmp             = word('PRG MM', (pre~='')+1)
				text    = system.tmp.logpre || pre' 'text

				MM_WriteLog 'text' level
return


Parse_Args: procedure Expose system.

				parse arg args

				tpl   = system.cmdopts',?/S'
				args  = translate(args, '  ', '9'x'=')

				pk    = pos('/K', tpl)
				ps    = pos('/S', tpl)

				select
								when pk=0 & ps=0        then    p = 0
								when pk=0 & ps>0        then    p = ps
								when ps=0 & pk>0        then    p = pk
								otherwise                       p = min(pk, ps)
				end

				p     = lastpos(',', left(tpl, p))
				tpl   = substr(tpl, p+1) || left(tpl, max(p-1, 0))

				do while tpl~=''
								parse var tpl template ',' tpl
								parse var template keyword '/' .

								bool    = pos('/S', template)>0
								key     = pos('/K', template)>0
								must    = pos('/A', template)>0
								num     = pos('/N', template)>0

								select
												when must       then            system.arg.keyword      = '0'x
												when bool       then            system.arg.keyword      = 0
												when num        then            system.arg.keyword      = 0

												otherwise                       system.arg.keyword      = ''
								end

								if bool | key   then    mode    = ~bool
								else                                                            mode    = 2

								system.arg.keyword      = Get_Arg(keyword, mode, system.arg.keyword)

								if keyword='?' & system.arg.keyword=1 then leave

								if must & system.arg.keyword='0'x then
												do
																tmp     = template 'missing!!!'

																say
																say ' ***' tmp '***'

																signal Usage
												end

								if num & ~datatype(system.arg.keyword, 'N') then
												if ~must & system.arg.keyword='' then   system.arg.keyword      = 0
												else
																do
																				tmp     = 'Numeric value expected for' template', but is "'system.arg.keyword'"!!!'

																				say
																				say ' ***' tmp '***'

																				signal Usage
																end
				end

				tmp     = '?'; if system.arg.tmp then signal Usage

				if args~='' then call Quit(10, 'Unknown option(s):' args)


				/* additional checks... */


				system.arg.area = upper(system.arg.area)

return


Quit:

				parse arg return_code, error_msg

				error_line    = 0
				rc                                              = 0
signal Exit


Read_Cfg: procedure Expose system. config.

				MM_ReadStem system.prg.cfg 'cfg'
				if RC~=0 then call Quit(31, 'Unable to read' system.prg.cfg'!!!')

				call Log('Reading config...')

				cnt     = 0

				/* Defaults
				 */
				config.total_output = 20
				config.blacklist = 57
				config.decint = 'DECIMAL'

				do l=0 to cfg.count-1
								parse value strip(translate(cfg.l, ' ', '9'x)) with key args ';' .
								key     = upper(strip(key))
								args    = strip(args)

								select
												when key=''               then iterate

												when key='#TOTAL'         then do
													if system.arg.total ~= '' then
														config.total_output = system.arg.total
													else
														config.total_output = args
												end

												when key='#BLACKLIST'     then config.blacklist = args

												when key='#DECINT'        then config.decint = args

												when key='#FROM'          then config.from = args
												when key='#TO'            then config.to_name = args
												when key='#SUBJECT'       then config.subject = args

												when key='#SMALLHEADER'   then
				if system.arg.smallheader then
					config.smallheader = 'YES'
				else
					config.smallheader = args
												when key='#USEHEADER'     then
				if system.arg.nouseheader then
					config.useheader = 'NO'
				else
					config.useheader = args
												when key='#POSTERSTATS'   then
				if system.arg.noposterstats then
					config.posterstats = 'NO'
				else
					config.posterstats = args
												when key='#RECEIVERSTATS' then
				if system.arg.noreceiverstats then
					config.receiverstats = 'NO'
				else
					config.receiverstats = args
												when key='#SUBJECTSTATS'  then
				if system.arg.nosubjectstats then
					config.subjectstats = 'NO'
				else
					config.subjectstats = args
												when key='#QUOTERSTATS'   then
				if system.arg.noquoterstats then
					config.quoterstats = 'NO'
				else
					config.quoterstats = args
												when key='#NODESTATS'     then
				if system.arg.nonodestats then
					config.nodestats = 'NO'
				else
					config.nodestats = args
												when key='#TEARSTATS'     then
				if system.arg.notearstats then
					config.tearstats = 'NO'
				else
					config.tearstats = args
												when key='#TIMESTATS'     then
				if system.arg.notimestats then
					config.timestats = 'NO'
				else
					config.timestats = args

												when key='#MISCSTATS'     then
				if system.arg.nomiscstats then
					config.miscstats = 'NO'
				else
					config.miscstats = args

												when key='#POSTERPOINTS'     then
												config.posterpoints = args


												when key='#USETEARSW'       then config.usetearsw = upper( args )

												otherwise say '*** CFG-ERROR: Unknown keyword "'key'" at line' l'!!!'
								end

								cnt     = cnt+1
				end

return


Replace: procedure

				parse arg string, new, old

				do while index(string, old) ~= 0
								interpret "parse var string l '"old"' r"
								string = l || new || r
				end

return string


Syntax:

				signal off syntax

				return_code             = 40
				error_line    = sigl
				error_msg                       = 'Syntax-error' rc 'at line' sigl '['errortext(rc)']'
				rc                                              = 0
signal Exit


Usage:

				rx.     = ''
				rx.0.0  = '[rx] '
				rx.0.1  = '[.rexx]'
				m       = pos('/e', system.prg.ver)>0

				say
				say 'Usage:' rx.m.0 || system.prg.name || rx.m.1 system.cmdopts
				say
call Quit(0, 'Usage requested.')




/* This is where the real stats code begins
 */


Read_Messages:

				/* Initialise totals to zero */

				total_users     = 0
				total_receivers = 0
				total_subjects  = 0
				total_bbs       = 0
				total_tear      = 0

				total_msgid     = 0
				total_reply     = 0
				total_chrs      = 0
				total_pid       = 0
				total_tid       = 0
				total_mood      = 0
				total_gif       = 0

				total_notear    = 0   /* total msgs with no tear line */

				total_path      = 0   /* highest total of nodes on msg's ^aPATH: lines */
				total_seenby    = 0   /* highest total of nodes on msg's SEEN-BY: lines */
				total_headerlines = 0
				total_textlines = 0
				total_footerlines = 0

				total_longtear  = 0   /* number of tear lines which are too long (>35 chars) */
				total_longorigin  = 0 /* number of origin lines which are too long (>79 chars) */

				/* For the time usage graphs */

				hour0001  = 0
				hour0203  = 0
				hour0405  = 0
				hour0607  = 0
				hour0809  = 0
				hour1011  = 0
				hour1213  = 0
				hour1415  = 0
				hour1617  = 0
				hour1819  = 0
				hour2021  = 0
				hour2223  = 0

				drop LMSGS.
				drop SMSGS.
				drop WMSG.
				drop multiareas.

				multiareas.count = 0
				totalmsgs = 0

				if Open(fh, system.arg.area, "R") then
					multi = 1
				else
					multi = 0

multiloop:

				if multi = 1 then
					system.arg.area=ReadLN( fh )

				if length(system.arg.area) = 0 then
					signal endmulti
				else do
					multiareas.count = multiareas.count+1
					i = multiareas.count
					multiareas.i = system.arg.area
					end

				MM_ListMsgs system.arg.area LMSGS

				if RC = 4 then
					 Call Quit(20,'Area 'system.arg.area' does not exist !')

				if system.arg.start ~= '' then
					 if system.arg.start > LMSGS.COUNT then
							system.arg.start = 'ALL'

				if upper(system.arg.start) = 'ALL' then startmsg = 0

				if system.arg.start ~= '' then
					 if datatype(system.arg.start,'N') then startmsg = LMSGS.COUNT-system.arg.start

				if datatype(startmsg,'N') = 0 then startmsg = 0


				if system.arg.sincelast = 1 then do

					if config.from ~= 'CONFIG.FROM' then
						 WMSG.FROM = config.from
					else
						 MM_GetSysOp 'WMSG.FROM'

					if config.to_name = 'CONFIG.TO_NAME' then
						 WMSG.TO = 'All'
					else
						 WMSG.TO = config.to_name

					if config.subject = 'CONFIG.SUBJECT' then
						 WMSG.SUBJ = 'Area Statistics : '|| Date() ||' for '|| system.arg.area
					else do
						 config.subject = replace(config.subject,system.arg.area,'%AREA')
						 config.subject = replace(config.subject,Date(),'%DATE')
						 WMSG.SUBJ = config.subject
						 end

					MM_SearchMsgs system.arg.area SMSGS '"'WMSG.FROM'"' '"'WMSG.TO'"' '"'left(WMSG.SUBJ,5)'#?"' !IMP

					if SMSGS.COUNT > 0 then do
						numb = SMSGS.COUNT-1
						startmsg = SMSGS.numb
						end
					else
						call Log('No messages for SINCELAST found - using 'startmsg' instead')

				END /* If SinceLast ... */


				call Log('Parsing '|| LMSGS.COUNT-startmsg ||' messages in '|| system.arg.area ||'...')

				totalmsgs=totalmsgs+(LMSGS.COUNT-startmsg)

				do i = startmsg to LMSGS.COUNT-1

					 found_user     = 0
					 found_receiver = 0
					 found_subject  = 0
					 found_bbs      = 0
					 found_tear     = 0

					 MM_ReadMsg system.arg.area LMSGS.i.NUM MSG


					total_headerlines = total_headerlines + MSG.head.count-1
					total_textlines = total_textlines + msg.text.count-1
					total_footerlines = total_footerlines + msg.foot.count-1


					 /* First strip any "Re: " out of the subject line */
					 if index(upper(MSG.SUBJ),"RE: ") ~= 0 then do
							MSG.SUBJ = right(MSG.SUBJ,(length(MSG.SUBJ)-4))
							end

					 do j = 1 to total_users
							if upper(MSG.FROM) = upper(user.j.name) then do
								 user.j.number  = user.j.number+1
								 found_user = 1

								 do k = 0 to MSG.TEXT.COUNT-1
										if index(MSG.TEXT.k,">")>0 & index(MSG.TEXT.k,">")<6 then do
											 if datatype(user.j.quote,'N') = 0 then user.j.quote = 0
											 user.j.quote = user.j.quote + 1                            /* set the amount the user /has/ quoted in every message */
											 end
										else if MSG.TEXT.k ~= "" then do
											 if datatype(user.j.noquote,'N') = 0 then user.j.noquote = 0
											 user.j.noquote = user.j.noquote + 1                        /* set the amount the user has *NOT* quoted in every message */
											 end /* if index( ... */
										end /* do k = ... */

								 end /* if MSG.FROM ... */
							end /* do loop - users */

					 do j = 1 to total_receivers
							if upper(MSG.TO) = upper(receiver.j.name) then do
								 receiver.j.number  = receiver.j.number+1
								 found_receiver = 1
								 end
							end /* do loop - receivers */

					 do j = 1 to total_subjects
							if upper(MSG.SUBJ) = upper(subject.j.text) then do
								 subject.j.number = subject.j.number+1
								 found_subject = 1
								 end
							end /* do loop - subjects */

					 do j = 1 to total_bbs
							if left((MSG.FROMADDR),((index((MSG.FROMADDR),".",1))-1)) = bbs.j.addr then do
								 bbs.j.number = bbs.j.number+1
								 found_bbs = 1
								 end
							end /* do loop - BBS's */

					 if left(MSG.FOOT.0,3) = '---' then do
						 if config.miscstats='YES' then
								if length( MSG.FOOT.0 ) > 35 then total_longtear = total_longtear + 1
						 if config.tearstats='YES' then do
							 if (config.usetearsw='YES') & (words( MSG.FOOT.0 ) > 2) then
								 /* is it *not* "--- Soft v1.0" or "--- Soft #12", but "--- Soft Ware" ? */
								 if ( index( word( MSG.FOOT.0, 3 ), '.' ) = 0 ) & ( index( word( MSG.FOOT.0, 3 ), '#' ) = 0 ) then do
									 if words( MSG.FOOT.0 ) > 3 then  /* e.g. "--- Mail Manager v1.22" ? */
										 MSG.FOOT.0 = left( MSG.FOOT.0, wordindex( MSG.FOOT.0, 4 )-2 )
									 /* otherwise it's "--- Soft Ware" - which is okay, so no need for an else */
								 end
								 else do
									 MSG.FOOT.0 = left( MSG.FOOT.0, wordindex( MSG.FOOT.0, 3 )-2 )
								 end
							 do j = 1 to total_tear
									if MSG.FOOT.0 = tear.j.text then do
											tear.j.number = tear.j.number+1
											found_tear = 1
											end
									end /* do loop - tear */
						 end /* if config.tearstats */
					 end /* if left... */
					 else do
							/* no tear line */
							total_notear = total_notear + 1
					 end

					 /* measure ^aPATH: and SEEN-BY: lines and other footer checks. */
					 pathsize = 0
					 seenbysize = 0
					 do k = 0 to MSG.FOOT.COUNT-1
							if left( msg.foot.k, 7 ) = '1'x || 'PATH: ' then do
								pathsize = pathsize + words( msg.foot.k ) - 1 /* minus PATH: itself */
							end
							if left( msg.foot.k, 9 ) = 'SEEN-BY: ' then do
								seenbysize = seenbysize + words( msg.foot.k ) - 1 /* minus SEEN-BY: itself */
							end
							if left( msg.foot.k, 11 ) = ' * Origin: ' then
								if length( msg.foot.k ) > 79 then
									total_longorigin = total_longorigin + 1
					 end /* do k */
					 /* check if we have any new records */
					 if pathsize > total_path then total_path = pathsize
					 if seenbysize > total_seenby then total_seenby = seenbysize


					 /* Kludge detection code.
						* No doubt this will become infamous very quickly...
						*/
					 if (upper(config.smallheader) ~= 'YES') & (upper(config.useheader) = 'YES') then do
							do j = 0 to MSG.HEAD.COUNT-1
								if left(MSG.HEAD.j, 8) = '01'x || 'MSGID: ' then
									total_msgid = total_msgid + 1
								if left(MSG.HEAD.j, 8) = '01'x || 'REPLY: ' then
									total_reply = total_reply + 1
								if left(MSG.HEAD.j, 7) = '01'x || 'CHRS: ' then
									total_chrs = total_chrs + 1
								if left(MSG.HEAD.j, 5) = '01'x || 'PID: ' then
									total_pid = total_pid + 1
								if left(MSG.HEAD.j, 5) = '01'x || 'TID: ' then
									total_tid = total_tid + 1
								if left(MSG.HEAD.j, 6) = '01'x || 'MOOD: ' then
									total_mood = total_mood + 1
								if left(MSG.HEAD.j, 6) = '01'x || 'GIF: ' then
									total_gif = total_gif + 1
							end
					 End /* if upper(config. ... */


					 /* Check times the message was written. Ohhh the code looks
						* dodgy ;)  I'm sure this could be sped up!
						*/
					 select
							when (left((right(MSG.DATE,8)),2)='00') | (left((right(MSG.DATE,8)),2)='01')   then hour0001 = hour0001 + 1
							when (left((right(MSG.DATE,8)),2)='02') | (left((right(MSG.DATE,8)),2)='03')   then hour0203 = hour0203 + 1
							when (left((right(MSG.DATE,8)),2)='04') | (left((right(MSG.DATE,8)),2)='05')   then hour0405 = hour0405 + 1
							when (left((right(MSG.DATE,8)),2)='06') | (left((right(MSG.DATE,8)),2)='07')   then hour0607 = hour0607 + 1
							when (left((right(MSG.DATE,8)),2)='08') | (left((right(MSG.DATE,8)),2)='09')   then hour0809 = hour0809 + 1
							when (left((right(MSG.DATE,8)),2)='10') | (left((right(MSG.DATE,8)),2)='11')   then hour1011 = hour1011 + 1
							when (left((right(MSG.DATE,8)),2)='12') | (left((right(MSG.DATE,8)),2)='13')   then hour1213 = hour1213 + 1
							when (left((right(MSG.DATE,8)),2)='14') | (left((right(MSG.DATE,8)),2)='15')   then hour1415 = hour1415 + 1
							when (left((right(MSG.DATE,8)),2)='16') | (left((right(MSG.DATE,8)),2)='17')   then hour1617 = hour1617 + 1
							when (left((right(MSG.DATE,8)),2)='18') | (left((right(MSG.DATE,8)),2)='19')   then hour1819 = hour1819 + 1
							when (left((right(MSG.DATE,8)),2)='20') | (left((right(MSG.DATE,8)),2)='21')   then hour2021 = hour2021 + 1
							when (left((right(MSG.DATE,8)),2)='22') | (left((right(MSG.DATE,8)),2)='23')   then hour2223 = hour2223 + 1

							otherwise say 'unknown hour'
							end

					 if found_user ~= 1 then do
							total_users = total_users +1
							user.total_users.name = MSG.FROM
							user.total_users.address = MSG.FROMADDR
							user.total_users.number = 1

							do k = 0 to MSG.TEXT.COUNT-1
										if index(MSG.TEXT.k,">")>1 & index(MSG.TEXT.k,">")<6 then do
											 if datatype(user.total_users.quote,'N') = 0 then user.total_users.quote = 0
											 user.total_users.quote = user.total_users.quote + 1                            /* set the amount the user /has/ quoted in every message */
											 end
										else if MSG.TEXT.k ~= "" then do
											 if datatype(user.total_users.noquote,'N') = 0 then user.total_users.noquote = 0
											 user.total_users.noquote = user.total_users.noquote + 1      /* set the amount the user has *NOT* quoted in every message */
											 end /* if index( ... */
										end /* do k = ... */

							end

					 if found_receiver ~= 1 then do
							total_receivers = total_receivers +1
							receiver.total_receivers.name = MSG.TO
							receiver.total_receivers.number = 1
							end

					 if found_subject ~= 1 then do
							total_subjects = total_subjects +1
							subject.total_subjects.text = MSG.SUBJ
							subject.total_subjects.number = 1
							end

					 if found_bbs ~= 1 then do
							total_bbs = total_bbs +1
							bbs.total_bbs.addr = left((MSG.FROMADDR),((index((MSG.FROMADDR),".",1))-1))
							bbs.total_bbs.number = 1
							end

					 if found_tear ~= 1 then do
							if left(MSG.FOOT.0,3) = '---' then do
								total_tear = total_tear +1
								tear.total_tear.text = MSG.FOOT.0
								tear.total_tear.number = 1
								end
							end

					 end /* do loop - message range */


					 /* Calculate the amount the users have quoted in percentage format
						*/

					 do i = 1 to total_users

							if (user.i.quote ~= 0) & (user.i.quote ~= 'USER.'|| i ||'.QUOTE') then
								 user.i.quoted = int((user.i.quote/(user.i.noquote+user.i.quote))*100)
							else
								 user.i.quoted = 0

							end /* do i = ... */

					if multi = 1 then
						if ~EOF(fh) then
							signal multiloop

endmulti:
					if multi then
						call Close(fh)

				call Log()
				call Log('Sorting and saving statistics...')
				call open(OutFile,system.tmpfile,'W')

				if upper(config.useheader)     = 'YES' then call MsgHeader()
				if upper(config.posterstats)   = 'YES' then call UserStats()
				if upper(config.receiverstats) = 'YES' then call ReceiverStats()
				if upper(config.subjectstats)  = 'YES' then call SubjectStats()
				if upper(config.quoterstats)   = 'YES' then call QuoterStats()
				if upper(config.tearstats)     = 'YES' then call TearStats()
				if upper(config.nodestats)     = 'YES' then call NodeStats()
				if upper(config.timestats)     = 'YES' then call TimeStats()
				if upper(config.miscstats)     = 'YES' then call MiscStats()

				if system.arg.postmsg = 0 then
					 Call WriteLN(OutFile,'Created by '|| system.prg.id ||' '|| system.prg.cr)

				call close(OutFile)
return




/***************************************************************************/
/* Int(). Returns an an integer from a specified number.                   */
/***************************************************************************/

int: procedure Expose config.

	parse arg number

	if upper(config.decint) = 'INTEGER' then do
		 if index(number,".") ~= 0 then
				result = left(number,(index(number,".")-1))
		 else
				result = number

		 end /* if config... */
	else do
		 if index(number,".") ~= 0 then
				result = left(number,(index(number,".")+1))
		 else
				result = number

		 end /* if config ... else ... */

return result


/* Does an integer return no matter what the prefs say
 */

int2: procedure

	parse arg number

	if index(number,".") ~= 0 then do
		 if left((right(number,(index(number,".")-1))),1) > '4' then number = number + 1 else nop
		 result = left(number,(index(number,".")-1))
		 end
	else
		 result = number

return result


/*
 * PostMsg - Writes the statistics into the area
 *
 * See also : SaveMsg
 */

PostMsg:

				call Log('Writing statistics in 'system.arg.area)

				drop WMSG.

				if config.from ~= 'CONFIG.FROM' then    /* if WMSG.FROM = 'WMSG.FROM' then MM uses Default SysOp. If WMSG.FROM = '' then MM uses '' ... */
					 WMSG.FROM = config.from

				if config.to_name = 'CONFIG.TO_NAME' then
					 WMSG.TO = 'All'
				else
					 WMSG.TO = config.to_name

				if config.subject = 'CONFIG.SUBJECT' then
					 WMSG.SUBJ = 'Area Statistics : '|| Date() ||' for '|| system.arg.area
				else do
					 config.subject = replace(config.subject,system.arg.area,'%AREA')
					 config.subject = replace(config.subject,Date(),'%DATE')
					 WMSG.SUBJ = config.subject
					 end

				WMSG.TEAR   = system.prg.id
				WMSG.ORIGIN = 'Created by '|| system.prg.id ||' '|| system.prg.cr
				WMSG.FILE   = system.tmpfile

				MM_WriteMsg system.arg.area WMSG

				if RC = 0 then
					 call Log('... successful')
				else
					 call Log('... error writing message !')

				if system.arg.export then
					 MM_Export system.arg.area


return



/* Simply a header stuck on the top of the stats showing some info
 */

MsgHeader:

				call Log('... creating header')

				call writeln(OutFile,'             .--------------------------------------------.')
				if multi then do
					call writeln(OutFile,'             | Statistics for areas :                     |')
					if multiareas.count > 1 then do
						do i = 2 to multiareas.count+1 by 2
							num=i-1

							if multiareas.i ~= 'MULTIAREAS.'i then
								item1 = multiareas.i
							else
								item1 = ''
							if multiareas.num ~= 'MULTIAREAS.'num then
								item2 = multiareas.num
							else
								item2 = ''

							call writeln(OutFile,'             | '|| right(item1,19) ||' - '|| left(item2,20) ||' |')
							end
						end
					end
				else
					call writeln(OutFile,'             | Statistics for area : '|| left(system.arg.area,20) || ' |')
				call writeln(OutFile,'             | Date created        : '|| left((date() ||' '|| time()),20) || ' |')
				call writeln(OutFile,'             | Number of messages  : '|| left(totalmsgs,20) ||' |')
				if upper(config.smallheader)     ~= 'YES' then do
					call writeln(OutFile,'             | of which:         '|| right(total_msgid, 4) ||' had MSGID: kludges, |')
					call writeln(OutFile,'             |  '|| right(total_chrs, 4) ||' had CHRS: ,    '|| right(total_reply, 4) ||' had REPLY: ,     |')
					call writeln(OutFile,'             |  '|| right(total_pid, 4) ||' had PID: ,     '|| right(total_tid, 4) ||' had TID: ,       |')
					call writeln(OutFile,'             |  '|| right(total_mood, 4) ||' had MOOD: ,    '|| right(total_gif, 4) ||' had GIF:         |')
				End /* if upper(config. ... */
				call writeln(OutFile,'             `--------------------------------------------''')
				call writeln(OutFile,'')

return



/* Stats on who's posted messages.
 */

UserStats:

				call Log('... users')

				Call WriteLN(OutFile,'         .-------------------------------.')
				Call WriteLN(OutFile,'         | Message Writers   : Total '|| left(total_users,3) ||' |')
				Call WriteLN(OutFile,' .-------+-------------------------------+-----------------------------.')
				Call WriteLN(OutFile,' | No.     Name                   Address          Msgs Posted  Quoted |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_users

						highest = 0 ; writer = 0

						do i = 1 to total_users
							 if user.i.number >= highest & user.i.used ~= 'TRUE' then do
									writer   = user.i.name
									highest  = user.i.number
									useraddr = user.i.address

									if user.i.quoted >= config.blacklist then do
										 extra_text = '!'
										 extra_! = 1
										 end
									else
										 extra_text = ' '

									/* look up the points address, or their bosses address?
									 */
									if upper(config.posterpoints) = 'YES' then
										MM_GetNodelistNode useraddr nodeinfo
									else
										MM_GetNodelistNode left((useraddr),((index((useraddr),".",1))-1)) nodeinfo

									if RC = 4 then do
										/* System not in the nodelist
										 */
										extra_text = extra_text || '# '
										extra_# = 1
									end
									else
										extra_text = extra_text || '  '


									num      = i
									End
							 End

						user.num.used='TRUE'

						writer     = overlay('.........................................................................',writer,(length(writer)+2))
						useraddr   = overlay('..................',(left(useraddr,(index(useraddr,"@")-1))),(length((left(useraddr,(index(useraddr,"@")-1))))+2))
						quotedtxt  = overlay(user.num.quoted,'..................',20)
						highesttxt = overlay(highest,'..................',20)
						highestpct = overlay(('('||int((highest/totalmsgs)*100)||'%)'),'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'.' || extra_text || left(writer,24-num_len)' 'left(useraddr,16) || right(highesttxt,5) ||' '|| right(highestpct,8) ||' '|| right(quotedtxt,6) ||'% |'

						Call WriteLN(OutFile,line)

						If Iteration=config.total_output then break
						End

				if (extra_! = 1) | (extra_# = 1) then do
					 Call WriteLN(OutFile,' +---------------------------------------------------------------------+')
					 end
				if extra_! = 1 then do
					 Call WriteLN(OutFile,' | NB: ! = Quoting level is considered excessive                       |')
					 end
				if extra_# = 1 then do
					 Call WriteLN(OutFile,' | NB: # = Node is not in the current nodelist                         |')
					 end

				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')

				extra_!    = 0
				extra_text = '   '

				Call WriteLN(OutFile,'')

return




/* Stats on who has received messages, and how many.
 */

ReceiverStats:

				call Log('... receivers')

				Call WriteLN(OutFile,'         .-------------------------------.')
				Call WriteLN(OutFile,'         | Message Receivers : Total '|| left(total_receivers,3) ||' |')
				Call WriteLN(OutFile,' .-------+-------------------------------+-----------------------------.')
				Call WriteLN(OutFile,' | No. Receiver                                        No. of messages |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_receivers

						highest = 0 ; receivertxt = 0

						do i = 1 to total_receivers
							 if receiver.i.number >= highest & receiver.i.used ~= 'TRUE' then do
									receivertxt=receiver.i.name
									highest=receiver.i.number
									num = i
									End
							 End

						receiver.num.used='TRUE'

						receivertxt = overlay('.........................................................................',receivertxt,(length(receivertxt)+2))
						highesttxt = overlay(highest,'..................',20)
						highestpct = overlay(('('||int((highest/totalmsgs)*100)||'%)'),'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'. ' || left(receivertxt,50-num_len) || right(highesttxt,5) ||' '|| right(highestpct,9) ||' |'

						Call WriteLN(OutFile,line)

						If iteration=config.total_output then break
						End

				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')
				Call WriteLN(OutFile,'')

return



/* Stats on subjects talked about, and popularity */

SubjectStats:

				call Log('... subjects')

				Call WriteLN(OutFile,'         .-------------------------------.')
				Call WriteLN(OutFile,'         | Message Subjects  : Total '|| left(total_subjects,3) ||' |')
				Call WriteLN(OutFile,' .-------+-------------------------------+-----------------------------.')
				Call WriteLN(OutFile,' | No. Subject                                         No. of messages |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_subjects

						highest = 0 ; sub = 0

						do i = 1 to total_subjects
							 if subject.i.number >= highest & subject.i.used ~= 'TRUE' then do
									sub=subject.i.text
									highest=subject.i.number
									num = i
									End
							 End

						subject.num.used='TRUE'

						sub        = overlay('.........................................................................',sub,(length(sub)+2))
						highesttxt = overlay(highest,'..................',20)
						highestpct = overlay(('('||int((highest/(totalmsgs))*100)||'%)'),'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'. ' || left(sub,50-num_len) || right(highesttxt,5) ||' '|| right(highestpct,9) ||' |'

						Call WriteLN(OutFile,line)

						If iteration=config.total_output then break
						End

				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')
				Call WriteLN(OutFile,'')

return




/* The "Quoter Blacklist" */

QuoterStats:

				call Log('... quoters')

				/* First, the "used" flag needs to be removed from the previous
				 * operation on the users. Also calculates the number of black listed.
				 */

				blacklisted = 0

				/* for calculating total quoted lines in the message spread */
				total_quote = 0
				total_noquote = 0
				total_quoted = 0

				do i = 1 to total_users
					 user.i.used = 0

					 if (user.i.quote ~= 'USER.'|| i ||'.QUOTE') then do
						 if (user.i.noquote ~= 'USER.'|| i ||'.QUOTE') then
							 total_quote = total_quote + user.i.quote       /* quote hold total number of lines which were quoted */
							 total_noquote = total_noquote + user.i.noquote /* noquote hold total number of lines which were not quoted */

						 if (user.i.quoted >= config.blacklist) & (user.i.quote ~= 'USER.'|| i ||'.QUOTE') then
								blacklisted = blacklisted + 1

						end /* if (user.i.quote ... */

					 end /* do i = ... */

				if total_quote = 0 then do
					total_quoted = 0
				end
				else do
					total_quoted = int((total_quote/(total_noquote+total_quote))*100)
				end

				Call WriteLN(OutFile,'         .-----------------------------.')
				Call WriteLN(OutFile,'         | Black list of quoters : '|| left(blacklisted,3) ||' |')
				Call WriteLN(OutFile,' .-------+-----------------------------+-------------------------------.')
				Call WriteLN(OutFile,' | No.   Name                                    Msgs Posted  Quoted % |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_users

						highest = 0 ; writer = 0 ; quotedtxt = 0

						do i = 1 to total_users
							 if user.i.quoted >= highest & user.i.used ~= 'TRUE' then do
									writer    = user.i.name
									highest   = user.i.quoted
									number_posted = user.i.number
									quotedtxt = user.i.quoted

									if user.i.quoted >= config.blacklist then do
										 extra_text = ' ! '
										 extra_! = 1
										 end
									else
										 extra_text = '   '

									num       = i
									End
							 End

						user.num.used='TRUE'

						writer     = overlay('.........................................................................',writer,(length(writer)+2))
						quotedtxt  = overlay(quotedtxt,'..................',20)
						highesttxt = overlay(number_posted,'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'.' || extra_text || left(writer,48-num_len) || right(highesttxt,5) ||' '|| right(quotedtxt,7) ||'%  |'

						Call WriteLN(OutFile,line)

						If Iteration=config.total_output then break
						End

				if total_quoted > 0 then do
					 Call WriteLN(OutFile,' +---------------------------------------------------------------------+')
					 Call WriteLN(OutFile,' | NB: Percentage of quoted text in messages parsed: '|| right( total_quoted, 4 ) ||'%             |')
					 end

				if extra_! = 1 then do
					 Call WriteLN(OutFile,' +---------------------------------------------------------------------+')
					 Call WriteLN(OutFile,' | NB: ! = Quoting level is considered excessive                       |')
					 end

					Call WriteLN(OutFile,' `---------------------------------------------------------------------''')


				extra_!    = 0
				extra_text = '   '

				Call WriteLN(OutFile,'')

return




/* Stats on the tear lines used or the most popular software
 */

TearStats:

				call Log('... tear lines')

				Call WriteLN(OutFile,'         .--------------------------------.')
				if (config.usetearsw='YES') then do
					Call WriteLN(OutFile,'         | Popular Software   : Total '|| left(total_tear,3) ||' |')
				end
				else do
					Call WriteLN(OutFile,'         | Message Tear Lines : Total '|| left(total_tear,3) ||' |')
				end

				Call WriteLN(OutFile,' .-------+--------------------------------+----------------------------.')
				Call WriteLN(OutFile,' | No.  Tear Line                                          Number Used |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_tear

						highest = 0 ; tearline = 0

						do i = 1 to total_tear
							 if tear.i.number >= highest & tear.i.used ~= 'TRUE' then do
									tearline=tear.i.text
									highest=tear.i.number
									num = i
									End
							 End

						tear.num.used='TRUE'

						tearline   = overlay('.........................................................................',tearline,(length(tearline)+2))
						highesttxt = overlay(highest,'..................',20)
						highestpct = overlay(('('||int((highest/(totalmsgs))*100)||'%)'),'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'. ' || left(tearline,50-num_len) || right(highesttxt,5) ||' '|| right(highestpct,9) ||' |'

						Call WriteLN(OutFile,line)

						If iteration=config.total_output then break
						End

				if total_notear > 0 then do
					Call WriteLN(OutFile,' +---------------------------------------------------------------------+')
					Call WriteLN(OutFile,' | NB: Messages with no tear line : '|| left( total_notear, 5 ) ||'                              |')
					end

				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')
				Call WriteLN(OutFile,'')

return




/* Which BBS is most popular/has most active users */

NodeStats:

				call Log('... nodes')

				drop NINFO.

				Call WriteLN(OutFile,'         .-----------------------------------.')
				Call WriteLN(OutFile,'         | Echomail Originators  : Total '|| left(total_bbs,3) ||' |')
				Call WriteLN(OutFile,' .-------+-----------------------------------+-------------------------.')
				Call WriteLN(OutFile,' | No. BBS / Node          Address      Location          Msgs Posted  |')
				Call WriteLN(OutFile,' +---------------------------------------------------------------------+')

				Do Iteration=1 to total_bbs

						highest = 0 ; address = 0

						do i = 1 to total_bbs
							 if bbs.i.number >= highest & bbs.i.used ~= 'TRUE' then do
									address=bbs.i.addr
									highest=bbs.i.number
									num = i
									End
							 End

						bbs.num.used='TRUE'

						MM_GetNodelistNode address NINFO

						if RC = 4 then do
							 NINFO.SYSTEM = 'Not in nodelist'
							 NINFO.CITY   = 'N/A'
							 end
						if (RC = 5) | (ninfo.system = 'NINFO.SYSTEM') then do
							 call Log('I can''t open the nodelists !',,1)
							 NINFO.SYSTEM = '...........'
							 NINFO.CITY   = '...........'
							 end

						NINFO.SYSTEM = overlay('...........................................',NINFO.SYSTEM,(length(NINFO.SYSTEM)+2))
						NINFO.CITY   = overlay('....................',NINFO.CITY,(length(NINFO.CITY)+2))
						address     = overlay('....................',address,(length(address)+2))
						highesttxt  = overlay(highest,'..................',20)
						highestpct  = overlay(('('||int((highest/(totalmsgs))*100)||'%)'),'..................',20)

						num_len = length(Iteration)
						if num_len < 2 then do
							num_len = 2
						end

						line=' | '|| right(Iteration,num_len)||'. ' || left(NINFO.SYSTEM,20-num_len) ||' '|| left(address,12) ||' '|| left(NINFO.CITY,17) || right(highesttxt,5) ||' '|| right(highestpct,8) ||' |'

						Call WriteLN(OutFile,line)

						If iteration=config.total_output then break
						End

				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')
				Call WriteLN(OutFile,'')

return



/*
 * Draws the time graphs. A bit dodgy maybe, but it is all my code I'm proud to say :)
 */

TimeStats:

		call Log('... time graphs')

		more50pcnt = 0

		if (hour0001/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour0203/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour0405/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour0607/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour0809/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour1011/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour1213/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour1415/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour1617/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour1819/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour2021/(totalmsgs))*100 > 50 then more50pcnt = 1
		if (hour2223/(totalmsgs))*100 > 50 then more50pcnt = 1

		Call WriteLN(OutFile,'         .------------------------------.')
		Call WriteLN(OutFile,'         | Most Popular Messaging Times |')
		Call WriteLN(OutFile,' .-------+-------+----------------------+------------------------------.')
		If more50pcnt then
			Call WriteLN(OutFile,' | Time Range    | 1%.........25%...........50%.........75%.......100% |')
		else
			Call WriteLN(OutFile,' | Time Range    | 1%........12.5%..........25%........37.5%.......50% |')
		Call WriteLN(OutFile,' +---------------+-----------------------------------------------------+')

		If more50pcnt then do

				call WriteCH(OutFile,' | 00:00 - 01:59 | ')
				do i = 1 to int2((hour0001/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0001/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 02:00 - 03:59 | ')
				do i = 1 to int2((hour0203/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0203/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 04:00 - 05:59 | ')
				do i = 1 to int2((hour0405/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0405/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 06:00 - 07:59 | ')
				do i = 1 to int2((hour0607/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0607/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 08:00 - 09:59 | ')
				do i = 1 to int2((hour0809/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0809/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 10:00 - 11:59 | ')
				do i = 1 to int2((hour1011/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1011/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 12:00 - 13:59 | ')
				do i = 1 to int2((hour1213/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1213/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 14:00 - 15:59 | ')
				do i = 1 to int2((hour1415/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1415/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 16:00 - 17:59 | ')
				do i = 1 to int2((hour1617/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1617/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 18:00 - 19:59 | ')
				do i = 1 to int2((hour1819/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1819/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 20:00 - 21:59 | ')
				do i = 1 to int2((hour2021/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour2021/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 22:00 - 23:59 | ')
				do i = 1 to int2((hour2223/(totalmsgs))*100/2)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour2223/(totalmsgs))*100/2))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')

			END
		ELSE do

				call WriteCH(OutFile,' | 00:00 - 01:59 | ')
				do i = 1 to int2((hour0001/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0001/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 02:00 - 03:59 | ')
				do i = 1 to int2((hour0203/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0203/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 04:00 - 05:59 | ')
				do i = 1 to int2((hour0405/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0405/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 06:00 - 07:59 | ')
				do i = 1 to int2((hour0607/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0607/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 08:00 - 09:59 | ')
				do i = 1 to int2((hour0809/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour0809/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 10:00 - 11:59 | ')
				do i = 1 to int2((hour1011/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1011/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 12:00 - 13:59 | ')
				do i = 1 to int2((hour1213/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1213/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 14:00 - 15:59 | ')
				do i = 1 to int2((hour1415/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1415/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 16:00 - 17:59 | ')
				do i = 1 to int2((hour1617/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1617/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 18:00 - 19:59 | ')
				do i = 1 to int2((hour1819/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour1819/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 20:00 - 21:59 | ')
				do i = 1 to int2((hour2021/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour2021/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')
			
				call WriteCH(OutFile,' | 22:00 - 23:59 | ')
				do i = 1 to int2((hour2223/(totalmsgs))*100)
					call WriteCH(OutFile,'*')
					end
				do i = 1 to 52-(int2((hour2223/(totalmsgs))*100))
					call WriteCH(OutFile,' ')
					end
				call WriteLN(OutFile,'|')

		END

		Call WriteLN(OutFile,' `---------------+-----------------------------------------------------''')
		Call WriteLN(OutFile,'')

return



/* Some miscellaneous statistics */

MiscStats:

				call Log('... misc')

				Call WriteLN(OutFile,'         .--------------------------.')
				Call WriteLN(OutFile,'         | Miscellaneous Statistics |')
				Call WriteLN(OutFile,' .-------+--------------------------+----------------------------------.')
				Call WriteLN(OutFile,' | Largest PATH: .............................................: '|| right( total_path, 6 ) ||' |')
				Call WriteLN(OutFile,' | Largest SEEN-BY: ..........................................: '|| right( total_seenby, 6 ) ||' |')
				Call WriteLN(OutFile,' | Total header lines (MSGID: etc.) ..........................: '|| right( total_headerlines, 6 ) ||' |')
				Call WriteLN(OutFile,' | Total footer lines (SEEN-BY: etc.) ........................: '|| right( total_footerlines, 6 ) ||' |')
				Call WriteLN(OutFile,' | Total message body lines ..................................: '|| right( total_textlines, 6 ) ||' |')
				Call WriteLN(OutFile,' |          ... total lines ..................................: '|| right( total_textlines+total_footerlines+total_headerlines, 6 ) ||' |')
				Call WriteLN(OutFile,' | Total tear lines over the 35 character standard ...........: '|| right( total_longtear, 6 ) ||' |')
				Call WriteLN(OutFile,' | Total origin lines over the 79 character standard .........: '|| right( total_longorigin, 6 ) ||' |')
				Call WriteLN(OutFile,' `---------------------------------------------------------------------''')
				Call WriteLN(OutFile,'')

return

