const string (11) configoutfile="DBOUT" external routine make db file(string (255) file) !Reads a text file containing bulletin board and distribution list details !for MAILER. If no errors are found, creates file DBOUT which can be given !to MAILER using the command GIVEDBFILE. Both programs can only be run in the !BBOARD process which requires ACR=10 and privileges 8, 18, 25 const integer max servers= 255 const integer max messages= 2000; !IN ANY ONE FOLDER const integer yes=1, no=0 const integer ad entry size= 128 const integer btable entry size=108 const integer dlist type=3 const integer bboard type=4 const integer max bboards=255 const integer max dlists=255 const integer dlist entry size=40 const integer folder marker=x'82828282' const integer default max msgs=128 const integer default fsize=4096 const integer max mailer flags= 530 const string (18) serv file= "MAILER.MAILSERVERS" const string (6) bboard process="BBOARD" const string (81) jobtext= c ".whenever anyfail .then .continue run(bboard.db_useraccy) run bboard.db_useraccy " record format addr entry f(string (31) rname, department, string (7) password, string (15) server, managr, integer timestamp, options, dt last told, fsys, dlist index, link) record format comf(integer ocp type, ipldev, sblks, sepgs, ndiscs, ddtaddr, gpctabsize, gpca, sfctabsize, sfca, sfck, dirsite, dcodeda, suplvn) record format btablef(string (31) bname, title, string (18) folder, byte integer sp0, half integer maxmsgs, maxdays, n msgs, sp1, integer dt last addition, sp2, sp3, sp4) record format dtablef(string (31) dname, integer offset, length) record (dtablef) array format dtable arf(1:max dlists) record format ff(integer end, start, size, filetype, sp0, dt, format, sp1, string (6) bowner, integer n boards, n dlists, board offset, sp2, string (255) jobtext, record (dtablef) array dtab(1:max dlists)) record format paf(integer dest, srce, flag, message count, secs, ident, bad bitcomp, p6) record format rf(integer conad, filetype, datastart, dataend) record format serv f(string (15) name, integer sp0, sp1, sp2) record format serv ff(integer mark, servers, string (15) authority, string (31) dead letters, record (serv f) array serv(1:max servers)) record format f index f(integer dt, (integer offset or byte integer status, x1, x2, x3)) record format folder f(integer end, start, size, filetype, checksum, datetime, format, spare, marker, max msgs, n msgs, sp0, record (f index f) array msg no(1:max messages)) record (btablef) array btab(1:max bboards) record (dtablef) array name dtab system routine spec changefilesize(string (31) file, integer newsize, integer name flag) external routine spec cherish(string (255) s) system routine spec connect(string (31) file, integer mode, hole, prot, record (rf) name r, integer name flag) external routine spec define(string (255) s) external string fn spec derrs(integer flag) external integer fn spec dfstatus(string (6) user, string (11) file, c integer fsys, act, value) external routine spec disconnect(string (255) s) external integer fn spec dmail(record (paf) name p, integer len, adr) external integer fn spec exist(string (31) s) system string fn spec failure message(integer i) system string fn spec itos(integer n) system routine spec move(integer len, from, to) system routine spec outfile(string (31) file, integer size, hole, prot, integer name conad, flag) external routine spec permit(string (255) s) system integer fn spec pstoi(string name s) external string fn spec ucstring(string (255) s) external string fn spec uinfs(integer i) routine spec fail(string (255) reason) integer i, b, lineno, flag, addr file conad, dlists, pt, boards integer conad, d string (255) rest, line, s, matchstring, rname string (31) this host record (paf) pa record (addr entry f) name addr entry record (comf) name com record (serv ff) name server record (ff) name f record (rf) r const string (1) snl=" " const string (28) array mailer flags(501:max mailer flags)= c "Invalid parameters", "Duplicate component:", "Unknown component", "Invalid command", "No valid recipients", "Too many recipients", "Addr table full", "Name table full", "Illegal name", "Mail service closed", "Recipient offline", "Message too long", "", "Missing component:", "No free message descriptors", "Invalid component:", "Total message kb exceeded", "Cannot return report file", "Message stored", "Forbidden component", "Create file fails", "User not accredited", "Invalid password", "Name not accredited", "Name already accredited", "Name belongs to another user", "Uncollected mail for R-name", "Invalid date/time after", "Not allowed in student procs", "Invalid Rname option" on event 9 start fail("input ended") finish routine leadtrail(string name s) length(s) = length(s)-1 while length(s)>0 and charno(s, length(s))=' ' s = substring(s, 2, length(s)) while length(s)>1 and charno(s, 1)=' ' end ; !of leadtrail routine readline integer i lineno = lineno+1 skipsymbol while next symbol=' ' line = "" cycle readsymbol(i) if i=nl then exit line = line.tostring(i) repeat if line->line.("!") start ; finish leadtrail(line) if line="" then readline end ; !of readline string fn compress(string (255) s) integer i string (255) t if s="" then result = "" for i = 1, 1, length(s) cycle if 'A'<=charno(s, i)<='Z' then charno(s, i) = charno(s, i)+32 repeat s = s.t while s->s.(" ").t result = s end ; !of compress string fn uccompress(string (255) s) string (255) t s = s.t while s->s.(" ").t result = ucstring(s) end ; !of uccompress routine check rname(string (31) rname, integer type, string (31) dept, integer level) string (255) s, stype integer flag s = "NAMESERVER INQUIRE ".rname pa = 0 flag = dmail(pa, length(s), addr(s)+1) if flag>0 start ; !name found if level=1 then return ; !no check on ownership addr entry == record(addr file conad+flag*ad entry size) if uccompress(rname)#uccompress(addr entry_rname) then fail("whoops!") if addr entry_managr#bboard process then c fail(rname." belong to ".addr entry_managr." instead of ".bboard process) if level=3 and addr entry_server#this host then fail(rname." belong to another host, ".addr entry_server) if addr entry_options#type then fail(rname." has wrong type in dir entry, ".itos(addr entry_options)) return ; !all checking done finish ; !name not found if level=1 then printstring("Warning - ".rname." not accredited".snl) and return if type=bboard type then stype = "BBOARD" else stype = "DLIST" s = "NAMESERVER ACCREDIT ".rname.",".stype.",,".dept pa = 0 flag = dmail(pa, length(s), addr(s)+1) printstring("Accredit ".stype." ".rname." ") if pa_flag#0 start if pa_flag>500 then printstring(mailer flags(pa_flag)) else printstring(derrs(pa_flag)) finish else printstring("successful") newline end ; !of check rname routine fail(string (255) reason) printstring("Fails on : ".matchstring." (line ".itos(lineno).")".snl." - ".reason.snl) stop end ; !of fail string fn next string (255) res if line="" then fail("should be 'name='") cycle if line->res.(",").line start leadtrail(line) if line="" then readline finish else res = line and line = "" leadtrail(res) matchstring = res result = res repeat end ; !of next routine match(string (31) item) string (255) param readline matchstring = line; !in case of errors unless matchstring->param.("=").line and compress(param)=item then fail("should be '".item."='") leadtrail(line) end ; !of match integer fn check item(string (31) item, integer size) integer i match(item) if size>0 start if length(line)>size then fail("too long") else result = 1 finish i = pstoi(line) unless 0<=i<=(-size) then fail("bad numeric value") result = i end ; !of check item routine noarchive(string (255) file) integer flag string (255) s if file -> s.(".").file start ; finish flag=dfstatus(uinfs(1),uccompress(file),-1,17,0) end ;!of noarchive routine check or create folder(string (255) file) record (folder f) name cf integer flag, conad connect(file, 0, 0, 0, r, flag) if flag=0 start if integer(r_conad+32)#folder marker then fail(file." is not a folder") noarchive(file) finish else start if exist(file)#0 then fail(failure message(flag)) outfile(file, default fsize, 0, 0, conad, flag) if flag=0 start cf == record(conad) cf_end = addr(cf_msg no(default max msgs))-conad+8 cf_start = cf_end cf_size = default fsize cf_filetype = 4 cf_format = 3; !UNSTRUCTURED cf_marker = folder marker cf_max msgs = default max msgs cf_n msgs = 0 printstring("Folder ".file." created".snl) cherish(file) noarchive(file) finish else start fail("Create folder ".file." fails ".failure message(flag).snl) finish finish end ; !of check folder routine last message details(string (31) file, integer bno) record (folder f) name cf integer flag, conad, dt connect(file, 1, 0, 0, r, flag) if flag=0 start cf == record(r_conad) if cf_n msgs>0 then dt = cf_msg no(cf_n msgs)_dt else dt=0 btab(bno)_dt last addition = dt btab(bno)_n msgs = cf_n msgs disconnect(file) finish else fail(failure message(flag)) end routine check size(integer newsize) integer flag newsize = (newsize+4095)//4096 if newsize<=f_size then return changefilesize(configoutfile, newsize, flag) if flag#0 then fail(failure message(flag)) f_size = newsize end ; !of check size string fn reduce rname(string (255) rname) integer i string (255) s rname = uccompress(rname) s = "" if length(rname)>0 start for i = 1, 1, length(rname) cycle if 'A'<=charno(rname, i)<='Z' or '0'<=charno(rname, i)<='9' then s = s.tostring(charno(rname, i)) repeat finish result = s end ; !of reduce rname routine set permission(string (255) s) integer i string (31) mode unless s->s.("/").mode then mode = "" unless length(s)=6 then fail("invalid username") for i = 1, 1, 6 cycle unless 'A'<=charno(s, i)<='Z' or charno(s, i)='?' then fail("invalid username") repeat permit(btab(b)_folder.",".s.",".mode) end ; !of set permission if uinfs(1)#"BBOARD" then printstring("Warning - not in BBOARD process".snl) lineno = 0 matchstring = "initialisation" define("1,".file) selectinput(1); !make sure input file is there com == record(x'80000000'+48<<18); !for finding ipl fsys connect("MAILER.ADDRFILE", 9, 0, (com_suplvn<<8)!x'80', r, flag) if flag#0 then fail("cant connect addrfile: ".failure message(flag)) addr file conad = r_conad; !required for looking up rnames connect(servfile, 9, 0, 0, r, flag) if flag#0 then fail("cant connect servfile: ".failure message(flag)) server == record(r_conad+r_datastart) this host = server_serv(1)_name noarchive("ERRORF") noarchive("DB") noarchive("USERACC") outfile(configoutfile, 4096*2, 0, 0, conad, flag) if flag#0 then fail(failure message(flag)) f == record(conad) f_jobtext = jobtext f_bowner = bboard process boards = check item("bboards", -max bboards); !read bboard details f_n boards = boards if boards>0 start for b = 1, 1, boards cycle i = check item("title", 31) btab(b)_title = line i = check item("name", 255) unless line->rname.("@").rest then fail("missing '@'") unless uccompress(rest)=server_authority then fail("cant accredit 'bboard@elsewhere'!") if rname->rname.("*").s start s = this host btab(b)_dt last addition = 1 finish else start s = "" btab(b)_dt last addition = 0 finish leadtrail(rname) btab(b)_bname = rname rname = rname.s check rname(rname, bboard type, btab(b)_title, 3) btab(b)_maxmsgs = check item("maxmsgs", -2000) btab(b)_maxdays = check item("maxdays", -365) i = check item("folder", 18) btab(b)_folder = bboard process.".".uccompress(line) check or create folder(btab(b)_folder) i = check item("permit", 255) until line="" cycle s = next if s="" then continue set permission(uccompress(s)) repeat repeat finish dtab == array(addr(f_dtab(1)), dtable arf); !read dtab details dlists = check item("dlists", -max dlists) f_n dlists = dlists pt = addr(f_dtab(1))+dlists*dlist entry size if dlists>0 start for d = 1, 1, dlists cycle checksize(pt+4096); !make sure we have room for list i = check item("title", 31) s = line; !save it for now i = check item("name", 31) unless line->rname.("@").rest then fail("missing '@'") unless uccompress(rest)=server_authority then fail("cant accredit 'dlist@elsewhere'!") leadtrail(rname) check rname(rname, dlist type, s, 2) dtab(d)_dname = reduce rname(rname) i = check item("list", 255) dtab(d)_offset = pt+1-conad until line="" cycle ; !take each name in turn rname = next if rname="" then continue unless rname->s.("@").rest then fail("missing '@'") leadtrail(s); leadtrail(rest) rest = uccompress(rest) if rest=server_authority then check rname(s, 0, "", 1) else start for i = 1, 1, server_servers cycle if server_serv(i)_name=rest then exit if i=server_servers then fail("host ".rest." not known") repeat finish string(pt) = rname i = pt pt = pt+byteinteger(pt)+1 byteinteger(i) = ',' repeat dtab(d)_length = pt-dtab(d)_offset-conad if dtab(d)_length=0 then fail("empty list") repeat finish else pt = addr(dtab(1)) if boards>0 start ; !check consistency matchstring = "end"; !in case of error for b = 1, 1, boards cycle if btab(b)_dt last addition=1 start btab(b)_dt last addition = 0 d = dlists s = reduce rname(btab(b)_bname) while d#0 cycle if s=dtab(d)_dname then exit d = d-1 repeat if d=0 then fail("missing dlist for bboard ".btab(b)_bname) finish last message details(btab(b)_folder, b) repeat finish f_board offset = (pt-conad+3)&x'fffffffc'; !round up to word i = f_n boards*btable entry size f_end = f_board offset+i checksize(f_end) if f_n boards>0 then move(i, addr(btab(1)), f_board offset+conad) disconnect(".ALL") end ; !of make db file external routine give dbfile(string (255) null) !Gives a new distribution list/bulletin board file to MAILER and tells it !to start using it. const integer take dbfile=28; !mailer service const integer pon and suspend=7 const integer sync1 type=1 integer flag const string (6) mailer="MAILER" const string (1) snl=" " record format comf(integer ocp type, ipldev, sblks, sepgs, ndiscs, ddtaddr, gpctabsize, gpca, sfctabsize, sfca, sfck, dirsite, dcodeda, suplvn) record format pe(integer dest, srce, p1, p2, p3, p4, p5, p6) record (pe) p external string fn spec derrs(integer flag) external integer fn spec dpon2(string (6) user, record (pe) name p, integer msgtype, outno) external integer fn spec dtransfer(string (6) user1, user2, string (11) file, newname, integer fsys1, fsys2, type) external integer fn spec ddestroy(string (6) user, string (11) file, string (8) date, integer fsys, type) system routine spec disconnect(string (255) s, integer name flag) external integer fn spec uinfi(integer i) external string fn spec uinfs(integer i) record (comf) name com disconnect(configoutfile, flag); !ignore flag com == record(x'80000000'+48<<18) flag = ddestroy(mailer, configoutfile, "", com_suplvn, 0); !ignore flag flag = dtransfer(uinfs(1), mailer, configoutfile, configoutfile, uinfi(1), com_suplvn, 1) if flag#0 then printstring("Transfer fails : ".derrs(flag).snl) and return p = 0 p_dest = take dbfile!x'ffff0000' flag = dpon2(mailer, p, sync1 type, pon and suspend) if flag#0 then printstring("DPON fails : ".derrs(flag).snl) and return printstring("Flag = ".derrs(p_p1).snl) end ; !of give dbfile end of file