From 40420d900a1ca0fba4042883b25c39dcadefc596 Mon Sep 17 00:00:00 2001 From: Ken Bowley Date: Fri, 17 Aug 2001 05:46:24 +0000 Subject: [PATCH] Initial revision --- AUTHORS | 31 + COPYING | 339 +++ CRON.sh | 100 + ChangeLog | 4062 ++++++++++++++++++++++++++++++++++ DEBUG | 31 + FILE_ID.DIZ.in | 23 + INSTALL | 251 +++ INSTALL.in | 251 +++ Makefile.am | 30 + Makefile.in | 395 ++++ NEWS | 0 README | 24 + README.GoldED | 90 + SETUP.sh | 365 +++ TODO | 123 + UPGRADE | 18 + acconfig.h | 72 + acinclude.m4 | 136 ++ aclocal.m4 | 149 ++ checkbasic | 40 + config.guess | 973 ++++++++ config.h.in | 239 ++ configure | 3881 ++++++++++++++++++++++++++++++++ configure.in | 160 ++ examples/Makefile.am | 20 + examples/Makefile.in | 298 +++ examples/etc.tar | Bin 0 -> 133120 bytes examples/menus.tar | Bin 0 -> 61440 bytes examples/txtfiles.tar | Bin 0 -> 92160 bytes files.css | 26 + html/Makefile.am | 84 + html/Makefile.in | 299 +++ html/basic.html | 152 ++ html/date.html | 1 + html/dist.html | 74 + html/flow.html | 169 ++ html/ftsc/fsc-0035.html | 79 + html/ftsc/fsc-0039.html | 362 +++ html/ftsc/fsc-0046.html | 227 ++ html/ftsc/fsc-0048.html | 417 ++++ html/ftsc/fsc-0049.html | 103 + html/ftsc/fsc-0050.html | 98 + html/ftsc/fsc-0053.html | 187 ++ html/ftsc/fsc-0056.html | 1078 +++++++++ html/ftsc/fsc-0057.html | 533 +++++ html/ftsc/fsc-0059.html | 1622 ++++++++++++++ html/ftsc/fsc-0062.html | 363 +++ html/ftsc/fsc-0070.html | 122 + html/ftsc/fsc-0072.html | 1925 ++++++++++++++++ html/ftsc/fsc-0087.html | 305 +++ html/ftsc/fsc-0088.html | 326 +++ html/ftsc/fsc-0091.html | 60 + html/ftsc/fsc-0092.html | 243 ++ html/ftsc/fsc-0093.html | 156 ++ html/ftsc/fsp-1001.html | 210 ++ html/ftsc/fsp-1002.html | 140 ++ html/ftsc/fsp-1003.html | 116 + html/ftsc/fsp-1004.html | 257 +++ html/ftsc/fsp-1005.html | 450 ++++ html/ftsc/fsp-1006.html | 159 ++ html/ftsc/fsp-1007.html | 162 ++ html/ftsc/fsp-1008.html | 275 +++ html/ftsc/fsp-1009.html | 142 ++ html/ftsc/fsp-1010.html | 242 ++ html/ftsc/fsp-1011.html | 1756 +++++++++++++++ html/ftsc/fta-1005.html | 268 +++ html/ftsc/fts-0001.html | 1260 +++++++++++ html/ftsc/fts-0004.html | 414 ++++ html/ftsc/fts-0005.html | 617 ++++++ html/ftsc/fts-0006.html | 870 ++++++++ html/ftsc/fts-0007.html | 1869 ++++++++++++++++ html/ftsc/fts-0008.html | 485 ++++ html/ftsc/fts-0009.html | 104 + html/ftsc/fts-4001.html | 192 ++ html/ftsc/ftscprod.html | 311 +++ html/ftsc/index.htm | 99 + html/gwnews.html | 381 ++++ html/images/b_arrow.gif | Bin 0 -> 1306 bytes html/images/connec.gif | Bin 0 -> 1156 bytes html/images/domains.gif | Bin 0 -> 9684 bytes html/images/e_menu.gif | Bin 0 -> 9776 bytes html/images/emareas.gif | Bin 0 -> 12641 bytes html/images/emgroup.gif | Bin 0 -> 7214 bytes html/images/fdb.gif | Bin 0 -> 8368 bytes html/images/fegroup.gif | Bin 0 -> 7631 bytes html/images/fileecho.gif | Bin 0 -> 9573 bytes html/images/filefind.gif | Bin 0 -> 8243 bytes html/images/files.gif | Bin 0 -> 10952 bytes html/images/go_to.gif | Bin 0 -> 1155 bytes html/images/hatch.gif | Bin 0 -> 7761 bytes html/images/language.gif | Bin 0 -> 8718 bytes html/images/larrow.gif | Bin 0 -> 1144 bytes html/images/magic.gif | Bin 0 -> 7172 bytes html/images/mbse.jpg | Bin 0 -> 10655 bytes html/images/mbsetup0.gif | Bin 0 -> 11329 bytes html/images/mbsetup1.6.S.gif | Bin 0 -> 6501 bytes html/images/mbsetup1.6.gif | Bin 0 -> 8669 bytes html/images/mbsetup2.gif | Bin 0 -> 9170 bytes html/images/modems0.gif | Bin 0 -> 9537 bytes html/images/newfiles.gif | Bin 0 -> 8784 bytes html/images/newgroups.gif | Bin 0 -> 8190 bytes html/images/nodelist.gif | Bin 0 -> 12115 bytes html/images/nodelist1.gif | Bin 0 -> 11133 bytes html/images/nodelist2.gif | Bin 0 -> 8986 bytes html/images/nodelist3.gif | Bin 0 -> 9576 bytes html/images/nodelist4.gif | Bin 0 -> 11176 bytes html/images/nodelist5.gif | Bin 0 -> 8446 bytes html/images/nodes.gif | Bin 0 -> 11535 bytes html/images/nodes1.gif | Bin 0 -> 8803 bytes html/images/nodes2.gif | Bin 0 -> 7790 bytes html/images/nodes3.gif | Bin 0 -> 9766 bytes html/images/nodes4.gif | Bin 0 -> 7749 bytes html/images/nodes5.gif | Bin 0 -> 8316 bytes html/images/oneliner.gif | Bin 0 -> 7681 bytes html/images/protocol.gif | Bin 0 -> 8586 bytes html/images/rarrow.gif | Bin 0 -> 1161 bytes html/images/security.gif | Bin 0 -> 8033 bytes html/images/taskmgr.gif | Bin 0 -> 13200 bytes html/images/tty.gif | Bin 0 -> 10032 bytes html/images/tty1.gif | Bin 0 -> 10047 bytes html/images/tty2.gif | Bin 0 -> 10357 bytes html/images/tty3.gif | Bin 0 -> 9243 bytes html/images/uarrow.gif | Bin 0 -> 1147 bytes html/images/users.gif | Bin 0 -> 13897 bytes html/index.htm | 136 ++ html/install.html | 54 + html/intergate.html | 102 + html/intro.html | 99 + html/invoking.html | 70 + html/known_bugs.html | 37 + html/license/copying.html | 360 +++ html/license/hydracom.html | 120 + html/license/index.htm | 39 + html/license/jam.html | 78 + html/manual.css | 24 + html/menus/control.html | 127 ++ html/menus/index.htm | 149 ++ html/menus/menu0.html | 176 ++ html/menus/menu100.html | 147 ++ html/menus/menu200.html | 138 ++ html/menus/menu300.html | 99 + html/menus/menu400.html | 60 + html/menus/menu500.html | 56 + html/mgetty.html | 172 ++ html/misc/dropfile.html | 117 + html/misc/filefind.html | 331 +++ html/misc/fileid.html | 386 ++++ html/misc/ftpserver.html | 98 + html/misc/index.htm | 46 + html/misc/ipmailer.html | 172 ++ html/misc/jam.html | 638 ++++++ html/misc/outbound.html | 114 + html/misc/semafore.html | 51 + html/misc/usleep.html | 61 + html/nodelist.html | 131 ++ html/postfix.html | 160 ++ html/programs/import.html | 41 + html/programs/index.htm | 50 + html/programs/mbaff.html | 99 + html/programs/mball.html | 77 + html/programs/mbchat.html | 61 + html/programs/mbcico.html | 222 ++ html/programs/mbdiff.html | 70 + html/programs/mbfbgen.html | 61 + html/programs/mbfido.html | 260 +++ html/programs/mbfile.html | 93 + html/programs/mbindex.html | 68 + html/programs/mblang.html | 38 + html/programs/mbmail.html | 47 + html/programs/mbmon.html | 45 + html/programs/mbmsg.html | 93 + html/programs/mbout.html | 105 + html/programs/mbpasswd.html | 66 + html/programs/mbsebbs.html | 149 ++ html/programs/mbseq.html | 49 + html/programs/mbsetup.html | 50 + html/programs/mbstat.html | 79 + html/programs/mbtask.html | 319 +++ html/programs/mbtoberep.html | 47 + html/programs/mbuser.html | 71 + html/programs/mbuseradd.html | 72 + html/routing.html | 211 ++ html/setup/archiver.html | 44 + html/setup/bbs.html | 42 + html/setup/bbslist.html | 28 + html/setup/domains.html | 48 + html/setup/emareas.html | 164 ++ html/setup/emgroup.html | 50 + html/setup/fdb.html | 58 + html/setup/fegroup.html | 64 + html/setup/fidonet.html | 42 + html/setup/fileecho.html | 94 + html/setup/filefind.html | 58 + html/setup/files.html | 79 + html/setup/global.html | 464 ++++ html/setup/hatch.html | 61 + html/setup/index.htm | 80 + html/setup/language.html | 57 + html/setup/magic.html | 74 + html/setup/mail.html | 35 + html/setup/modems.html | 88 + html/setup/newfiles.html | 54 + html/setup/newgroups.html | 49 + html/setup/nodes.html | 146 ++ html/setup/oneliner.html | 37 + html/setup/protocol.html | 55 + html/setup/safe.html | 29 + html/setup/security.html | 56 + html/setup/services.html | 69 + html/setup/sitedoc.html | 37 + html/setup/softinfo.html | 31 + html/setup/taskmgr.html | 67 + html/setup/tic.html | 37 + html/setup/timebank.html | 29 + html/setup/ttyinfo.html | 73 + html/setup/users.html | 80 + html/setup/virscan.html | 52 + html/ups.html | 45 + install-sh | 251 +++ lang/Language.xref | 472 ++++ lang/Makefile.am | 37 + lang/Makefile.in | 372 ++++ lang/README | 28 + lang/dutch.txt | 472 ++++ lang/english.txt | 472 ++++ lang/italian.txt | 472 ++++ lang/spanish.txt | 472 ++++ lib/FAQ | 106 + lib/Makefile.am | 35 + lib/Makefile.in | 504 +++++ lib/README | 35 + lib/README.memwatch | 98 + lib/USING | 169 ++ lib/ansi.h | 56 + lib/attach.c | 113 + lib/batchrd.c | 91 + lib/bluewave.h | 1162 ++++++++++ lib/charconv.c | 723 ++++++ lib/charconv_hz.c | 482 ++++ lib/charconv_jp.c | 806 +++++++ lib/charconv_utf.c | 267 +++ lib/charset.c | 424 ++++ lib/clcomm.c | 462 ++++ lib/clcomm.h | 113 + lib/client.c | 211 ++ lib/common.h | 914 ++++++++ lib/crc.c | 303 +++ lib/dbcfg.c | 96 + lib/dbcfg.h | 11 + lib/dbdupe.c | 183 ++ lib/dbdupe.h | 12 + lib/dbftn.c | 101 + lib/dbftn.h | 16 + lib/dbmsgs.c | 357 +++ lib/dbmsgs.h | 21 + lib/dbnode.c | 205 ++ lib/dbnode.h | 18 + lib/dbtic.c | 305 +++ lib/dbtic.h | 19 + lib/dbuser.c | 101 + lib/dbuser.h | 16 + lib/dostran.c | 96 + lib/execute.c | 190 ++ lib/expipe.c | 196 ++ lib/faddr.c | 100 + lib/falists.c | 228 ++ lib/ftn.c | 683 ++++++ lib/ftnmsg.c | 183 ++ lib/ftscprod.006 | 289 +++ lib/ftscprod.c | 296 +++ lib/getheader.c | 188 ++ lib/gmtoffset.c | 169 ++ lib/hdr.c | 47 + lib/jam.h | 196 ++ lib/jammsg.c | 1370 ++++++++++++ lib/jammsg.h | 27 + lib/jamsys.h | 100 + lib/libs.h | 89 + lib/mbfile.c | 304 +++ lib/mbinet.h | 24 + lib/mbse.h | 117 + lib/memwatch.c | 2356 ++++++++++++++++++++ lib/memwatch.c.org | 2360 ++++++++++++++++++++ lib/memwatch.h | 701 ++++++ lib/mime.c | 266 +++ lib/mkprod.awk | 15 + lib/msg.c | 321 +++ lib/msg.h | 140 ++ lib/msgflags.c | 144 ++ lib/msgtext.c | 335 +++ lib/msgtext.h | 34 + lib/nntp.c | 294 +++ lib/nodelist.c | 607 +++++ lib/nodelock.c | 157 ++ lib/noderecord.c | 58 + lib/packet.c | 190 ++ lib/parsedate.c | 1780 +++++++++++++++ lib/pktname.c | 286 +++ lib/pop3.c | 202 ++ lib/rawio.c | 238 ++ lib/records.h | 123 + lib/rfcaddr.c | 328 +++ lib/rfcdate.c | 192 ++ lib/rfcmsg.c | 168 ++ lib/semafore.c | 73 + lib/signame.c | 95 + lib/smtp.c | 213 ++ lib/strcasestr.c | 25 + lib/structs.h | 1546 +++++++++++++ lib/strutil.c | 357 +++ lib/term.c | 245 ++ lib/test.c | 106 + lib/unpacker.c | 102 + mbcico/Makefile.am | 36 + mbcico/Makefile.in | 536 +++++ mbcico/README | 35 + mbcico/answer.c | 163 ++ mbcico/answer.h | 8 + mbcico/atoul.c | 44 + mbcico/atoul.h | 8 + mbcico/binkp.c | 1228 ++++++++++ mbcico/binkp.h | 84 + mbcico/call.c | 380 ++++ mbcico/call.h | 10 + mbcico/callall.c | 146 ++ mbcico/callall.h | 9 + mbcico/callstat.c | 82 + mbcico/callstat.h | 26 + mbcico/chat.c | 253 +++ mbcico/chat.h | 8 + mbcico/config.h | 24 + mbcico/dial.c | 166 ++ mbcico/dial.h | 11 + mbcico/dietifna.c | 149 ++ mbcico/dietifna.h | 9 + mbcico/emsi.c | 612 +++++ mbcico/emsi.h | 52 + mbcico/emsidat.c | 502 +++++ mbcico/emsidat.h | 10 + mbcico/filelist.c | 500 +++++ mbcico/filelist.h | 12 + mbcico/filetime.c | 121 + mbcico/filetime.h | 11 + mbcico/ftsc.c | 486 ++++ mbcico/ftsc.h | 10 + mbcico/hydra.c | 1690 ++++++++++++++ mbcico/hydra.h | 206 ++ mbcico/lutil.c | 94 + mbcico/lutil.h | 9 + mbcico/m7recv.c | 190 ++ mbcico/m7recv.h | 8 + mbcico/m7send.c | 191 ++ mbcico/m7send.h | 7 + mbcico/mbcico.c | 413 ++++ mbcico/mbcico.h | 9 + mbcico/mbout.c | 344 +++ mbcico/nlinfo.c | 129 ++ mbcico/nlinfo.h | 9 + mbcico/openfile.c | 282 +++ mbcico/openfile.h | 9 + mbcico/openport.c | 617 ++++++ mbcico/openport.h | 25 + mbcico/opentcp.c | 303 +++ mbcico/opentcp.h | 81 + mbcico/outstat.c | 354 +++ mbcico/outstat.h | 12 + mbcico/portsel.c | 254 +++ mbcico/portsel.h | 24 + mbcico/rdoptions.c | 138 ++ mbcico/rdoptions.h | 7 + mbcico/recvbark.c | 230 ++ mbcico/recvbark.h | 7 + mbcico/respfreq.c | 663 ++++++ mbcico/respfreq.h | 11 + mbcico/scanout.c | 244 ++ mbcico/scanout.h | 13 + mbcico/sendbark.c | 186 ++ mbcico/sendbark.h | 7 + mbcico/session.c | 572 +++++ mbcico/session.h | 69 + mbcico/statetbl.h | 48 + mbcico/tcp.c | 136 ++ mbcico/tcp.h | 9 + mbcico/tcpproto.c | 478 ++++ mbcico/tcpproto.h | 9 + mbcico/ttyio.c | 590 +++++ mbcico/ttyio.h | 183 ++ mbcico/ulock.c | 141 ++ mbcico/ulock.h | 8 + mbcico/wazoo.c | 128 ++ mbcico/wazoo.h | 8 + mbcico/xmrecv.c | 604 +++++ mbcico/xmrecv.h | 7 + mbcico/xmsend.c | 523 +++++ mbcico/xmsend.h | 9 + mbcico/yoohoo.c | 637 ++++++ mbcico/yoohoo.h | 8 + mbcico/zmmisc.c | 999 +++++++++ mbcico/zmodem.h | 199 ++ mbcico/zmrecv.c | 577 +++++ mbcico/zmrle.c | 197 ++ mbcico/zmsend.c | 695 ++++++ mbfido/Makefile.am | 65 + mbfido/Makefile.in | 678 ++++++ mbfido/README | 16 + mbfido/addbbs.c | 341 +++ mbfido/addbbs.h | 9 + mbfido/addpkt.c | 244 ++ mbfido/addpkt.h | 10 + mbfido/aliasdb.c | 217 ++ mbfido/aliasdb.h | 12 + mbfido/announce.c | 470 ++++ mbfido/announce.h | 9 + mbfido/areamgr.c | 1105 +++++++++ mbfido/areamgr.h | 12 + mbfido/atoul.c | 46 + mbfido/atoul.h | 8 + mbfido/backalias.c | 98 + mbfido/backalias.h | 8 + mbfido/bread.c | 111 + mbfido/bread.h | 10 + mbfido/bwrite.c | 114 + mbfido/bwrite.h | 11 + mbfido/cookie.c | 90 + mbfido/cookie.h | 8 + mbfido/echoout.c | 85 + mbfido/echoout.h | 8 + mbfido/fflist.c | 149 ++ mbfido/fflist.h | 34 + mbfido/filefind.c | 523 +++++ mbfido/filefind.h | 9 + mbfido/filemgr.c | 974 ++++++++ mbfido/filemgr.h | 11 + mbfido/flock.c | 82 + mbfido/flock.h | 10 + mbfido/forward.c | 300 +++ mbfido/forward.h | 9 + mbfido/fsort.c | 145 ++ mbfido/fsort.h | 20 + mbfido/grlist.c | 141 ++ mbfido/grlist.h | 19 + mbfido/hash.c | 52 + mbfido/hash.h | 8 + mbfido/hatch.c | 201 ++ mbfido/hatch.h | 9 + mbfido/importmsg.c | 908 ++++++++ mbfido/importmsg.h | 22 + mbfido/importnet.c | 173 ++ mbfido/importnet.h | 8 + mbfido/lhash.c | 515 +++++ mbfido/lhash.h | 147 ++ mbfido/magic.c | 427 ++++ mbfido/magic.h | 19 + mbfido/makestat.c | 434 ++++ mbfido/makestat.h | 9 + mbfido/maketags.c | 132 ++ mbfido/maketags.h | 9 + mbfido/maptabs.tgz | Bin 0 -> 10605 bytes mbfido/mbaff.c | 196 ++ mbfido/mbaff.h | 9 + mbfido/mbdiff.c | 576 +++++ mbfido/mbdiff.h | 12 + mbfido/mbfido.c | 663 ++++++ mbfido/mbfido.h | 15 + mbfido/mbfile.c | 1002 +++++++++ mbfido/mbfile.h | 12 + mbfido/mbindex.c | 985 +++++++++ mbfido/mbindex.h | 31 + mbfido/mbmail.c | 418 ++++ mbfido/mbmail.h | 6 + mbfido/mbmsg.c | 702 ++++++ mbfido/mbmsg.h | 14 + mbfido/mbseq.c | 72 + mbfido/mbseq.h | 6 + mbfido/message.c | 882 ++++++++ mbfido/message.h | 12 + mbfido/mgrutil.c | 223 ++ mbfido/mgrutil.h | 15 + mbfido/mkftnhdr.c | 543 +++++ mbfido/mkftnhdr.h | 10 + mbfido/mkrfcmsg.c | 1490 +++++++++++++ mbfido/mkrfcmsg.h | 8 + mbfido/mover.c | 73 + mbfido/mover.h | 10 + mbfido/msgutil.c | 226 ++ mbfido/msgutil.h | 13 + mbfido/newspost.c | 232 ++ mbfido/newspost.h | 9 + mbfido/notify.c | 170 ++ mbfido/notify.h | 9 + mbfido/pack.c | 416 ++++ mbfido/pack.h | 11 + mbfido/paths.h.in | 7 + mbfido/ping.c | 149 ++ mbfido/ping.h | 9 + mbfido/post.c | 245 ++ mbfido/post.h | 9 + mbfido/postemail.c | 122 + mbfido/postemail.h | 8 + mbfido/postnetmail.c | 316 +++ mbfido/postnetmail.h | 8 + mbfido/ptic.c | 782 +++++++ mbfido/ptic.h | 7 + mbfido/rnews.c | 652 ++++++ mbfido/rnews.h | 20 + mbfido/rollover.c | 418 ++++ mbfido/rollover.h | 10 + mbfido/scan.c | 1085 +++++++++ mbfido/scan.h | 10 + mbfido/scannews.c | 1437 ++++++++++++ mbfido/scannews.h | 39 + mbfido/sendmail.c | 149 ++ mbfido/sendmail.h | 10 + mbfido/tic.c | 451 ++++ mbfido/tic.h | 72 + mbfido/toberep.c | 79 + mbfido/toberep.h | 9 + mbfido/tosspkt.c | 400 ++++ mbfido/tosspkt.h | 9 + mbfido/tracker.c | 518 +++++ mbfido/tracker.h | 16 + mbfido/ulock.c | 182 ++ mbfido/ulock.h | 11 + mbfido/utic.c | 262 +++ mbfido/utic.h | 15 + mbfido/viadate.c | 68 + mbfido/viadate.h | 9 + mbmon/Makefile.am | 11 + mbmon/Makefile.in | 353 +++ mbmon/common.c | 918 ++++++++ mbmon/common.h | 97 + mbmon/mbmon.c | 451 ++++ mbmon/mbmon.h | 14 + mbmon/mutil.c | 548 +++++ mbmon/mutil.h | 22 + mbsebbs/Makefile.am | 61 + mbsebbs/Makefile.in | 633 ++++++ mbsebbs/bank.c | 576 +++++ mbsebbs/bank.h | 7 + mbsebbs/bbslist.c | 708 ++++++ mbsebbs/bbslist.h | 11 + mbsebbs/bye.c | 164 ++ mbsebbs/bye.h | 8 + mbsebbs/change.c | 817 +++++++ mbsebbs/change.h | 26 + mbsebbs/chat.c | 194 ++ mbsebbs/chat.h | 8 + mbsebbs/commonio.c | 746 +++++++ mbsebbs/commonio.h | 108 + mbsebbs/email.c | 1041 +++++++++ mbsebbs/email.h | 15 + mbsebbs/encrypt.c | 142 ++ mbsebbs/encrypt.h | 9 + mbsebbs/exitinfo.c | 404 ++++ mbsebbs/exitinfo.h | 13 + mbsebbs/file.c | 2167 ++++++++++++++++++ mbsebbs/file.h | 24 + mbsebbs/filesub.c | 1099 +++++++++ mbsebbs/filesub.h | 28 + mbsebbs/fsedit.c | 753 +++++++ mbsebbs/fsedit.h | 7 + mbsebbs/funcs.c | 1031 +++++++++ mbsebbs/funcs.h | 23 + mbsebbs/funcs4.c | 1051 +++++++++ mbsebbs/funcs4.h | 31 + mbsebbs/getdef.c | 393 ++++ mbsebbs/getdef.h | 10 + mbsebbs/language.c | 169 ++ mbsebbs/language.h | 13 + mbsebbs/lineedit.c | 577 +++++ mbsebbs/lineedit.h | 7 + mbsebbs/mail.c | 2163 ++++++++++++++++++ mbsebbs/mail.h | 21 + mbsebbs/mball.c | 963 ++++++++ mbsebbs/mball.h | 17 + mbsebbs/mbchat.c | 257 +++ mbsebbs/mbfbgen.c | 332 +++ mbsebbs/mblang.c | 136 ++ mbsebbs/mbpasswd.c | 663 ++++++ mbsebbs/mbpasswd.h | 30 + mbsebbs/mbsebbs.c | 241 ++ mbsebbs/mbsebbs.h | 10 + mbsebbs/mbstat.c | 284 +++ mbsebbs/mbstat.h | 14 + mbsebbs/mbtoberep.c | 102 + mbsebbs/mbuser.c | 361 +++ mbsebbs/mbuser.h | 9 + mbsebbs/mbuseradd.c | 265 +++ mbsebbs/mbuseradd.h | 10 + mbsebbs/menu.c | 672 ++++++ mbsebbs/menu.h | 9 + mbsebbs/misc.c | 446 ++++ mbsebbs/misc.h | 15 + mbsebbs/msgutil.c | 279 +++ mbsebbs/msgutil.h | 14 + mbsebbs/myname.c | 72 + mbsebbs/myname.h | 7 + mbsebbs/newuser.c | 518 +++++ mbsebbs/newuser.h | 9 + mbsebbs/nextuser.c | 360 +++ mbsebbs/nextuser.h | 7 + mbsebbs/offline.c | 2910 ++++++++++++++++++++++++ mbsebbs/offline.h | 52 + mbsebbs/oneline.c | 447 ++++ mbsebbs/oneline.h | 13 + mbsebbs/page.c | 296 +++ mbsebbs/page.h | 13 + mbsebbs/pinfo.c | 159 ++ mbsebbs/pinfo.h | 9 + mbsebbs/pop3.c | 212 ++ mbsebbs/pop3.h | 9 + mbsebbs/pwcheck.c | 108 + mbsebbs/pwcheck.h | 8 + mbsebbs/pwio.c | 249 +++ mbsebbs/pwio.h | 19 + mbsebbs/rad64.c | 157 ++ mbsebbs/rad64.h | 15 + mbsebbs/safe.c | 457 ++++ mbsebbs/safe.h | 11 + mbsebbs/salt.c | 98 + mbsebbs/salt.h | 9 + mbsebbs/sgetpwent.c | 167 ++ mbsebbs/sgetpwent.h | 7 + mbsebbs/shadowio.c | 232 ++ mbsebbs/shadowio.h | 27 + mbsebbs/statetbl.h | 48 + mbsebbs/timecheck.c | 96 + mbsebbs/timecheck.h | 8 + mbsebbs/timeout.c | 144 ++ mbsebbs/timeout.h | 12 + mbsebbs/user.c | 1157 ++++++++++ mbsebbs/user.h | 19 + mbsebbs/xmalloc.c | 71 + mbsebbs/xmalloc.h | 8 + mbsetup/Makefile.am | 24 + mbsetup/Makefile.in | 502 +++++ mbsetup/grlist.c | 177 ++ mbsetup/grlist.h | 18 + mbsetup/ledit.c | 1598 +++++++++++++ mbsetup/ledit.h | 80 + mbsetup/m_archive.c | 577 +++++ mbsetup/m_archive.h | 13 + mbsetup/m_bbs.c | 120 + mbsetup/m_bbs.h | 8 + mbsetup/m_domain.c | 485 ++++ mbsetup/m_domain.h | 10 + mbsetup/m_farea.c | 587 +++++ mbsetup/m_farea.h | 11 + mbsetup/m_fdb.c | 282 +++ mbsetup/m_fdb.h | 8 + mbsetup/m_ff.c | 449 ++++ mbsetup/m_ff.h | 10 + mbsetup/m_fgroup.c | 585 +++++ mbsetup/m_fgroup.h | 12 + mbsetup/m_fido.c | 558 +++++ mbsetup/m_fido.h | 11 + mbsetup/m_global.c | 1995 +++++++++++++++++ mbsetup/m_global.h | 16 + mbsetup/m_hatch.c | 625 ++++++ mbsetup/m_hatch.h | 10 + mbsetup/m_lang.c | 527 +++++ mbsetup/m_lang.h | 12 + mbsetup/m_limits.c | 593 +++++ mbsetup/m_limits.h | 13 + mbsetup/m_magic.c | 537 +++++ mbsetup/m_magic.h | 11 + mbsetup/m_mail.c | 91 + mbsetup/m_mail.h | 12 + mbsetup/m_marea.c | 1469 ++++++++++++ mbsetup/m_marea.h | 17 + mbsetup/m_menu.c | 597 +++++ mbsetup/m_menu.h | 9 + mbsetup/m_mgroup.c | 570 +++++ mbsetup/m_mgroup.h | 12 + mbsetup/m_modem.c | 716 ++++++ mbsetup/m_modem.h | 11 + mbsetup/m_new.c | 556 +++++ mbsetup/m_new.h | 10 + mbsetup/m_ngroup.c | 513 +++++ mbsetup/m_ngroup.h | 12 + mbsetup/m_node.c | 1209 ++++++++++ mbsetup/m_node.h | 12 + mbsetup/m_ol.c | 534 +++++ mbsetup/m_ol.h | 12 + mbsetup/m_protocol.c | 538 +++++ mbsetup/m_protocol.h | 12 + mbsetup/m_service.c | 435 ++++ mbsetup/m_service.h | 10 + mbsetup/m_task.c | 243 ++ mbsetup/m_task.h | 10 + mbsetup/m_tic.c | 98 + mbsetup/m_tic.h | 4 + mbsetup/m_ticarea.c | 1256 +++++++++++ mbsetup/m_ticarea.h | 16 + mbsetup/m_tty.c | 518 +++++ mbsetup/m_tty.h | 10 + mbsetup/m_users.c | 509 +++++ mbsetup/m_users.h | 11 + mbsetup/m_virus.c | 419 ++++ mbsetup/m_virus.h | 12 + mbsetup/mbsetup.c | 452 ++++ mbsetup/mutil.c | 140 ++ mbsetup/mutil.h | 10 + mbsetup/screen.c | 271 +++ mbsetup/screen.h | 19 + mbsetup/stlist.c | 117 + mbsetup/stlist.h | 17 + mbtask/Makefile.am | 34 + mbtask/Makefile.in | 396 ++++ mbtask/callstat.c | 135 ++ mbtask/callstat.h | 26 + mbtask/issue | 12 + mbtask/libs.h | 166 ++ mbtask/mbtask.c | 1440 ++++++++++++ mbtask/mbtask.h | 52 + mbtask/nodelist.c | 572 +++++ mbtask/nodelist.h | 189 ++ mbtask/outstat.c | 249 +++ mbtask/outstat.h | 10 + mbtask/scanout.c | 242 ++ mbtask/scanout.h | 13 + mbtask/signame.c | 94 + mbtask/signame.h | 9 + mbtask/taskcomm.c | 466 ++++ mbtask/taskcomm.h | 7 + mbtask/taskdisk.c | 93 + mbtask/taskdisk.h | 8 + mbtask/taskinfo.c | 138 ++ mbtask/taskinfo.h | 10 + mbtask/taskregs.c | 478 ++++ mbtask/taskregs.h | 49 + mbtask/taskstat.c | 438 ++++ mbtask/taskstat.h | 20 + mbtask/taskutil.c | 439 ++++ mbtask/taskutil.h | 42 + missing | 190 ++ mkinstalldirs | 40 + script/Makefile.am | 29 + script/Makefile.in | 306 +++ script/README | 7 + script/installinit | 556 +++++ script/maint | 26 + script/mbse.start | 32 + script/mbse.stop | 38 + script/midnight | 28 + script/monthly | 15 + script/rc | 15 + script/rc.shutdown | 14 + script/weekly | 18 + stamp-h.in | 1 + 750 files changed, 177485 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 CRON.sh create mode 100644 ChangeLog create mode 100644 DEBUG create mode 100644 FILE_ID.DIZ.in create mode 100644 INSTALL create mode 100644 INSTALL.in create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 README.GoldED create mode 100644 SETUP.sh create mode 100644 TODO create mode 100644 UPGRADE create mode 100644 acconfig.h create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100755 checkbasic create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 configure create mode 100644 configure.in create mode 100644 examples/Makefile.am create mode 100644 examples/Makefile.in create mode 100644 examples/etc.tar create mode 100644 examples/menus.tar create mode 100644 examples/txtfiles.tar create mode 100644 files.css create mode 100644 html/Makefile.am create mode 100644 html/Makefile.in create mode 100755 html/basic.html create mode 100755 html/date.html create mode 100644 html/dist.html create mode 100644 html/flow.html create mode 100755 html/ftsc/fsc-0035.html create mode 100755 html/ftsc/fsc-0039.html create mode 100755 html/ftsc/fsc-0046.html create mode 100755 html/ftsc/fsc-0048.html create mode 100755 html/ftsc/fsc-0049.html create mode 100755 html/ftsc/fsc-0050.html create mode 100755 html/ftsc/fsc-0053.html create mode 100755 html/ftsc/fsc-0056.html create mode 100755 html/ftsc/fsc-0057.html create mode 100755 html/ftsc/fsc-0059.html create mode 100755 html/ftsc/fsc-0062.html create mode 100755 html/ftsc/fsc-0070.html create mode 100755 html/ftsc/fsc-0072.html create mode 100755 html/ftsc/fsc-0087.html create mode 100755 html/ftsc/fsc-0088.html create mode 100755 html/ftsc/fsc-0091.html create mode 100755 html/ftsc/fsc-0092.html create mode 100755 html/ftsc/fsc-0093.html create mode 100755 html/ftsc/fsp-1001.html create mode 100755 html/ftsc/fsp-1002.html create mode 100755 html/ftsc/fsp-1003.html create mode 100755 html/ftsc/fsp-1004.html create mode 100755 html/ftsc/fsp-1005.html create mode 100755 html/ftsc/fsp-1006.html create mode 100755 html/ftsc/fsp-1007.html create mode 100755 html/ftsc/fsp-1008.html create mode 100755 html/ftsc/fsp-1009.html create mode 100755 html/ftsc/fsp-1010.html create mode 100755 html/ftsc/fsp-1011.html create mode 100755 html/ftsc/fta-1005.html create mode 100755 html/ftsc/fts-0001.html create mode 100755 html/ftsc/fts-0004.html create mode 100755 html/ftsc/fts-0005.html create mode 100755 html/ftsc/fts-0006.html create mode 100755 html/ftsc/fts-0007.html create mode 100755 html/ftsc/fts-0008.html create mode 100755 html/ftsc/fts-0009.html create mode 100755 html/ftsc/fts-4001.html create mode 100755 html/ftsc/ftscprod.html create mode 100644 html/ftsc/index.htm create mode 100755 html/gwnews.html create mode 100644 html/images/b_arrow.gif create mode 100644 html/images/connec.gif create mode 100644 html/images/domains.gif create mode 100644 html/images/e_menu.gif create mode 100644 html/images/emareas.gif create mode 100644 html/images/emgroup.gif create mode 100644 html/images/fdb.gif create mode 100644 html/images/fegroup.gif create mode 100644 html/images/fileecho.gif create mode 100644 html/images/filefind.gif create mode 100644 html/images/files.gif create mode 100644 html/images/go_to.gif create mode 100644 html/images/hatch.gif create mode 100644 html/images/language.gif create mode 100644 html/images/larrow.gif create mode 100644 html/images/magic.gif create mode 100644 html/images/mbse.jpg create mode 100644 html/images/mbsetup0.gif create mode 100644 html/images/mbsetup1.6.S.gif create mode 100644 html/images/mbsetup1.6.gif create mode 100644 html/images/mbsetup2.gif create mode 100644 html/images/modems0.gif create mode 100644 html/images/newfiles.gif create mode 100644 html/images/newgroups.gif create mode 100644 html/images/nodelist.gif create mode 100644 html/images/nodelist1.gif create mode 100644 html/images/nodelist2.gif create mode 100644 html/images/nodelist3.gif create mode 100644 html/images/nodelist4.gif create mode 100644 html/images/nodelist5.gif create mode 100644 html/images/nodes.gif create mode 100644 html/images/nodes1.gif create mode 100644 html/images/nodes2.gif create mode 100644 html/images/nodes3.gif create mode 100644 html/images/nodes4.gif create mode 100644 html/images/nodes5.gif create mode 100644 html/images/oneliner.gif create mode 100644 html/images/protocol.gif create mode 100644 html/images/rarrow.gif create mode 100644 html/images/security.gif create mode 100644 html/images/taskmgr.gif create mode 100644 html/images/tty.gif create mode 100644 html/images/tty1.gif create mode 100644 html/images/tty2.gif create mode 100644 html/images/tty3.gif create mode 100644 html/images/uarrow.gif create mode 100644 html/images/users.gif create mode 100755 html/index.htm create mode 100755 html/install.html create mode 100644 html/intergate.html create mode 100644 html/intro.html create mode 100644 html/invoking.html create mode 100644 html/known_bugs.html create mode 100644 html/license/copying.html create mode 100644 html/license/hydracom.html create mode 100644 html/license/index.htm create mode 100644 html/license/jam.html create mode 100644 html/manual.css create mode 100644 html/menus/control.html create mode 100644 html/menus/index.htm create mode 100644 html/menus/menu0.html create mode 100644 html/menus/menu100.html create mode 100644 html/menus/menu200.html create mode 100644 html/menus/menu300.html create mode 100644 html/menus/menu400.html create mode 100644 html/menus/menu500.html create mode 100644 html/mgetty.html create mode 100644 html/misc/dropfile.html create mode 100644 html/misc/filefind.html create mode 100644 html/misc/fileid.html create mode 100644 html/misc/ftpserver.html create mode 100644 html/misc/index.htm create mode 100644 html/misc/ipmailer.html create mode 100644 html/misc/jam.html create mode 100644 html/misc/outbound.html create mode 100644 html/misc/semafore.html create mode 100644 html/misc/usleep.html create mode 100644 html/nodelist.html create mode 100644 html/postfix.html create mode 100755 html/programs/import.html create mode 100644 html/programs/index.htm create mode 100644 html/programs/mbaff.html create mode 100644 html/programs/mball.html create mode 100755 html/programs/mbchat.html create mode 100644 html/programs/mbcico.html create mode 100644 html/programs/mbdiff.html create mode 100755 html/programs/mbfbgen.html create mode 100644 html/programs/mbfido.html create mode 100644 html/programs/mbfile.html create mode 100644 html/programs/mbindex.html create mode 100644 html/programs/mblang.html create mode 100755 html/programs/mbmail.html create mode 100644 html/programs/mbmon.html create mode 100644 html/programs/mbmsg.html create mode 100644 html/programs/mbout.html create mode 100644 html/programs/mbpasswd.html create mode 100644 html/programs/mbsebbs.html create mode 100644 html/programs/mbseq.html create mode 100644 html/programs/mbsetup.html create mode 100644 html/programs/mbstat.html create mode 100644 html/programs/mbtask.html create mode 100644 html/programs/mbtoberep.html create mode 100644 html/programs/mbuser.html create mode 100644 html/programs/mbuseradd.html create mode 100644 html/routing.html create mode 100644 html/setup/archiver.html create mode 100644 html/setup/bbs.html create mode 100644 html/setup/bbslist.html create mode 100644 html/setup/domains.html create mode 100644 html/setup/emareas.html create mode 100644 html/setup/emgroup.html create mode 100644 html/setup/fdb.html create mode 100644 html/setup/fegroup.html create mode 100644 html/setup/fidonet.html create mode 100644 html/setup/fileecho.html create mode 100644 html/setup/filefind.html create mode 100644 html/setup/files.html create mode 100644 html/setup/global.html create mode 100644 html/setup/hatch.html create mode 100644 html/setup/index.htm create mode 100644 html/setup/language.html create mode 100644 html/setup/magic.html create mode 100644 html/setup/mail.html create mode 100644 html/setup/modems.html create mode 100644 html/setup/newfiles.html create mode 100644 html/setup/newgroups.html create mode 100644 html/setup/nodes.html create mode 100644 html/setup/oneliner.html create mode 100644 html/setup/protocol.html create mode 100755 html/setup/safe.html create mode 100644 html/setup/security.html create mode 100644 html/setup/services.html create mode 100644 html/setup/sitedoc.html create mode 100644 html/setup/softinfo.html create mode 100644 html/setup/taskmgr.html create mode 100644 html/setup/tic.html create mode 100755 html/setup/timebank.html create mode 100644 html/setup/ttyinfo.html create mode 100644 html/setup/users.html create mode 100644 html/setup/virscan.html create mode 100644 html/ups.html create mode 100755 install-sh create mode 100644 lang/Language.xref create mode 100644 lang/Makefile.am create mode 100644 lang/Makefile.in create mode 100644 lang/README create mode 100644 lang/dutch.txt create mode 100644 lang/english.txt create mode 100644 lang/italian.txt create mode 100644 lang/spanish.txt create mode 100644 lib/FAQ create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100644 lib/README create mode 100644 lib/README.memwatch create mode 100644 lib/USING create mode 100644 lib/ansi.h create mode 100644 lib/attach.c create mode 100644 lib/batchrd.c create mode 100644 lib/bluewave.h create mode 100644 lib/charconv.c create mode 100644 lib/charconv_hz.c create mode 100644 lib/charconv_jp.c create mode 100644 lib/charconv_utf.c create mode 100644 lib/charset.c create mode 100644 lib/clcomm.c create mode 100644 lib/clcomm.h create mode 100644 lib/client.c create mode 100644 lib/common.h create mode 100644 lib/crc.c create mode 100644 lib/dbcfg.c create mode 100644 lib/dbcfg.h create mode 100644 lib/dbdupe.c create mode 100644 lib/dbdupe.h create mode 100644 lib/dbftn.c create mode 100644 lib/dbftn.h create mode 100644 lib/dbmsgs.c create mode 100644 lib/dbmsgs.h create mode 100644 lib/dbnode.c create mode 100644 lib/dbnode.h create mode 100644 lib/dbtic.c create mode 100644 lib/dbtic.h create mode 100644 lib/dbuser.c create mode 100644 lib/dbuser.h create mode 100644 lib/dostran.c create mode 100644 lib/execute.c create mode 100644 lib/expipe.c create mode 100644 lib/faddr.c create mode 100644 lib/falists.c create mode 100644 lib/ftn.c create mode 100644 lib/ftnmsg.c create mode 100644 lib/ftscprod.006 create mode 100644 lib/ftscprod.c create mode 100644 lib/getheader.c create mode 100644 lib/gmtoffset.c create mode 100644 lib/hdr.c create mode 100644 lib/jam.h create mode 100644 lib/jammsg.c create mode 100644 lib/jammsg.h create mode 100644 lib/jamsys.h create mode 100644 lib/libs.h create mode 100644 lib/mbfile.c create mode 100644 lib/mbinet.h create mode 100644 lib/mbse.h create mode 100644 lib/memwatch.c create mode 100644 lib/memwatch.c.org create mode 100644 lib/memwatch.h create mode 100644 lib/mime.c create mode 100644 lib/mkprod.awk create mode 100644 lib/msg.c create mode 100644 lib/msg.h create mode 100644 lib/msgflags.c create mode 100644 lib/msgtext.c create mode 100644 lib/msgtext.h create mode 100644 lib/nntp.c create mode 100644 lib/nodelist.c create mode 100644 lib/nodelock.c create mode 100644 lib/noderecord.c create mode 100644 lib/packet.c create mode 100644 lib/parsedate.c create mode 100644 lib/pktname.c create mode 100644 lib/pop3.c create mode 100644 lib/rawio.c create mode 100644 lib/records.h create mode 100644 lib/rfcaddr.c create mode 100644 lib/rfcdate.c create mode 100644 lib/rfcmsg.c create mode 100644 lib/semafore.c create mode 100644 lib/signame.c create mode 100644 lib/smtp.c create mode 100644 lib/strcasestr.c create mode 100644 lib/structs.h create mode 100644 lib/strutil.c create mode 100644 lib/term.c create mode 100644 lib/test.c create mode 100644 lib/unpacker.c create mode 100644 mbcico/Makefile.am create mode 100644 mbcico/Makefile.in create mode 100644 mbcico/README create mode 100644 mbcico/answer.c create mode 100644 mbcico/answer.h create mode 100644 mbcico/atoul.c create mode 100644 mbcico/atoul.h create mode 100644 mbcico/binkp.c create mode 100644 mbcico/binkp.h create mode 100644 mbcico/call.c create mode 100644 mbcico/call.h create mode 100644 mbcico/callall.c create mode 100644 mbcico/callall.h create mode 100644 mbcico/callstat.c create mode 100644 mbcico/callstat.h create mode 100644 mbcico/chat.c create mode 100644 mbcico/chat.h create mode 100644 mbcico/config.h create mode 100644 mbcico/dial.c create mode 100644 mbcico/dial.h create mode 100644 mbcico/dietifna.c create mode 100644 mbcico/dietifna.h create mode 100644 mbcico/emsi.c create mode 100644 mbcico/emsi.h create mode 100644 mbcico/emsidat.c create mode 100644 mbcico/emsidat.h create mode 100644 mbcico/filelist.c create mode 100644 mbcico/filelist.h create mode 100644 mbcico/filetime.c create mode 100644 mbcico/filetime.h create mode 100644 mbcico/ftsc.c create mode 100644 mbcico/ftsc.h create mode 100644 mbcico/hydra.c create mode 100644 mbcico/hydra.h create mode 100644 mbcico/lutil.c create mode 100644 mbcico/lutil.h create mode 100644 mbcico/m7recv.c create mode 100644 mbcico/m7recv.h create mode 100644 mbcico/m7send.c create mode 100644 mbcico/m7send.h create mode 100644 mbcico/mbcico.c create mode 100644 mbcico/mbcico.h create mode 100644 mbcico/mbout.c create mode 100644 mbcico/nlinfo.c create mode 100644 mbcico/nlinfo.h create mode 100644 mbcico/openfile.c create mode 100644 mbcico/openfile.h create mode 100644 mbcico/openport.c create mode 100644 mbcico/openport.h create mode 100644 mbcico/opentcp.c create mode 100644 mbcico/opentcp.h create mode 100644 mbcico/outstat.c create mode 100644 mbcico/outstat.h create mode 100644 mbcico/portsel.c create mode 100644 mbcico/portsel.h create mode 100644 mbcico/rdoptions.c create mode 100644 mbcico/rdoptions.h create mode 100644 mbcico/recvbark.c create mode 100644 mbcico/recvbark.h create mode 100644 mbcico/respfreq.c create mode 100644 mbcico/respfreq.h create mode 100644 mbcico/scanout.c create mode 100644 mbcico/scanout.h create mode 100644 mbcico/sendbark.c create mode 100644 mbcico/sendbark.h create mode 100644 mbcico/session.c create mode 100644 mbcico/session.h create mode 100644 mbcico/statetbl.h create mode 100644 mbcico/tcp.c create mode 100644 mbcico/tcp.h create mode 100644 mbcico/tcpproto.c create mode 100644 mbcico/tcpproto.h create mode 100644 mbcico/ttyio.c create mode 100644 mbcico/ttyio.h create mode 100644 mbcico/ulock.c create mode 100644 mbcico/ulock.h create mode 100644 mbcico/wazoo.c create mode 100644 mbcico/wazoo.h create mode 100644 mbcico/xmrecv.c create mode 100644 mbcico/xmrecv.h create mode 100644 mbcico/xmsend.c create mode 100644 mbcico/xmsend.h create mode 100644 mbcico/yoohoo.c create mode 100644 mbcico/yoohoo.h create mode 100644 mbcico/zmmisc.c create mode 100644 mbcico/zmodem.h create mode 100644 mbcico/zmrecv.c create mode 100644 mbcico/zmrle.c create mode 100644 mbcico/zmsend.c create mode 100644 mbfido/Makefile.am create mode 100644 mbfido/Makefile.in create mode 100644 mbfido/README create mode 100644 mbfido/addbbs.c create mode 100644 mbfido/addbbs.h create mode 100644 mbfido/addpkt.c create mode 100644 mbfido/addpkt.h create mode 100644 mbfido/aliasdb.c create mode 100644 mbfido/aliasdb.h create mode 100644 mbfido/announce.c create mode 100644 mbfido/announce.h create mode 100644 mbfido/areamgr.c create mode 100644 mbfido/areamgr.h create mode 100644 mbfido/atoul.c create mode 100644 mbfido/atoul.h create mode 100644 mbfido/backalias.c create mode 100644 mbfido/backalias.h create mode 100644 mbfido/bread.c create mode 100644 mbfido/bread.h create mode 100644 mbfido/bwrite.c create mode 100644 mbfido/bwrite.h create mode 100644 mbfido/cookie.c create mode 100644 mbfido/cookie.h create mode 100644 mbfido/echoout.c create mode 100644 mbfido/echoout.h create mode 100644 mbfido/fflist.c create mode 100644 mbfido/fflist.h create mode 100644 mbfido/filefind.c create mode 100644 mbfido/filefind.h create mode 100644 mbfido/filemgr.c create mode 100644 mbfido/filemgr.h create mode 100644 mbfido/flock.c create mode 100644 mbfido/flock.h create mode 100644 mbfido/forward.c create mode 100644 mbfido/forward.h create mode 100644 mbfido/fsort.c create mode 100644 mbfido/fsort.h create mode 100644 mbfido/grlist.c create mode 100644 mbfido/grlist.h create mode 100644 mbfido/hash.c create mode 100644 mbfido/hash.h create mode 100644 mbfido/hatch.c create mode 100644 mbfido/hatch.h create mode 100644 mbfido/importmsg.c create mode 100644 mbfido/importmsg.h create mode 100644 mbfido/importnet.c create mode 100644 mbfido/importnet.h create mode 100644 mbfido/lhash.c create mode 100644 mbfido/lhash.h create mode 100644 mbfido/magic.c create mode 100644 mbfido/magic.h create mode 100644 mbfido/makestat.c create mode 100644 mbfido/makestat.h create mode 100644 mbfido/maketags.c create mode 100644 mbfido/maketags.h create mode 100644 mbfido/maptabs.tgz create mode 100644 mbfido/mbaff.c create mode 100644 mbfido/mbaff.h create mode 100644 mbfido/mbdiff.c create mode 100644 mbfido/mbdiff.h create mode 100644 mbfido/mbfido.c create mode 100644 mbfido/mbfido.h create mode 100644 mbfido/mbfile.c create mode 100644 mbfido/mbfile.h create mode 100644 mbfido/mbindex.c create mode 100644 mbfido/mbindex.h create mode 100644 mbfido/mbmail.c create mode 100644 mbfido/mbmail.h create mode 100644 mbfido/mbmsg.c create mode 100644 mbfido/mbmsg.h create mode 100644 mbfido/mbseq.c create mode 100644 mbfido/mbseq.h create mode 100644 mbfido/message.c create mode 100644 mbfido/message.h create mode 100644 mbfido/mgrutil.c create mode 100644 mbfido/mgrutil.h create mode 100644 mbfido/mkftnhdr.c create mode 100644 mbfido/mkftnhdr.h create mode 100644 mbfido/mkrfcmsg.c create mode 100644 mbfido/mkrfcmsg.h create mode 100644 mbfido/mover.c create mode 100644 mbfido/mover.h create mode 100644 mbfido/msgutil.c create mode 100644 mbfido/msgutil.h create mode 100644 mbfido/newspost.c create mode 100644 mbfido/newspost.h create mode 100644 mbfido/notify.c create mode 100644 mbfido/notify.h create mode 100644 mbfido/pack.c create mode 100644 mbfido/pack.h create mode 100644 mbfido/paths.h.in create mode 100644 mbfido/ping.c create mode 100644 mbfido/ping.h create mode 100644 mbfido/post.c create mode 100644 mbfido/post.h create mode 100644 mbfido/postemail.c create mode 100644 mbfido/postemail.h create mode 100644 mbfido/postnetmail.c create mode 100644 mbfido/postnetmail.h create mode 100644 mbfido/ptic.c create mode 100644 mbfido/ptic.h create mode 100644 mbfido/rnews.c create mode 100644 mbfido/rnews.h create mode 100644 mbfido/rollover.c create mode 100644 mbfido/rollover.h create mode 100644 mbfido/scan.c create mode 100644 mbfido/scan.h create mode 100644 mbfido/scannews.c create mode 100644 mbfido/scannews.h create mode 100644 mbfido/sendmail.c create mode 100644 mbfido/sendmail.h create mode 100644 mbfido/tic.c create mode 100644 mbfido/tic.h create mode 100644 mbfido/toberep.c create mode 100644 mbfido/toberep.h create mode 100644 mbfido/tosspkt.c create mode 100644 mbfido/tosspkt.h create mode 100644 mbfido/tracker.c create mode 100644 mbfido/tracker.h create mode 100644 mbfido/ulock.c create mode 100644 mbfido/ulock.h create mode 100644 mbfido/utic.c create mode 100644 mbfido/utic.h create mode 100644 mbfido/viadate.c create mode 100644 mbfido/viadate.h create mode 100644 mbmon/Makefile.am create mode 100644 mbmon/Makefile.in create mode 100644 mbmon/common.c create mode 100644 mbmon/common.h create mode 100644 mbmon/mbmon.c create mode 100644 mbmon/mbmon.h create mode 100644 mbmon/mutil.c create mode 100644 mbmon/mutil.h create mode 100644 mbsebbs/Makefile.am create mode 100644 mbsebbs/Makefile.in create mode 100644 mbsebbs/bank.c create mode 100644 mbsebbs/bank.h create mode 100644 mbsebbs/bbslist.c create mode 100644 mbsebbs/bbslist.h create mode 100644 mbsebbs/bye.c create mode 100644 mbsebbs/bye.h create mode 100644 mbsebbs/change.c create mode 100644 mbsebbs/change.h create mode 100644 mbsebbs/chat.c create mode 100644 mbsebbs/chat.h create mode 100644 mbsebbs/commonio.c create mode 100644 mbsebbs/commonio.h create mode 100644 mbsebbs/email.c create mode 100644 mbsebbs/email.h create mode 100644 mbsebbs/encrypt.c create mode 100644 mbsebbs/encrypt.h create mode 100644 mbsebbs/exitinfo.c create mode 100644 mbsebbs/exitinfo.h create mode 100644 mbsebbs/file.c create mode 100644 mbsebbs/file.h create mode 100644 mbsebbs/filesub.c create mode 100644 mbsebbs/filesub.h create mode 100644 mbsebbs/fsedit.c create mode 100644 mbsebbs/fsedit.h create mode 100644 mbsebbs/funcs.c create mode 100644 mbsebbs/funcs.h create mode 100644 mbsebbs/funcs4.c create mode 100644 mbsebbs/funcs4.h create mode 100644 mbsebbs/getdef.c create mode 100644 mbsebbs/getdef.h create mode 100644 mbsebbs/language.c create mode 100644 mbsebbs/language.h create mode 100644 mbsebbs/lineedit.c create mode 100644 mbsebbs/lineedit.h create mode 100644 mbsebbs/mail.c create mode 100644 mbsebbs/mail.h create mode 100644 mbsebbs/mball.c create mode 100644 mbsebbs/mball.h create mode 100644 mbsebbs/mbchat.c create mode 100644 mbsebbs/mbfbgen.c create mode 100644 mbsebbs/mblang.c create mode 100644 mbsebbs/mbpasswd.c create mode 100644 mbsebbs/mbpasswd.h create mode 100644 mbsebbs/mbsebbs.c create mode 100644 mbsebbs/mbsebbs.h create mode 100644 mbsebbs/mbstat.c create mode 100644 mbsebbs/mbstat.h create mode 100644 mbsebbs/mbtoberep.c create mode 100644 mbsebbs/mbuser.c create mode 100644 mbsebbs/mbuser.h create mode 100644 mbsebbs/mbuseradd.c create mode 100644 mbsebbs/mbuseradd.h create mode 100644 mbsebbs/menu.c create mode 100644 mbsebbs/menu.h create mode 100644 mbsebbs/misc.c create mode 100644 mbsebbs/misc.h create mode 100644 mbsebbs/msgutil.c create mode 100644 mbsebbs/msgutil.h create mode 100644 mbsebbs/myname.c create mode 100644 mbsebbs/myname.h create mode 100644 mbsebbs/newuser.c create mode 100644 mbsebbs/newuser.h create mode 100644 mbsebbs/nextuser.c create mode 100644 mbsebbs/nextuser.h create mode 100644 mbsebbs/offline.c create mode 100644 mbsebbs/offline.h create mode 100644 mbsebbs/oneline.c create mode 100644 mbsebbs/oneline.h create mode 100644 mbsebbs/page.c create mode 100644 mbsebbs/page.h create mode 100644 mbsebbs/pinfo.c create mode 100644 mbsebbs/pinfo.h create mode 100644 mbsebbs/pop3.c create mode 100644 mbsebbs/pop3.h create mode 100644 mbsebbs/pwcheck.c create mode 100644 mbsebbs/pwcheck.h create mode 100644 mbsebbs/pwio.c create mode 100644 mbsebbs/pwio.h create mode 100644 mbsebbs/rad64.c create mode 100644 mbsebbs/rad64.h create mode 100644 mbsebbs/safe.c create mode 100644 mbsebbs/safe.h create mode 100644 mbsebbs/salt.c create mode 100644 mbsebbs/salt.h create mode 100644 mbsebbs/sgetpwent.c create mode 100644 mbsebbs/sgetpwent.h create mode 100644 mbsebbs/shadowio.c create mode 100644 mbsebbs/shadowio.h create mode 100644 mbsebbs/statetbl.h create mode 100644 mbsebbs/timecheck.c create mode 100644 mbsebbs/timecheck.h create mode 100644 mbsebbs/timeout.c create mode 100644 mbsebbs/timeout.h create mode 100644 mbsebbs/user.c create mode 100644 mbsebbs/user.h create mode 100644 mbsebbs/xmalloc.c create mode 100644 mbsebbs/xmalloc.h create mode 100644 mbsetup/Makefile.am create mode 100644 mbsetup/Makefile.in create mode 100644 mbsetup/grlist.c create mode 100644 mbsetup/grlist.h create mode 100644 mbsetup/ledit.c create mode 100644 mbsetup/ledit.h create mode 100644 mbsetup/m_archive.c create mode 100644 mbsetup/m_archive.h create mode 100644 mbsetup/m_bbs.c create mode 100644 mbsetup/m_bbs.h create mode 100644 mbsetup/m_domain.c create mode 100644 mbsetup/m_domain.h create mode 100644 mbsetup/m_farea.c create mode 100644 mbsetup/m_farea.h create mode 100644 mbsetup/m_fdb.c create mode 100644 mbsetup/m_fdb.h create mode 100644 mbsetup/m_ff.c create mode 100644 mbsetup/m_ff.h create mode 100644 mbsetup/m_fgroup.c create mode 100644 mbsetup/m_fgroup.h create mode 100644 mbsetup/m_fido.c create mode 100644 mbsetup/m_fido.h create mode 100644 mbsetup/m_global.c create mode 100644 mbsetup/m_global.h create mode 100644 mbsetup/m_hatch.c create mode 100644 mbsetup/m_hatch.h create mode 100644 mbsetup/m_lang.c create mode 100644 mbsetup/m_lang.h create mode 100644 mbsetup/m_limits.c create mode 100644 mbsetup/m_limits.h create mode 100644 mbsetup/m_magic.c create mode 100644 mbsetup/m_magic.h create mode 100644 mbsetup/m_mail.c create mode 100644 mbsetup/m_mail.h create mode 100644 mbsetup/m_marea.c create mode 100644 mbsetup/m_marea.h create mode 100644 mbsetup/m_menu.c create mode 100644 mbsetup/m_menu.h create mode 100644 mbsetup/m_mgroup.c create mode 100644 mbsetup/m_mgroup.h create mode 100644 mbsetup/m_modem.c create mode 100644 mbsetup/m_modem.h create mode 100644 mbsetup/m_new.c create mode 100644 mbsetup/m_new.h create mode 100644 mbsetup/m_ngroup.c create mode 100644 mbsetup/m_ngroup.h create mode 100644 mbsetup/m_node.c create mode 100644 mbsetup/m_node.h create mode 100644 mbsetup/m_ol.c create mode 100644 mbsetup/m_ol.h create mode 100644 mbsetup/m_protocol.c create mode 100644 mbsetup/m_protocol.h create mode 100644 mbsetup/m_service.c create mode 100644 mbsetup/m_service.h create mode 100644 mbsetup/m_task.c create mode 100644 mbsetup/m_task.h create mode 100644 mbsetup/m_tic.c create mode 100644 mbsetup/m_tic.h create mode 100644 mbsetup/m_ticarea.c create mode 100644 mbsetup/m_ticarea.h create mode 100644 mbsetup/m_tty.c create mode 100644 mbsetup/m_tty.h create mode 100644 mbsetup/m_users.c create mode 100644 mbsetup/m_users.h create mode 100644 mbsetup/m_virus.c create mode 100644 mbsetup/m_virus.h create mode 100644 mbsetup/mbsetup.c create mode 100644 mbsetup/mutil.c create mode 100644 mbsetup/mutil.h create mode 100644 mbsetup/screen.c create mode 100644 mbsetup/screen.h create mode 100644 mbsetup/stlist.c create mode 100644 mbsetup/stlist.h create mode 100644 mbtask/Makefile.am create mode 100644 mbtask/Makefile.in create mode 100644 mbtask/callstat.c create mode 100644 mbtask/callstat.h create mode 100644 mbtask/issue create mode 100644 mbtask/libs.h create mode 100644 mbtask/mbtask.c create mode 100644 mbtask/mbtask.h create mode 100644 mbtask/nodelist.c create mode 100644 mbtask/nodelist.h create mode 100644 mbtask/outstat.c create mode 100644 mbtask/outstat.h create mode 100644 mbtask/scanout.c create mode 100644 mbtask/scanout.h create mode 100644 mbtask/signame.c create mode 100644 mbtask/signame.h create mode 100644 mbtask/taskcomm.c create mode 100644 mbtask/taskcomm.h create mode 100644 mbtask/taskdisk.c create mode 100644 mbtask/taskdisk.h create mode 100644 mbtask/taskinfo.c create mode 100644 mbtask/taskinfo.h create mode 100644 mbtask/taskregs.c create mode 100644 mbtask/taskregs.h create mode 100644 mbtask/taskstat.c create mode 100644 mbtask/taskstat.h create mode 100644 mbtask/taskutil.c create mode 100644 mbtask/taskutil.h create mode 100755 missing create mode 100755 mkinstalldirs create mode 100644 script/Makefile.am create mode 100644 script/Makefile.in create mode 100644 script/README create mode 100755 script/installinit create mode 100644 script/maint create mode 100644 script/mbse.start create mode 100644 script/mbse.stop create mode 100644 script/midnight create mode 100644 script/monthly create mode 100644 script/rc create mode 100644 script/rc.shutdown create mode 100644 script/weekly create mode 100644 stamp-h.in diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..9cf718d8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,31 @@ + MBSE BBS AUTHORS. + +All following people have contributed to the MBSE BBS project. I'm sure that +people are missing from this list. The list is not in any special order. + +Michiel Broek mbse@users.sourceforge.net 2:280/2802 +Joaquim Homrighausen joho@abs.lu +Andrew Milner andrew@fido.lu +Mats Wallin mw@fido.lu +Eugene G. Crosser crosser@average.org +Stanislav Voronyi stas@uanet.kharkov.ua +T. Tanaka +Martin Junius +Omen Technology Inc +Arjen G. Lentz +Cristof Meerwald +P. Saratxaga +Dima Maloff +Jan van de Werken +Sean Rima +Juergen Heisel +Jim Hansen +Ken Bowley +Redy Rodriguez 2:283/613.6 +Johannes Lundberg 2:206/149@fidonet, +Vincent Danen +Francois Thunus francois@telematique.org +Johan Lindh +William McBrine +Harald Wuensch +NERvOus nervous@nervous.it diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..e77696ae --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/CRON.sh b/CRON.sh new file mode 100644 index 00000000..631538b7 --- /dev/null +++ b/CRON.sh @@ -0,0 +1,100 @@ +#!/bin/sh +# +# Crontab setup script for MBSE BBS +# +# (C) Michiel Broek, v0.06 06-Mar-2001 + +echo "MBSE BBS for Linux crontab setup. Checking your system..." + +# Basic checks. +if [ `whoami` != "mbse" ]; then +cat << EOF +*** Run $0 as "mbse" user only! *** + + Because the crontab for mbse must be changed, you must be mbse. + +*** SETUP aborted *** +EOF + exit 2 +fi + +if [ "$MBSE_ROOT" = "" ]; then + echo "*** The MBSE_ROOT variable doesn't exist ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +if [ "`grep mbse: /etc/passwd`" = "" ]; then + echo "*** User 'mbse' does not exist on this system ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +if [ "`crontab -l`" != "" ]; then + echo "*** User 'mbse' already has a crontab ***" + echo "*** SETUP aborted ***" + exit 2 +fi + +MHOME=$MBSE_ROOT + +clear +cat << EOF + Everything looks allright to install the default crontab now. + If you didn't install all bbs programs yet, you better hit + Control-C now and run this script when everything is installed. + If you insist on installing the crontab without the bbs is complete + you might get a lot of mail from cron complaining about errors. + + The default crontab will have entries for regular maintenance. + You need to add entries to start and stop polling fidonet uplinks. + There is a example at the bottom of the crontab which is commented + out of course. + + IMPORTANT: the first crontab entry is to set the Zone Mail Hour. + This entry is set for Holland, Amsterdam. ZMH is 02:30 - 03:30 UTC + for zone 2. CET is one hour plus in wintertime and two hours plus + in summertime. If you run "mbstat check" at each possible begin + and end of ZMH you must run it at 03:30, 04:30 and 05:30 local CET. + You must calculate and set the times for your own timezone and own + Fidonet Zone Mail Hour. + + On most systems you can edit the crontab by typing "crontab -e". + + Hit Return to continue or Control-C to abort. +EOF +read junk + +echo "Installing MBSE BBS crontab..." + +crontab - << EOF +#------------------------------------------------------------------------- +# +# Crontab for mbse bbs. +# +#------------------------------------------------------------------------- + +# User maintenance etc. Just do it sometime when it's quiet. +00 09 * * * $MHOME/etc/maint + +# Midnight event at 00:00. +00 00 * * * $MHOME/etc/midnight + +# Weekly event at Sunday 00:05. +05 00 * * 0 $MHOME/etc/weekly + +# Monthly event at the 1st day of the month at 00:10. +10 00 1 * * $MHOME/etc/monthly + +#----------------------------------------------------------------------------- +# +# From here you should enter your outgoing mailslots, when to send mail etc. + +# Mail slot example. +#00 02 * * * export MBSE_ROOT=$MHOME; \$MBSE_ROOT/bin/mbout poll f16.n2801.z2 -quiet +#00 03 * * * export MBSE_ROOT=$MHOME; \$MBSE_ROOT/bin/mbout stop f16.n2801.z2 -quiet + +EOF + +echo "Done." + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 00000000..c89e14f9 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4062 @@ + MBSEBBS History. + + The good news is at the bottom :-) + +v0.00 Started work on the Rapidbbs sources to make new structures, + headerfiles and makefiles. + The whole thing will include Fidonet echomail and tic file processing. + +v0.01 Until v0.06 lots of sourcecode fixes, bugs removed which became + visible after writing the new header and makefiles. Included common + and jamapi libraries. The jamapi is not in use yet but will be the + final message base format. + + Rewritten the mbse deamon. This deamon monitors the bbs and all the + utilities. + + Written an import util to import textfiles from the databases exported + by a little Pascal program that exports the RA databases from the DOS + bbs. + + Started writing a new setup utility. While doing this the old config + program is being stripped down. + + Renamed the filelist program to allfiles. + +v0.06 In the internal mbsed server structure added information for user + online messages. Added ADIS:2,pid,flag; set users Do Not Disturb + flag, also changed the bbs to sent that flag. + + Added Status commands to the mbsed, test for BBS open, and Zone + Mail Hour. 2 new statements in etc/mbsed.conf. The mbsebbs now + tests at startup for ZMH and BBS open. If it is closed the user is + disconnected with the reason why. + +v0.07 The new structures are ready. The bbs can run with local mail only. + + Renamed the filepack program to mbfile, it will do a lot more later. + + Removed the whoson program, the functions are in the setup program now. + + Added in the setup program the oneliner editor, protocols editor, + language setup editor, limits editor. + The oneliner editor has an import facility to import plain textfiles + to add oneliners. + + Changed structures again, lastcaller and ttyinfo. + + Removed the usered program, the users editor is in setup now. + + Fixed the download (non batching) function DownloadB, it does work + more or less. Changed the calling program from execl() to system() + to fix the stack problems. Now need testing voor carrier loss and + timeouts. + + After testing with a DOS-PC (A real fast 286 10 MHz state of the art + of the eighties, directly connected to the tty port) the Good_Bye + function needed 5 seconds extra delay to be shure all data is + send to the user. Also the parent died too fast so the mbsed server + wasn't notified when the client was logged off. + + In the bbs chat.c added unlink the /tmp/.BusyChatting file so the + chat could be more than once in a session. + + In the internal mbsed server structure added information for user + online messages. Added ADIS:2,pid,flag; set users Do Not Disturb + flag, also changed the bbs to sent that flag. + + Added Status commands to the mbsed, test for BBS open, and Zone + Mail Hour. 2 new statements in etc/mbsed.conf. The mbsebbs now + tests at startup for ZMH and BBS open. If it is closed the user is + disconnected with the reason why. + +v0.08 Added the JAM c api. This is a modified version for Linux. + + Reading JAM messages and Quickscan JAM messages implemented. Removed + support for the old message base format. The function Msg_Post() does + not work anymore, must be rewritten to support JAM. + + In the msgpack program removed all code for the old message base + format. Inluded support for client/server. + + Removed all structures of the old message base format, the only + format left is JAM. + + +v0.09 22-Mar-1998. + In Language data compiler removed output to screen for each compiled + line. When finished compiling it reports the number of language lines. + + Changed the number of lines for the line editor in Post_Msg() and + Reply_Msg() in a #define statement. In the language source it still + allways says 60 lines. + + Bugfix in mbsetup: edit message area item 7 an 8 didn't work. + + Start writing of man pages. + + Start writing mbfido, the net- echomail tosser, scanner and packer. + Succeeded tossing echomail, no dupechecking, links checking or other + checks are done. No reply linking either. + + mbsetup: Added Fidonet aka setup. + + Moved JAM I/O functions to the common directory. + + Created the mbmon program out of mbsetup. Removed those items from + mbsetup. + + Start build of the dbase library, this library will contain functions + to access the configuration datafiles for all utilities except the + mbsetup program. + +v0.10 15-Apr-1998. + Allfiles changed to make use of the common and dbase libraries. Does + logging now of activities. Removed links to src/bbs/funcs4.c + + Added fileareas and filesdatabase import to the import program. + + Corrected file area mismatches in mbsebbs and fedit. + + Mbsetup: finished global setup. Fixed pull filegroup and messagegroup. + Added edit bbs file areas. Changed format of fareas.data. + + mbfido: Added first dupechecks, only logging. Fixed errors in dbase + search routines, caused mail to be tossed in the wrong directories. + Added tossing of bad (unknown areas) and dupe mail in the bad and + dupe boards. Checks for .PKT destination implemented. Ideas for + netmail tracking written. Dupe checking seems to work, but I can't + compare it with my other tosser yet. Note after more testing: + it's better than GEcho's 1.11+ dupechecking. + + allfiles: Opens header.txt now only before processing the areas. + Added footer.txt. Both files must be in the configfiles directory, + if they are not present, nothing will be inserted. Removed all code + that constantly opened and closed the output file. Added logging for + total processing time. Added new lines to the area headers. Areas + are only written if there are downloadable files in them. Download + counter now represents bbs downloads, ftp downloads and file requests. + The last two counters are not in use yet. + +v0.11 26-Apr-1998 + mbsebbs: In the mail reader swapped From and To language fields, the + names were in the right place. Added the nodenumber after the from + name. Must be set for messagearea type (Local/Net/Echo). + + mbfido: Corrected some loglevels. + + userpack: rewritten from scratch. Deletes unix accounts as well, uses + /usr/sbin/userdel to do this, so shadow support works just fine. + This program must be run as setuid root setgid root. + + structs.h: removed flags for Unixmode and all related flags. + + mbuseradd: written. This is a setuid root setgid root version of + adduser, this program is called by newuser to create the unix account + of a bbs user. It also creates the homedirectory, the .profile file + and expires the unix account password. When a new created unix user + logs in he will be prompted for a new password. + + newuser: lots of rewriting. Added inactivity timers. Now we have + always unix accounts and fido bbs accounts. It will also die + nicely when the user did hangup on us or waited for idle timeout. + + mbsebbs: Check for unix account, if it doesn't exist the user is + forced to create a unix account. If unix login we now have a pause() + at the same place the password prompt is so the user can see the + opening screen and read it. + Removed the code that there was a parent (guarding users logon time) + and a child process (running the user). There is only one process now. + Implemented keyboard input timers. The total onlinetime must be + guarded in another way now, ie. checking must be done at prompts. + In the mean time proper idletimeout, hangup and error conditions + will log the user off in a neat way and writing into the logs about + what happened is mostly solved. + + mbsebbs and newuser: New users can only be handled by the newuser + program. Listed users only by the mbsebbs program. You need 2 accounts + without a password for this. Maybe I'll chain these 2 programs later. + + misc: compiling is a mess again, more libraries are needed, time to + close this version. + +v0.12 07-May-1998. + mbsed: Rename the logfile from "mbsed" to "mbsed.log". The mbsed + logfile is opened and closed everytime now. Logfile cleanup utils + can now safely remove the logfile, make it smaller etc. + + mbsebbs: Splitted misc.c into bye.c, pinfo.c and misc.c + + dbase library: added userrecord search. Added netmailboard search. + + mbfido: removed segmentation fault caused by a too long kludge, added + a check for the stringlength (512 bytes). Removed bugs in netmail + destination tests. Implementation of ftn netmail import into JAM area. + Only the first netmail area is used, no need for several areas now. + + mbsebbs: Added aka display when reading netmail. Changed autowrap + to line 74. + Added test for users handle when scanning new mail. + Removed test tlcap() when comparing names. The tosser should correct + the names. + Changed the MsgSelectPrompt() to default return the lastread pointer + instead of message 1. + Changed Read_a_Message() so it will return TRUE if message read was ok, + FALSE otherwise. + CheckMail() now starts searching at the users lastread pointer. It + now also keeps track of messages to the user, and gives the option + to read them. Reply is not possible yet, but posting isn't working + also. + Added a check that the receivername must exist to prevent false new + mail. + Changed UserList() to skip the empty userbase records. + Place the users timecheck functions in a separate file, made it work + again. Inserted timecheck points at several prompts. + Changed the timebank to reflect new timecheck routine's. + Moved the exitinfo functions to a separate file, several other modules + now use new functions in this file instead of internal ones. + Changed FileArea_List() to work with options (F+ and F-) for direct + area change. + Improved the fatal menu error construction. The user now sees a message + and will logoff by SIGILL. + +v0.13 24-May-1998. + mbfido: + Added a debug line to show flagfield of the original packet. + Added code to fill the message header MsgIdCRC and ReplyCRC + fields. + Added version info in the logfile. + + mbsebbs: + Corrected unixmode login problem if there where more than one + field within the gecos field of the passwd file. + Added version info in the logfile. + Changed the setting of signal handlers, removed SIGINT, added + SIGILL. + Supress display goodby screen in case of a SIGHUP. + Display ttyinfo.comment instead if ttyname in connect info. + Added create/check for subdirectories wrk and tag in the users + homedirectory, wrk is for the users homedir fileoptions, tag + is where symlinks of tagged files area placed. + Corrected message diplayed to user when logging in during zone + mail hour. + Removed menu option GlobalDownload, see new feature below. + Implemented download file tagging in menus FileList and + NewFilesScan. + Implemented download tagged files, the old download function + is gone. + Moved Change_Protocol and Set_Protocol from file.c to change.c + where they belong. Change_Protocol is now Chg_Protocol as all + other functions in change.c use the same naming convention. + Made KeywordScan and FilenameScan working without coredumps, + implemented file tagging. + Made enum vars for WhosDoingWhat. + Changed the internal filearea record number, area 1 is now 1, + not 0. This should prevent a lot of bugs. + Now setting large timeouts on the client/server guard during + filetransfers to prevent server disconnection. Changed mbsed + and common.a for that. + Added logging info when user is kicked out if the BBS is + closed. + Split file.c into file.c and filesub.c + Added menu function 111, Copy file to home directory. + Download_Home, Delete_Home, List_Home, Upload_Home now all work + with the new directory structure. Upload and Download homedir + do not count uploaded/downloaded bytes, the user gets no ratio + bonus after upload, only the up/downloads are counted. + Quota check for users home directory. The value can be set + with the mbsetup program, value is MBytes. + Removed error message if user selected a menu option where he + has no access rights for. The user now sees nothing. If you + want to give a response, use the menu system! + Reset colors to lightgray on black after logoff. + Added menu function EditTaglist. + + mbsed: + Invented two new commands, ATIM:1,n; which set a new client/ + server timeout, and ADEF:0; which resets the client/server + timeout to 600 seconds. + + common.a: + Implemented the two new client/server commands: ATIM and ADEF. + + mbsetup: + In global BBS setup, added editing Users Quota. + + import: + In FDB import, changed the filenames to lowercase. + + allfiles: + Output list now contains CR/LF at the end of each line. + + mbuseradd: + Added the line "export TERM=pcansi" to the generated .profile + in the new users home directory. This seems to work quite well + for all kinds of clients. + + + +v0.14 02-Jun-1998. + msgpack: + Renamed to mbmsg, it will do more as just packing messages. + Implemented using the msgbase.a library: Purging (Days old + and Max msgs), Packing deleted messages and Reply linking. + During pack the messages are renumbered and lastread pointers + are adjusted. + + mbsetup: + Added edit messagebase storage type. + + msgbase.a: + New library, universal message base library, must support + JAMmb, Fido *.MSG, Passthru, Usenet news and E-Mail. + This came original from LoraBBS, written by Marco Maccaferri. + I changed the sources to normal C code without objects, that + was the fastest method to mix it with the existing sources. + I dropped support for Hudson and Squish. + Only JAM is supported for a start. + The JAM module renumbers the messages while packing. + Added support for lastread pointers. + Changed all msg handling so that the messagetext must contain + all the kludges to be compatible with several message bases. + This means that the JAM module now handles the kludges in the + text, storing and retrieving it between the *.jhr files and + text. This also means that the applications don't have to + worry about kludges. + + mbsebbs: + Changed mail.c to work with the new msgbase library, dropped + the old jamapi. Scanning new messages looks slower, maybe + the speed improvement must be made in the msbase library. + Applied all changes in the messagebase library to the bbs + program. + + mbfido: + Applied all changes in the messagbase library in the tosser + module. While doing that I saw some bugs but they don't + mather anymore. + + + +v0.15 13-Jun-1998. + msgbase.a: + Implemented msgbase locking for JAM messagebase. Dropped + future support for other messagebase formats, I stick to + JAM and only JAM, it can do all we need, including mailer + netmail directory. + Implemented all possible attributes in the interface. + + dbase.a: + Removed some bugs in dbmsgs.c + Added code to update the nodes and msgs data records if they + are changed. + During msgs record loading the group record will also be + loaded if it's defined. + Added support for .tic area lookup. + + mbmsg: + Implemented msgbase locking during msgbase updates. + Added colours. + + mbfido: + Implemented msgbase locking during msgbase updates. + Implemented simple echomail forwarding in the queue. + Splitted tosspkt.c into importmsg.c echoout.c and tosspkt.c + to make the source more readable. + Started collecting SEEN-BY and ^APATH information in memory. + Started appending SEEN-BY entries during echomail forward. + Added code which should append SEEN-BY and PATH lines in + outgoing echomail. + In the startup code changed the catching/ignoring of signals. + Activated mail send and received counters in the nodes + records. + Activated echomail received counters. + Started working on .tic file processing, using my own MBFIX + code (in Turbo Pascal) as a guide. + + mbsed: + Changed the server locking in a more portable and secure way. + Added sequencer counter for generating MSGID numbers and + message packet numbers. + Removed a bug in response strings when the BBS is closed. + The signal SIGTERM is now ignored, we wait for SIGKILL only + so we keep running as long as possible. + + mbmon: + Added support for sequence numbers display. + + mbsebbs: + Removed a bug in the syntax of BBS closed messages. + Added a toggle switch to display message kludges for the sysop. + Added hilite color for quoted message lines in message read. + + mbstat: + The BBS close command doesn't need a reason anymore. + Implemented the wait function. We only wait for users online + and utilities that we want to complete their actions. Depending + on the type of init program, if it uses shutdown scripts, you + can now wait for the system to become idle before the real + system shutdown starts. + + + common.a: + Added a flag "show_log" to the Syslog function to suppress + logging to the screen. + + mbsetup: + Added support to edit .tic areas. + Started working on the creation of a site document, this is + a complete overview of the whole setup. + + +v0.16 06-Jul-1998. + + General: + This version is the first version installed on the real BBS + server, line #2. While doing this I discovered lots of errors + in the Makefiles because I installed it from scratch. I also + found out that GEcho and or RA is screwing up some JAM bases + causing this program to dump core. Did some testing, download + and mail reading is ok. + + mbsebbs: + NewfilesScan and show files listings now work with the file + upload dates instead of the real filedates. + + mbfido: + It's possible to import .tic files into the bbs. + Unknown echomail areas now log with WriteError(). + Added functions to pack mail for downlinks and put it in + the mailer outbound. + Because of small diffrences between ifcico and DOS mailers + running 2 mailers together still doesn't work for attached + files and mail. + Fixed a bug in outbound mail packets, the packed messages + didn't start with 0x0002 so downlinks didn't process the + messages. Output of echomail works now! + When processing large amounts of .tic files, the processing + stopped after about 30 files. Added 2 forgotten fclose + statements. + Added sorting functions for filenames with date/time. All + inbound processing is now sorted by date and time, oldest + files first. + + common.a: + In mbfile.c changed file_cp() to copy file attributes as well. + + userpack: + Changed commandline syntax. + + mbmsg: + Changed commandline syntax. + + mbstat: + Changed commandline syntax. + Added colors. + Does timeout after one hour waiting for the BBS to become free. + + mbsetup: + Added setup for .tic magic records. + Improved logging reason when tossing messages not for us. + + dbase.a: + Remove a bug where reading downlinks from areas base gave + nothing. (Introduced in 0.15). + + mbmon: + Corrected the screen header. + + +v0.17 30-Jul-1998 + + mbfido: + When importing files to the BBS the destination directory + is checked and created if it doesn't exist. + Improved checks when to rearchive incoming files. + Forgot to chdir back to the inbound when rearc failed. + Switching virus check off when the inbound file isn't an + compressed archive. Should check incoming *.exe (selfextracting + archives). + Keep number of files now works. + TIC forwarding to downlinks implemented. There are 2 netmails + for each forwarded file, one for the file itself and one for + the .tic file. The subjectline is to short under Unix. The + second netmail is an empty one, lets see how this works. + Added cookies. + Packing ARCmail now checks for bundles older then 5 days and + creates new bundles if found. + Added netmail pack to ARCmail. + Improved errorlogging again when tossing bad echomail. + Scan for outgoing echomail from the bbs is working. It is a + complete messagebase scan for now. + TIC forwarding again with one netmail, I faked the subject + line, all files seem to come from C:\FILES\. This seems to + give no problems with the other end of the link. + + mbmsg: + Improved debug logging. + Processing in only one area didn't work anymore. + + mbsebbs: + Made post new message work. + Now unlocking and closeing the messagebase after a crash. + Moved the lineeditor to a seperate source module. + Reply to messages is working, also from scan for new mail. + Comment to sysop now works. + Removed the Voting door. + + +v0.18 10-Aug-1998. + + general: + New record structure for fidonet networks. This makes + it possible to use the same nodelist indexes as ifmail. + Note that de define -DHAS_NDBM_H may only be set if you + have done this also in the ifmail package! This is set + in ~/src/mbfido/Makefile + + run_inout: + A shell script run from the mbse crontab (every minute) to + see if there is something to do. It scan's the protected + inbound and scan's for the ~/sema/mailout semafore. + + mbsebbs: + Creates a ~/sema/mailout semafore if mail is entered. + Added extra debug logging during newmail scan. On the live + bbs mbsebbs keeps on dumping core probably due to RA or GEcho. + Most amusing is that after crashing mbsebbs, RA will see new + netmail again, as if only mbsebbs knows how to handle the + users lastread pointers and fixes them for RA; sigh. + + mbfido: + Start working on the netmail tracker/router. It works without + an external routing file, although hosts will need one. + It works on checking known nodes, then nodelists, and then + known nodes again. This is very experimental. + + mbsetup: + Changed to the new fidonet structures. + + import: + Changed to the new fidonet structures. + + general: + Installed at 13-Aug-1998 at the BBS for testing. + + +v0.19 14-Aug-1998 + + general: + Wrote some documentation about how to setup the ftp server + so that it works together with MBSE BBS. + + mbsebbs: + After download the message "updating download counters" now + will first send a to overwrite the zmodem init string + on the users screen. + Added structures for bluewave. + Now scans for new files at logon. + Removed global variable sUserName, gave some strange results. + Added logging which msg area was active when a segmentation + fault occurs. + + script: + A new subdirectory for /bin/sh scripts. Look out with this + one, if you modify the scripts in ~/etc or ~/bin directly + they will be overwritten with each new install. + + mbuseradd: + Add each new user to /etc/ftpusers to prevent them to login + under their own name in the ftp server. + + fbgen: + Setting umask to 002. + + fileedit: + Removed, was obsolete. + + import: + Setting umask to 007. + + common.a: + mkdirs now creates directories with permission 0775. + Added dos<->unix filenames translation. + Rewrote tu() and tl() functions. + + mbfile: + Setting umask to 002. + Now checks for files on disk, but missing in the fdb. Deletes + them when found (exept some). + Now when packing the fdb records marked for deletion, also + if the file is on disk, it is deleted. + Added some commands to the todo list. + With the check command it now reports the area number to the + mbsed server, so mbmon will display how far it is. This will + also avoid timeouts on large areas. + Now handles multiple commands in one run. Pack will run + automatic if there are files deleted. + + mbfido: + Set a semafore "msglink" when the message base is modified. + Added more debug logging for files descriptions. + Implemented dos<->unix filename translation for tic file + forward. + File attaches in .flo files now are DOS filenames and .flo + files are now DOS-compatible. + If there are no more then 2 Long Description lines we asume + that there is a better single (old style) Description line. + There are uplinks that make a mess of these lines. + Netmail forwarding should work now as long as the nodes via + we must route are in our setup. + + mbsed: + Added in wait for free the mbindex and mbuser programs. + + mbindex: + Written. Heavlily based on Eugene Crosser's ifindex. + + mbsetup: + Written the menu editor and removed the old mbconfig program. + Added some editor commands to the user editor. + + mbuser: + Now leaves the records alone with the NeverDelete flag set. + + mbmsg: + Added logging when a segmentation fault occurs which was the + last message area. + + +v0.20 24-Aug-1998 + + common.a: + Moved from mbfido the modules ftn, falists, nlindex and + nodelist to this library. More programs will need it. + + mbindex: + Changed some loglevels. Removed the -force switch, compile + is always forced now. + Removed a bug to the path of the index files. + + import: + Now using dos2unix pathname translation for fileareas and + mailareas import. + + mbfido: + Changed some logging. Removed ftn, falists, nlindex and + nodelist modules, they are now in the common library. + + +v0.21 25-Aug-1998 + + mbindex: + Trashed the index files when a new nodelist in the setup + was added. (ifindex did this also). Now it will allways + force to recreate the index files. + Now sends username who started mbindex to mbsed. + + mbfido: + Imported files into bbs areas now get filemode 0644 instead + of 0660 so the ftp/www clients will really see them. + Corrected the experimental replace test, could never work. + If after trigger the compile nodelist flag there came in + another file, the flag was reset. + Now sends username who started mbfido to mbsed. + + mbsebbs: + Created a language crossreference listing. Corrected some + language numbers. + After changing the language, it is now confirmed in the + new selected language. + When the language file is missing, the error message no longer + comes from the missing language file, now it is hardcoded. + Minimum location length is now adjustable with mbsetup, + changed language prompt 74. + Replaced hardcoded messages in chat with language prompts + 59 and 60. + Changed error logging in exitinfo.c + When reading messages the more prompt is now language prompt + 61 instead of hardcoded. + Posting messages is now blocked for Noreply boards. Language + prompt 438. + In message readpanel now language prompts 211 and 212 for + Next reply: and Reply to: threads. + In message area select now using prompt 207. + In newmailscan, added prompt 218 and the Quit option. + In message status, added prompt 226. + Readpanel, added prompt 227. + Delete specific message subfunction does work now. + In display file with more, changed prompt 72. + Changed prompts in file.c and filesub.c. + The info screen is 1 character smaller, 79 characters, some + terminal programs did extra line wrapping. + Added new language file format, the datafile now includes + the keys users can press. + Moved the loading of user's preffered language more to the + begin of the login procedure. + When the user is unknown (ordinary BBS account), the newuser + programm is started. If that runs successfull (depends on the + user on-line), mbsebbs will be run again. It's probably wise + to merge these 2 programs. + + mbsetup: + Minimum location length installed in menu 1.5 + + allfiles: + Now sends username who started allfiles to mbsed. + + mbfile: + Now sends username who started mbfile to mbsed. + + mbmsg: + Now sends username who started mbmsg to mbsed. + + mbstat: + Now sends username who started mbstat to mbsed. + + mbuser: + Now sends username who started mbuser to mbsed. + Did leave the users.data file owned by root. It is now + set to the owner and group of the "mbse" account. + Added screen output for non-quiet mode. + + lang: + Changed to compile new language datafile format, including + the keys a user can press. + + newuser: + Added new language file format, the datafile now includes + the keys users can press. + Now always asks Date of Birth, this is necessary for later + checks. + At the end now engages mbsebbs. + + mbuseradd: + Now uses the created gid and uid voor changing ownership + of files and directories. + + +v0.22 06-Sep-1998 + + mbsetup: + Changed logfile to one master logfile. + Added menus for offline reader. + + allfiles: + Changed logfile to one master logfile. + + mbsebbs: + Changed logfile to one master logfile. + Started offline reader. + + mbfile: + Changed logfile to one master logfile. + Corrected creating full path/filename in pack files. + Added creating and removing symlinks for file requests. + Now deletes files during "kill" instead of only marking. + Simplified log messages. + Added commandline switch "req", this will only check the + file request symlinks. + + mbmsg: + Changed logfile to one master logfile. + + fbgen: + Changed logfile to one master logfile. + + newuser: + Changed logfile to one master logfile. + + mbuser: + Changed logfile to one master logfile. + + mbstat: + Changed logfile to one master logfile. + + mbindex: + Changed logfile to one master logfile. + + mbfido: + Changed logfile to one master logfile. + Added creating and deleting of symlinks for file requests. + Files removed from the filedatabase when running "keep files" + are now also removed from disk. + Removed some debug logging for netmail forwarding. It seems + to work. + Replace files now works more or less. Moved the fdb packer. + + mbindex: + Only logs crash cause if errorlevel > 0. + Removed some invisible screen output in quiet mode. Cron did + notice this. + + lang: + Renamed to mblang, also the source directory is now mblang. + The directory lang will now be used for language sources. + + +v0.23 20-Sep-1998. + + global: + Added #pragma pack(1) to ~/src/include/libs.h so that all + datafiles are now compatible over several hard and software + platforms. I needed this to implement the BlueWave Offline + Reader into the bbs. Increased the QWK tagname field to 20 + characters. + + mbsebbs: + Made menu execution logging more readable. + If a user has no archiver set, set default to ZIP at logon. + Changed logging in the Download Direct command. + Implemented first raw version of BlueWave Offline Reader. + Needs some security improvements, file requesting, filters + but it works for now. + Checking for a Unix account was done before the password was + checked, so if the password was wrong the user was asked for + a new Unix account again. + + mbfido: + For netmail import now searches the netmail area on zone:net + match. + + import: + Removed bugs when converting DOS to Unix paths which resulted + in corrupted pathnames. + + mbsetup: + Corrected linefeed problem in language doc printing. + Horizontal line drawing now with low-ASCII instead of Alternate + Character Set. + + mbmon: + Horizontal line drawing now with low-ASCII instead of Alternate + Character Set. + Corrected a color problem in View BBS Information, and added + display BBS startdate. + + +v0.24 30-Sep-1998. + + structs.h: + New fields in config.data: OLR_MaxMsgs, OLR_NewFileLimit, + OLR_MaxFreq. + New fields in mareas.data: OLR_Default, OLR_Forced. + New fields in ttys.data: honor_zmh. + Added Areafilename field to group records. + + mbsebbs: + Combined some functions from offline.c and mail.c into + msgutil.c + Messages posted with a OLR are now counted in the users record. + Closeing the bbs during Zone Mail Hour can now be set for each + individual line. + Now counting and marking the date/time when posting messages + in mareas.data. + + mbsetup: + Corrected some sitedoc problems in global setup. + Added sitedoc printing for mail setup. + Added file and mailgroups setup to the nodes setup. + Added newfiles reports setup. + Added filefind areas setup. + + mbfile: + Corrected spelling error. + + mbaff: + New program. Announce new files and FileFind (Allfix). + + mbfido: + In .tic file processing if we were a pointaddress, the path + checking always gave an error. The check of our boss is + skipped now. + The correct .tic area and filedate is now set in the toberep + database. + + mbmsg: + Improved initialisation. + + +v0.25/a 12-Oct-1998. + + general: + From now on version numbering will get /a (Alpha), /b (Beta) + and /g (Gamma) release extensions. This is necessary for + live testing at my bbs. + + mbfido: + The Cost field in the toberep.data file was not set. + + msgbase.a: + Added extra screen output in certain error conditions. + Added a trick to generate a FromAddress from the Msgid + in case there is no FromAddress. This was left blank by + GEcho 1.11+ (DOS). + + mbaff: + Added some IsDoing information for the monitor. + Setting ReplyCRC to -1 instead of 0 if it's an original + message. + Minimum searchstring length is now 3 characters (hardcoded). + Added a check to see if there is a FromAddress and a Subject + before a message is added to the scanlist. + + mbsebbs: + Corrected spelling error in OLR download logging. + + mbsetup: + Changed some page layouts in the sitedocs, added some + forgotten formfeeds. + + +v0.25/b 14-Oct-1998. + + mbfido: + If the tic queue directory didn't exist, it is now created. + Netmail messages now have zone:net aka matching on the + destination and from addresses. + Started with the AreaMgr and FileMgr functions. It can respond + to %help. + Added the notify function. + + mbsetup: + When picking a mailgroup in messages setup or a filegroup + in ticsetup, the ftn aka is copied from the group setup as + a default aka for that area. + When setting the area tag and if the OLR tagname is empty, the + area tag is copied there as a default. + + +v0.26/a 17-Oct-1998. + + general: + In some databases in the header there is now a time_t field + added. This is to mark the last statistics counters rollover. + Programs that count statistics must perform an rollover when + it's run on a new day, week or month. + + warning: + To upgrade the databases, enter the setup for message areas, + tic areas, nodes, file groups and message groups and save + the databases. + + mbfido: + Implemented new statistic counters. + Implemented rollover of the statistic counters every week and + new month. + Changed program locking, now it locks the whole program in + stead of short moments. + + mbsebbs: + Implemented new statistic counters. + + mbaff: + It now counts the posted messages in the message area. + Corrected the announce message text. + + +v0.26/b 20-Oct-1998 + + mbsetup: + Wrote the hatch manager. All basic functions are present now. + All databases that can be packed after deleting records can + do this now. During update those databases area sorted. This + is not for the message areas, files areas and the userbase. + These files may not be packed. + + + +v0.27/a 29-Oct-1998 + + general: + Changed the database format for the files. Added support for + long filenames. The .tic file area is also stored in the + records to make the rescan function work later. + The files database must be rebuild for this release!!! + The BBS and the rest of the programs now use different + loglevels. + Changed the sourcefile distribution name to mbseN_NN.tgz. + + upgrade: + Delete all file databases! + mbsetup 1-5-20: set utils loglevel. + run mbfile check -debug to fix the files references. + + dbase.a: + Functions added to connect and disconnect nodes from echimail + and file areas. + Now marking the nodes record invalid after update. This should + prevent corrupting the nodes.data file from now on. + + common.a: + Added a function to convert ifcico addresses to internal fido + addresses. + Removed a pointer bug in the aka2str function. + + mbfido: + Added most AreaMgr and FileMgr functions. Needs a lot of + code cleanup but most things work for now. + Now imports the TIC area name in the filedatabase. This can + later be used for %resend requests. + The long filename field is filled with the dos filename for the + time being. + + +v0.27/b 04-Nov-1998 + + general: + Changed the top Makefile, it "forgot" the script directory. + This release adds nodelist diff processing and hatching of + new files, for example the nodelist you just created. + Switched to compiling with ndbm.h, this is now default + because the nodelist can now be opened by several programs + at the same time (for reading). Support for dbm.h will be + dropped, it gives trouble and cannot be used on a multiline + system. + Created the semafore.doc document for semafore handling. + + common.a: + Added the semafore functions. + + import: + Implemented long filenames on files database import. + + + mbfido: + Changed the way of counting FILE_ID.DIZ lines in archives. + Made macro's in tic processing case insensitive. + Implemeted automatic hatching of files. + Creates the "mbindex" semafore when new nodelists have been + put in place. + + mbuseradd: + Changed the contents of users .profile to: + . $MBSE_ROOT/etc/profile + The file $MBSE_ROOT/etc/profile contains the global startup + commands for normal bbs users. + + + mbsebbs: + Changed debug logging of DisplayFile function. + Logs the tty line comment after the username at login. + Linked with the new common/semafore functions. + + mbdiff: + New program. Nodelist diff processor. Creates the "mailin" + semafore when it created a zipped nodelist. + + mbsetup: + Added tic echo group pick in hatch and magic setup. + Removed setup of semafore path's, they are now hardcoded. + + mbcico: + A quick hack of Eugene G. Crosser's ifcico. At this time + only the logging functions using mbsed are implemented. + It needs ~/etc/mbcico.conf for configuration together with + the standard database configuration. In time, the mbcico.conf + file will not be needed anymore. For testing in this release + it does the job. + + mbaff: + Linked with the new common/semafore functions. + Creates also the msglink semafore when mail is written. + + mbindex: + Removes the "mbindex" semafore when the nodelists are + successfull compiled. During compiling it places the + "compiling" semafore. + + mbmsg: + Removes the "msglink" semafore when the messagebases are + linked. + + mbstat: + Now maintains the semafore's "bbsopen", "bbsclosed", "zmh" and + "scanout" according to semafore.doc. You must schedule + "mbstat check" in the crontan at the start op ZMH and end of + ZMH both on summer and wintertime. If you did configure the + ZMH right in UTC in $MBSE_ROOT/etc/mbsed.conf this will work + if you did setup your timezone correctly. + + + +v0.28/a 18-Nov-1998. + + general: + Modified the structs files to add a database for modems, + changed the tty database to link it with the modems, added + fields in the nodes database for the mailer, added fields + in the global config file to add setup for the mailer. + Dropped nodelist V21 flag, added V32T and VFC flags. The + U flags for modem capabilities must be implemented somehow. + + upgrade: + To upgrade, enter the global setup and leave it, say yes to + save changes. Enter the nodes setup, enter one of the nodes + record, exit and save changes. Setup the modems database. + Enter the tty ports setup, link the modems to the POTS and + ISDN lines and save it. + + common.a: + In crc added crc16ccitt functions. + In clcomm the function IsDoing(char *) now accepts formatted + parameters. + Added function SetTTY(char *). + Added debug logging of nodelist flags. + Changed the way the nodelist flags are parsed, sometimes + U flags became standard flags, and standard flags became U + flags. 'U' became a flag also. + Moved some common files from mbcico and mbfido into the + library. + + mbsetup: + Changed the lineeditor to accept the comma character. + Added modem setup, changed tty lines setup to pick a modem. + Changed nodes setup, finally added the statistics screen. + Changed fidonet setup, first zone is now called "primary zone" + + mbfido: + Added IsDoing info during date rollover. + Removed a bug causing a segmentation fault when a mail packet + had an error. + Removed check that incoming packets must come from a node in + our setup. All received mail packets are now processed. + Echomail must still come from nodes in our setup, the rest goes + to /dev/null + Moved some sources to the common library. + In forward() changed the uppercase functions for the subject + line. The original filename became uppercase also. + Corrected debug logging for packet date, the month was 0-11 in + stead of 1-12. + Added logging for ftsc product name and version. + + mbcico: + Added some EMSI extra logging. + Added more IsDoing info for mbmon. + Corrected the Makefile after testinstall on the live bbs. + Changed the order of the EMSI data to send to the remote + party to be more standard. McMail (maybe others too) didn't + recognize all options send too early. + Added EMSI logging for 'link', 'comp' and 'tranx'. + Moved some sources to the common library. + Completely rewritten the chat module. Everything received + from the modem is now logged. Because all modem responses + including echo from commands, are now logged, the aftercall + function (get modem aftercall or caller id), will go to the + logfile as well. (not tested, I have no CLIP capable modem). + Added patches from ifcico-3.0.cm.alpha-4.0 to filelist.c, + this should better handle files sent/notsent in failed + sessions. + Added counters for sent and received bytes. + Completely rewritten the scanout function. It now searches + only in the outbound directories defined in the setup. + In the fidonet networks of the setup the first defined zone + is the default zone for that domain. Other zones get a hex + extensions with zone number. + Scanning mail for the CallAll option now selects outside ZMH + only crash mail, during ZMH crash and normal mail. Logging + of selecting mail is improved. + When calling a node is failed for 30 attempts, the node will + not be called anymore. If the problem if corrected you now + must manually edit the .sts file or delete it to call that + node again. (Option for the future outbound manager). I think + that sessions errors do this after 3 attempts. + When calling a node, mbcico more ore less automatic selects + a tty with modem that matches the nodelist entries of the + node to call. ISDN is not yet supported. Also a best speed + test must set priority of ports to use. + + mbmsg: + Supressed error message if there was no semafore "msglink" + to remove. + + mbsed: + Added command SZMH, requesting Zone Mail Hour status. + Added command ATTY, setting a new tty port. + + mbdiff: + Removed some unnecessary debug log information. This program + seems to work fine now. (Wow, only needed 2 releases for + this one). + + +v0.28/b 09-Dec-1998 + + general: + Added structure for the mailer history file. + + mbaff: + Removed some debugging logmessages. + + mbsebbs: + Removed some debugging logmessages for newmail scan. + Removed some debugging logmessages from timer functions. + + mbmsg: + Added program info logline. + + mbcico: + Added monitor info during FTS-0001 sessions. + + mbout: + New program, the Outbound Manager, many ideas stolen from other + programs of the ifmail package. + + + +v0.29/a 11-Dec-1998 + + common.a: + Opening of nodelists is now logged at debug level. + Added .pol files to pktname.c + Moved attach.c from mbfido to common library. + Nodelock now tests for own locks, if so, no error is given. + + mbfido: + Worked on the uppercase bug again. It will only happen when + we must forward a file. + Moved attach.c to the common library. + + mbout: + Implemented file requests. + Implemented creating and removing of .pol files to make and + remove polls. + + mbcico: + Calls nodes when .pol file is present. + Made file requests working again, the .req files where not + added to the filelist to send. + When reading node options the NoEMSI and NoWazoo flags weren't + copied to the options. + Corrected a bug in yoohoo.c where it didn't initialize + remote->addr->name to NULL in checkhello(), this caused + a segmentation error and failing Yoohoo/2U2 sessions. Note + that this error is in ifcico as well. + Over TCP/IP with ifcico as other mailer EMSI, Yoohoo/2U2 and + FTS-0001 in- and outbound sessions are working. For other + mailers we will see if it will work in real live. + + +v0.29/b 17-Dec-1998. + + general: + Installed 0.29/alpha on the bbs. + Installed usleep() code in some utils. See usleep.doc for + details. + Changed the nodelist flag definitions to prevent conflicts + with system macro's. + + common.a: + Locking and unlocking nodes gives better error logging. It + now also checks our own pid if the lock was already made + instead of complaining. + + mbfido: + Removed some bugs in logging in magic.c + Changed FILE_ID.DIZ file checking for empty lines. + Now always marks a file announced when importing into the bbs. + Added code to prevent terminal output in quiet mode. + Added usleep() code in statistics rollover. + Added usleep() code in importmsg. (sleep each message). + Added usleep() code in LoadTic. (sleep each .tic file). + Added usleep() code in scan for mail. + Removed error message when "mailout" semafore didn't exist + in scan for mail. + + mbcico: + During outbound EMSI session we send the NRQ option flag, + requests on hold for us are not allowed when we callout. + When calling a node the first thing now is lock the node + to prevent further checking if the node is already locked. + Putstatus is logged for studying status updates. + Experimental status resetting of all nodes after successfull + session. + + mball: + Renamed from allfiles. + Now creates allfiles and newfiles reports. Honors maximum + security level to include in the lists (no flags yet). + Optional parameter -zip will create allfiles.zip and + newfiles.zip. + Installed usleep() code. + It is finished. + + mbout: + No more error message when a file attach in a .flo file is + nolonger on disk. This can happen if nodes don't poll often + enough. + + mbmsg: + Installed usleep() code. + Removed color code output when in quiet mode. + + mbaff: + Installed usleep() code. + Now marks the file announced after scanning the bbs for + uploads. + + mbfile: + Added the usleep() code. + Added some code to lower the disk i/o. + + mbstat: + Now logs status of ZMH with the "check" command. + + mbuseradd: + Added a check to see if the "shadow password suite" is + installed. It is absolutely necessary to have this. + If /etc/login.defs is present, the useradd program gets an + extra parameter "-M", to override the creating of the users + home directory. (Found on Redhat 5.1). + Added an extra check if reading the /etc/passwd file failed. + Added newline characters after some error messages. + + +v0.29/b2 24-Dec-1998 + + general: + Added modem.stripdash and ttyinfo.portspeed in structs.h + + common.a: + Changed logging functions in clcomm.c, repeated messages are + now counted and reported how many there were. A full filesystem + will hopefully not happen anymore. + Added the Nopper function, this one can be called often but + only once a minute a NOP is send to the server to prevent a + timeout disconnect. + + mbcico: + Removed some debugging logs. Added some return codes from the + tty drivers in zmodem send and receive. (removed later, it + didn't work). + Added Nopper code in file transfer protocols. + + mbout: + When creating a poll the node's status record is reset, so if + the node was undiable, it will start polling again. This will + not happen for sessions handshake errors and port errors. + + mbsetup: + In edit tty added edit portspeed. + In edit modem added edit stripdash. + + mbsed: + Corrected ZMH status response. + + mbstat: + Corrected ZMH status check. + + +v0.29/b3 28-Dec-1998. + + mbcico: + Inserted new ttyio code from the German version made by + P. Saratxaga and T. Tanaka. I hope the Zmodem problems will + now be solved. + Added Hydra filetransfer protocol. + Removed Janus, it wasn't implemented anyway. + Corrected modem init routine. + Implemented aftercall function. + + mbsetup: + Removed setup to disable Janus protocol. + + +v0.29/b4 29-Dec-1998. + + general: + Changed the Makefiles. Now only in ~/src/CONFIG you can place + extra defines. + Added compile switches -Wshadow -Wwrite-strings + -Wstrict-prototypes. This gave a lot of code cleanup, maybe some + strange errors are gone. + + common.a: + Corrected the repeative log counter. + Included in nlindex.c HAS_BSD_DB + + mbcico: + Improved ttyio logging, maybe we can better see what is going + wrong when transfering files. + EMSI compatibility protocol now gives Hydra first, then Direct + Zap. + Added file transfer counters to Hydra. Changed Hydra logging + a bit. + + mbindex: + Changed nodebld.c to inlcude HAS_BSD_DB + + mbuser: + Did some screen output when it was in quiet moded. + + +v0.30/a 01-Jan-1999. + + mbfido: + Removed a bug in the program lock that could cause a segfault. + In delete viruswork made rm now work in forced mode. + Hatch files now logs only hatched files. Added the + statistics update. + Changed completly the call module. There were some locking + problems and modem access attempts when the port was closed. + In Hydra the transfercounters are now updated after each + succesfull block. + Added more debugging log to the ttyio driver. + In answer mode we grep the environment variables CONNECT + and CALLER_ID created by mgetty and make log entries. + Swapped timer numbers in Hydra, in tty_write we now don't + test the read timer anymore, this gave unexpected timeouts + and is not according the Hydra specs. + Changed more debugging in ttyio, zmodem and zedzap are still + not working well. + Undiable nodes will not be added to the callist anymore. + + mbsed: + Added some logging in the ZMH status check to see what goes + wrong with asking ZMH status. + Changed the statusfile locking, now the lock tests are done + at 100 mSec intervals instead of 1 Second. + + mbsebbs: + Added CONNECT and CALLER_ID environment variables logging. + + newuser: + Added CONNECT and CALLER_ID environment variables logging. + + +v0.30/b1 10-Jan-1999. + + common.a: + Removed a bug in client.c that caused a segmentation fault + when the connected tty was /dev/console. It is now possible + to run clients from sysv init during system boot. + + mbsed: + Removed a bug in the ZMH status function. + Changed statusfile lock form 15 x 100 mSec to 10 x 250 mSec. + + +v0.30/b2 16-Jan-1999. + + general: + Defined bitmasks for logging. There are now maximum 26 debug + logflags. The logflags are changed from int to long. + All programs have been changed to use these flags now. + + upgrade: + In mbsetup set the new flags in menu 1.5.19 1.5.20 and 1.18.1 + + note: + This version still only compiles on Slackware 3.2 maybe + others, but not on RedHat 5.1 5.2 and RedHat 5.2 Sparc. + + +v0.31/a 23-Jan-1999. + + update: + Recompile the nodelists. Remove old index.dir and index.pag + files from the nodelist directory. + Set new value for dialdelay. + + general: + Removed mbsed from this source tree. From now on this will + be distributed as a seperate archive. + Finally found out why this package wouldn't work with glibc. + Complete rewrite of the nodelist indexes. I don't use any + dbm, ndbm anymore. I wanted username lookup included and + full support for ISDN and TCP/IP only nodes. + It now compiles on RedHat 5.2 Sparc and Intel. + + common.a: + Removed a serious memory leak causing the system to exhaust + all available memory during long filetransfer sessions. + Rewrote the nodelist lookup functions. Search is very fast + because the index file is sorted on nodenumber. + The nodelists will be closed after each lookup so that mbindex + may always compile new indexes. + + mbcico: + In call.c changed the port closing, it will now also close the + port after an unsuccessfull call so multiple calls in one + run will now hopefully work. + Removed a bug when calling a TCP/IP node it was trying to + dial with a modem. + Added random number generator to set the dialdelay before a + call is made. + + mbindex: + Total rewrite for the new nodelist indexes. In -quiet mode + it does the usleep(1) call every 80 lines (if set). Note + that in quiet mode it still runs faster then with screen + output. + The index file is sorted before it is written to disk. This + makes node lookup very fast (faster then with ndbm). + The old files stay on disk in case they are open, which can + only be for less then a second. + The semafore compile is not created anymore, instead the + mbindex program creates a lockfile to prevent that another + mbindex can run. Compiling the nodelists can now be done at + any moment. + Username indexes are not supported at this moment. + + mbstat: + Now only changes ZMH status if the status is really changed. + Will create the "scanout" semafore if ZMH status changes (I + did document it). + + mbmsg: + Changed the logging, killing messages now logs in columns, so + you can easy see how the mailflow and killing develops. + Removed some debug logging (finally). + When screen output is on, the last line is now erased after + processing. + + mbsetup: + Changed helptekst for mailer->dialdelay. + + mball: + Now creates semafore "mailin" when ready so the produced + allfiles and newfiles listings will be imported by mbfido tic. + + mbsed: + Changed the $MBSE_ROOT/sta directory to $MBSE_ROOT/var and + changed the names of the status and reginfo files. + +v0.31/b 06-Feb-1999 + + common.a: + Changed raw keyboard read to get cursor movement keys and other + gray keyboard keys. Only cursor movements is guaranteed to work + This is a limitation of PC-ANSI clients. + This change is needed to write the fullscreen editor. + Removed memory leaks from getheader.c and mbfile.c + Switched to one single .h file. + If loggin "message repeated n times" the first character is now + uppercase as in normal logmessages. + + mbsebbs: + Implemented raw keyboard read changes. + All actions in change.c are now logged. + Made change voice and data phone work. + Removed the (dangerous) gets function from funcs.c + + mbsetup: + Removed ncurses code. + In line editor the delete and insert key is finally working. + Modified help tekst for modem hangup string. + + mbmon: + Removed ncurses code. + In line editor the delete and insert key is finally working. + + mbcico: + If modem hangup string is empty only DTR-drop will be used + to hangup the modem line. + During ZMH mbcico will now only call nodes for which it has + non archived mail (netmail). + Changed ttyio debug logs, could block the session. + For magic file and execute requests now looks for both upper- + and lowercase matches. + Filerequests are searched in the internal database on both + long and short filenames, password protection is supported, + and the request counter in the FDB is updated. + + mbindex: + Doesn't complain anymore when the semafore "mbindex" didn't + exist when it tried to remove it. + Now tests for latest nodelist by filedate instead of file + extension number. + + mbfido: + Creates magic file names for magic filerequests. + + + +v0.32/a 16-Feb-1999 + + update: + Remove symlink directories. + + general: + Changed elapsed time logging, now ranges from seconds to + days with the same stringlength. + Moved signal names to common.a, also included the names + for i386 and Sparc systems. + Added PackNetmail flag to nodes record. + + msgbase.a: + Removed automatic adding of FMPT and TOPT kludges in netmail. + Applications are responsible for adding kludges. + + mbfile: + Removed code to work on symlinks for ifcico file requests. + + mbfido: + Added some code to prevent memory leaks. + The .pkt password check now always logs bad passwords, only + when mail password check is set, bad passwords are fatal. + Added code to keep dupe databases in maximum limits. + Now forcing chdir to inbound before processing each .tic file. + It will now export netmail from the message base. It also + supports packed und unpacked netmail. + Added TZUTC kludge (FSP-1001). + + mbcico: + Changed zmrecv debug logging for hanging session with one + of my links using InterMail 2.50 ML, rev B020. + If polling all lines of a multiline node and the first line + was successfull, mbcico would still poll the other lines. + The random dialdelay is now always 10 seconds or more to give + mgetty the chance to reset the modem and takeover the line + between multiple calls. + During dialdelay the IsDoing status is now sent every second + to the mbsed so you can watch it with mbmon. + + mbsetup: + Changed nodes setup so that password may be upper or lowercase + for remotes that are case sensitive (was always uppercase). + Added support for PackNetmail flags in nodes editor. + + scripts: + In run_inout added the news gateway (echomail => news). + + mbindex: + Now only tries to compile files with a numeric extension, + 2 or 3 digits length. + + mbsebbs: + Wrote a simple fullscreen message editor, more or less + Wordstar compatible. + Fixed a small problem in the line editor. + The maximum size of a message is now 500 lines. + When replying to a message, the original message is quoted + into the textbuffer including an introduction line. + When replying to a message, "Re: " is inserted in the + subject if there was none. + It is now possible to send and reply netmails. + Added TZUTC kludge (FSP-1001). + + mbout: + With poll and stop command you can enter multiple nodes. + With the request command you can enter multiple files. + The request command doesn't create a .flo file anymore, the + actual calling of the node must be done with the poll + command. + + mbaff: + Added TZUTC kludge (FSP-1001). + + mbsed: + Implemented CIPM and CSPM commands (online messages between + users). Updated the programnames list for check if the bbs + is idle. Changed the reginfo file lock to 30 x 150 mSec. + Fixed the Linux Sparc version. + + +v0.32/b 15-Mar-1999 + + upgrade: + Delete the newuser program and any accounts using it. + Move compiled language datafiles to ~/etc. + Move config.data from ~ to ~/etc. + Remove ~/lang directory + chown -R mbse.bbs ~/home/* + Upgrade mbsed to at least v0.32 Alpha. + + general: + The mbsebbs program now runs setuid "mbse" setgid "bbs". + All files are now owned by mbse.bbs, even the bbs users + private files. + All references to directories for the configuration are now + hardcoded to ~/etc, ~/fdb, ~/log, ~/tmp and ~/var. + The directory ~/lang is no longer needed. + The directory /tmp is no longer used, using ~/tmp instead. + Moved the language sources and installation into this source + tree. + + mbfido: + Forgot to append after the TZUTC kludge. + If we were a point, a route to our boss was not found. + Updated for hardcoded paths. + + mbsebbs: + Now runs setuid "mbse" and setgid "bbs". Changed the parameters + to the mbuseradd program. The newuser program is now part of + mbsebbs. + It is now possible to run mbsebbs as a shell, it is even wise + to do so! + Updated for hardcoded paths. + Sending and receiving online messages is now handled thru + mbsed. You need at least mbsed v0.32 Alpha. + Removed the last "gets" function. + + newuser: + No longer exists. + + mbuseradd: + Changed parameters to this program. + Finally worked around the problem of different passwd programs, + we will now let the user supply a new password instead of + creating an empty expired password. The shadow password suite + isn't necessary anymore but it may be wise to use it. + It will not install /bin/bash as user shell anymore, during + loading of the bbs users could get a shell prompt if they were + fast enough. The mbsebbs program is now installed as shell. + + mbsetup: + Updated for hardcoded paths. + Updated screen 1.3, global paths. There is only one screen now. + + mbmon: + Updated for hardcoded paths. + + mball: + Updated for hardcoded paths. + + fbgen: + Updated for hardcoded paths. + + mbfile: + Updated for hardcoded paths. + + mbmsg: + Updated for hardcoded paths. + + mbuser: + Updated for hardcoded paths. + + mbcico: + Updated for hardcoded paths. + If the tty port was locked by another process, mbcico tried + to close the port of that process (and luckily it failed). + Now it won't try to close that port and try to remove the + lockfile. Corrected the logmessages during this situation. + + mbaff: + Updated for hardcoded paths. + + mbsed: + Forgot to close the reginfo file after the CIPM command, + eventualy the bbs stopped logging because mbsed ran out of + file descriptors. + Added the GDST command, to get the status of all (but no + more then 10) mounted filesystems. + + +v0.33/a 25-Mar-1999 + + general: + Changed the users structure for IEMSI flags. + + update: + Open in mbsetup the users database, record 1, and close it. + This will upgrade the users database with new fields. + + mbcico: + Will dispatch mbsebbs when the EMSI string is EMSI_NAK instead + of EMSI_INQ. We then assume the client is an IEMSI client. + In the tty driver changed some error messages to debug log + messages. + + mbsebbs: + Didn't flush the screenbuffer when asking the user to read new + mail so the user couldn't see the prompt. + For OLR download the maxumimum number of file requests is now + taken from the main configuration. + Added IEMSI login support. Tested with FrontDoor 2.11/sw. + Flushed a prompt after file download. + The users filetaglist is removed from disk during logoff. + Deleted Toggle Expertmode, menu 307. + Added Toggle New Mail Check, menu 313, text code ^U1. + Added Toggle New Files Check, menu 315, text code ^U2. + Added Toggle Fullscreen Editor, menu 316, text code ^U3. + Added Toggle Bulltins Read, menu 307. + + mbfido: + Added more debugging messages for netmail processing. Netmail + between a boss and point are being bounced between each other. + At least they don't dissapear anymore. + When forwarding a netmail, all original characters were + lost and messages may have become undeliverable. + + mbsetup: + Added new menu choices that were added to mbsebbs. + + +v0.33/b1 29-Mar-1999 + + general: + Added support for "pktdate" from Tobias Ernst. This is a Y2K + .pkt analyzer and fixer. It is called before each .pkt file + is processed. Indeed, he did also made a Linux version. + Added support for ISDN and TCP/IP nodelist flags. They may + be in the Userflag field or in the authorized flags field. + + mbsetup: + Added .pkt preprocessor installation to global->mail for + the pktdate program. + + mbfido: + Inserted code to call the .pkt preprocessor. + Should insert ^aVia line in forwarded netmails and exported + netmails from the local msgbase. + Will now put netmail for direct links that are not in our + setup (by the stupidity of the Sysop, including me) still in + the outbound (normal status) instead of /dev/zero. + + mbcico: + Added support for ISDN and TCP/IP nodelist flags. + Will now call TCP/IP nodes. This is experimental! It uses the + proposal of Lothar Behet (2:2446/301) of 25 Oct 1998. The + defined flags may be in the User field or authorized fields. + At this moment only the IFC protocol is supported, the ITN + support on port 60177 is under construction. + + mbout: + Added support for ISDN and TCP/IP nodes. + + +v0.33/b2 02-Apr-1999 + + general: + 2 new configuration items, user levels to allow sending of + Crashmail and File Attaches. + + update: + Set Crashmail and File Attach levels in screen 1.4 + + common.a: + Updated nodelist flags and rendundency flags according to + errflags.zc2 dated 20 Mar 1999 (from 2:2/0). I should make + an external table for this. + If a semafore already existed (or was removed), nothing will + be done anymore. When a semafore is created, fsync is called + to make sure it is on disk. + Totally rewritten the .pkt header read function, it is now + more portable and does only one disk read to do that. + + mbfido: + Commented out some debugging logmessages in magic file test. + Corrected the ^aVia lines, in one case the Sysop name was + included, in all cases the year was only 2 digits. For + debugging the milliseconds fields are now different in all 3 + functions that create Via lines. + Now creates .pkt headers in a more portable way and only needs + one disk write to do that. + Now creates message headers in a more portable way. + When creating notify messages, the correct local time is now + entered. + Created a new fidonet date parser, removed the bison parser. + When messages are exported, the fidonet date is generated from + the internal structure, so incorrect received dates are + hopefully corrected on the fly. You should not need pktdate + anymore. + Now sets the local time when a message is imported. + + mbsetup: + When creating new message areas, the security fields will not + be preset anymore. + Removed the gid and start uid values. + Added setup for CrashMail and File Attaches. + + mbsebbs: + Remove an extra close menufile in the menu processing. The + Sparc version aborted with Segfault error on this. + When a message is created, the time is now the correct + local time. + Now sets the local time when a message is received by the user. + When a netmail address is entered, the user will now see the + nodelist bbs name and is asked to verify it. + Only above CrashMail level and if the destination node is CM, + the crash option is presented. + When creating a new user, the gid is now taken from the running + process instead of the setup. + + + +v0.33/b3 06-Apr-1999. + + general: + Due to hardware problems on my bbs, I was forced to takeover + the whole bbs on MBSE BBS, RA is now retired. This means that + lots of things must be solved in a hurry from now on, there's + no way back for me. The MOBO died, it is now replaced by an + old 386/DX33, so I have to fix the parts that slowing things + down. It must be able to run good enough on that board. This + also means that only necessary things are developed from now + on to create a stable and useable version. + + msgbase.a: + The message header read function doesn't seek the whole + messagebase anymore if it needs the next header. This will + roughly triple the speed of scan for new mail. + + mbfido: + Removed check for connected uplink if .tic file was a local + hatched file, there are no uplinks for local hatched files. + Finally found the bug where the TOPT and FMPT kludge info + dissapeared from the netmails causing mail for points to bounce + back to the boss. + Added commandline switch -full to force scan to scan the whole + messagebase for outgoing mail. + If ~/tmp/scan.mail exists the area and message numbers are used + to quick export messages. + It can now attach file attaches. File attaches are not routed. + If the imported file has a magic name, this magic is added to + the file description. + + mbcico: + Will stop calling a node after 3 attempts if there are no + matching ports, or if there is a port error. + + mbsebbs: + Abort on SIGHUP is not logged as error anymore but as normal + log message "Lost Carrier". + With netmails files can now be attached if the user has a high + enough security level. Files must be in translatable DOS range. + Fixed segfault when user tried to select an non existing + filearea. + Creates ~/tmp/scan.mail for posted messages to allow quickscan. + + mbaff: + Creates ~/tmp/scan.mail for posted messages to allow quickscan. + + mbsetup: + Finally added the pull uplink in file and mail group editors. + In the tic area and echomail area editors if the group is + selected and the uplink address is set in the group, the the + first default connection for that area is the uplink. + + +v0.33/b4 13-Apr-1999 + + upgrade: + The ticarea, hatch and magic datafiles are changed in format. + Order of update is important! + 1. Compile all sources, don't install. + 2. Make backup of all .data files in ~/etc. + 3. Announce new files. + 4. Remove *.*.*.*.bill files from the ~/tmp directory. + 5. Disconnect all modems, networks and stop the cron daemon. + 6. Run mbsetup from the source directory. ~/mbb0_33b/mbsetup + 7. Menu 10.2, leave and update the database. + 8. Menu 10.3, leave and update the database. + 9. Menu 10.4, leave and update the database. + 10. If all is well, install the binaries, check mbsetup. + 11. Start cron daemon, connect modems and networks. + + common.a: + Removed errormessage when created semafore succeeded when it + opened file descriptor 0. + + mbcico: + When searching for file requests it tried to use ~/fareas.data + instead of ~/etc/fareas.data. + + mbsetup: + Changed the tic areaname field from 12 to 20 characters. + Corrected screen numbers in hatch and magic pick areas. + Setting the magic "to area" now also uses the picklist. + Does normal logging again. + + mbfido: + Doesn't import the file area name anymore in the filesdatabase. + This needs a workaround because this field is now too small. + The check for quick scanned exported messages failed for + echomail if there was more then one downlink. This forced a + complete scan to be done while everything was really ok. + The .tic file dupecheck is moved to do a little later so that + if some checks fail, the file is not in the dupe database yet. + If the destination path is not available, the file and .ticfile + are moved to the bad directory. + Reads "Fullname" field from .tic file, logging only for now. + Will now process archived tic bundles with extension .c00 where + the numbers can be any digit. (Harald again :=). + More errorchecking in Magic file procesing. + Turned some debugging logging back on. + Corrected a bug that sometimes caused a segfault during tic + processing. + Corrected a routing problem if mail was to be sent to one of + my own points, in case there where more than one point. + + mbmon: + Does normal logging again. + + mbfile: + Calls the Nopper() function now to keep the connection with + the server alive. Good for slow systems and lots of files in + one area. + Removed a small memory leak in the check function. + + mball: + Creates "00index" files in each download directory that is in + range of anonymous ftp users. These files contain the file + names and file descriptions of that directory. A new command + "index" is added. + + mbaff: + Corrected for the .tic areaname size of 20 characters. + + mbsebbs: + Fixed segfault when user was trying to select a non existing + message area. + + +v0.33/b5 26-Apr-1999 + + general: + A new set of grouprecords is created. This is for the announce + of new files, so reports can be created by subject, ie. + Windows, Erotic pictures, Utilities etc. The groupnames are + part of the bbs file areas. + + upgrade: + Set in menu 1.15 the number of newfiles groups. + Create the several newfiles groups. + Install in all bbs file areas the right newfiles groups. + Install in all newfiles reports the right newfiles groups. + + mbsetup: + Will now ask if messagebase must be created if it doesn't + exist. + Implemented the setup of newfiles groups. + Will now show the TZUTC time instead of system generated + timezone (didn't work on RH systems). + + mbcico: + Changed some logging, removed some debug logging. + + mbfido: + Corrected a errormessage when the file import failed in a + non existing area. + If the file is imported in a bbs area, and that area has a + separate Newfiles groupname, that name will be stored in the + toberep.data file for announce. + If a fdb area doesn't exist during file import, it will be + created on the fly. + Doesn't send empty netmails anymore if node has tic messages + off. Only messages with text in it are send now. + Switched .tic description lines logging on again because there + are some strange descriptions coming in. + Fixed a problem when there was only a normal description line + in the incoming tic file, the downlinks got a shortened + description line. + Doesn't strip Hi-ASCII from FILE_ID.DIZ file anymore, only + control characters. Stripping of Hi-ASCII should only be done + by file announce programs (if the moderator wants that). + + mbdiff: + Removed a lot of debug logging. + Removed unarchive functions as they are already in the common + library. + + mbindex: + Removed some debug logging. + It now deletes old nodelists from the nodelist directory exept + the most recent two lists. + + mbsebbs: + Added logging of selected file and message areas by the users. + During mailscan and filescan inserted call to Nopper(). + Wrote a new Getstr function to create Unix accounts, this + one won't accept spaces. (Thanks to Henk de Graaf, a user + who failed to login). + The username won't be converted to lowercase anymore when + his Unix account is created. + The Unix name has to be at least 3 characters. + + mbaff: + In the announce function new uploads will get the area number + as fileecho name so they will be announced by area. + + + +v0.33/b6 30-Apr-1999 + + common.a: + Execute now only logs result messages if there was an error. + + mbaff: + Added High ANSI to Low ASCII translation for echomail areas + that need it. + + mbsetup: + Added High Ascii switch in filefind setup. + Corrected menu numbering. + + mbfido: + After tossing a .pkt the result is only logged if there was + an error. + Removed 2 debug messages during netmail import. + Made logging of "Keep files" final. + Allowed hi-ascii in .tic files for the descriptions. + Build in a check for multiple "Desc" lines in .tic file, + only one is allowed. Offenders are logged, See FSC-0087. + + mbsebbs: + Quick_Bye() is now logged (if possible). + + mbdiff: + The resulting new archived nodelist will now be a lowercase + name instead of a uppercase name. + The new nodelist will be default be archived with the same + archiver as the diff file came in, if it's not available + there is now a fallback to ZIP which is always available. + + +v0.33/b7 10-May-1999 + + upgrade: + ACRmail 0.60 file naming convention is default off for + existing nodes, check their setup. + + msgbase.a: + Added a counter which keeps track of the size of the message + being written. + + common.a: + Will now create unique arcmail names for out of zone mail if + it is turned on. This should prevent creation of duplicate + arcfile names to the same node. + Corrected logging of bestaka_s function. + Doesn't create 00000000.fr0 ARCfile names anymore if our + system is the point sending to the boss. + + mbaff: + In the announce function added logging of the size of the + written message. + Inserted a checkpoint log after each announced block. + Inserted code to split messages after 13000 bytes. + + mbfido: + Removed "Packing Mail" logmessage. + Imported netmail will now allways get the Private status. + Added code to replace the archive comment, currently this + works with .zip and .rar archivers, others don't support + this. + The ^aVia line was inserted at the begin of a forwarded + message instead of at the bottom, it also had the address + of the origin system instead of our own system. + Also moved the ^aVia line in the other 2 functions to the + bottom. + + mbfile: + If during the check for missing files in a download area there + is an extra file and it is not a regular file, it wil be + ignored. This allows the use of subdirectories. + + scripts: + Added support for binkd, if it is installed in ~/bin and the + binkd.cfg is in ~/etc it will be started and stopped as the + rest of the bbs. + + mbsetup: + Added in nodes setup ARCmail 0.60 naming convention switch. + + mbcico: + When there are session errors, the status counter is now + increased with 5, so maximum 6 calls are done. (was infinite). + + +v0.33/b8 23-May-1999 + + mbfido: + Corrected Connection time log messages. + + mbcico: + Restored the original filetime functions. + Removed 2 debugging log messages. + Made the filerequest processor 3 times faster. The remote + doesn't timeout anymore during the search for files. It + must still be made faster. + + mbsetup: + Added the (hidden) option to move echomail areas. + + mbout: + Will also clear the status record of a node with the poll + command if the reason was session errors. + + mbdiff: + Changed available archiver tests, and fallback to ZIP + archiving. It is finally working. + + mbsebbs: + Corrected the reply test for new users when they had entered + their name. + Updated language number 413. + New users won't see the "new files" when they logon the first + time. (They saw all the files on the bbs). + If IEMSI login is aborted or failed, IEMSI won't be used + anymore during login. + When the offline reader packs netmail, only personal mail is + now added to the dowload packet. + + +v0.33/b9 12-Jun-1999 + + update: + Change scripts that call mbuser. + + general: + Changed startup and finish logging of all programs to use + one style. + + mbaff: + New file reports that are splitted over several messages will + now report the right report totals. + Removed some development debugging logs for splitting messages. + + mbdiff: + Removed all extra debugging logs from version beta-8. + + mbuser: + Made command syntax and helpscreen as in all other programs. + This affects the scripts. + + mbsebbs: + For the "comment to sysop" function the .quote file in the + users homedirectory will now be truncated to 0 bytes to erase + its contents. + The "mailout" semafore is now only set at the end of the user + session. + Inserted the Nopper() call in the fullscreen editor to prevent + server timeout when writing a long message. + When writing a netmail to an unknown node, the user must verify + to send the mail anyway. New language prompt 241. + If a user is short with transfertime for a download, it will + be written to the logfile. + + mbfido: + The notify function will now only include areas that are + "Active" in the reports. + Changed the ASCII filtering of reading .tic and FILE_ID.DIZ + files, High-ASCII characters are not lost anymore. + The packet password is now only checked if the originating node + is in our setup. + Before processing AreaMgr and FileMgr messages the right + noderecord is loaded again in case it was replaced. + + +v0.33/b10 19-Jun-1999 + + general: + The man pages are removed. + + mbfido: + Removed logging of file descriptions. + Changed logging of replacing archive banner. + + mbaff: + Removed logging of splitting messages. + Removed several other debugging logmessages. + + mbsebbs: + Removed some debugging logging from download functions. + Corrected a logmessage for new users, language line 66 + is now obsolete. + + mbsetup: + Included (Spacebar = toggle) message in yes/no switches. + + mbuseradd: + Removed the creation of .profile in the users home directory, + this is not necessary because the users shell is mbsebbs. + + +v0.33/b11 29-Jun-1999 + + Most fixes in this release are from Jan van de Werken who is beta- + testing v0.33/b10. + + upgrade: + In mbsetup menu 1.14 set new fields 21 and 22. + In mbsetup, enter menu 8.5, set security levels for transfer + protocols and save the database. + + general: + Added 2 global setup integers for splitting newfiles reports. + + common.a: + Removed Getstr() function. + + mbfido: + Changed AreaMgr and FileMgr message body checks, lines with + more than 1 space or tab and empty lines are skipped. + Removed debug logging for import local netmail. + + mbsetup: + Added in menu 1.14 setup for newfiles reports message split + at a gently size (after a group of files) and a forced + message size. + In nodes setup, new records now default have Advanced tic off. + In nodes setup corrected several numbering errors. + New defaults for global configuration by Jan van de Werken. + To confuse all non-Unix users, all file attaches seem to + come from our A: drive. + Corrected a lot more wrong screen numbers. + + mbaff: + Implemented gently and hard splitting newfiles reports using + the global setup. + + mbsebbs: + Rewrote all user input functions. They should beep now if + the user does something wrong. + Changed the GetPhone functions, the format is not fixed + anymore and it accepts only 0..9 + - characters. This should + work in all countries now. Minimum length is 6 characters. + Changed the language prompts 45, 47 and 48. + Language prompt 46 is not in use anymore. + Removed the logdate2 function, it wasn't used. + Added GetstrP() function (instead of Getstr() in common.a). + Change transfer protocol now checks for the proper security + level. + + scripts: + Updated most scripts, added more comments, added tests to + see if MBSE_ROOT is already set, style fixes. + + +v0.33/b12 08-Jul-1999 + + general: + Removed creation of .VERSION file from the main Makefile. + + mbfido: + The echomail areatag is forced to uppercase. + Removes stale FILE_ID.DIZ files before processing a new one. + + mbsetup: + The new fields 1.14.21 and 1.14.22 where placed at the wrong + column on the screen. + Changed the default values for gently and forced message split + to 27 and 30 KBytes. + Corrected a missing linefeed in sitedoc protocols listing. + Corrected a menu error in menu 8. + Corrected placement of menu item 1.4.11 + Some cosmetic changes in the sources. + Corrected help message in screen 7.x.23, caused mbsetup to + crash. + + mbsebbs: + The info screen now displays compile date and time. + The Area listings for file areas and message areas now break + lines at column 79 and send cr/lf at the end of the line. + Also, area numbers increased to 5 digits (was 3). + Added cr/lf to language prompt 220 in mail.c + + lang: + Shortened prompt 220 with 1 character. + + +v0.33/b13 28-Jul-1999 + + general: + Added structure for file request index. + + update: + Run "mbfile index" once. + Include "mbfile index" in the maint script. + Modify "run_inout" script to start "mbfile index -quiet" if + the semafore "reqindex" is present. + Modify "run_inout" script to replace the fixed .pkt filenames + with stdin from the mbseq program, ie: 12345678.pkt will + become `mbseq`.pkt + Set the filerequest limits in menu 1.17.22 and 1.17.23 + You may specify portspeeds above 57600 in the tty's setup. + + common.a: + Corrected a comment in pktname.c + Changed error logging in execute.c + Moved execsh() from mbcico into common library. + + mbcico: + Removed some debugging logmessages from yoohoo.c + Changed some debugging logging from 'Session' to 'EMSI'. + File request response messages now contain MSGID, PID and TZUTC + lines and request limits. + Filerequest limits implemented. + Filerequest search now uses the index file created by mbfile, + should be fast enough now. + Moved execsh() to common library. + Magic execute request result is now send by mail instead of + an ASCII textfile. + Made some changes in zmmisc.c according to ifmail-2.13, sessions + with D'Bridge 1.58 seems to work now. + Logging of "chat: read return -1" suppressed, this is most of + the time caused by modem hangup during dial and is not a real + error. + During outbound scan missing directories will be created. + A major error in callall.c prevented crash arcmail to be sent. + Rewrote all functions that created mail, less disk I/O. Also + made the .pkt headers the same as the mbfido program did. + Will now handle serial port speeds upto 4000000 baud if your + hardware can handle that. + + mbsebbs: + Finally implemented user access flags. + Removed some debug logging. + Changed "Terminated on SIGALRM" error logging to normal log + with "User inactivity timeout" message. + + mbsetup: + In edit users toggle of flagbits is now correct, no "notflags" + anymore. + Added setting of filerequest limits in menu 1.17 + Changed fieldlength for integers to 7 digits. Now you can + enter all available portspeeds in the tty setup. + + mbfile: + New command: index. This will create ~/etc/request.index + which contains a sorted index of all requestable files on + your bbs. This index is used by the mbcico request processor + to speed up the filerequest search. The "reqindex" semafore + is removed when it is finished. + + mbfido: + Creates "reqindex" semafore if there were files imported. + The check for stale FILE_ID.DIZ files was at the wrong point. + Will pack the mailqueue if the temporary .pkt file is bigger + then the maximum size of that .pkt and creates a fresh one. + + mbseq: + New program. Write a 8 character hexadecimal unique sequence + number to stdout. This can be used in shellscripts to create + unique filenames. The sequence numbers are fetched from mbsed. + + +v0.33/b14 16-Aug-1999 + + general: + This is the first public release. + + mbcico: + Revised zmodem protocol, changed timers etc. Used latest + information (Aug 1999) found at Omen Technology's ftp site. + In the openfile function added support to skip files already + present in the inbound. + Hydra and TCP protocol transmitters now send the filetime + rounded up to even seconds just like zmodem already did, so + the filetime is always the same on DOS (Fat) as on Unix + systems. + Zmodem will now skip files already present in the inbound. + Hydra will now skip files already present in the inbound. + TCPproto will now skip files already present in the inbound. + Changed EMSI debug logging, should be more clear now. + Does finish zmodem session with D'Bridge [1a] 1.58 now. + + scripts: + Added support for UPS. The UPS software should set the + semafore "upsalarm" when it's running on battery power. Most + utilities will the not run anymore to prevent data-loss. + The semafore "upsdown" should be set just before the UPS + starts the real shutdown. This will force the mbstat program + to timout after 30 seconds. + + mbstat: + The wait command will only wait for 30 seconds instead of + one hour if the semafore "upsdown" exists. + + +v0.33/g1 01-Sep-1999 + + general: + Many brave souls have downloaded and tested the previous + version. Most changes in this release are bugs found by all + these people. + Added checks in the Makefile to test the MBSE_ROOT variable, + written by Jan van.de.Werken. + Added checks in some Makefiles for root privileges for + make install. + + upgrade: + Enter mbsetup 1.1.10 and set the name to "bbs". + Check UnSecure switch in echomail areas. Should be off unless + you need it. + Remove the line LOGDEBUG from $MBSE_ROOT/etc/client.conf + + common.a: + Added the original copyright in for the 32 bits crc code. + Checking .pkt header now checks valid system aka's. + Removed reading LOGDEBUG from ~/etc/client.conf, wasn't used. + Added SigName for Alpha CPU (not tested). + + mbfido: + Removed debug message in addpkt. + Added 2 extra DeleteVirusWork() calls in tic processing at + points where processing is aborted and left the temp directory + with unwanted files. This also happened when a virus was + detected. + Will now import echomail from points who are connected to + the normal nodenumber instead of the hub/host number. + Will now try to import bad netmail into a netmail directory + instead of losing it. + Changed the check for received echomail, the sending node + must be in the export list, unless the msg area UnSecure flag + is set. + Implemented the connected systems Excluded flag for echomail + connections in import/export echomail. + Implemented the connected systems Excluded flag in the AreaMgr. + The Notify function now also sends statistic reports to the + node. + Fixed a routing problem (I hope) for out of zone routed + netmail. + When scanning outbound netmail the domain field is zeroed in + the destination address to prevent garbage in the domain field. + Patches by Jan van.de.Werken, files import now set the name to + FileMgr instead of sysop's name. + AreaMgr and FileMgr generated messages now have AreaMgr or + FileMgr as "From" name instead of the sysop's name. + + mbcico: + Restored some zmodem code that was changed in beta-14. + Added some other code for error handling (Carrier lost). + Zmodem file transfers are streaming again. + Added a tty flush in the TCP/IP transmitter. + Solved the EMSI handshake problem with T-Mail mailers. + + mbsetup: + Added menu 1.1.10 to setup the name of the bbs startup + account. The default is "bbs". + Changed ImpSeenby switch in UnSecure switch in message areas + setup. + In message areas the Excluded flag is added to the systems, + you can now disable a node from an area if a moderator wants + that. + In edit users added a switch to toggle OLR Extended Message + Info in OLR download. + + mbsebbs: + Now reads the bbs startup name from the configuration instead + of using the hardcoded name "bbs" + Writes a door.sys dropfile in users homedir. The first line is + fixed to COM0 forcing doors to run in local mode. The second + line is 0, meaning 0 baud is local mode. Let's see how this + works. + Added some logging for the OLR upload function. + Now tests lowercase filenames also for reply packets created + by MultiMail. + Now includes the ^aMSGID string in BlueWave download messages. + Optional includes all other kludges in BluwWave download. + + +v0.33/g2 02-Oct-1999 + + general: + Moved the mbsed back into this archive. Included the new + installation procedure. + Moved the example files into this archive. + + upgrade: + Remove $MBSE_ROOT/bin/fbgen. + If you want to switch off CFG.dospath, be sure your outbound + is empty or mail and files will get lost!!! Thus: type + "mbout stat" and see if nothing is there before you do that. + + common.a: + Patches by JvdW, if CFG.dospath is empty then fileattaches + will contain Unix style filenames, otherwise the ataches + are translated to DOS style. + + dbase.a: + If SearchTic and SearchMsg function the area must be active + in order to be found. + + mbaff: + Removed a bug in scanning uploads function that created empty + lines in the toberep.data file. Also forced the long + description strings to be no longer then 48 characters. + + fbgen: + Finally fixed this one. Can now read multiple description + lines from files.bbs. Renamed to mbfbgen. + The dangerous gets function is replaced. + + mbsetup: + The edit path function now checks if the directory has read + access instead of write access, it might be on CD-rom. + + mbfile: + Skips the kill and pack functions on CD-rom areas. + Skips the check of files on disk against the database on + CD-rom areas. + + mball: + Doesn't create 00index files on CD-rom areas anymore. + + mbcico: + More bugfixes in TCP protocol. Better error handling for + disconnected sessions. + Creates inbound tmp directories when they don't exist. + Now presents the EMSI info from the tty records if + possible. + + script: + Corrected a syntax error in the maint script. + + mbfido: + The areamgr and filemgr names are not hardcoded anymore, + the names presented are the first names defined in the + setup. + Outbound processing now also works if CFG.dospath is empty, + then Unix style fileattaches will be created. + Rewrite of file import function by JvdW to fix some bugs. + FileMgr and AreaMgr global connect and disconnect now + check if the area is set to Active. + Rewrote ARCmail naming, zero length archives older then + 6 days are deleted. If a zero length archive then still + exists, the extension number is bumped. This should + prevent using the same archive name on the same day to + nodes with more then one mailsession each day. + + +v0.33/g3 18-Oct-1999 + + general: + Ideas for generating ARCmail names by Sean Rima and JvdW + implemented. + Lot's of cosmetic stuff to make commandlines, help screens, + more clear and the same for each program by JvdW. + + update: + In mbsetup 1.14.15 check that this is zero or the number of + old days you want echomail rejected. + Check in mbsetup nodes->mail that "ARCmail a..z" is off + for nodes that can't handle that. + + mbcico: + File attaches that are no longer on disk are now correctly + removed from the flo files. Changed logging for this. + The scanout function now removes truncated ARCmail files + that are not of the current day or are older then 6 days. + Corrected a bug that the inbound directory wasn't created + when it didn't exist. + + mbsebbs: + Now allows netmail crash replies. + Can now reply netmail that came in via the UUCP gateway, + when the reply is saved the message is readdressed to the + gateway. + Disabled the download transfertime check before starting a + download. It gave unpredicteble results if the users previous + download cps was bad for some reason, the user couldn't + download. + + mbsetup: + New menu item in 1.14, "Reject old", to reject incoming + echomail older then this number of days, or zero to not + check the age. + In nodes->mail setup added a switch to allow a..z + ARCmail archives extensions. + Made editing log (debug) switches more clear. + Some editing keys now beep if you do something wrong. + + mbfido: + The pack function now supports 'a..z' ARCmail extensions + if this is on for that node. + It's possible to reject too old echomail. + Short commands and options now displayed in the help. + The fileforward netmail now set's the filemgs name first + character to uppercase. + The uploader name with file import now only has one + name anymore, the first character is capitalized. This + line should not be too long, this gives ugly listings. + System aka's in the same zone other then the aka of echomail + area are added to the seen-by lines. + Added experimental zonegate support for echomail. + Removed some debug logging in tic processing. + + mbaff: + Short commands and options are now possible, like other + programs already did. + + mbout: + Short commands and options are now possible, like other + programs already did. + The scanout function now removes truncated ARCmail files + that are not of the current day or are older then 6 days. + Suppressed the help message for file attach, it is not + yet implemented. + + mbfile: + Short commands and options now displayed in the help. + + mbmsg: + Short commands and options are now possible, like other + programs already did. + + mball: + Short commands and options now displayed in the help. + + mbstat: + Short commands and options are now possible, like other + programs already did. + + mbfbgen: + Handles files.bbs lines of 255 characters instead of 80. + + +v0.33/g4 05-Nov-1999. + + mbfido: + The final seenby lines are deduped and sorted before writing + them to the in and exported echomails. + Areamgr and Filemgr messages now have a capitalized first + "From" name character. + Areamgr new function: flow reports. Can be requested by + %flow and is automatic generated with notify reports. + Areamgr, increased the area tag from 20 to 25 characters + in the notify reports and %list, %query, %unlinked response + messages. + Corrected a bug creating garbage at the end of the magic + execute commandline. + + mbsebbs: + Reply to UUCP gateway didn't work in real live, it seemed + that the official UUCP gate had no ':' character after the + REPLYADDR and REPLYTO kludges, while my testsystem running + ifmail 2.12 for the gate does. I now test both cases. + + mbcico: + Implemented remove ARCmail older then n days. + + mbout: + Implemented remove ARCmail older then n days. + + mbsetup: + Added integrity check for edit message groups. + Added integrity check for edit fileecho groups. + + +v0.33/g5 13-Nov-1999. + + upgrade: + Edit /etc/inetd.conf to add "-t ifc" for standard ifcico + protocol, "-t itn" for telnet protocol. + If you don't use the original binkp mailer, you may want to + add entries for the binkp protocol, this will show the + remote that you don't support the binkp protocol. + The installation scripts are updated. See the file SETUP.sh + on how the files /etc/services and /etc/inetd.conf should + look like. + + mbcico: + Implemented "not supported" binkp protocol. + Revised commandline parameters, in TCP/IP slave mode the + mode must be given on the commandline, -t ifc for standard + ifcico protocol, -t itn for telnet protocol, -t ibn for + binkp protocol. + Starting mbcico without arguments will show the help screen. + Now all programs do that exept the mbsebbs binary. + + mbsebbs: + Changed language prompts 214 and 215. + Added language prompt 46. + Added message export to file function. The file will be saved + in the users private homedirectory, the filename is created + as _.msg in MS-DOS format. + Corrected display header of users home directory file list. + Added import file in message function, the file must be in the + users private homedirectory. This only works in the fullscreen + editor. + + mbfido: + Inserted 2 sync() calls during mailtoss. I hope this prevents + temporary missing archives and .pkt files. + New command, "tag", writes areas tagfiles for each mail and + tic file group to the ~/doc directory. Filenames are automatic + created. + + mbsetup: + In edit tic area and edit message area editing of connected + systems now uses the excisting node setup. + Made a new menu selector for areas with Global and Move + options. + Implemented new menu selector in message and tic areas select. + If you jump directly to a message or tic area with select, the + offset is recalculated to that area range. + Added global editing functions in message areas setup. Functions + are add, delete, change connected systems, aka to use and some + other settings. + Edit a nodes aka's is checked if these aka's are used in tic + and message areas. + Delete a node is checked against aka's used in tic and message + areas. + +v0.33/g6 22-Nov-1999 + + mbsetup: + Removed a bug where you could not add new aka's to nodes due to + the aka's checking. + With database intergrity checks the cause of blocked actions + is now logged in mbsetup.log + If you change the number of connected systems or maximum groups + in global setup, the databases affected will be automatic + updated. + + mbfido: + When writing a notify message to selected nodes all other nodes + received status messages. + Corrected uploader name, removed "BBS" string. + Installed patches from JvdW in file forward to correct some + segfaults with the subject variable. + The local hatched files are now moved to the inbound so that + the unarchiver programs can find these files. + + mbcico: + Added very experimental binkp protocol. Handle with care and + at your own risk. This isn't finished yet. + + SETUP.sh: + Fixed the script, there was one "fi" missing so the script + crashed and didn't do all changes. + + +v0.33/g7 05-Dec-1999 + + mbcico: + Fixed some logging in binkp protocol. It works for normal + mail and files transport. + + mbsebbs: + Export message to users work directory did not put the + message in the work directory but in the home directory. + + mbfido: + Netmail to unknown bbs users are now readdressed to the + sysop. Should be a bounce message. + Added a experimental test for empty imported netmails. + The netmail area Private flag is checked to see if we keep the + original Private flag or force imported netmail to Private. + + +v0.33/g8 12-Dec-1999 + + general: + Changed the Makefile, make zip now puts FILE_ID.DIZ in the + root of the directory tree so that file processors will + find it now. This is a version of this file. + + common.a: + Removed and changed nodelist lookup debug logging. + + mbuseradd: + Now check the excistance of the users home directory, if it + is found then it is removed before the home directory is + created again. This fixes problems with RedHat 6.1. + + mbfido: + Global AreaMgr commands cannot disconnect message areas anymore + that are mandatory. + Removed some routing tracking debug messages. + Added check to see why not connected echomail is imported to + the netmail of the last user in the userbase. + Changed check to "Sysop of z:n/n@network" to readdress to + the sysop's real name. + After readdress a netmail to the sysop, the usersearch is now + done again. + If locking the message base during import fails, import is + aborted. + + +v0.33/g9 18-Dec-1999 + + upgrade: + If you ever used DOSEMU then do a rm -Rf .dosemu in each users + home directory. The ownership of these files are changed so + they are created again when the user runs a door for the + first time. + If you have created ttyinfo records with just digits in it + for the /dev/pty/0 type tty entries, you need to change them + to pty/0 type entries. The example etc files are now containing + these entries. + + general: + All sources recompiled with memwatch. I will not name all + places where I found memory leaks, it was a lot. Still busy + finding them, but most programs are allright now. + You can turn memwatch on and off in the file CONFIG. If you + change it, do a "make clean" before recompiling the sources. + Changed my Fidonet address, the testsystem is listed now and + removed my old e-mail address which was not valid anymore. + Changed the installation script. + For RedHat 6.1 and newer a different /etc/rc.d/init.d/mbsed + file is created then before because the su command behaves + different. The install script will try to detect this. + Thanks to Juergen Heisel for finding this problem. + Changed more startup and shutdown scripts. + Changed language prompts 306, 311 and 324 to reflect + GigaBytes storage instead of MegaBytes. + Changed language prompt 327, it had a space too many at the + end. + + common.a: + In the attach function implemented the global leavecase + switch to be able to turn off the forced uppercase for + file attaches when dos translation is on. + + mbfido: + Found a bug where mbfido ran out of file descriptors during + toss, only about 1012 messages were tossed and then the whole + thing started tossing everything to bad. Jim Hansen who + reported the problem, reported that tossing 37500 messages + now works fine. + Added the commandline switch -unsecure to be able to run an + unsecure toss, ie. no originating checks are performed. + Handle with care. + Forwarded netmail packets got the wrong from address in the + .pkt header. + Added fsync calls after every write to a message packet. + When writing .tic files to other nodes now the real aka of + the tic area is used in the From address instead of bestaka + match of the destination. + All system aka's in the same zone are now added to the .tic + Seenby lines. + Will now gently stop processing if the upsdown semafore is + detected. + Added a check with file import that there are no more then + 25 description lines. + + mbsebbs: + Added new controlcode, ^KM displays the users lastread pointer + in the current message area. + When reading new mail at logon, the users lastread pointers + are not updated anymore in echomail/news areas to prevent that + the users skips unread messages. + Only if a message area is Public/Private and a reply is given + the user gets the question Private y/N. On other cases the + flag is automatic set. + With netmail reply if enough security level a file may be + attached. + The door.sys dropfile date formats are now fixed. Depending + on the menu settings it can be original (pre 2000) format or + have four digit year numbers, the new style. Writing the + dropfile can also be suppressed. + Removed the setuid calls before and after running a door, + mbsebbs now always runs as user "mbse". + The $HOME environment variable is now forced to the users + real home directory, even if mbsebbs is started as user bbs. + When the user logs in, the existance of the subdirecties + .dosemu/run and .dosemu/tmp are created in the users home + directory if they don't exist. DOSEMU is happy with that. + Because of this, all files in the users directories are now + only owned by user mbse. + Moved the setup of last message and file area to a later + startup point in userlogin. + Autoexecuted menus are now also checked for user security + and user age. + Fixed the screen output of several bbs list menus. + Now handles the /dev/pty/0 device names found on newer + Linux distributions. + It will now also create the necesary subdirectories for the + /dev/pty/n devices. + + mbaff: + The written messages statistics counters always counted at + sunday in januari. + + mbmsg: + Added message post from a file function. + + mbsetup: + With the filebase editor I got segmentation faults on a Sun + Sparc machine, changed the filedate calls. They show up the + local time now also. + Added the global editor for the tic areas. + Added in menu 1.3 a switch to leave to case for .flo files + original, ie. not forcing it to uppercase. + Added menu creation in menus setup. + Added setup to suppress the creation of a door.sys dropfile, + and the ability to write the years in four digit format in + the door.sys file. Newer doors seem to understand this. + Added delete menu item in menu setup, finally. + Added menu item move. + The menu editor now shows the autoexec menus with the + lightred lowercase "a" at the selection key position. + When a new config.data is created, the default loglevels + are now set to normal values. + + mbcico: + Forgot to implement the NoTCP global and per node flag. + If you are not permanent connected to the net, use these + to prevent the use of internet protocols. + + mbmon: + Screen 5 now calls Nopper() to keep the server alive. + Corrected screen display numbers 5 and 6. + + +v0.33.10 24-Jan-2000 + + general: + Changed version numbering. From now on, minor odd numbers + are testversions, even are stable. Same as with the + Linux kernel. + Changed the setup script, it should now detect SuSE systems. + This is not tested. + + update: + Remove (as root) all bbs users from /etc/ftpusers. They are + not needed (and never were). + Compile and install this release. + Kill mbsed (killall -9 mbsed). + Edit $MBSE_ROOT/etc/mbsed.conf, remove the line with logdebug + and the commentlines above. + Start mbsed again (/opt/mbse/bin/mbsed). + Then start mbsetup, open the global menu 1, and exit. Answer + yes to update. + If you have any echomail passthru areas, give them a + message base path. Passthru doesn't exist anymore. + + common.a: + The file_crc function now supports the usleep(1) code + for background processing. + The logfunctions now replace and with spaces. + + msgbase.a: + Corrected a bug in the Pack function when the headerfile + was corrupt. If the header is corrupt, the index file is + used to find the right recordposition again. Errors are + logged. + + mbsed: + Removed the logdebug loglevels. Logging is fixed now. + Changed the answers for the SBBS command. + + mbsetup: + Added a global setup screen for the ftp server. + Added a switch in the menus setup for doors to set a flag + to create door.sys files for dosemu/Vmodem use. + Revised the message area setup screen. + Changed text's in global mailer setup to indicate that the + mailer flags are for TCP/IP connections. + + mbuseradd: + Doesn't add usernames anymore to /etc/ftpusers. This is not + needed for standard ftp security. + + mbcico: + Added send filerequest to the binkp protocol. In single + batch mode, you need to connect a second time to get the + request response. This is normal single batch behaviour. + Nodelist flag for Binkp mode is XX. (For POTS/ISDN XA). + Added received filerequest to the binkp protocol. In single + batch mode this will put the files on hold. Multiple batch + mode works now but is only tested against another mbcico + mailer. + Calling internet nodes could not use a forced hostname or + IP address. Fixed. Added search in nodes setup phone + fields for hostname/IP address, search in nodelist location + entry (2 nodes on the world do that, I needed one of them), + and the IP notation in the nodelist phone field (000-...). + Hostnames after the flags are not resolved, hostnames + should be in the system name field. + In the binkp protocol the flags from the global mailer + setup are sent as our flags. + + mbsebbs: + The next two pathes are from Ken Bowley. + Changed the fullscreen editor with patches from Ken Bowley. + Improved behaviour for inserting and deleting text. + Changed the door.sys creation, if the COM port option in + the menu files is on, the door.sys file writes COM1 in + it with a portspeed of 115200. This is for running doors + under dosemu and a patched Vmodem. + Made newmail scan and other checks for personal mail case + insensitive. + The fullscreen editor source now has an extra define FSEDIT + to enable heavy debugging logs. + It didn't respect the BBS closed status on lines that did + not honor ZMH status. + Removed "Re:" debug logging from mail.c + + mbfido: + Corrected the queue path for tic passthru areas, the + destination path missed a /. + Delete file from the inbound with passthru areas is now at a + later point. + Removed the message passthru switch, you needed and area + anyway. + + mbstat: + Corrected screen output when it was waiting for the bbs to + close. + + mbftpd: + New! Special ftp server for MBSE BBS. Should use BBS users + access restrictions etc. Doesn't work yet so don't use it. + It is included in the distribution, but not compiled or + installed. + + +v0.33.11 07-Mar-2000 + + upgrade: + Change the CLIENT line in ~/etc/mbsed.conf, the authcode must + now come behind the hostname. Remove the AUTHCODE line. + Kill the old mbsed, start the version from this version. + The same changes must be made to ~/etc/client.conf + Run mbsetup, goto 1.17 and 1.18 and set it up for your system. + Check the QWK area names in the message areas: if there are + areanames longer then 13 characters edit them so that they + fit in the 13 characters limit. In previous versions this field + was 20 characters. + + general: + Added global config to create www pages for downloads. + Included the mbftpd directory in the main Makefile. Don't use + the mbftpd program yet! + Updated the documentation, some parts were 2 versions behind. + + common.a: + Execute external programs now lowers process priority to 15, + and restores to 0 after execution. This should make running + (de)compressors and other utilities "nicer". + If a client fails server authorization, it will now proper + close the server connection. + + mbsed: + The syntax of the client lines in mbsed.conf is changed, + multiple lines are now allowed, hostnames and authcodes must + be on one line now. + It is now possible to close the connection when not authorized. + Minimized the number of response codes. Updated the + documentation. + + mbsetup: + Added global setup menu for the html pages creation. + The length of the QWK area names in the message areas setup + is changed from 20 to 13 characters for the QWK specifications. + Removed selection of menu number 216 from the menu editor. + + mball: + The index command now also creates index.html files for web + clients. The index files are stored in the download directories. + If a download directory contains .gif or .jpg files then + thumbnails will be created and the thumbnails will be used in + in the index.html files. + You need "convert" of the ImageMagick package to use that + future. + + mbfile: + Added 'index*' to the list of filenames that isn't checked + with the mbfile check option. + Pack and Move file functions will now also delete or move the + thumbnail files. + + mbcico: + Changed the binkp receiver timeout code to prevent a hanging + receiver. This only happens sometimes on a Sun Sparc (and + still does). + Changed the modem chat logging. It is now visible what is + really send and received from to the modem. + + mbsebbs: + Added wordwrap in the fullscreen texteditor. Patches by + Ken Bowley. + Replaced hardcoded prompts in offline.c with language prompts. + New prompts are 66, 228, 229, 256, 260, 277, 297, 338, 374, + 377, 391..397, 411, 425, 439..460. Replaced a language prompt + in the Language load function with a hardcoded message. + Removed menu option 216, download pointmail. + Added QWK download and upload. Not fully tested yet!! + Added ASCII download. + File descriptions with color info will now be displayed in + color. + + mball: + File descriptions with color info suppresses the color info + in the all/newfiles listings and 00index files. + + +v0.33.12 24-Apr-2000 + + upgrade: + After compiling and installing set the amount of free + diskspace in mbsetup menu 1.4.22 to your choice. + Kill and reload mbsed. + If you use the web interface for the file areas create + the directory css in your webserver document root and copy + files.css from the distribution archive in it. Then run + mball index. Customize files.css to your taste. + + general: + Changed the ~/tmp/scan.mail file to ~/tmp/echomail.jam and + ~/tmp/netmail.jam in the standard JAM format. + Added file README.GoldED + + common.a: + Added function to check for free diskspace on ext2, msdos and + vfat filesystems, except floppies. + + mbsetup: + New nodes now have "Notify" default off. + Renamed menu 1.4. + Added minimum diskspace setting to menu 1.4. + Added force FNC switch to the nodes setup. + + mbfido: + Exported netmail are checked until any tearline, not MBSE's + tearline alone. + If exported echomail doesn't have a ^aPID kludge, the ^aTID + kludge will be inserted anyway. + Removed some debugging info from the ARCmail pack function. + When netmail to points is written with GoldED there was no + ^aTOPT kludge. Any missing ^aTOPT, ^aFMPT and ^aINTL kludges + are now added if they were not found during mailscan. + The unarc/viruscheck directory is now completly removed after + use and created again. Sometimes files with strange names + were left behind with a normal recursive remove. + Now checks at regualar points the free diskspace. Execution + aborts if it is too low. + + mbsebbs: + Inserted ^aINTL: kludge instead of ^aINTL without colon. + Corrected the users age calculation, the users age increased + one month after his birthday. + + mbsed: + Added some fsync() calls to ensure disk writes. + Now starts logging reginfo locking after the fifth attempt. + + mbcico: + Made some small changes to the binkp batch function. + Added free diskspace check during outbound calls. + Added BSY command support for binkp during file transfer stage. + Changed binkp timer reset points during file transfer stage. + The binkp receiver now checks diskspace before accepting a + new file, it sends BSY if too low to the remote. + If in nodes setup the FNC flag is set, the binkp protocol + will now send old 8.3 uppercase filenames to the remote. + + mball: + The WWW pages now include a stylesheet so it is more easy + to create a personal look and feel for the pages. The + stylesheet goes into htdocsroot/css/files.css An example + is included in this distribution. + + mbaff: + Added free diskspace check. + + mbindex: + Added free diskspace check. + + mbdiff: + Added free diskspace check. + + mbmsg: + Added free diskspace check. + + mbuser: + Added free diskspace check. + + +v0.33.13 12-Jun-2000 + + upgrade: + Make all files and install them as root. + If you use GoldED or other mail utilities as another user + change $MBSE_ROOT/sema and $MBSE_ROOT/tmp to mode 777. + Kill mbsed with signal 9. + Now start mbsed again (/opt/mbse/bin/mbsed). + + general: + The install script now sets the $MBSE_ROOT/sema and tmp + directories to mode 777. + Updated the internet news gate documentation. + + msgbase.a: + Now creates all JAM files with mode 0666. + + mbcico: + The binkp driver skipped aka's when the node number + was zero. + Changed on hold logmessage. + + mbfido: + When forwarding a netmail, a temp file was closed twice, + this caused a segfault on glibc-2 systems. + In the logfile areamgr notify messages had the same orgin + and destination address. + + mbsed: + Changed the signal handlers. It will now allways try to + cleanup lost clients. It will also not hang anymore when a + client aborts for 10 minutes and use 100% cpu time. + + mbsebbs: + Changed logging in filearea select. + Permanent removed download checktime function, this was + already off. + Added error logging for setting filearea 0 during logoff. + Only netmail replies via an internet gate are now readressed + to a UUCP address. + + +v0.33.14 03-Jul-2000 + + upgrade: + Read this section carefully!!! This is a large update. + Backup the whole BBS configuration. + Compile and install all programs. + Kill -9 pid of mbsed. Restart mbsed. + Delete file ~/var/mailer.hist + Delete in all outbounds the *.sts files. + Start mbsetup, set item 1.5.14 if you want new users to + get an email box, you should do this. + Set 1.13.4, 1.13.5 and 1.13.6 to the node where the pop3, + smpt and nntp servers are, normally this is "localhost". + Set 1.13.10 to the Fidonet aka you will use for incoming + and outgoing email via the Fidonet UUCP gate. + Set 1.13.11 to the node address of the Fidonet UUCP gate. + Set 1.13.12: use "No ISP" if you dont't have internet + access, you will then use the default Fidonet UUCP gate. + Set it to "Dial ISP" if you connect sometimes to the internet + of have a cable modem without a DNS entry. Set it to + "Perm ISP" if you have a permanent connection to the internet + and you system has a valid DNS name. + With mbsetup open the userbase, close it and answer yes to + the save question. If you want existing users to have + private email, set 15.36 for each user to yes. You should + do this to accept email from the UUCP gate. + Open the message areas setup (9.2), exit and answer yes to + the save question, this will update this database. + Remove any existing email areas in the normal mail setup, + menu 9.2 (you should not have had any yet). + With mbsetup open menu 16, this will add the default services + database. Add entries as needed. + With mbsetup open menu 17, this will add the default domain + translate database. Insert entries as needed. Move the new + entries so that the .fidonet .ftn translation is the last + entry. + Go back to the start of this section and check! + + general: + Introduced users private email. Each user has (if set) three + email boxes: mailbox, archive and trash. + New system settings GiveEmail, POP3 host, SMTP host, Email Aka, + UUCP gate aka and Email mode. + New menus for email: 216 Read email, 217 Post email, 218 Trash + email, 219 Choose mailbox, 220 Quickscan email. + New user settings Email and plain password. + All users can now have private email boxes. + In normal mail areas you can't create email boards anymore. + Some documentation is updated for new features and some + changes are made to explain some things better. + Added a services database. These are mail accounts that can + perform certain actions. + Added domain translation database, this will translate fido + domains to internet domains and back. + Changed the message areas to contain newsgroups information. + + common.a: + The nodelist lookup function didn't recognize the internet + protocol flags followed by a colon and portnumber. + Move some functions from mbfido and mbmsg in here. + Added characterset convertor from ifmail. It uses the same + maptabs. + Moved some other functions into this library. + + mbinet.a: + New library, internet protocol interfaces. Has interfaces + to SMTP, NNTP and POP3 protocols. + + msgbase.a: + The MsgIdCRC and ReplyIdCRC values were not set in the message + headers. + Added protection for too long subfield strings. + Made some stringlengths longer, following JAM specs. + + clcomm.a: + When closing the server connection the autorisation table will + now be freed before the program ends. + + mbcico: + During binkp calls the mailer history wasn't filled with + session information. + Some system names were too long for the history info. + Will now properly initialize the mailer history file when it + doesn't exist. + With incoming calls the "Node not in setup..." debug log + message at startup is supressed. + Will send netmail with Immediate flag set allways. + Will now also poll non-CM systems outside ZMH. You should + know what you are doing! + The format of the outbound .sts files is changed to prevent + problems on Sparc systems. + Made the FTS-0001 sessions work again. + With outbound sessions the RH1 link option is set. + If a file is received and there is alread an empty file with + the same name, that one is removed to prevent filename extension + bumping. This may be a leftover from a previous failed session. + + mbout: + Won't create polls for nodes not in the nodelist, nodes that + are Down or Hold. Removing polls is always possible. + When multiple polls on the commandline are given, if one of + these nodes is down/hold, then all other polls are still + created. + When creating a poll for a non-CM node outside ZMH, a warning + is given and written in the log. + Added the fileattach command. + The format of the outbound .sts files is changed to prevent + problems on Sparc systems. + + mbfido: + In the rollover function the mailer history is truncated each + month. The current and previous month records stay. + When forwarding .tic files, the files are now attached to the + routevia address if this is set for a node. + Processes scanning of netmail with the immediate flag set. + Added more debugging info for the scan function. + Uses the services database to decide incoming netmail to handle + by AreaMgr, FileMgr or Email. + Moved some functions to common.a + Configuration errors found during mailscan are now logged. + Removed a small memory leak from the magic manager. + Added experimental email import from a FTN UUCP gateway. + The AreaMgr now refuses to disconnect a node who is cutoff from + an mail area to prevent reconnection. + If from a received tic file the accompaning file is missing in + the inbound the errormessage will now say that instead of the + wrong message "Permission denied". + + mbsetup: + In edit fido aka's when you remove a secondary nodelist the aka + is now automatic erased. + The line editor now checks if a line only contains spaces, if + so, the line is returned erased. Trailing spaces are still + possible! + Added global settings and user settings for the new options. + Added 5 new menu choices, Post Email, Read Email, Trash Email, + Choose Mailbox and Quickscan Email. + Added setup for the services database. + Added setup for the domain translation database. + Corrected some sitedocs chapters numberings. + Added setup parameters for news in the message areas editor. + For new installations there will now be a default system + location filled in. This will prevent "mbstat open" to hang + for sysops that didn't do proper system setup. + + mbmsg: + The post function created the semafore scanout instead of + mailout. + Moved some functions to common.a + Messages written with GoldED were deleted by age because some + GoldED versions don't set the Processed date. + + mbsebbs: + Added DoNop() to message read function to prevent losing the + connection with mbsed with long messages. + Added netmail Immediate option for non CM nodes. + Replaced some hardcoded prompts by language prompts. + Duplicate phonenumbers check is finally working. + Added better check for personal mail. + The messagearea overview now also counts messages written by + the user as personal messages. + Changed the newuser function to set system and bbs password + in one function so the user creates the password only once. + During normal login (via user bbs) the plain user password is + stored in the userbase. This will not work with Unix login. + New textcontrolcode: Control-K + N, current e-mail mailbox name. + Updated the change password menu command to use the new + mbpasswd wrapper. + If a user decided to Quit check for newmail, the bbs crashed + with a segfault. + Will not insert Re: in the subject of the subject contained a + Re^2: produced by GoldED. + Patched the fullscreen editor with code from Johannes Lundberg + to correct the "invalid screencoordinates" problem. + Adds the ^aCHRS kludge with CP437. + Will now free the server authorisation tables on exit. + The users plain password is now written to door.sys + + mbsed: + Removed the fsync calls in the logfile write functions, + it never did any harm and the fsync calls do really slowdown + the system. + The locking functions only waited for 2,5 second instead of 15. + + mbpasswd: + New wrapper, sets a new password for a user from the + commandline. + + mbuseradd: + Doesn't ask the user for a new Unix password anymore, mbpasswd + is used instead to set the password. + + lang: + Added 10 new language prompts, 461 upto 470. + Changed language prompts 39, 40 and 388. + + mblang: + Corrected a bug reported by Johannes Lundberg (2:206/149). + + mbuser: + Will now remove blank records at the end of the database. + + mball: + The index function now translates the characterset from CP437 + to ISO-8859-1. + + mbdiff: + Removed a small memory leak. + + mbindex: + Writes an error in the logfile when no nodelist is defined for + a network that is defined in the network setup. Processing of + all other lists will be completed. + + mbmon: + Will now free the server autorisation table at exit. + + mbmail: + New program, use this to replace ifmail from the ifmail package + for the email gateway if you had that installed. If it is then + it's probably configured in /etc/sendmail.cf or whatever other + MTA you are using. + + +v0.33.15 08-Oct-2000 + + upgrade: + After installing the new binaries kill mbsed. Start mbsed. + Start mbsetup, open global menu 1, exit and save. This will + set the default value for newsarticles dupe database size. + Set the real news areas to the type News instead of Echomail. + Copy mbsebbs-0.33.15/script/run_inout to $MBSE_ROOT/etc + Compile the nodelists again with mbindex. + + general: + All version information for the sources now comes from the + generated file config.h + Tested on Slackware 7.1 (i386) and Debian 2.2 potato (Sparc). + Changed the SS() macro to MBSE_SS() to prevent conflicts + with system libraries. + Changed the way debug logging is, see the file DEBUG for + details. + Updated the ftscprod list with version 006 of 22 jan 2000. + I dared to ask for a product code with the FTSC commitee. + Removed the McMail.bug file from the distribution because + later releases (after 1.0) don't have problems anymore with + EMSI handshake. + Added nodelist capability flag IFT for future extension. + Added forgotten nodelist capability flag Z19. + Changed the analogue modems priority. + + lib: + When there was more then 6 Gig diskspace free, several programs + complained about negative diskspace available. + The logger now registers the /dev/pts/n devices correct. + Changed the logger for the new debug way of logging. + The logger is now protected for stringlength overflow. + + mbfido: + When exporting echomail all system aka's in the same zone are + now added to the SEEN-BY lines. + Experimentail newsgroup postings from local posted echomail + and received echomail. + Now closes active SMTP and NNTP servers only once if they have + been used instead of opening and closing for each message. + The filemover now creates destination directories if they don't + excist. + Added patches from Redy Rodriguez of 2:283/613.6: + . Added %RESCAN and %MSGS to the Areamgr. + . It also fixes two bugs in %QUERY: it incorrectly listed the + linked areas (I have added the great totals at the end of + answers to %QUERY and %LIST); and it also corrects its not + recognizing the area tag if you ask for it in lower case + letters (should always be in upper case). + . The AREA: kludge in echomail is now only tested if it is the + first line of the message. + . Added the message area autocreate function. See the manual + for details how to set it up. + mbfido now creates MBSE-FIDO ^aPID and ^aTID kludges. + Crashmail to points will be sent to their boss node. + Sending email now uses the mkrfcmsg function. + Incoming .pkt files not ending with a zero word are now + processed as if they were ok. The will not end up in the bad + directory anymore. + In magic unpackfile for test there is now an calloc for the + cwd buffer to see if that removes a NULL pointer free'd error. + + SETUP.sh + Added extra check for Slackware systems. Since 7.0 there is + an extra check needed to prevent detecting a Mandrake system. + Corrected a minor typo for Debian startup script. + + mbsetup: + The PickAka function loaded the global setup again when + editing the global setup so you did loose all recent changes. + Added a menu entry in menu 1.13 to set the size of the news + articles dupes database. + In screen 9.2 changed the order of fields 19, 20, 21 and 22 + because item 8. got partly overwritten by linewrapping. + + mbsed: + Corrected the data given for disk statistics for large disks. + The log function now prints all characters to the logfile. + + mbsebbs: + New users have now default the fullscreen message editor. + Added patches from Redy Rodriguez of 2:283/613.6: + . Changed language prompts 136...141 and added 471. Changed + the timestatistics output in funcs4.c for the changed + language prompts. It is now full international. + mbsebbs now creates MBSE-BBS ^aPID kludges. + It is now possible to reply crash to points by testing the + status of the bossnode. Also crash posting to points is + now possible. + Changed some debugging code of the fullscreen editor. + Message reading on Sparc systems works again. + The offline reader functions Tag areas, Untag areas and View + tags will now display the more/y/= prompt when the listings are + longer then the screenlength. Patches by Redy. + When posting a news article the To: field is automatic filled + with "All". + Postings to email and newsgroups now add some RFC headers for + mbfido to process. The style of GoldED is used. + + mbcico: + mbcico now creates MBSE-CICO ^aPID kludges. + The binkp transmitter now sends a zero length dataframe after + the transmitted file to all mailers except mbcico. + Removed a small bug in EMSI handshake routine. + Revised modem7 timeouts. Corrected checksum error for first + time receive of filename. + Did final testing for FTS-0001 sessions, a lot of bugs are + repaired. Note that most of them may be present in ifcico. + In a FTS-0001 session wazoo filerequests are also honored. + Sometimes received wazoo requests were renamed to temp + filenames and not responded to. + Corrected the helpscreen for the TCP/IP modes. + Improved the random dial delay time generation. + + mbmon: + The logger now registers the /dev/pts/n devices correct. + + mbchat: + Patches for new device pty names by Redy Rodriguez. + + fbutil: + New utility written and maintained by Johannes Lundberg, + 2:206/149@fidonet, . + + run_inout: + Changed this script to check for the inbound/bad directory, + if it doesn't excist it is created. + Removed all old news/email gateway stuff. + The goldnode compiler is called if it is in $MBSE_ROOT/bin. + + +v0.33.16 07-Jan-2001 + + upgrade: + Edit the crontab to comment out the lines with run_inout, + mailer and mbstat check. + Compile the sources. + Stop the bbs, kill mbsed. + Install the new binaries. + Start the bbs as root with the new init script. It will be + in some init.d subdirectory depending on your distribution. + If you can't find it, reboot. + If you want to start using the newsgate, run mbfido news -learn + the first time to learn which articles there are. + Edit menu item 1.14.3 and check that it's empty if you don't + use it. + + CRON.sh: + Removed the lines that ware replaced by the mbtask program. + + SETUP.sh + Changed binkd into binkp because binkp is the official protocol + name. + Corrected a problem installing on a system without shadow + passwords. + Removed the part where the init scripts are installed. They + are now in a new script in the script directory. + + clcomm.a: + New function Syslogp, to log unformatted strings, the normal + formatted string logfunction did hang sometimes when logging + strings containing the % character. + Improved some error messages in the NNTP and SMTP connections. + + common.a: + Protected uniq_list and sort_list against NULL pointers. + Handles the error strings now if there is a $ at the start + of an logstring. This was only in the daemon but that didn't + give the right errorstrings. Nobody noticed this error has + been here from the beginning. + Protected the chkftnmsgid function from NULL input. + + libdbase.a: + Dupe checking databases are now loaded in memory when needed + and written to disk only once when ready. + + general: + Two new global switches, don't regate and allow control + messages. + Changed the maptab cp437__iso-8859-1 to translate 8bits dos + graphics to 7bits characters to make all fancy dos like + textboxes more readable on Unix systems. + New setup parameters for UUCP newsfeeds. + Added support for the PPC cpu. + + mbtask: + New daemon. Takes over the functions of the run_inout and + mailer scripts. This program launches every program needed + to run the bbs. It will also check Zone Mail Hour. + + mbsed: + Corrected a spelling error in the program header. + Made the userlog full transparant. + Fixed a memory leak in the userlog function. + Changed file locking of mbsed status files to use fcntl() + instead of placing lockfiles. + + mbfido: + Protected the rfcmsgid function against NULL input. + Build some protection against too long lines in ftn messages + that were gated from rfc and regated to news. + Removed a lot of #ifdef statements for gating behaviour and + made a lot of code permamenent. + Original code for #ifdef ALLOW_CONTROL and DONT_REGATE is now + under control of configuration settings. + Forwarded files had an old copyright message in the tic files. + When sending messages to the SNMP or NNTP servers a line with + only a dot in it will be sent as a space and a dot to prevent + that the server thinks it's the end of the message. + When sending or forwarding messages to a destination with a + routevia address, the arcmail will be packed with the flavor + of the new destination node. + Magic execute uses the exec call now instead of the system + call, the programs to execute must now be in MBSE_ROOT/bin or + it will fail. + If a MSGID is missing the dupecheck includes the message text + in the dupecheck. (Redy). + Local posted echomail gated to news has now the right From: + address format and the right UTC time. + Imported news messages had an AREA: line in the message text. + Gating news to echomail doesn't crash anymore. Fixed several + bugs to make this finally work. + During gating news to echomail the mbmon program now displays + what is going on. + Added usleep code during news scanning. + The program is now installed setuid mbse and setgid bbs. This + allows it to be called by other users as mbse. + New commandline, uucp. This allows mbfido to process incoming + uucp newsbatches. Call it from uucp by: + cat newsbatch | /opt/mbse/bin/mbfido uucp -quiet or + cat newsbatch | /opt/mbse/bin/mbnews + It will handle compressed and uncompressed newsbatches. + If a scanned netmail should be send via your own UUCP gate, the + message will be handled further by the ExportEmail function. + All other UUCP destinations will be send via the remote UUCP + systems. + News articles that need to be send via NNTP are now first stored + in a temporary file. At the end of the mbfido run it will try + to post these articles. If it fails (newsserver down), the temp + file stays for a later try. + Added newsserver options for submitting articles via rnews and + to an UUCP remote host. + Added alias database again that was in the original ifmail. + Made a universal email post function. + Removed sourcefiles addos.*, they were not used. + If in configuration the root for the html pages is blank, then + no html pages will be created. + Netmail send to "ping" are bounced back to the sender if your + system is the final destination. If such a netmail is passing + thrue, the receiver is notified (trace). All ^aVia lines are + added to the replies. Systems running MBSE 0.33.16 and up may + now add the PING flag to the nodelist. + + mbmail: + If there is no Organization header, the BBS default origin + line will be used. + Removed a lot of #ifdef statements for gating behaviour and + made a lot of code permamenent. + Original code for #ifdef ALLOW_CONTROL and DONT_REGATE is + now under control of configuration settings. + The packet routing is now determined using the mail tracker. + The point of splitting large messages is now set at the point + from the setup instead of hardcoded at 12 Kbytes. + The program is now installed setuid mbse and setgid bbs so that + braindead MTA's can still deliver mail to the Fidonet. + Mail for users at your own bbs is now imported into the netmail + board. + Added REPLYTO: REPLYADDR: and MSGID: kludges if these where + not yet present in the message. + Added alias database again that was in the original ifmail. + + mbsetup: + In menu 1.13 added allow control and don't regate setup. + In all menus the default prompt selection is now "-" instead + of "0", so just pressing enter will leave from a menu. + When editing a new message area the area is automatic made + active when you assign a group to the area. + Most databases now create default records the first time. + The sitedoc pages for the tty lines were to big for each + printed page. + Splitted menu 1.13 in a Fidonet and Internet part, added setup + parameters for UUCP newsfeeds. + In the services setup the UUCP/Email entry is now added for + first time installations. + + mbmon: + In all menus the default prompt selection is now "-" instead + of "0", so just pressing enter will leave from a menu. + + mbout: + Fixed the helpscreen. + + mbstat: + Removed the check command, this is now done by the mbtask + daemon. + + mbcico: + Doesn't use tmpnam anymore during execute magic request. + The openfile function doesn't use tempnam anymore if a filename + is created after 62 name bumps. + When searching for a matching aka and your first aka is + disabled the first active aka is used as default. + The closefile function doesn't use the tempnam function anymore. + + mbsebbs: + When posting news articles when not permament connected to the + internet, the From address will be Fido style. + Messages for offline packets are now packed using the + following tests: + - If area is netmail then only personal messages are + included (unchanged). + - If area is not netmail, and msg-kinds are private then + only personal messages are included. + - If area is not netmail, and msg-kinds are both (pvt/pub) + then personal messages and messages without pvt flag are + included. + - Otherwhise all messages are included in the packet. + Removed debug messages for the POP3 protocol. + + mbpasswd: + Fixed a compile problem on systems without shadow passwords. + Thanks to Mario Mure. + Corrected a missing library in salt.c + Corrected a missing conditional header file in encrypt.c + + mbmsg: + Wrote wrong CHRS kludge in the post function. + + mbfile: + Warns about empty file areas during kill files. + + +v0.33.17 21-May-2001 + + upgrade: + Compile the sources. + Stop the bbs using the init script mbsed as root: + Slackware 7.0 and older: /opt/mbse/etc/rc.shutdown + Slackware 7.1 and newer: /etc/rc.d/init.d/mbsed stop + RedHat and Mandrake: /etc/rc.d/init.d/mbsed stop + SuSE: /sbin/init.d/mbsed stop + Debian: /etc/init.d/mbsebbs stop + Install the new programs. + Start the bbs using the examples above and use the word start. + Use mbsetup menu 1.18 to change the Zone Mail Hour if you are + not in Fidonet zone 2. + + general: + The daemon mbsed is now obsolete, all these functions are now + in the mbtask daemon. For client/server communications Unix + Datagram sockets are used instead of TCP stream sockets. + Italian language added, translated by nervous@nervous.it + Spanish language added, translated by Redy Rodriguez. + JAM messagebase locking is now according to the JAM specs. + + docs: + Added fsc-0088, fts-4001 and a page to describe the use of a + UPS with MBSE BBS. + Updated documentation to show all changes. + Added in file area setup and message area setup the description + of the global commands. + + SETUP.sh: + Removed installing mbse as port in /etc/services + + common.a: + The diskfree check now ignores a mounted filesystem at /boot + because that filesystem is usually small and not needed by + mbse. + The diskfree check should support reiserfs now (not tested). + Code and logging cleanup in packet.c + + dbase.a: + Removed debug logging from the dupes databases. + + mbinet.a: + When an NNRP server asked for authentication after the first + command instead of after connect, the user authentication + wasn't started. + + mbsed: + Obsolete and removed. + + mbtask: + Does all things mbsed used to do, it uses Unix Datagram sockets + to communicate with the clients. + If IP addresses to test are entered in the setup it will check + if the internet connection is available with ICMP ping. + Added Internet connection status, system running status and + system load average to the GSTA command for mbmon. + Create's the file ~/etc/config.data if it doesn't excist and + fills it with default parameters. + Note: the internet connection status is for future use. + + mbfido: + The pktdate logresult is now only displayed if there was + something wrong. + The Checkdupe fallback logmessage is removed. + Corrected a small bug in the news to echomail gate to get the + correct replyto and replyaddr kludges in the messages. + Changed the tosspkt messages read functions back to the way it + was so the namefield may be exactly 36 characters long excluding + the null terminator. + The PING function didn't work if the message came from a node + not in the setup. + The PING reply now has a Re: prepended. + The scannews function now acts better on nntp error conditions. + Local posted echomail dropped the subject when it was gated to + news. + If imported netmail doesn't have a FMPT kludge and there is + pointinfo in the MSGID line, the pointinfo is taken from the + MSGID line. + Improved the TRACE message of the PING function to make it + more clear that it is a TRACE message. + The PING reply now uses the aka from address that was original + the destination address instead of the matched aka in the + reply message. + Added a hack to try to process .tic files that are not lowercase + filenames. + Added support for a system alias file to convert fidonet + addresses to RFC addresses. + In the mbnews function the tests for the headers Newsgroups: + and Message-ID: are now case insensitive. + File attaches with the leave case option set did not get the + TFS or KFS flags set in the attachement. + + mbdiff: + Removed some debugging logmessages. + + mbfile: + Removed some unnecessary logmessages. + + mbmon: + When viewing the bbs lastcaller list the clock wasn't updated. + The commandline option doesn't work anymore because we + now use Unix Datagram sockets to communicate with the server, + so we must be on the same system. + Added Internet status, running status and system load average + to the Server Statistics screen. + Minor adjustments to the screen layout of the Filesystem Usage + screen. + + mbindex: + Sends the correct IsDoing information to mbtask during sort and + write. + + mbsetup: + Added setup screen for the task manager. + Some menus didn't have the default "-" character in the prompt. + The language setup now adds Italian and Spanish on new + installations. + In main system aka's shortened the domain names from 12 to 11 + characters length to prevent SIGSEGV in mbsetup. + Improved help messages when editing aka's. + Corrected chapter numbering in sitedoc. + Changed page layout sitedoc 8.1 + Removed initialisation of ~/etc/config.data, this is now in + mbtask. + In golded.inc AKAMATCHECHO is no YES. + In golded.inc writing the AKAMATCH aka's other then fidonet + didn't really match the aka's, the main aka was written instead. + + mball: + Removed two redundant log messages. + + mbmail: + The program wrote mbfido instead of mbmail in the logfile. + + mbsebbs: + During login with two names the second name now also checks + for empty responses from the user. + Removed some IEMSI debugging messages. + Removed the timeleft debug message. + Removed logmessage if no newfiles were found. + Removed rendunant log message abount start newfiles scan. + Removed logmessage if no newmail was found. + Removed debug email setarea message. + The list of languages to select is now divided in two columns. + The message to sysop function now doesn't quote and doesn't + write "Sysop wrote to ..." anymore. Thanks to Harald Wuensch. + The program now uses umask(007) instead of umask(000) + In the displayfile function the ^B syntax (show text above + sec. level) is now: ^B^B^B without + the < and > characters. Thanks to Harald Wuensch. + Removed (press enter to Quit) from language prompt 379 since + there is no default choice. + Adjusted a lot of strings for filenames and paths to PATH_MAX + in stead of 80 characters length. + Moved the Nopper call in the fullscreen editor to a place were + it always should work. + + mbcico: + The session debug logmessages are set to the special loglevel. + Implemented EMSI-II, FSC-0088. + When calling a TCP/IP node with hostname in nodelist system + name and a valid phonenumber, and if the hostname could not + be resolved, mbcico would dialout and try to establish a + TCP/IP session over the modem connection. Now the TCP/IP + flags are cleared and mbcico will fallback to valid old style + phone sessions. + In binkp added the M_NUL PHN and M_NUL OPM to log if they are + received from the remote. We also send these flags. + In binkp we now always send and empty dataframe after a file + is sent, most binkp implementations need this to detect EOF. + We don't log received empty frames anymore, we just drop them. + + mbpasswd: + Added check that username and password may not be longer then + 16 characters. + Fixed the error message on some systems about USERGROUPS_ENAB. + + mbuseradd: + Error messages now go to stderr. + Increased stringslength of some internal variables to PATH_MAX. + Check all arguments that they are no longer then 80 characters. + The user is now the owner of his homedir. In this homedir a + directory Maildir with subdirs cur, new and tmp are created, + also owned by the user. Some MTA's need this (Qmail). + Doesn't create the .hushlogin file anymore, not needed. + + mbmsg: + Now runs umask(007) + + mbuser: + If users at the end of the userbase are deleted and the database + should be truncated, these users were not removed from the Unix + system and their homedirectories weren't removed also. + Added a check to see if the sysop defined in the main config + also exists in the user database because these two must match. + + mbstat: + Added the semafore command to set internal mbtask semafore's. + + script/installinit: + Corrected a bug for Slackware 7.0.0 were the wrong initscripts + were installed. + + examples: + Replaced the internet menu and txtfiles with versions that work + with the current menu structure. + diff --git a/DEBUG b/DEBUG new file mode 100644 index 00000000..154ab8f5 --- /dev/null +++ b/DEBUG @@ -0,0 +1,31 @@ + Debugging with MBSE BBS. + +From version 0.33.15 I changed the way debug logging goes. There are no more +#ifdef .. #endif directives in the code that change the loging behaviour. +Lines that could be logged in the code for debug are now written in two +possible ways: + +Syslog('b', "This is always logged for debug"); +Syslog('B', "This is logged if most_debug flag is true"); + +The difference is the uppercase or lowercase logclass. Uppercase is only logged +if the global flag most_debug is set to true. If you want to use it in one of +the sources declare that flag like this: + +extern int most_debug; + +Then, from the moment you need the extra debugging, insert + +most_debug = TRUE; + +in the code, and set it to FALSE when you are done. + +I did this because the extra debug is good for developers but not for regualar +users that need some extra logging. The log output with the most_debug flag +set to TRUE can be huge and does affect system performance. + +For those who are developing code for MBSE BBS, use two kinds on debug logging. + + + Michiel Broek. + diff --git a/FILE_ID.DIZ.in b/FILE_ID.DIZ.in new file mode 100644 index 00000000..f0842fc0 --- /dev/null +++ b/FILE_ID.DIZ.in @@ -0,0 +1,23 @@ +-= MBSE BBS System v@VERSION@ for Linux =- +MBSE BBS is a full Fidonet capable ANSI bbs +package including a mailer (ifcico clone), +tosser, ticfile processor, filefind and other +utilities. +The bbs supports full configurable ANSI +menus, multiple languages, IEMSI, standard +file transfer protocols, native Linux doors +and BlueWave and QWK offline readers. +The mailer supports FTS-0001, YooHoo/2U2, +EMSI protocols over modem, TCP/IP IFC and +Binkd protocol. Zedzap, Zmodem, Telink and +Hydra file transfer protocols. Full FTN mail +support, including automatic routing for hub +and host systems. +Internal mail format is JAM (c) messagebase. +Full tic file support, including extended +tic files. Costsharing will be added later. +Originating sites 2:280/2802@fidonet and +http://mbse.sourceforge.net/ +Copyright by Michiel Broek. +Released under the terms of the GNU Public +License. diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..66812a54 --- /dev/null +++ b/INSTALL @@ -0,0 +1,251 @@ + New installation procedure. + --------------------------- + +The old initial system setup was a little tricky and didn't work on some +systems. This procedure is tested on Slackware, RedHat, Mandrake, SuSE and Debian. +I have not tested on other distributions. Installation is now done by a +script which will do the dirty work. This script can be executed once only, +unless you undo all changes the script has done. Basicly, if you already +have installed MBSE BBS, or there are parts left of an old installation, the +script will abort and inform you why. I hope this will give a better and more +universal setup on most distributions. + + + + Installing MBSE BBS for the first time. + --------------------------------------- + +Login as root and type the following commands to do the basic install: + +cd /tmp +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +sh ./SETUP.sh + +This will setup a new directory structure /opt/mbse and create's some +necessary users. If this in successfull, logout and login as user "mbse". +To build and install mbse bbs type the following commands: + +cd +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +./configure +make +su +[type rootpassword] +make install +exit +/opt/mbse/bin/mbtask + +The next step is to read the documentation in /opt/mbse/html with a browser. +After your system is configured and tested type "sh ./CRON.sh" to install +a default crontab for the bbs. + + + Upgrading MBSE BBS on a running system. + --------------------------------------- + +Login as user "mbse", backup your bbs configuration, and then type the +following commands: + +cd +tar xfvz /pathtopackage/mbsebbs-0.33.17.tar.gz +cd mbsebbs-0.33.17 +./configure +make +su +[type rootpassword] +make install +exit + +Read the ChangeLog file for update instructions from the version +you were running and the version you have just installed over the old +version. Perform the upgrades step by step, version by version. + + +Next the instructions for the standard GNU installation programs: + + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/opt/mbse/bin', `/opt/mbse/etc', etc. You can specify an +installation prefix other than `/opt/mbse' by giving `configure' the +option `--prefix=PATH'. This is NOT ADVISED for MBSE BBS!!! + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/INSTALL.in b/INSTALL.in new file mode 100644 index 00000000..b3b5ff30 --- /dev/null +++ b/INSTALL.in @@ -0,0 +1,251 @@ + New installation procedure. + --------------------------- + +The old initial system setup was a little tricky and didn't work on some +systems. This procedure is tested on Slackware, RedHat, Mandrake, SuSE and Debian. +I have not tested on other distributions. Installation is now done by a +script which will do the dirty work. This script can be executed once only, +unless you undo all changes the script has done. Basicly, if you already +have installed MBSE BBS, or there are parts left of an old installation, the +script will abort and inform you why. I hope this will give a better and more +universal setup on most distributions. + + + + Installing MBSE BBS for the first time. + --------------------------------------- + +Login as root and type the following commands to do the basic install: + +cd /tmp +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +sh ./SETUP.sh + +This will setup a new directory structure /opt/mbse and create's some +necessary users. If this in successfull, logout and login as user "mbse". +To build and install mbse bbs type the following commands: + +cd +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +./configure +make +su +[type rootpassword] +make install +exit +/opt/mbse/bin/mbtask + +The next step is to read the documentation in /opt/mbse/html with a browser. +After your system is configured and tested type "sh ./CRON.sh" to install +a default crontab for the bbs. + + + Upgrading MBSE BBS on a running system. + --------------------------------------- + +Login as user "mbse", backup your bbs configuration, and then type the +following commands: + +cd +tar xfvz /pathtopackage/@PACKAGE@-@VERSION@.tar.gz +cd @PACKAGE@-@VERSION@ +./configure +make +su +[type rootpassword] +make install +exit + +Read the ChangeLog file for update instructions from the version +you were running and the version you have just installed over the old +version. Perform the upgrades step by step, version by version. + + +Next the instructions for the standard GNU installation programs: + + +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/opt/mbse/bin', `/opt/mbse/etc', etc. You can specify an +installation prefix other than `/opt/mbse' by giving `configure' the +option `--prefix=PATH'. This is NOT ADVISED for MBSE BBS!!! + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..f8e838f5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign dist-zip no-installinfo no-installman +EXTRA_DIST = COPYING DEBUG CRON.sh FILE_ID.DIZ.in README \ +README.GoldED SETUP.sh TODO UPGRADE files.css checkbasic + +SUBDIRS = @SUBDIRS@ + + +install-exec-local: + @./checkbasic + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(mkinstalldirs) $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + $(mkinstalldirs) $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + $(mkinstalldirs) $(prefix)/{english,english/txtfiles,english/menus,english/macro} + $(mkinstalldirs) $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + $(mkinstalldirs) $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chown @OWNER@.@GROUP@ $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + chown @OWNER@.@GROUP@ $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + chown @OWNER@.@GROUP@ $(prefix)/{english,english/txtfiles,english/menus,english/macro} + chown @OWNER@.@GROUP@ $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + chown @OWNER@.@GROUP@ $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chmod 777 $(prefix)/{sema,tmp} + $(mkinstalldirs) /var/spool/mbse + $(mkinstalldirs) /var/spool/mbse/{nodelist,unknown,inbound,outbound,badtic,ticqueue,ftp,mail} + chown -R @OWNER@.@GROUP@ /var/spool/mbse + chmod -R 755 /var/spool/mbse + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..30d9e12f --- /dev/null +++ b/Makefile.in @@ -0,0 +1,395 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +AUTOMAKE_OPTIONS = foreign dist-zip no-installinfo no-installman +EXTRA_DIST = COPYING DEBUG CRON.sh FILE_ID.DIZ.in README README.GoldED SETUP.sh TODO UPGRADE files.css checkbasic + + +SUBDIRS = @SUBDIRS@ +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = INSTALL FILE_ID.DIZ +DIST_COMMON = README ./stamp-h.in AUTHORS COPYING ChangeLog \ +FILE_ID.DIZ.in INSTALL INSTALL.in Makefile.am Makefile.in NEWS TODO \ +acconfig.h acinclude.m4 aclocal.m4 config.guess config.h.in configure \ +configure.in install-sh missing mkinstalldirs + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --foreign --include-deps Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in acinclude.m4 + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @if test ! -f $@; then \ + rm -f stamp-h; \ + $(MAKE) stamp-h; \ + else :; fi +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h 2> /dev/null +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in + @if test ! -f $@; then \ + rm -f $(srcdir)/stamp-h.in; \ + $(MAKE) $(srcdir)/stamp-h.in; \ + else :; fi +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in 2> /dev/null + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: +INSTALL: $(top_builddir)/config.status INSTALL.in + cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status +FILE_ID.DIZ: $(top_builddir)/config.status FILE_ID.DIZ.in + cd $(top_builddir) && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive install-info-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP_ENV) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) dist + -rm -rf $(distdir) + @banner="$(distdir).tar.gz is ready for distribution"; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-zip: distdir + -chmod -R a+r $(distdir) + zip -rq $(distdir).zip $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP_ENV) $(TAR) chozf $(distdir).tar.gz $(distdir) + zip -rq $(distdir).zip $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-info-am: +install-info: install-info-recursive +all-recursive-am: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile config.h +all-redirect: all-recursive-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-hdr mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-hdr clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-hdr distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + -rm -f config.status + +maintainer-clean-am: maintainer-clean-hdr maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +install-data-recursive uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-info-am \ +install-info all-recursive-am install-exec-local install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +install-exec-local: + @./checkbasic + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(mkinstalldirs) $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + $(mkinstalldirs) $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + $(mkinstalldirs) $(prefix)/{english,english/txtfiles,english/menus,english/macro} + $(mkinstalldirs) $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + $(mkinstalldirs) $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chown @OWNER@.@GROUP@ $(prefix)/{bin,etc,etc/maptabs,doc,fdb,home,log,magic,sema,var,tmp} + chown @OWNER@.@GROUP@ $(prefix)/{dutch,dutch/txtfiles,dutch/menus,dutch/macro} + chown @OWNER@.@GROUP@ $(prefix)/{english,english/txtfiles,english/menus,english/macro} + chown @OWNER@.@GROUP@ $(prefix)/{italian,italian/txtfiles,italian/menus,italian/macro} + chown @OWNER@.@GROUP@ $(prefix)/{spanish,spanish/txtfiles,spanish/menus,spanish/macro} + chmod 777 $(prefix)/{sema,tmp} + $(mkinstalldirs) /var/spool/mbse + $(mkinstalldirs) /var/spool/mbse/{nodelist,unknown,inbound,outbound,badtic,ticqueue,ftp,mail} + chown -R @OWNER@.@GROUP@ /var/spool/mbse + chmod -R 755 /var/spool/mbse + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..193a4492 --- /dev/null +++ b/README @@ -0,0 +1,24 @@ + MBSE BBS Packages. + + +Distribution naming scheme: + +mbd0_30a.tgz +^^^^ ^^^ + ||| || + ||| |+---- Alpha, Beta, Gamma or none for stable version. + ||| +----- Minor version number (2 digits). + ||+-------- Major version number. + |+--------- Package type, see next section. + +---------- Always mb (2 alpha characters). + +Package types: + + b - The complete MBSE BBS package, including mailer and utilities. + i - Internet <> Fidonet gateway software. + p - Pointlist processing software. + + +Note that for distribution via Fidonet Technology networks the naming scheme +is restricted to dos 8.3 conventions, while longer names would be nicer. + diff --git a/README.GoldED b/README.GoldED new file mode 100644 index 00000000..86c25345 --- /dev/null +++ b/README.GoldED @@ -0,0 +1,90 @@ + README for GoldED users. + + +Since MBSE BBS version 0.33.12 GoldED and MBSE BBS can be used together +without problems as long as you use it to read the sysop mail. The +mbsetup program can export a file called /opt/mbse/etc/golded.inc which +will contain your main Aka's, Aka matching, sysop name and all your mail +areas. This file is only (re)created if you change the global settings or +one of the mail areas. The first time you must force this by making a change +somewhere. + +Now create /opt/mbse/etc/golded.cfg, here is what I wrote: + +; GoldED.cfg +; +; Internet Addressing +; +INTERNETADDRESS Michiel_Broek@f2802.n280.z2.fidonet.org +INTERNETGATE UUCP 2:292/875 +; +; +OUTBOUNDPATH /SYS/usr/mail/out +REPLYLINK chain +STYLECODES yes +; +; +; MESSAGE READER +; +DISPMSGSIZE KBYTES +DISPATTACHSIZE KBYTES +DISPLOCALHIGH YES +DISPPAGEBAR YES +VIEWHIDDEN YES +VIEWKLUDGE NO +VIEWQUOTE YES +; +INCLUDE /opt/mbse/etc/golded.inc +; +; The end. + +Put in /opt/mbse/.profile the following line: +export GOLDED=$HOME/etc + +When you now start GoldED you use it as the sysop. Make sure that the sysop's +userrecord is the first user in the MBSE BBS userbase. If not, the lastread +pointers are not right. + + +Compile instructions for GoldED 3.0.1 written by Johannes Beekhuizen, 2:280/1018 + +* Unpack the sources in some directory (/tmp): + cd /tmp + tar -zxvf ???/ged_301.tgz + This will create a directory golded-3.0.1, so if you did this in /tmp then + there is now a directory called /tmp/golded-3.0.1 which will be called + from now on. +* Set the environment variables GSRC, GOBJ and GLIB to basedir. In a bash + shell this is: + export GSRC=/tmp/golded-3.0.1 + export GOBJ=/tmp/golded-3.0.1 + export GLIB=/tmp/golded-3.0.1 +* Build the program 'gbuild': + cd /gbuild + make lnx + cp gbldnx /opt/mbse/bin + The location of gbldlnx is not important, as long as it is in your PATH. +* Create the directories needed for compilation and installation: + cd /goldlib + make install +* Next build GoldED: + cd /goldlib/gall + make lnx + cd /goldlib/gcfg + make lnx + cd /goldlib/gmb3 + make lnx + cd /golded3 + cp mygolded.__h mygolded.h + Edit the file mygolded.h to suit your own taste. + make lnx + strip gedlnx + cp gedlnx /opt/mbse/bin +* Now build goldnode: + cd /goldnode + make lnx + strip gnlnx + cp gnlnx /opt/mbse/bin +* Example configurations and documentation are in /golded3/cfgs + and /golded3/docs. + diff --git a/SETUP.sh b/SETUP.sh new file mode 100644 index 00000000..a8eadb62 --- /dev/null +++ b/SETUP.sh @@ -0,0 +1,365 @@ +#!/bin/sh +# +# Basic setup script for MBSE BBS +# +# (C) Michiel Broek, v0.17 26-May-2001 +# +# Customisation section, change the next variables to your need. +# However, all docs refer to the setup below. +# +# Basic bbs root directory. +clear +MHOME=/opt/mbse +PATH=/bin:/sbin:/usr/bin:/usr/sbin: +DISTNAME= +DISTVERS= + +#------------------------------------------------------------------------ +# +# Logging procedure, needs two parameters. +# +log() { + /bin/echo `date +%d-%b-%y\ %X ` $1 $2 >> SETUP.log +} + + +#------------------------------------------------------------------------ +# +cat << EOF +MBSE BBS for Linux first time setup. Checking your system..." + +If anything goes wrong with this script, look at the output of +the file SETUP.log that is created by this script in this +directory. If you can't get this script to run on your system, +mail this logfile to Michiel Broek at 2:280/2802 or email it +to mbroek@users.sourceforge.net + +EOF + +echo -n "Press ENTER to start the basic checks " +read junk + +log "+" "MBSE BBS $0 started by `whoami`" +log "+" "Current directory is `pwd`" + + +# +# First do various tests to see which Linux distribution this is. +# +if [ -f /etc/slackware-version ]; then + # Slackware 7.0 and later + DISTNAME="Slackware" + DISTVERS=`cat /etc/slackware-version` +else + if [ -f /etc/debian_version ]; then + # Debian, at least since version 2.2 + DISTNAME="Debian" + DISTVERS=`cat /etc/debian_version` + else + if [ -f /etc/SuSE-release ]; then + DISTNAME="SuSE" + DISTVERS=`cat /etc/SuSE-release | grep VERSION | awk '{ print $3 }'` + else + if [ -f /etc/redhat-release ]; then + DISTNAME="RedHat" + DISTVERS=`cat /etc/redhat-release | awk '{ print $5 }'` + else + if [ -f /etc/mandrake-release ]; then + DISTNAME="Mandrake" + # Format: Linux Mandrake release 8.0 (Cooker) for i586 + DISTVERS=`cat /etc/mandrake-release | awk '{ print $4 }'` + else + if [ -f /etc/rc.d/rc.0 ] && [ -f /etc/rc.d/rc.local ]; then + # If Slackware wasn't detected yet it is version 4.0 or older. + DISTNAME="Slackware" + DISTVERS="Old" + else + DISTNAME="Unknown" + fi + fi + fi + fi + fi +fi + + +log "+" "Detected \"${DISTNAME}\" version \"${DISTVERS}\"" + +# Basic checks. +if [ `whoami` != "root" ]; then +cat << EOF +*** Run $0 as root only! *** + + Because some of the system files must be changed, you must be root + to use this script. + +*** SETUP aborted *** +EOF + log "!" "Aborted, not root" + exit 2 +fi + +if [ "$MBSE_ROOT" != "" ]; then + echo "*** The MBSE_ROOT variable exists: $MBSE_ROOT ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, MBSE_ROOT variable exists: ${MBSE_ROOT}" + exit 2 +fi + +if [ "`grep mbse: /etc/passwd`" != "" ]; then + echo "*** User 'mbse' already exists on this system ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, user 'mbse' already exists on this system" + exit 2 +fi + +if [ "`grep bbs: /etc/group`" != "" ]; then + echo "*** Group 'bbs' already exists on this system ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, group 'bbs' already exists on this system" + exit 2 +fi + +if [ -f /etc/passwd.lock ]; then + echo "*** The password file is locked, make sure that nobody" + echo " is using any password utilities. ***" + echo "*** SETUP aborted ***" + log "!" "Aborted, password file is locked" + exit 2 +fi +clear + +if [ -d /opt ]; then + log "+" "Directory /opt already present" +else + mkdir /opt + echo "Directory /opt created." + log "+" "Directory /opt created" +fi + + +cat << EOF + Basic checks done. + + The detected Linux distribution is $DISTNAME $DISTVERS + + Everything looks allright to start the installation now. + Next the script will install a new group 'bbs' and two new + users, 'mbse' which is the bbs system account, and 'bbs' which + is the login account for bbs users. This account will have no + password! The shell for this account is the main bbs program. + + One final important note: This script will make changes to some + of your system files. Because I don't have access to all kinds of + distributions and configurations there is no garantee that this + script is perfect. Please make sure you have a recent system backup. + Also make sure you have resque boot disks and know how to repair + your system. It might also be wise to login as root on another + virtual console incase something goes wrong with system login. + + If you are not sure, or forgot something, hit Control-C now or +EOF + +echo -n " press Enter to start the installation " +read junk +clear + + +#------------------------------------------------------------------------ +# +# The real work starts here +# +log "+" "Starting installation" +echo "Installing MBSE BBS for the first time..." +echo "" +echo -n "Adding group 'bbs'" +groupadd bbs +log "+" "[$?] Added group bbs" +echo -n ", user 'mbse'" +useradd -c "MBSE BBS Admin" -d $MHOME -g bbs -G uucp -m -s /bin/bash mbse +log "+" "[$?] Added user mbse" +chmod 770 $MHOME +log "+" "[$?] chmod 770 $MHOME" + +echo -n " writing '$MHOME/.profile'" +cat << EOF >$MHOME/.profile +# profile for mbse +# +export PATH=\$HOME/bin:\$PATH +export MBSE_ROOT=\$HOME +export GOLDED=\$HOME/etc +# For xterm on the Gnome desktop: +cd \$HOME +EOF +echo "" +log "+" "Created $MHOME/.profile" + +# On some systems there is a .bashrc file in the users homedir. +# It must be removed. +if [ -f $MHOME/.bashrc ] || [ -f $MHOME/.bash_profile ]; then + echo "Removing '$MHOME/.bash*'" + rm -f $MHOME/.bash* + log "+" "Removed $MHOME/.bash* files" +fi + +echo "" +echo "Now set the login password for user 'mbse'" +passwd mbse +log "+" "[$?] Password is set for user mbse" + +echo -n "Adding user 'bbs'" +mkdir $MHOME/home +log "+" "[$?] Created directory $MHOME/home" +chown mbse.bbs $MHOME/home +log "+" "[$?] chown mbse.bbs $MHOME/home +chmod 775 $MHOME/home +log "+" "[$?] chmod 775 $MHOME/home +useradd -c "MBSE BBS Login" -d $MHOME/home/bbs -g bbs -s $MHOME/bin/mbsebbs bbs +log "+" "[$?] Added user bbs" +# Some systems (RedHat and Mandrake) insist on creating a users homedir. +# These are full of garbage we don't need. Kill it first. +if [ -d $MHOME/home/bbs ]; then + rm -Rf $MHOME/home/bbs + log "+" "[$?] Removed $MHOME/home/bbs" +fi +mkdir $MHOME/home/bbs +log "+" "[$?] mkdir $MHOME/home/bbs" +chmod 770 $MHOME/home/bbs +log "+" "[$?] chmod 770 $MHOME/home/bbs" +chown mbse.bbs $MHOME/home/bbs +log "+" "[$?] chown mbse.bbs $MHOME/home/bbs" +touch $MHOME/home/bbs/.hushlogin +log "+" "[$?] touch $MHOME/home/bbs/.hushlogin" + +echo ", removing password:" +echo -n "$$" >/etc/passwd.lock +if [ -f /etc/shadow ]; then + log "+" "Shadow password system" + # Not all systems are the same... + if [ "`grep bbs:\!\!: /etc/shadow`" != "" ]; then + sed /bbs:\!\!:/s/bbs:\!\!:/bbs::/ /etc/shadow >/etc/shadow.bbs + else + sed /bbs:\!:/s/bbs:\!:/bbs::/ /etc/shadow >/etc/shadow.bbs + fi + log "+" "[$?] removed password from user bbs" + mv /etc/shadow /etc/shadow.mbse + log "+" "[$?] made backup of /etc/shadow" + mv /etc/shadow.bbs /etc/shadow + log "+" "[$?] moved new /etc/shadow in place" + if [ "$DISTNAME" = "Debian" ] || [ "$DISTNAME" = "SuSE" ]; then + # Debian and SuSE use other ownership of /etc/shadow + chmod 640 /etc/shadow + chgrp shadow /etc/shadow + log "+" "[$?] Debian/SuSE style owner of /etc/shadow (0640 root.shadow)" + else + chmod 600 /etc/shadow + log "+" "[$?] Default style owner of /etc/shadow (0600 root.root)" + fi + echo " File /etc/shadow.mbse is your backup of /etc/shadow" +else + log "+" "Not a shadow password system" + if [ "`grep bbs:\!\!: /etc/passwd`" != "" ]; then + sed /bbs:\!\!:/s/bbs:\!\!:/bbs::/ /etc/passwd >/etc/passwd.bbs + else + sed /bbs:\!:/s/bbs:\!:/bbs::/ /etc/passwd >/etc/passwd.bbs + fi + log "+" "[$?] Removed password of user bbs" + mv /etc/passwd /etc/passwd.mbse + log "+" "[$?] Made backup of /etc/passwd" + mv /etc/passwd.bbs /etc/passwd + log "+" "[$?] Moved new /etc/passwd in place" + chmod 644 /etc/passwd + log "+" "[$?] Changed owner of /etc/passwd" + echo " File /etc/passwd.mbse is your backup of /etc/passwd" +fi +rm /etc/passwd.lock +echo "" + +if [ "`grep binkp /etc/services`" = "" ]; then + BINKD=TRUE +else + BINKD=FALSE +fi +if [ "`grep fido /etc/services`" = "" ]; then + FIDO=TRUE +else + FIDO=FALSE +fi + +log "+" "Services: binkp=$BINKD fido=$FIDO" + +if [ "$FIDO" = "TRUE" ] || [ "$BINKD" = "TRUE" ]; then + echo -n "Modifying /etc/services" + log "+" "Modifying /etc/services" + mv /etc/services /etc/services.mbse + cat /etc/services.mbse >/etc/services + echo "#" >>/etc/services + echo "# Unofficial for MBSE BBS" >>/etc/services + echo "#" >>/etc/services + if [ "$BINKD" = "TRUE" ]; then + echo -n ", binkp at port 24554" + echo "binkp 24554/tcp # mbcico IBN mode">>/etc/services + fi + if [ "$FIDO" = "TRUE" ]; then + echo -n ", fido at port 60179" + echo "tfido 60177/tcp # mbcico ITN mode">>/etc/services + echo "fido 60179/tcp # mbcico IFC mode">>/etc/services + fi + chmod 644 /etc/services + echo ", done." +fi + + +if [ "`grep mbcico /etc/inetd.conf`" = "" ]; then + echo -n "Modifying /etc/inetd.conf" + log "+" "Modifying /etc/inetd.conf" + mv /etc/inetd.conf /etc/inetd.conf.mbse + cat /etc/inetd.conf.mbse >/etc/inetd.conf +cat << EOF >>/etc/inetd.conf + +#:MBSE-BBS: bbs service +binkp stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t ibn +tfido stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t itn +fido stream tcp nowait mbse $MHOME/bin/mbcico mbcico -t ifc + +EOF + chmod 644 /etc/inetd.conf + if [ -f /var/run/inetd.pid ]; then + echo -n ", restarting inetd" + kill -HUP `cat /var/run/inetd.pid` + log "+" "[$?] restarted inetd" + else + log "!" "Warning: no inetd.pid file found" + fi + echo ", done." +fi + + +echo "" +echo -n "Press Enter to continue" +read junk +clear + +cat << EOF + The script made it to the end, that looks good. Before you logout do some + sanity checks; + + 1. Can you still login as a normal user. + + 2. Login on another virtual console, network or whatever as user 'mbse'. + Then type 'echo \$MBSE_ROOT'. Does this show the path to + '$MHOME' or nothing. + + 3. Login on another virtual console as user 'bbs'. It should not ask for + a password, but should direct try to start the bbs. This is not + installed yet but you should see error messages and then be logged out. + + If these three tests weren't successfull, restore /etc/passwd and + or /etc/shadow, the backup copies have the extension '.mbse'. + Then issue (as root of course) the following commands: + + userdel bbs + userdel -r mbse + groupdel bbs +EOF + diff --git a/TODO b/TODO new file mode 100644 index 00000000..19d00855 --- /dev/null +++ b/TODO @@ -0,0 +1,123 @@ + MBSE BBS V0.33.17 TODO list. + ---------------------------- + + These are a list of things that must be implemented one way or + another. Some things are urgent and necessary to operate the bbs + without human intervention, others are just for comfort, or nice. + I think this list will always contain items, I only hope the urgent + matters will be removed. + Note that most goodies are still in my mind instead of in this file. + Classes: U = Urgent. + N = Normal, second priority. + L = Cosmetic or nice to have. + + +mbsebbs: + L: Reading of function keys over modem lines, or worse PPP connections, + must be fixed. Timing problems together with modem buffering? + It works with direct serial connections. Note, this also happens + on busy LAN's between Linux boxes with normal xterm's. + Note: this problem almost dissapeared after kernel upgrade to + 2.2.16. + + L: Must include SEEN-BY and other hidden lines into BlueWave and QWK + mail, must be user selectable. see remarks of William McBrine. + The default is oke now. + + N: Rewrite chat to use "mbtask". Write chat functions into "mbmon" + + N: Implement session and time/day limits. + + N: Display textfiles and archives. + + N: Check for tagged files before logoff + + N: If a message doesn't end with a newline in the FS-editor, the last + line will dissapear when reading the message. + + N: Can't post messages to users handle. + + L: Implement telnet door. + + N: Deleting a line in the FS editor with the BS key gives a SEGFAULT. + +mbfido: + U: Code cleanup and make a structure in this program. Remove duplicate + or similar functions. + + N: Remove memory leak during toss. (It's ok for less 5000 messages for + each run). + + N: Make a workaround for the fileecho name in the filesdatabase. + + N: Implement long filename support from .tic files. + + N: When a news article is received from a mailinglist there is a valid + To: address in the message, the gate doesn't see that and uses the + name to "All". + +mbcico: + L: Implement modem connect response translation for ISDN lines, i.e. + make the CAUSE responses human readable. see McMail for this + option. + + N: Implement MD5 crypt in binkp protocol driver. + + N: Remove code to make automatic calls after mbtask does this. + +mbfile: + N: Add a check to see if the magic filenames are valid. + + N: Adopt files with check for FILE_ID.DIZ + + N: Export to files.bbs + + N: Add + + N: Update <-touch> + + N: Rearc + +mbaff: + L: Add setup parameters for minimum length of keywords. + +mbindex: + N: Add usernames index. + +mbmon: + L: Logfile tail functions. + + L: Chat with bbs users. + +mbtask: + L: Add chat protocol. + + N: Let mbtask control the mailer and mailer calls. + + N: Implement nodelist Txx flags. + + N: Add events. + +mbsetup: + U: PickAka function lets mbsetup crash if domain is 12 characters + + L: Generate crossreference document: + File Areas <=> BBS groups + File Areas <=> Newfiles groups + Filefind flags <=> TIC Areas + Echomail <=> Mail groups + Echomail <=> Nodes + Fileechos <=> Groups + Fileechos <=> Nodes + Fileechos <=> BBS Areas + Fileechos <=> Magic processing + Fileechos <=> Hatch + Newfiles <=> BBS Areas + Newfiles <=> File groups + Echomail groups <=> Nodes + Echomail groups <=> Areas + Fileecho groups <=> Nodes + Fileecho groups <=> File echos + Fileecho groups <=> Newfile reports + Fileecho groups <=> BBS Areas + diff --git a/UPGRADE b/UPGRADE new file mode 100644 index 00000000..a8d9facc --- /dev/null +++ b/UPGRADE @@ -0,0 +1,18 @@ + UPGRADE INSTRUCTIONS. + + +Read the file ChangeLog from the version you are currently running +until you reach the current version. With every version that needs +upgrade you will find the instructions there. Read them carefully +and perform all necessary steps. + +Read the file ChangeLog from the version you are currently running +until you reach the current version. With every version that needs +upgrade you will find the instructions there. Read them carefully +and perform all necessary steps. + +Yes, I wrote this twice, please do the same with the update +instructions. + + Michiel. + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 00000000..1af3260c --- /dev/null +++ b/acconfig.h @@ -0,0 +1,72 @@ +/* acconfig.h for the MBSE BBS package */ + +#define AUTHOR @COPYRIGHT@ + +/* Memory debugging */ +#undef MEMWATCH + +/* Has strcasestr function */ +#undef HAVE_STRCASESTR + +/* Has mkstemp function */ +#undef HAVE_MKSTEMP + +/* If you have gettimeofday function */ +#undef HAVE_GETTIMEOFDAY +#undef HAVE_DECLARED_TIMEZONE +#undef HAVE_TM_GMTOFF +#undef HAVE_TM_ZONE + +/* If you don't have pid_t */ +#undef DONT_HAVE_PID_T + +/* Believe ZFIN */ +#undef BELEIVE_ZFIN + +/* Add pid to mbmail */ +#undef ADD_PID + +/* FSC-0070 */ +#undef FSC_0070 + +/* NOPROTO in lhash.h ??? */ +#undef NOPROTO + +/* No Hash Comp function */ +#undef NO_HASH_COMP + +/* News postings */ +#undef RESTAMP_FUTURE_POSTINGS +#undef RESTAMP_OLD_POSTINGS + +/* From mbftpd: */ +#undef FNM_PATHNAME +#undef IP_TOS +#undef M_UNIX +#undef NBBY +#undef REGEX +#undef REGEXEC +#undef SHADOW_PASSWORD +#undef SO_OOBINLINE + +/* mbuseradd */ +#undef AGING +#undef ATT_AGE +#undef ATT_COMMENTS +#undef AUTH_METHODS +#undef CKDEFS +#undef DOUBLESIZE +#undef HAVE_A64L +#undef HAVE_FCHMOD +#undef HAVE_FCHOWN +#undef HAVE_FSYNC +#undef HAVE_LCKPWDF +#undef HAVE_LIBCRACK +#undef HAVE_LIBCRACK_HIST +#undef KEEP_NIS_AT_END +#undef MD5_CRYPT +#undef PAM +#undef SW_CRYPT + + +/* That's it */ diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..102dc3e3 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,136 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 00000000..6b6e035a --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,149 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + + diff --git a/checkbasic b/checkbasic new file mode 100755 index 00000000..2dac4920 --- /dev/null +++ b/checkbasic @@ -0,0 +1,40 @@ +#!/bin/sh +# +# checkbasic - A script for mbse bbs that checks if your +# installation is correct. If it is then +# normal installation is allowed. If it is +# pristine, basic installation must be done. +# If it bad or incomplete installed it will +# give an errormessage. +# +# v1.00 08-Oct-2000 (c) Michiel Broek. + +if [ "`grep mbse: /etc/passwd`" != "" ]; then + if [ "`grep bbs: /etc/group`" != "" ]; then + if [ -n "$MBSE_ROOT" ]; then + if [ "$LOGNAME" = "mbse" ]; then + # + # Looks good, normal mbse user and environment is set. + # Exit with errorcode 0 + echo "Hm, looks good..." + exit 0 + else + echo "*** You are not logged in as user 'mbse' ***" + exit 1 + fi + else + echo "*** MBSE_ROOT environment is not set or you are not 'mbse' ***" + exit 1 + fi + else + echo "*** Group 'bbs' is missing on your system ***" + exit 1 + fi +else + echo "*** User 'mbse' is missing on your system ***" + echo " It looks like you need to do a basic install." + echo " Make sure you are root and type ./SETUP.sh and" + echo " read the file INSTALL for instructions." +fi + + diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..4e5345fa --- /dev/null +++ b/config.guess @@ -0,0 +1,973 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + macppc:NetBSD:*:*) + echo powerpc-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 ) + sed 's/^ //' << EOF >$dummy.c + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (${CC-cc} $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*T3E:*:*:*) + echo t3e-cray-unicosmk${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # uname on the ARM produces all sorts of strangeness, and we need to + # filter it out. + case "$UNAME_MACHINE" in + arm* | sa110*) UNAME_MACHINE="arm" ;; + esac + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <$dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c </dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:UnixWare:*:*) + if /bin/uname -X 2>/dev/null >/dev/null ; then + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + fi + echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION} + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..01df6d68 --- /dev/null +++ b/config.h.in @@ -0,0 +1,239 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if your system has a working fnmatch function. */ +#undef HAVE_FNMATCH + +/* Define if your struct stat has st_blksize. */ +#undef HAVE_ST_BLKSIZE + +/* Define if you have the strftime function. */ +#undef HAVE_STRFTIME + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if your struct tm has tm_zone. */ +#undef HAVE_TM_ZONE + +/* Define if you don't have tm_zone but do have the external array + tzname. */ +#undef HAVE_TZNAME + +/* Define if utime(file, NULL) sets file's timestamp to the present. */ +#undef HAVE_UTIME_NULL + +/* Define if you have . */ +#undef HAVE_VFORK_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* Define to `unsigned' if doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define if your declares struct tm. */ +#undef TM_IN_SYS_TIME + +/* Define to `int' if doesn't define. */ +#undef uid_t + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#undef YYTEXT_POINTER + +/* Memory debugging */ +#undef MEMWATCH + +/* If you have gettimeofday function */ +#undef HAVE_GETTIMEOFDAY +#undef HAVE_DECLARED_TIMEZONE +#undef HAVE_TM_GMTOFF +#undef HAVE_TM_ZONE + +/* If you don't have pid_t */ +#undef DONT_HAVE_PID_T + +/* Add pid to mbmail */ +#undef ADD_PID + +/* FSC-0070 */ +#undef FSC_0070 + +/* News postings */ +#undef RESTAMP_FUTURE_POSTINGS +#undef RESTAMP_OLD_POSTINGS + +/* From mbftpd: */ +#undef FNM_PATHNAME +#undef IP_TOS +#undef M_UNIX +#undef NBBY +#undef REGEX +#undef REGEXEC +#undef SHADOW_PASSWORD +#undef SO_OOBINLINE + +/* Define if you have the a64l function. */ +#undef HAVE_A64L + +/* Define if you have the c64i function. */ +#undef HAVE_C64I + +/* Define if you have the fchmod function. */ +#undef HAVE_FCHMOD + +/* Define if you have the fchown function. */ +#undef HAVE_FCHOWN + +/* Define if you have the fsync function. */ +#undef HAVE_FSYNC + +/* Define if you have the getcwd function. */ +#undef HAVE_GETCWD + +/* Define if you have the gethostname function. */ +#undef HAVE_GETHOSTNAME + +/* Define if you have the gettimeofday function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define if you have the getwd function. */ +#undef HAVE_GETWD + +/* Define if you have the lckpwdf function. */ +#undef HAVE_LCKPWDF + +/* Define if you have the mkdir function. */ +#undef HAVE_MKDIR + +/* Define if you have the mkstemp function. */ +#undef HAVE_MKSTEMP + +/* Define if you have the mktime function. */ +#undef HAVE_MKTIME + +/* Define if you have the putenv function. */ +#undef HAVE_PUTENV + +/* Define if you have the re_comp function. */ +#undef HAVE_RE_COMP + +/* Define if you have the regcmp function. */ +#undef HAVE_REGCMP + +/* Define if you have the regcomp function. */ +#undef HAVE_REGCOMP + +/* Define if you have the rmdir function. */ +#undef HAVE_RMDIR + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the strcasestr function. */ +#undef HAVE_STRCASESTR + +/* Define if you have the strcspn function. */ +#undef HAVE_STRCSPN + +/* Define if you have the strdup function. */ +#undef HAVE_STRDUP + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strspn function. */ +#undef HAVE_STRSPN + +/* Define if you have the strstr function. */ +#undef HAVE_STRSTR + +/* Define if you have the strtol function. */ +#undef HAVE_STRTOL + +/* Define if you have the strtoul function. */ +#undef HAVE_STRTOUL + +/* Define if you have the uname function. */ +#undef HAVE_UNAME + +/* Define if you have the header file. */ +#undef HAVE_CRYPT_H + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Version number of package */ +#undef VERSION + diff --git a/configure b/configure new file mode 100755 index 00000000..e24a5388 --- /dev/null +++ b/configure @@ -0,0 +1,3881 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_default_prefix=/opt/mbse +ac_help="$ac_help + --enable-memwatch MEMWATCH debugging" +ac_help="$ac_help + --enable-fsc-0070 Enable FSC 0070" +ac_help="$ac_help + --enable-add-pid Enable add PID" +ac_help="$ac_help + --with-log-compress=METHOD Log compression method (default gzip)" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=lib/libs.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + + + +SUBDIRS=". lib mbcico mbfido mbftpd mbmon mbsebbs mbtask mbsetup fbutil import lang examples html script" + + +MBSE_PACKAGE=mbsebbs +MBSE_VERSION=0.33.17 + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:575: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:628: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:685: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=$MBSE_PACKAGE + +VERSION=$MBSE_VERSION + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:731: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:744: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:757: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:770: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:783: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + +GROUP="bbs" +OWNER="mbse" + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:805: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:835: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + if test -z "$CC"; then + case "`uname -s`" in + *win32* | *WIN32*) + # Extract the first word of "cl", so it can be a program name with args. +set dummy cl; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:886: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="cl" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + ;; + esac + fi + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:918: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 929 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:934: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:960: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:965: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes +else + GCC= +fi + +ac_test_CFLAGS="${CFLAGS+set}" +ac_save_CFLAGS="$CFLAGS" +CFLAGS= +echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:993: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi + +# Extract the first word of "gawk", so it can be a program name with args. +set dummy gawk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1027: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="gawk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "nawk", so it can be a program name with args. +set dummy nawk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1056: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="nawk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Extract the first word of "awk", so it can be a program name with args. +set dummy awk; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1085: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="awk" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1123: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1176: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1205: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1237: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1268: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1289: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1306: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1323: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +missing_dir=`cd $ac_aux_dir && pwd` +for ac_prog in flex lex +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1353: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LEX" && break +done +test -n "$LEX" || LEX=""$missing_dir/missing flex"" + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1386: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:1420: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking lex output file root""... $ac_c" 1>&6 +echo "configure:1462: checking lex output file root" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; } +fi +fi + +echo "$ac_t""$ac_cv_prog_lex_root" 1>&6 +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6 +echo "configure:1483: checking whether yytext is a pointer" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_prog_lex_yytext_pointer=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi + +echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + cat >> confdefs.h <<\EOF +#define YYTEXT_POINTER 1 +EOF + +fi + +CFLAGS="$CFLAGS -Wall -Wshadow -Wwrite-strings -Wstrict-prototypes -pipe" + +# Check whether --enable-memwatch or --disable-memwatch was given. +if test "${enable_memwatch+set}" = set; then + enableval="$enable_memwatch" + memwatch=$enableval +else + memwatch=no +fi + +# Check whether --enable-fsc0070 or --disable-fsc0070 was given. +if test "${enable_fsc0070+set}" = set; then + enableval="$enable_fsc0070" + fsc0070=$enableval +else + fsc0070=no +fi + +# Check whether --enable-addpid or --disable-addpid was given. +if test "${enable_addpid+set}" = set; then + enableval="$enable_addpid" + addpid=$enableval +else + addpid=no +fi + + +if test "$memwatch" = "yes"; then + cat >> confdefs.h <<\EOF +#define MEMWATCH 1 +EOF + +fi +if test "$fsc0070" = "yes"; then + cat >> confdefs.h <<\EOF +#define FSC_0070 1 +EOF + +fi +if test "$addpid" = "yes"; then + cat >> confdefs.h <<\EOF +#define ADD_PID 1 +EOF + +fi + +cat >> confdefs.h <> confdefs.h <<\EOF +#define RESTAMP_FUTURE_POSTINGS 1 +EOF + + +echo $ac_n "checking for setspent in -lshadow""... $ac_c" 1>&6 +echo "configure:1579: checking for setspent in -lshadow" >&5 +ac_lib_var=`echo shadow'_'setspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + +if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 +else + echo $ac_n "checking for getspnam in -lshadow""... $ac_c" 1>&6 +echo "configure:1625: checking for getspnam in -lshadow" >&5 +ac_lib_var=`echo shadow'_'getspnam | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 + else + echo $ac_n "checking for setspent in -lc""... $ac_c" 1>&6 +echo "configure:1671: checking for setspent in -lc" >&5 +ac_lib_var=`echo c'_'setspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lc $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + if test -f /etc/shadow; then + SHADOW_PASSWORD=1 + fi + fi + fi +fi +if test "$SHADOW_PASSWORD" = "1"; then + if test "$ac_cv_func_fgetspent" != "yes"; then + echo $ac_n "checking for fgetspent in -lshadow""... $ac_c" 1>&6 +echo "configure:1721: checking for fgetspent in -lshadow" >&5 +ac_lib_var=`echo shadow'_'fgetspent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lshadow $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + + if test "$result" = "yes"; then + if test "$LIBSHADOW" != "1"; then + LIBS="$LIBS -lshadow" + fi + fi + fi + cat >> confdefs.h <<\EOF +#define SHADOW_PASSWORD 1 +EOF + +fi +echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:1773: checking for crypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + result=yes +else + echo "$ac_t""no" 1>&6 +result=no +fi + +if test "$result" = "yes"; then + LIBS="$LIBS -lcrypt" + for ac_hdr in crypt.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1819: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1829: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +fi + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr that defines DIR""... $ac_c" 1>&6 +echo "configure:1862: checking for $ac_hdr that defines DIR" >&5 +if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_hdr> +int main() { +DIR *dirp = 0; +; return 0; } +EOF +if { (eval echo configure:1875: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_dirent_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_dirent_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done +# Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. +if test $ac_header_dirent = dirent.h; then +echo $ac_n "checking for opendir in -ldir""... $ac_c" 1>&6 +echo "configure:1900: checking for opendir in -ldir" >&5 +ac_lib_var=`echo dir'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldir $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -ldir" +else + echo "$ac_t""no" 1>&6 +fi + +else +echo $ac_n "checking for opendir in -lx""... $ac_c" 1>&6 +echo "configure:1941: checking for opendir in -lx" >&5 +ac_lib_var=`echo x'_'opendir | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lx $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$LIBS -lx" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1983: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +#include +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1996: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext < +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:2063: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:2087: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:2108: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in fcntl.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h netinet/in.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:2132: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2142: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2169: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2182: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking for tm_zone in struct tm""... $ac_c" 1>&6 +echo "configure:2203: checking for tm_zone in struct tm" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm_zone'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include <$ac_cv_struct_tm> +int main() { +struct tm tm; tm.tm_zone; +; return 0; } +EOF +if { (eval echo configure:2216: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm_zone=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm_zone=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm_zone" 1>&6 +if test "$ac_cv_struct_tm_zone" = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_TM_ZONE 1 +EOF + +else + echo $ac_n "checking for tzname""... $ac_c" 1>&6 +echo "configure:2236: checking for tzname" >&5 +if eval "test \"`echo '$''{'ac_cv_var_tzname'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#ifndef tzname /* For SGI. */ +extern char *tzname[]; /* RS6000 and others reject char **tzname. */ +#endif +int main() { +atoi(*tzname); +; return 0; } +EOF +if { (eval echo configure:2251: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + ac_cv_var_tzname=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_var_tzname=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_var_tzname" 1>&6 + if test $ac_cv_var_tzname = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_TZNAME 1 +EOF + + fi +fi + + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2274: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2328: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:2349: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:2383: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:2416: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2449: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#if STDC_HEADERS +#include +#include +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for st_blksize in struct stat""... $ac_c" 1>&6 +echo "configure:2482: checking for st_blksize in struct stat" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_st_blksize'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct stat s; s.st_blksize; +; return 0; } +EOF +if { (eval echo configure:2495: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_st_blksize=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_st_blksize=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_st_blksize" 1>&6 +if test $ac_cv_struct_st_blksize = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_ST_BLKSIZE 1 +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:2516: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#include +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:2530: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:2551: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:2564: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + + +for ac_func in c64i a64l fchmod fchown fsync lckpwdf strcasestr mkstemp +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:2588: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2616: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + +echo $ac_n "checking for working fnmatch""... $ac_c" 1>&6 +echo "configure:2641: checking for working fnmatch" >&5 +if eval "test \"`echo '$''{'ac_cv_func_fnmatch_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # Some versions of Solaris or SCO have a broken fnmatch function. +# So we run a test program. If we are cross-compiling, take no chance. +# Thanks to John Oleynick and Franc,ois Pinard for this test. +if test "$cross_compiling" = yes; then + ac_cv_func_fnmatch_works=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_fnmatch_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_fnmatch_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_fnmatch_works" 1>&6 +if test $ac_cv_func_fnmatch_works = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_FNMATCH 1 +EOF + +fi + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:2680: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:2726: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'ac_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + ac_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_memcmp_clean" 1>&6 +test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}" + +echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 +echo "configure:2762: checking whether setpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext < +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} + +EOF +if { (eval echo configure:2790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setpgrp_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setpgrp_void=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 +if test $ac_cv_func_setpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define SETPGRP_VOID 1 +EOF + +fi + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:2814: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +#include +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:2836: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <&6 +echo "configure:2855: checking for strftime" >&5 +if eval "test \"`echo '$''{'ac_cv_func_strftime'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char strftime(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_strftime) || defined (__stub___strftime) +choke me +#else +strftime(); +#endif + +; return 0; } +EOF +if { (eval echo configure:2883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_strftime=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_strftime=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'strftime`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +else + echo "$ac_t""no" 1>&6 +# strftime is in -lintl on SCO UNIX. +echo $ac_n "checking for strftime in -lintl""... $ac_c" 1>&6 +echo "configure:2905: checking for strftime in -lintl" >&5 +ac_lib_var=`echo intl'_'strftime | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lintl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_STRFTIME 1 +EOF + +LIBS="-lintl $LIBS" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking whether utime accepts a null argument""... $ac_c" 1>&6 +echo "configure:2951: checking whether utime accepts a null argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_utime_null'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + rm -f conftestdata; > conftestdata +# Sequent interprets utime(file, 0) to mean use start of epoch. Wrong. +if test "$cross_compiling" = yes; then + ac_cv_func_utime_null=no +else + cat > conftest.$ac_ext < +#include +main() { +struct stat s, t; +exit(!(stat ("conftestdata", &s) == 0 && utime("conftestdata", (long *)0) == 0 +&& stat("conftestdata", &t) == 0 && t.st_mtime >= s.st_mtime +&& t.st_mtime - s.st_mtime < 120)); +} +EOF +if { (eval echo configure:2972: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_utime_null=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_utime_null=no +fi +rm -fr conftest* +fi + +rm -f core core.* *.core +fi + +echo "$ac_t""$ac_cv_func_utime_null" 1>&6 +if test $ac_cv_func_utime_null = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_UTIME_NULL 1 +EOF + +fi + +ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for vfork.h""... $ac_c" 1>&6 +echo "configure:2997: checking for vfork.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3007: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VFORK_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for working vfork""... $ac_c" 1>&6 +echo "configure:3032: checking for working vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + echo $ac_n "checking for vfork""... $ac_c" 1>&6 +echo "configure:3038: checking for vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vfork(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vfork) || defined (__stub___vfork) +choke me +#else +vfork(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3066: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vfork=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vfork=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +ac_cv_func_vfork_works=$ac_cv_func_vfork +else + cat > conftest.$ac_ext < +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_VFORK_H +#include +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include , + but some compilers (e.g. gcc -O) don't grok . + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +EOF +if { (eval echo configure:3183: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_vfork_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_vfork_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_vfork_works" 1>&6 +if test $ac_cv_func_vfork_works = no; then + cat >> confdefs.h <<\EOF +#define vfork fork +EOF + +fi + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:3206: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3234: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:3258: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3286: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_func in getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3313: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3341: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <&6 +fi +done + + +# Extract the first word of "compress", so it can be a program name with args. +set dummy compress; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3369: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_COMPRESS'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$COMPRESS" in + /*) + ac_cv_path_COMPRESS="$COMPRESS" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_COMPRESS="$COMPRESS" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_COMPRESS="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_COMPRESS" && ac_cv_path_COMPRESS="no-compress-found-during-configure" + ;; +esac +fi +COMPRESS="$ac_cv_path_COMPRESS" +if test -n "$COMPRESS"; then + echo "$ac_t""$COMPRESS" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +for ac_prog in gzip +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:3407: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GZIP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GZIP" in + /*) + ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_GZIP="$GZIP" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GZIP="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +GZIP="$ac_cv_path_GZIP" +if test -n "$GZIP"; then + echo "$ac_t""$GZIP" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$GZIP" && break +done +test -n "$GZIP" || GZIP="no-gzip-found-during-configure" + +# Check whether --with-log-compress or --without-log-compress was given. +if test "${with_log_compress+set}" = set; then + withval="$with_log_compress" + LOG_COMPRESS=$with_log_compress +else + LOG_COMPRESS=gzip +fi + +case "$LOG_COMPRESS" in +gzip) + LOG_COMPRESS=$GZIP + LOG_COMPRESSEXT=".gz" ;; +compress) + LOG_COMPRESS=$COMPRESS + LOG_COMPRESSEXT=".Z" ;; +*) + LOG_COMPRESS=$LOG_COMPRESS + LOG_COMPRESSEXT=".unknown" ;; +esac + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile + lib/Makefile + mbcico/Makefile + mbfido/Makefile + mbfido/paths.h + mbftpd/Makefile + mbmon/Makefile + mbsebbs/Makefile + mbtask/Makefile + mbsetup/Makefile + fbutil/Makefile + script/Makefile + import/Makefile + lang/Makefile + examples/Makefile + html/Makefile + INSTALL + FILE_ID.DIZ + config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@SUBDIRS@%$SUBDIRS%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@GROUP@%$GROUP%g +s%@OWNER@%$OWNER%g +s%@CC@%$CC%g +s%@AWK@%$AWK%g +s%@RANLIB@%$RANLIB%g +s%@YACC@%$YACC%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@CPP@%$CPP%g +s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g +s%@LIBOBJS@%$LIBOBJS%g +s%@COMPRESS@%$COMPRESS%g +s%@GZIP@%$GZIP%g +s%@LOG_COMPRESS@%$LOG_COMPRESS%g +s%@LOG_COMPRESSEXT@%$LOG_COMPRESSEXT%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..c73f639f --- /dev/null +++ b/configure.in @@ -0,0 +1,160 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(lib/libs.h) +AM_CONFIG_HEADER(config.h) +SUBDIRS=". lib mbcico mbfido mbftpd mbmon mbsebbs mbtask mbsetup fbutil import lang examples html script" +AC_SUBST(SUBDIRS) + +dnl General settings for MBSE BBS +MBSE_PACKAGE=mbsebbs +MBSE_VERSION=0.33.17 +AC_SUBST(PACKAGE, $MBSE_PACKAGE) +AC_SUBST(VERSION, $MBSE_VERSION) +AM_INIT_AUTOMAKE($MBSE_PACKAGE, $MBSE_VERSION) +AC_PREFIX_DEFAULT(/opt/mbse) +GROUP="bbs" +OWNER="mbse" +AC_SUBST(GROUP) +AC_SUBST(OWNER) + +dnl Checks for programs. +AC_PROG_CC +dnl ALternate awk check, I skip mawk because it doesn't work for MBSE. +AC_CHECK_PROG(AWK, gawk, gawk) +AC_CHECK_PROG(AWK, nawk, nawk) +AC_CHECK_PROG(AWK, awk, awk) +AC_PROG_INSTALL +AC_PROG_MAKE_SET +AC_PROG_RANLIB +AC_PROG_YACC +AM_PROG_LEX +CFLAGS="$CFLAGS -Wall -Wshadow -Wwrite-strings -Wstrict-prototypes -pipe" + +dnl Additional commandline switches +AC_ARG_ENABLE(memwatch, [ --enable-memwatch MEMWATCH debugging], [ memwatch=$enableval ], [ memwatch=no ]) +AC_ARG_ENABLE(fsc0070, [ --enable-fsc-0070 Enable FSC 0070], [ fsc0070=$enableval ], [ fsc0070=no ]) +AC_ARG_ENABLE(addpid, [ --enable-add-pid Enable add PID], [ addpid=$enableval ], [ addpid=no ]) + +if test "$memwatch" = "yes"; then + AC_DEFINE(MEMWATCH) +fi +if test "$fsc0070" = "yes"; then + AC_DEFINE(FSC_0070) +fi +if test "$addpid" = "yes"; then + AC_DEFINE(ADD_PID) +fi + +dnl Defines for MBSE BBS (must use tests or --enable-stuff later) +AC_DEFINE_UNQUOTED(RESTAMP_OLD_POSTINGS, 21) +AC_DEFINE(RESTAMP_FUTURE_POSTINGS) + +dnl Checks for libraries. +AC_CHECK_LIB(shadow,setspent,result=yes,result=no) +if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 +else + AC_CHECK_LIB(shadow,getspnam,result=yes,result=no) + if test "$result" = "yes"; then + LIBS="$LIBS -lshadow" + SHADOW_PASSWORD=1 + LIBSHADOW=1 + else + dnl some libc's (glibc 2.x) keep shadow functions in -lc + AC_CHECK_LIB(c,setspent,result=yes,result=no) + if test "$result" = "yes"; then + if test -f /etc/shadow; then + SHADOW_PASSWORD=1 + fi + fi + fi +fi +if test "$SHADOW_PASSWORD" = "1"; then + if test "$ac_cv_func_fgetspent" != "yes"; then + AC_CHECK_LIB(shadow,fgetspent,result=yes,result=no) + if test "$result" = "yes"; then + if test "$LIBSHADOW" != "1"; then + LIBS="$LIBS -lshadow" + fi + fi + fi + AC_DEFINE(SHADOW_PASSWORD) +fi +AC_CHECK_LIB(crypt,crypt,result=yes,result=no) +if test "$result" = "yes"; then + LIBS="$LIBS -lcrypt" + AC_CHECK_HEADERS(crypt.h) +fi + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h malloc.h sys/file.h sys/ioctl.h sys/time.h syslog.h termio.h unistd.h netinet/in.h) +AC_STRUCT_TIMEZONE + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_UID_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_ST_BLKSIZE +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_CHECK_FUNCS(c64i a64l fchmod fchown fsync lckpwdf strcasestr mkstemp) +AC_FUNC_FNMATCH +AC_PROG_GCC_TRADITIONAL +AC_FUNC_MEMCMP +AC_FUNC_SETPGRP +AC_TYPE_SIGNAL +AC_FUNC_STRFTIME +AC_FUNC_UTIME_NULL +AC_FUNC_VFORK +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(getcwd gethostname gettimeofday getwd mkdir mktime putenv re_comp regcmp regcomp rmdir select socket strcspn strdup strerror strspn strstr strtol strtoul uname) + +dnl Check for external programs +AC_PATH_PROG(COMPRESS,compress,no-compress-found-during-configure) +AC_PATH_PROGS(GZIP,gzip,no-gzip-found-during-configure) +dnl +AC_ARG_WITH(log-compress,[ --with-log-compress=METHOD Log compression method (default gzip)], LOG_COMPRESS=$with_log_compress, LOG_COMPRESS=gzip) +case "$LOG_COMPRESS" in +gzip) + LOG_COMPRESS=$GZIP + LOG_COMPRESSEXT=".gz" ;; +compress) + LOG_COMPRESS=$COMPRESS + LOG_COMPRESSEXT=".Z" ;; +*) + LOG_COMPRESS=$LOG_COMPRESS + LOG_COMPRESSEXT=".unknown" ;; +esac +AC_SUBST(LOG_COMPRESS) +AC_SUBST(LOG_COMPRESSEXT) +dnl + +AC_OUTPUT( + Makefile + lib/Makefile + mbcico/Makefile + mbfido/Makefile + mbfido/paths.h + mbftpd/Makefile + mbmon/Makefile + mbsebbs/Makefile + mbtask/Makefile + mbsetup/Makefile + fbutil/Makefile + script/Makefile + import/Makefile + lang/Makefile + examples/Makefile + html/Makefile + INSTALL + FILE_ID.DIZ +) + diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 00000000..1897e136 --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = etc.tar menus.tar txtfiles.tar + +install-exec-local: + @if [ ! -f $(sysconfdir)/mareas.data ]; then \ + tar xfC etc.tar $(sysconfdir) ; \ + echo "Installing default databases" ; \ + fi + @if [ ! -f $(prefix)/english/menus/main.mnu ]; then \ + tar xfC menus.tar $(prefix)/english/menus ; \ + echo "Installing default english menus" ; \ + fi + @if [ ! -f $(prefix)/english/txtfiles/main.ans ]; then \ + tar xfC txtfiles.tar $(prefix)/english/txtfiles ; \ + echo "Installing default english txtfiles" ; \ + fi + diff --git a/examples/Makefile.in b/examples/Makefile.in new file mode 100644 index 00000000..301fa5c2 --- /dev/null +++ b/examples/Makefile.in @@ -0,0 +1,298 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = etc.tar menus.tar txtfiles.tar +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps examples/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = examples + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ ! -f $(sysconfdir)/mareas.data ]; then \ + tar xfC etc.tar $(sysconfdir) ; \ + echo "Installing default databases" ; \ + fi + @if [ ! -f $(prefix)/english/menus/main.mnu ]; then \ + tar xfC menus.tar $(prefix)/english/menus ; \ + echo "Installing default english menus" ; \ + fi + @if [ ! -f $(prefix)/english/txtfiles/main.ans ]; then \ + tar xfC txtfiles.tar $(prefix)/english/txtfiles ; \ + echo "Installing default english txtfiles" ; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/examples/etc.tar b/examples/etc.tar new file mode 100644 index 0000000000000000000000000000000000000000..e8f29f648acf1bcca724ff8948ce3f3a393c0929 GIT binary patch literal 133120 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 literal 0 HcmV?d00001 diff --git a/examples/menus.tar b/examples/menus.tar new file mode 100644 index 0000000000000000000000000000000000000000..13decbaf5676103e1caef904cdf4603d48d9a1bd GIT binary patch literal 61440 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 literal 0 HcmV?d00001 diff --git a/examples/txtfiles.tar b/examples/txtfiles.tar new file mode 100644 index 0000000000000000000000000000000000000000..0accd21789f2c05c9fc62622f9c44f33cf4de60a GIT binary patch literal 92160 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 /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + rm -Rf $(prefix)/html + $(mkinstalldirs) $(prefix)/html + @echo "Installing html documentation in $(prefix)/html" + @cp -Pr $(EXTRA_DIST) $(prefix)/html + chown -R @OWNER@.@GROUP@ $(prefix)/html + chmod -R 0644 $(prefix)/html/*.htm* + chmod -R 0644 $(prefix)/html/images/*.gif + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/html/basic.html b/html/basic.html new file mode 100755 index 00000000..16beffc6 --- /dev/null +++ b/html/basic.html @@ -0,0 +1,152 @@ + + + + + + + + +MBSE BBS basic installation. + + + +
+
Last update 27-May-2001
+

 

+ +

MBSE BBS Basic Installation

+ +

Introduction.

+

+Before you compile and install MBSE BBS you must first setup the basic +environment. If you don't do this, things will fail. +

 

+ +

Step 1: planning the filesystems.

+

+MBSE BBS is default installed in /opt/mbse. The spoolfiles (in and +outbound, message bases) go into /var/spool/mbse. In the /opt/mbse +path are several subdirectories, bin for the binaries, etc for the +configuration and some scripts, english and dutch for the language +files and menus, home for the users homedirectories, log for the +logfiles, magic for the filerequest magicnames, fdb for the files +database, var for some statistic files and tmp as temp directory. +

+Don't use UMSDOS or SAMBA filesystems for the bbs, stick by the standard Linux +filesystems (ext2). If you intent to make your bbs also accessible +by FTP and WWW you must create the directory structure under the ftp user +behind the pub directory. Read the +ftp server doc for details. If you don't follow these guidlines, you +will run into trouble later and have to spend a lot of time in correcting +this error. +

+The default setup will be as follows:
+

+/opt/mbse		binaries, config and user home directories.
+/var/spool/mbse		In/outbound, queues, download directories.
+
+

 

+ +

Step 2: Running the installation script.

+

+The installation script must be run by root. It checks if there is a +previous or failed installation on your system. If that's so the script will +not run. In other words, you can only run this script once. The script makes +backup copies of the system files it changes, these files will get the +extension .mbse To run the installation script you need +the archive mbbsebbs-0.33.nn.tar.gz. +Unpack this archive on your system, in /tmp will do fine: +

+cd /tmp
+tar xfvz /path/to/the/mbsebbs-0.33.nn.tar.gz
+
+To start the script type: +
+cd mbsebbs-0.33.nn
+sh ./SETUP.sh
+
+The script does the following: +
    +
  1. Create the group bbs +
  2. Create the user mbse +
  3. Create a .profile for user mbse +
  4. Create and set owner of directory tree under /opt/mbse +
+Then the script will ask you to give a password for user mbse +This password is for system maintenance and for you to make changes to the +bbs. You will need that frequently but you should not make that password +easy to guess of course. The script will then continue again: +
    +
  1. The user bbs is added. +
  2. The password will be removed from user bbs This action +will make changes in /etc/shadow (if you have that) otherwise in /etc/passwd. +
  3. If they don't exist in the file /etc/services the services fido, tfido +and binkp will be added. +
  4. If they don't exist in the file /etc/inetd.conf the internet protocols +for the mailer will be added. The inetd is restarted to +activate the changes. +
+

 

+ +

Step 3: Check the basic installation

+

+The last screen of the script is about sanity checks. Perform those checks! +If something is wrong, now is the time to fix it. Don't panic and remember +the backups of the system files that are changed are in /etc with the +extension .mbse i.e: those were the original files. +

 

+ +

Step 4: Install the basic packages.

+

+Login as user mbse. While in the home directory unpack the distribution +archives: +

+tar xfvz /path/to/mbsebbs-0.33.nn.tar.gz
+
+You now have the subdirectory with sources in the right place. Indeed, if you +have a new installation, you also have unpacked the archive somewere else +to run the installation script. That one can be removed. +Next build the binaries and install them using the folowing commands: +
+cd ~/mbsebbs-0.33.nn
+./configure
+make
+su
+password: enter root password here
+make install
+exit
+
+The last part of the installation procedure shows you the location of the bbs +startup script that is added to your system. Because this is your first +time installation, example menus, textfiles and some databases are installed. +If they already excist on your systems (when you do an upgrade) they +will not be installed again. +

+Now you must start the mbtask daemon by hand by typing /opt/mbse/bin/mbtask. +Check the file /opt/mbse/log/mbtask.log for startup problems. You may notice that +the program mbcico is started everytime, this is not a problem, it simply doesn't work right +now because you haven't configured anything yet. +

 

+ +

Step 5: (RedHat) startup problems.

+

+From RedHat 6.1 (not the older versions) the behaviour of the +su is changed. This may be true for other distributions since +the end of 1999 and for Mandrake as well. The file /etc/rc.d/init.d/mbsed that is +created by the setup script is different then before. The new command +is su - instead of simply su. It might be +that other new distributions also need the extra minus sign. If that's the +case, please let me know and tell me how I can test what version it is. +

 

+ +

Step 6: ready.

+

+Now the basic environment is finished, the next thing is to install +the scripts, examples and configuration. +

 

+Back to Index +Back to Index + +

+ + diff --git a/html/date.html b/html/date.html new file mode 100755 index 00000000..05612d1a --- /dev/null +++ b/html/date.html @@ -0,0 +1 @@ +
Last update 18-Sep-1999
diff --git a/html/dist.html b/html/dist.html new file mode 100644 index 00000000..01da8e5f --- /dev/null +++ b/html/dist.html @@ -0,0 +1,74 @@ + + + + + + + + +Linux distributions. + + + +
+
Last update 06-Jun-2001
+

 

+ +

Linux Distributions.

+

+ +

Which distribution

+

+Linux is available in several distributions, they all have advantages and +disadvantages for bbs use. Which distribution to pick is very personal. +You should also consider the fact if the bbs machine is the same machine on +which you do your daily work on or if you use a seperate system for the bbs. +I will describe the distributions below for use on dedicated bbs computers, +that means you don't do daily work on them and don't use them to play games. +Most important is that this is my personal view. +

 

+ +

Slackware

+

+I am using MBSE BBS on several Slackware distributions. You can make a very small +setup for MBSE BBS like Zipslack. Not included is the mgetty package. +

 

+ +

Redhat and Mandrake

+

+I write this as if these are the same which isn't true of course. From MBSE +BBS's point of view they are almost the same, so that's why I treat them as +the same distributions. For people with little Linux experience these +distributions are a good choice if you can spare the diskspace. I haven't +found a simple dedicated setup for the bbs, so the safest way is to install +allmost everything, which is quite simple. This will cost you about 1200 Megs. +Maybe that someone more experienced with these distro's can give more details +on how to build a small server. Please note that from RedHat 6.1 and up the +startup script (/etc/rc.d/init.d/mbsed) is different than before. Maybe +this is needed for Mandrake 6.1 and up too. +

 

+ +

SuSe

+

+Since SuSE 7.1 the setup scripts are working and tested. Older distro's +might work. +

 

+ +

Debian

+

+The installation works on a Debian 2.1 and 2.2 distribution without any problems. +How to build an optimized Debian system is not tested by me. +

 

+ +

Famous last words...

+

+I don't have the diskspace for all kinds of Linux distributions to install +at the same time, with the current size of Linux, I only have 2 versions +installed. Also, I don't buy every new distro that's available. If you have +a problem with that, just send me the new distro on CD to test by snailmail. +

 

+ +Back Go Back + + + diff --git a/html/flow.html b/html/flow.html new file mode 100644 index 00000000..0adb03cd --- /dev/null +++ b/html/flow.html @@ -0,0 +1,169 @@ + + + + + + + + +Running a BBS under Linux. + + + +

+
Last update 06-Jun-2001
+

 

+ +

Running a BBS under Linux.

+

+ +

Introduction

+

+Everyone who has been running a (single line) BBS under DOS until now will +need to understand that running a BBS under Linux (or any other multitasking +os) is completly different of what you are used to. Under DOS things were +quite simple, from AUTOEXEC.BAT you started a new .BAT file that would run +forever and started all needed programs after each other. +The programs that where started +depended on the errorlevel of the previous program. Only one program could +run at the same time. +

+People who had previous run a BBS on another multitasking os, or were running +a BBS on a small lan with a fileserver and workstations for each line, are +already more used to the idea of running more programs at the same time, +and to "signal" what to do next with semafore files. +

+The Linux aproach is more or less the same, but there are more differences. +The main difference is that there is no mailer connected with the modem waiting +for a call, instead there is a getty process watching your modem(s). Another +big difference is that you don't see what's happening, there is no screen +with the mailer or bbs picture on it. All programs run in the background. If +you don't like that, stop now and go back to your old DOS bbs. It's just the +way everything is done. +

+Programs that must start at specific times (events in DOS), are started from +cron, this is the event scheduler for Linux (and other Unixes). With this +program maintenance can be started, polls created etc. For starting programs +when they are needed there is a taskmanager loaded at system bootup. This +taskmanager "watches" the semafore directory of the bbs and will start what +is needed. +

 

+ +

Waiting for a call .....

+

+Under Linux this is done with the mgetty program, this is the +process that is connected with each modem (or ISDN adapter) and waits for a +call. The mgetty program (written by Gert Doering, gert@greenie.muc.de) will +detect the call, and find out what or who did make the call. It can detect +incoming humans who want a login prompt, PPP calls from users who want to +make a PPP connection (browsing your BBS whith netscape for example), A fax +machine trying to deliver a fax and finally a mailer trying to establish +an EMSI, FSC-0006 or FSC-0001 session. The mgetty program is responsible for +starting the right client programs. How to do this is explained in the +installation manuals, but be sure to compile it with Fido and PPP support. +

 

+ +

A Human is calling.

+

+This could be a bbs user. For each user to login to your bbs there must be a +unix account. They automatic create such an account the first time they login +with the bbs account. During the creation of their account the shell that is +installed for there account is the mbsebbs binary, so that's the only thing +that they get if they call in. When they logout the bbs, or drop carrier etc, +the session is ended and mgetty takes over the line again. +Note that they will never can get a Unix shell +unless you install a door in the bbs that calls a shell for them. +

+There are probably more accounts on your system that can callin, mbse is +such an account, this is the MBSE BBS maintenance account. This user will +get the shell prompt. Use good passwords for shell accounts, and never change +your setup so that the root user can directly login except from the console. +If you need root access, login as mbse and type su at the prompt to become +root. You might consider installing SSH on your system for remote maintenance. +

 

+ +

A PPP call is detected.

+

+Installing a PPP server on your system is beyound the scope of this project. +However if you did install it, users can login your bbs with their favourite +browser and use your bbs. Note that the necessary tools to automatic create +newsgroups don't excist at this time. With the proper setup you can automatic +create and maintain html pages for the file areas. +

 

+ +

A mailer call is detected.

+

+If a mailer is detected by mgetty, the mbcico program is started and will +take over from mgetty. It will establish a mail session with the caller and +the mail and or files will be exchanged just like any DOS mailer would do. +After the call, mbcico will hangup and mgetty will take control of your modem +again. If there is any mail received, mbcico will place the semafore mailin +so that another process can take care of the received mail. Mbcico will also +detect some IEMSI terminal programs (Frontdoor), and will start the bbs. +

 

+ +

There is mail in the inbound

+

+As I said before, if the mailin semafore is present, the task manager will +then start the mbfido program that will toss the mail, process any files +received and if necessary it will create other semafore's for example to link +the message bases, start the nodelist compiler etc. Note that this can be done +while there may be a new mailsession going on, a bbs user is online, it doesn't +matter. Processing mail and files can be done real multitasking without any +damage to other processes. +

 

+ +

It's time to poll a node

+

+At the time that you whish to poll a node, let cron create "poll" requests. +When a poll is created, the semafore scanout is also created. +The taskmanager will then start mbcico at regular intervals so that mail will +get out. If there is no more mail to send, the scanout semafore is removed. +If a timeslot ends, you can just remove the "poll" requests that didn't succeed. +

 

+ +

It's Zone Mail Hour, so now what

+

+Relax, if you have netmail ready for nodes the +mailer script will try to send these mails to those nodes. If it was crash +mail, and the destination was a non CM node, the mailer will try to send those +mails too. Note that other crashmails are send anytime. Also note that packed +mail and files are not send during ZMH. If a node calls you during ZMH he will +get everything that's waiting, including packed mail and files. The task manager +(more on that later) calculates the Zone Mail Hour from UTC time, you don't +have to change anything for summer- and wintertime. +

 

+ +

Daily maintenane

+

+This is started by cron jobs. There is no need to take +your bbs lines down during maintenance, you can do it any time of the day. +I have made several scripts for this, daily, weekly and monthly. +

 

+ +

How about system load

+

+Because Linux is a 32 bit os, not bothered with a graphical user interface +(unless you install it), it has all the time in the world to serve your +bbs programs. Background programs are build to release time to the Linux os, +they don't need to run fast because it's background processing. The bbs and +the mailer, have a low server load although there is no timerelease build +in. Only the bbs has some short moments when it needs a lot of your system, +for example when a user logs in and scans for new mail. The bbs I run is a +486-DX4 100 MHz, 20 MB ram, with 2 analogue lines, this seems to work fine. +When this system's MOBO died, I used a 386DX33 for several months with +20 MB ram, and the only thing users ever noticed was that scanning for new +mail was slower. I think this is the slowest harware that will work. +However, you must always use 16550A uarts for the COM ports. For best +performance use SCSI disks. I noticed that old 5"FH SCSI disks perform better +for bbs usage then modern EIDE disks. This is probably caused by the fact that +the kernel needs more time for the cheap IDE bus. +If you want to use X11 on your bbs, you need more ram and a faster CPU or a +separate machine via a lan and export the display to that machine. +

 

+ +Back Go Back +

+ + + diff --git a/html/ftsc/fsc-0035.html b/html/ftsc/fsc-0035.html new file mode 100755 index 00000000..f8999636 --- /dev/null +++ b/html/ftsc/fsc-0035.html @@ -0,0 +1,79 @@ + + +Transparant Gateways to and from FidoNet. + + + + +
+                  Transparent Gateways to and from FidoNet 
+                           Technical Considerations
+                                    FSC-0035
+
+                            Michael Shiels 22 June 89
+
+Copyright 1989, Michael Shiels.  All rights reserved.  The right to distribute 
+for non-commercial use is granted to the FidoNet Technical Standards Committee,
+provided that no fee is charged.  This may be posted on FidoNet electronic BBSs
+which charge no fee for accessing this document.  Any and all other reproduction
+or excerpting requires the explicit written consent of the author.
+
+
+Gateways
+--------
+
+Gatewaying between Fidonet and other networks seems to be the latest feature
+which hopefully brings more benefits to the users of each network.  But there
+are some real problems with gatewaying and doing "transparent" replies.
+This proposal should allow for almost totally transparent gateways but requires
+the co-operation of BBS software writers to support this following protocol.
+
+Incoming Messages
+-----------------
+
+When a message is entered into fidonet from another network it will be entering
+through one machine (say 1/2).  The userid on the other network may not match
+very will with the 2 word 36 character userid on Fidonet.  So the following is
+done to store away the proper userid of the sender.
+
+Two (2) lines are added to the message (usually at the top of the text portion
+hidden by the infamous ^A KLUDGE).
+
+^AREPLYADDR .....\r
+
+which signifies the FULL userid of the person on the other network.  The first
+36 characters or the full userid if less than 36 characters long, are stored
+in the FROM field of the message header.  When replies are done they use a 
+second line of the following form.
+
+^REPLYTO zone:net/node firstname lastname
+
+which is used to signify the "userid" which mail destined to this other network
+must be sent to and on which machine that userids resides.  Replies are sent
+to this zone:net/node and userid with the first line of the message being
+changed into 'TO: ....' where .... is the FULL userid from the ^AREPLYADDR
+line.
+
+Should you have constructive correction or criticism, please contact:
+
+Michael Shiels
+FidoNet: 1:250/410   michael.shiels@masnet.fidonet.org
+uucp: ?!tmsoft!masnet!michael.shiels
+Internet: michael.shiels@masnet.uucp
+
+----------
+FidoNet is a trademark of Tom Jennings and Fido Software, to whom we all owe
+        much thanks for the origin and spirit of FidoNet.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0039.html b/html/ftsc/fsc-0039.html new file mode 100755 index 00000000..53e8e955 --- /dev/null +++ b/html/ftsc/fsc-0039.html @@ -0,0 +1,362 @@ + + +A Type-2 Packet Extension Proposal. + + + + +
+Document: FSC-0039
+Version:  04
+Date:     29-Sep-90
+
+
+                      A Type-2 Packet Extension Proposal
+                       Mark A. Howard 1:260/340@FidoNet
+
+  Status of this document:
+  ------------------------
+  This FSC suggests a proposed protocol for the FidoNet(r) community,
+  and requests discussion and suggestions for improvements.  Distribution
+  of this document is unlimited.
+
+  Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+  FTS-0001 is a copyrighted work of Randy Bush.
+
+  Introduction
+  ------------
+  This document serves two major purposes.  The first is an attempt to define
+  and document the Type-2 packet which is widely in use in FidoNet today.
+  Although FTS-0001 defines the structure of a Type-2 packet, the natural
+  evolution of our network, mostly with regards to addressing methodology,
+  has made it necessary to utilize hitherto unused portions of the header
+  to insert Zone and Point information.  Also, it has become apparent that
+  some of the existing fields are not large enough to accomplish their
+  original tasks.
+
+  The second is to propose a simple mechanism to allow FidoNet to begin to
+  utilize advanced mail packing techniques.  It is quite apparent that while
+  Type-2 has served us faithfully for some time now, the evolution of our
+  network in terms of technical and physical complexity has caused us to
+  consider more efficient and functional ways to pack mail.
+
+  It should be made clear that with the exception of the Capability Word,
+  Capability Word Validation Copy, ProductCode(hi), and Revision(minor),
+  which are proposed extensions to the Type-2 packet header, this FSC is
+  an attempt to correctly document existing practices with regards to the
+  insertion of zone and point info by at least three mail processors in
+  use today.
+
+
+  The Type-2 Header (Where's the Zone?)
+  -------------------------------------
+  Although FTS-0001 has recently been updated to reflect the use of some of
+  the areas in the packed message header for zone data, at least two other
+  methods for inserting the zone information have been adopted, making it
+  necessary to provide support for both formats in all of the zone aware mail
+  processors.  The end result is more code, and redundant information in the
+  packet header.
+
+  This has presented a problem in logistics, as it is difficult to consider
+  the project of updating mail processors using one type to use the other.
+  As sufficient indentification is provided, in the form of the product code,
+  to determine the expected location of the zone information, and because
+  code already exists in most of the mail processors to overcome this, this
+  proposal does not attempt to suggest that one method be used over the
+  other, rather the intent is to attempt to document the extensions in use,
+  and the products involved.
+
+  See the accompanying chart and cross-reference.
+
+
+  The Product Code
+  ----------------
+  Based upon the current rate of requests for product codes from the FTSC,
+  it is probable that the Product Code byte will not be large enough to
+  accomodate all of the codes required.  While it is not reasonable to
+  expect that all Type-2 processors will eventually check the hi-order byte
+  proposed here, it is likely that 'current' mail processors will.  This
+  can be nothing but benefical, as it will force users to upgrade their
+  mail processors to a product which will as a minimum, support Type-2
+  with Zone and Point extensions, and quite possibly, processors that will
+  utilize more advanced mail packing techniques, making Type-2 extinct once
+  and for all.
+
+ 
+  The Capability Word  (How do we GET there from here?)
+  -----------------------------------------------------
+  Everybody would like to see more efficient and functional ways to pack and
+  exchange mail.  Several Type-3 message bundle proposals exist, but none
+  really address a problem which must be solved first.  The problem is that
+  since FidoNet is a hobbyist network, no demands can be placed on any one
+  sysop to upgrade or change their bundling software.  Because of this, it
+  is necessary to consider strategies which allow for the existence of Type-2
+  bundlers in the network topology.
+
+  Considerable advantages can be realized, however, between systems that
+  consent to use advanced bundling techniques.  One way to do this is to
+  simply send netmail to all of your connecting systems, saying "Hey, I've
+  got a Type-3 bundler now, how about you?"  This could become quite
+  tiresome, and does not represent much of an improvement on the current
+  situation.
+
+  What would be desirable is a network that would 'upgrade itself'.  Given a
+  situation where mail processors of various capabilities will exist in a
+  network topology, the goal is to provide a mechanism whereby two links can
+  determine and utilize the most efficient bundling method to use, in a
+  manner transparent to the sysop.
+
+  For instance, let's say that the FTSC releases the Type-7 All New Singing
+  and Dancing bundle format.  Well, your current version of SlingToss can
+  only support Types 2, 3, and 5.  One of your downlinks gets a new version
+  of MailMangle which can support Types 2, 3, 4, and 7.  Well, it is quite
+  obvious that since you and he are exchanging 4 megs of mail each night,
+  and it's an overseas call, that it would be in your interest to obtain a
+  new version of SlingToss which can support Type 7.
+
+  Note that this is *optional*.  Because both processors can support Type-3,
+  they will continue to exchange Type-3 mail quite happily, even though
+  MailMangle is happily advertising the availability of Type-7.  Even your
+  downlinks which are still using stone-age Type-2 processors will be fine,
+  as SlingToss will always export Type-2 bundles when no higher capability
+  can be determined.
+
+  So, after dashing off the check to the author, your new version of
+  SlingToss comes in the mail!  You rush over to your system, and install it.
+  The next time SlingToss exports mail to the MailMangle system, it says
+  "Hey!  I can now support Type 2, 3, 5, and 7!  So, whattya got?"  This is
+  no skin off MailMangle's nose, he's had Type-7 for quite a while, and he
+  begins to export Type-7 bundles to SlingToss.  "It's about time.", he says.
+
+  Now, this scenario is made possible by implementing a 'Capability Word' in
+  the present and future packet headers.  The Capability Update mechanism
+  depends on several assumptions:
+
+  1)   Any Advanced Capability Bundler *MUST* be capable of receiving and
+     faithfully processing Type-2 bundles.  Hopefully, the inbound packets
+     will be in the new format proposed by this document, but then again,
+     this is not an exact science.  What this means is that it is likely
+     that some packets may arrive with the Capability Word (CW) set to 0.
+     In this case, Type-2 is assumed, assuring compatibility.  The only
+     caveat is that it is conceivable that some obscure mail processor
+     uses the location proposed for the CW for other arcane purposes.  This
+|    can detected through the CWValidation Copy, which is byte-swapped and
+|    compared with the CW at that time.  If a mismatch is found, a CW of
+|    type 0 is assumed, and a Type-2 bundling method is used.
+
+  2) An Advanced Capability Bundler, hereafter referred to as a Type-N
+     Bundler, must have a method to store and maintain the node-by-node
+     capability information.  This can be done many ways, and in fact
+     several processors already have begun to maintain node information
+     outside of that found in AREAS.BBS, mostly to implement pre-arranged
+     alternate compression methods.  In a text configuration file, you
+     might see the following:
+
+     ;       Address      Comp    Send  LastCW ; Comments
+     Node    1:260/340    ZIP     Auto  7      ; Auto detect & upgrade
+     Node    1:135/20     LZH     3     2,3,7  ; Always send Type-3
+     Node    1:           ARC     2     0      ; Stone-Age processor
+     Node    1:135/4      ---     Auto  7      ; Sent me netmail
+     Node    1:           ---     0     0      ; Don't send CW
+
+     In this example, the fields are:
+
+     Address - downlink address.  Note that this is not necessarily
+               relative to echomail, only, it is possible to append
+               information to the node database as netmail packets are
+               receieved from different addresses.
+
+     Comp    - desired mail compression method.
+
+     Send    - Auto - automatically determined maximum common packing
+                      method to use.  Automatically update to LastCW
+                      when packing.
+
+     LastCW  - Last CW received from remote system.
+
+
+  3) A Type-N Bundle will always advertise it's capabilities in the CW
+     regardless of the type being sent.  As shown in the above example,
+     it allows Type-N processors to automatically track the capability
+     of your system.  Again, in cases where a stone-age processor is
+     being used, this field will be ignored, and in the unusual event
+     that it is not ignored, and is somehow harmful to the far system,
+     the Type-N processor can be configured to send a CW of 0.
+
+  The format of the Capability Word is designed to support up to 15 future
+  bundle types, and is bit-mapped to facilitate the easy determination of
+  the maximum common level supported between two nodes:
+
+                 msb           Capability Word               lsb
+  Node Supports  ------------FTSC Type Supported----------------
+
+                  U 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2
+
+  2, 3, and 7     0  0  0  0  0  0  0  0  0  0  1  0  0  0  1  1
+  2, 3, and 5     0  0  0  0  0  0  0  0  0  0  0  0  1  0  1  1
+  2 (this FSC)    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
+  Stone Age**     0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
+                  ^
+                  +--- Indicates UseNet RFC-822 capability
+
+                  ** - a mismatch in the CWValidation Copy also
+                       produces a CW=0.
+
+  In this example, the Type-N bundler would first compare the remote CW
+| and the byte-swapped remote CWValidation Copy, and check for a mismatch.
+  Prior to the compare, the MSB of the CW's are masked, as this bit is
+  reserved to indicate whether the mail processor is capable of also
+  accepting UseNet RFC-822 bundles.  Following the MSB mask, and bit
+  comparison, if they do not match, a remote CW of 0 is assumed.  If they
+  match, the Type-N processor would AND the local and remote CW words,
+  obtaining a CW expressing the Types which are in common to both systems.
+  The most significant Type will be used, by default, but note that this
+  assumes that new bundling Types will be increasingly more efficient or
+  in some way more beneficial.
+
+  Because this may not always be the case, there should be a method provided,
+  as illustrated above, to override the automatic upgrade should this become
+  the case.
+
+  The MSB of the CW is used to indicate whether the mail processor can accept
+  UseNet RFC-822 bundles or not.  It is a separate indicator, and not intended
+  to be used as a part of the above comparison, however can be used to also
+  advertise RFC-822 capability to other systems.  Since RFC-822 is 'set in
+  stone', there is no need to assign more than one capability bit.
+
+  It might seem somewhat limiting to only consider the possibility of 15
+  different future bundling methods, but it is my opinion that the careful
+  use of a 'Sub-Type' byte in the packet header can allow for the variations
+  on a single theme, and that proposals for new formats should be evaluated
+  by the FTSC to determine whether sufficient benefit can be realized in
+  the implementation of the given format, prior to assigning a new type
+  code.
+
+
+  Mailers
+  -------
+  It is quite clear to me that should this concept take hold, that the
+  logical place to store node capability data is in the local nodelist
+  database, or an index-associated data file.  As above, it is necessary
+  to generate Type-2 packets for whatever purpose, unless it is known
+  by prior association, that the far mailer can accept other types of
+  packets.  It is also quite reasonable to assume that a nodelist flag
+  could be assigned to advertise the CW for a given node, which the
+  native mailer nodelist compiler could then immediately determine the
+  preferred bundling method for any given node in FidoNet.
+
+  Another possibility would be to pass a capability advertisement in the
+  extensible portion of a handshake protocol, which may or may not already
+  exist in FidoNet.
+
+  The approach suggested previously in this document suggests the use of
+  a text configuration file, but it is quite obvious that many benefits
+  can be realized through the use of the nodelist, including the use of
+  additional flags to indicate the preferred compression method, etc.
+
+
+  Summary
+  -------
+  This document has been created in an attempt to define a method to allow
+  the future expansion and enhancement of FidoNet technology mail processors
+  and mailers, and in a way that is the least disruptive to existing mail
+  operations.  The intent is to provide for an environment that is as open,
+  and extensible as possible.
+
+  The mechanism described should allow many different types of processors
+  (FTSC-registered) to exist in the network at once, and to provide an
+  environment which is designed to operate at it's maximum efficiency
+  wherever possible or practical.
+
+  Revision 2 of this document was produced to implement suggestions made
+  primarily by Jan Vroonhof, who suggested the use of the CW Validation
+  Copy.  Jan presented this idea in his FSC-0048, along with other concepts
+  relating to the correct indentification and handling of zone and point
+  addressing.   This document sanctions the improvements to the CW as
+  recommended, but does not address or support the other extensions
+  recommended in FSC-0048.
+
+
+  Thanks
+  ------
+  To Ward Christensen, creator of XModem and BYE.
+
+     Tom Jennings, who started this whole mess.
+
+     Joaquim Homrighausen, for lots of good ideas, and motivation.  Here's
+                           another Lamborghini to work on.
+
+     Wynn Wagner, Oliver McDonald, Roeland Meyer, Andrew Farmer, Claude
+     Warren, Jan Vroonhof, Bob Hartman, and Vince Perriello, who all
+     contributed in some way to the creation of this document, mostly
+     through their messages in NET_DEV.
+
+
+
+  Type-2 Packet Format (proposed, but currently in use)
+  -----------------------------------------------------
+    Field    Ofs Siz Type  Description                Expected value(s)
+    -------  --- --- ----  -------------------------- -----------------
+    OrgNode  0x0   2 Word  Origination node address   0-65535
+    DstNode    2   2 Word  Destination node address   1-65535
+    Year       4   2  Int  Year packet generated      19??-2???
+    Month      6   2  Int  Month  "        "          0-11 (0=Jan)
+    Day        8   2  Int  Day    "        "          1-31
+    Hour       A   2  Int  Hour   "        "          0-23
+    Min        C   2  Int  Minute "        "          0-59
+    Sec        E   2  Int  Second "        "          0-59
+    Baud      10   2  Int  Baud Rate (not in use)     ????
+    PktVer    12   2  Int  Packet Version             Always 2
+    OrgNet    14   2 Word  Origination net address    1-65535
+    DstNet    16   2 Word  Destination net address    1-65535
+    PrdCodL   18   1 Byte  FTSC Product Code     (lo) 1-255
+  * PVMajor   19   1 Byte  FTSC Product Rev   (major) 1-255
+    Password  1A   8 Char  Packet password            A-Z,0-9
+  * QOrgZone  22   2  Int  Orig Zone (ZMailQ,QMail)   1-65535
+  * QDstZone  24   2  Int  Dest Zone (ZMailQ,QMail)   1-65535
+    Filler    26   2 Byte  Spare Change               ?
+| * CapValid  28   2 Word  CW Byte-Swapped Valid Copy BitField
+  * PrdCodH   2A   1 Byte  FTSC Product Code     (hi) 1-255
+  * PVMinor   2B   1 Byte  FTSC Product Rev   (minor) 1-255
+  * CapWord   2C   2 Word  Capability Word            BitField
+  * OrigZone  2E   2  Int  Origination Zone           1-65535
+  * DestZone  30   2  Int  Destination Zone           1-65535
+  * OrigPoint 32   2  Int  Origination Point          1-65535
+  * DestPoint 34   2  Int  Destination Point          1-65535
+  * ProdData  36   4 Long  Product-specific data      Whatever
+    PktTerm   3A   2 Word  Packet terminator          0000
+
+  * - extensions to FTS-0001
+
+  Ofs, Siz are in hex, other values are decimal.
+
+
+  Zone/Point Aware Mail Processors (probably a partial list)
+  ----------------------------------------------------------
+    Prod
+    Code Name - Uses QOrg/QDstZone Orig/DestZone Orig/DestPoint
+    ---- ----------- ------------- ------------- --------------
+    0x0C  FrontDoor  Reads/Updates      Yes           Yes
+    0x1A  DBridge        ?????          Yes           Yes
+    0x45  XRS        Reads/Updates      Yes           Yes
+    0x29  QMail           Yes          ?????      Not point-aware
+    0x35  ZMailQ          Yes          ?????      Not point-aware
+    0x3F  TosScan    Reads/Updates      Yes           Yes
+
+
+
+
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0046.html b/html/ftsc/fsc-0046.html new file mode 100755 index 00000000..09688a5d --- /dev/null +++ b/html/ftsc/fsc-0046.html @@ -0,0 +1,227 @@ + + +A Product Identiefier for FidoNet Message Handlers. + + + +
+Document: FSC-0046
+Version:  005
+Date:     30-Aug-94
+
+
+
+
+
+
+
+
+            A Product Idenfifier for FidoNet Message Handlers
+
+                            Joaquim Homrighausen
+                       2:270/17@fidonet or joho@abs.lu
+
+                              August 30, 1994
+
+         Copyright 1994 Joaquim Homrighausen; All rights reserved.
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+    Purpose
+
+    This document should serve as a guide for the product identfier, PID
+    hereafter, format for FidoNet message handlers. The purpose behind PIDs
+    is related to my attempt to remove the requirement of Origin lines in
+    conference mail messages.
+
+    While I fully understand that this won't happen in all conferences, I
+    would like to provide the facility to those who can use it (i.e. for
+    conferences where all the participants are using software that supports
+    messages without origin lines).
+
+    Another use for PIDs is to minimize the excessive amount of information
+    some programs put on the tear lines which increases overall
+    transportation cost and time of conference mail.
+
+
+    PID
+
+    A PID replaces the program identifier often seen on the tear line of
+    conference mail messages and is hidden behind a ^A (ASCII SOH, 01h).
+    This also allows for better tracking of software causing problems in
+    conferences.
+
+:   Only one PID per message is allowed and should only be added by the
+:   program that creates the message. I.e. programs passing the message on
+:   to someone else may not add additional PIDs. If a PID is added, no
+:   program information may be present after the tear line.
+
+    A PID also offers the ability to add serial numbers to identify a
+    specific copy of a program as being the source of a message with little
+    or no effort.
+
+
+    Format
+
+      ^APID:  [ ]
+
+
+    Sample
+
+      ^APID: FM 2.11.b
+
+      Would identify FrontDoor's editor, beta version 2.11 and replace:
+
+       --- FM 2.11 (beta)
+
+
+    Fields
+
+    pID         The ID of the product responsible for creating the message.
+                This should be kept as short as possible. The maximum
+                length for this field is 10 characters.
+
+    version     The version of the product including any alpha, beta, or
+                gamma status. Only the relevant part of the version should
+                be included. I.e. 1.00 should be expressed as 1, 1.10 as
+                1.1 and 1.01 as 1.01. Alpha, beta, or gamma status should
+                be expressed by appending a / or . followed by a, b, or g
+                and optionally a revision indicator, such as a1, b2, etc.
+                The maximum length for this field is 10 characters.
+
+    serial#     The serial number of the product, omitted if irrelevant
+                or zero. The maximum length for this field is ten (10)
+                characters.
+
+
+    TID
+
+    TIDs or "Tosser IDs" started to appear shortly after the first
+    revision of this document was released. They are added by Conference
+    Mail ("EchoMail") processors when a message is exported from the
+    local message base and injected into the network distribution scope
+    for a conference.
+
+    When a Conference Mail processor adds a TID to a message, it may not
+    add a PID. An existing TID should, however, be replaced. TIDs follow
+    the same format used for PIDs, as explained above.
+
+
+    List of products
+
+    The accompanying file, PIDLIST.TXT, is a list of products known to
+    support the PID proposal. Software authors are encouraged to inform
+    the author of this document of changes and additions to this list.
+
+     --- end of file "fsc-0046.005" ---
+
+
+
+Document: PIDLIST.TXT (FSC-0046)
+Date:     30-Aug-94
+
+
+
+                     A list of used product idenfifiers
+
+                            Joaquim Homrighausen
+                      2:270/17@fidonet or joho@abs.lu
+
+
+
+Product identifiers
+
+Product                Version  ID        Author
+-----------------------------------------------------------------------------
+!!MessageBase           1.6+    !!MB      Holger Lembke          2:240/500.20
+Alert                   2.1+    Alert     Richard Kail           2:310/25.2
+ANet                    921213+ ANet      Thomas Ekstroem        2:201/411
+ArcMail RISC OS         1.04+   AM        Philip Blundell        2:440/34.4
+Artmail Mailer System   1.00+   ART       Klaus Landefeld        2:247/402
+Auto Message Taker      1.00+   AMT       Patrik Torstensson     n/a
+AVALON                  3.10+   AVALON    Stephan Slabihoud      2:2401/103.6
+CrossPoint              2.10+   XP        Peter Mandrella        2:243/97.80
+EchoSprint              1.02+   ES        Ben Elliston           3:620/262
+Enhanced Mail MAnager   .01+    EMMA      Johan Zwiekhorst       2:292/118
+Enhanced Message EDitor .02+    EMED      Johan Zwiekhorst       2:292/118
+EZMail                  .67+    EZMail    Torben Paving          2:234/41
+F_POINT                 1.1+    F_POINT   Florian Rupp           2:248/107.2
+FastEcho                1.21a+  FastEcho  Tobias Burchhardt      2:245/39
+FileScan                1.5+    FileScan  Matthias Duesterhoeft  2:241/4513
+Freqit (Windows)        1.0+    FIW       Marvin Hart            1:106/462
+Freqit (MS-DOS)         1.0+    FID       Marvin Hart            1:106/462
+FrontDoor APX           1.00+   FDAPX     Joaquim Homrighausen   2:270/17
+FrontDoor (Editor)      2.00+   FM        Joaquim Homrighausen   2:270/17
+FrontDoor (Mailer)      2.00+   FD        Joaquim Homrighausen   2:270/17
+FrontEnd FX             1.00+   FEFX      Eric Theriault         1:132/220
+GEcho                   1.00+   GE        Gerard van der Land    2:2802/110
+GeeMail                 2.00+   GeeMail   Lech Szychowski        2:480/4.7
+HbToSca                 1.00+   HTS       Jani Laatikainen       2:220/150
+HyperBBS                2.00+   HyperBBS  Jani Laatikainen       2:220/150
+JetMail                 1.00+   JetMail   Daniel Roesen          2:243/93.8
+LazyBBS                 .5+     LazyBBS   Franck Arnaud          2:320/100
+Mail FX                 1.00+   MFX       Eric Theriault         1:132/220
+MsgTrack                3.20+   MT        Andrew Farmer          1:243/1
+NewsFlash               1.01+   NwF       Chris Lueders          2:2402/330
+NodeDiff Processor      3.00+   NDP       Serge Vikulov          2:5080/5
+Notify                  2.1     Notify    Frank Schuhardt        2:247/160
+OFFFax                  3.03    OFFFax    Frank Schuhardt        2:247/160
+Pobble                  0.15+   Pobble    Josh Parsons           3:771/340
+QBBed                   2.64+   qbbed     Werner Berghofer       2:310/90.100
+RemoteAccess            1.10+   RA        Andrew Milner          2:270/18
+RASS                    1.00+   RASS      Yossi Gottlieb         2:403/139.75
+SendFile                1.00+   SendFile  Mike Shoyher           2:5020/17.3
+Synchronet              1.00+   SYNC      Rob Swindell           1:103/705
+TB-Edit                 1.10+   TB-Edit   Arjen Lentz            2:283/512
+TB-Mailer               1.97+   TB-Mailer Arjen Lentz            2:283/512
+TB-Point                .10+    TB-Point  Arjen Lentz            2:283/512
+TechBBS                 1.00    TECHBBS   Marcel Tegelaar        2:281/409
+TechMail                1.00    TECHMAIL  Raymond van der Holst  2:281/409.2
+TosScan                 1.10+   TosScan   Joaquim Homrighausen   2:270/17
+TPCS                    .89b    TPCS      Krister Hansson-Renaud 2:201/201.7
+                                          Mikael Kjellstrom      2:201/201.10
+XRobot                  3.00+   XRobot    Joaquim Homrighausen   2:270/17
+Xrs Alternative Packer  1.04+   XAP       Jeroen Smulders        2:512/1.8
+ZeroToss                1.00    ZeroToss  Jeff Masud             1:103/115
+-----------------------------------------------------------------------------
+
+
+Product identifier registration
+
+Simply fill in the required information and send this form to the author of
+this document via private netmail.
+
+ Product: _________________________________________
+
+ Version: __________
+
+PID info: _________________________________________
+
+  Author: _________________________________________
+
+ Address: ___________________________ (eMail address)
+
+--- end of file "pidlist.txt" ---
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0048.html b/html/ftsc/fsc-0048.html new file mode 100755 index 00000000..c43b8505 --- /dev/null +++ b/html/ftsc/fsc-0048.html @@ -0,0 +1,417 @@ + + +A Proposed Type-2 Packet Extension. + + + + +
+Document: FSC-0048
+Version:  002
+Date:     21-Oct-90
+
+
+
+
+
+                   A Proposed Type-2 Packet Extension
+                              Jan Vroonhof
+                           2:281/1.12@fidonet
+                              Oct 21, 1990
+
+
+
+
+
+     Status of this document
+     =======================
+
+     This  FSC  suggests  a proposed  protocol  for  the  FidoNet(r) 
+     community,   and   requests  discussion  and  suggestions   for 
+     improvements. Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and  Fido 
+     Software.
+
+     Purpose
+     =======
+
+     The  final  goal of this document is to become  a  widely  used 
+     standardised  extension to FTS-0001,  like FTS-0006,  0007  and 
+     0008  are,  and  provide  an elegant way to  switch  to  a  new 
+     bundling  method  without requiring major  effort  or  breaking 
+     anything.
+
+     Prologue
+     ========
+
+     The  main  thing  that needs stressing is  that  the  additions 
+     covered  by this document are FULLY (I repeat FULLY)  BACKWARDS 
+     COMPATIBLE  with  FTS-0001 (and other  existing  standards  and 
+     practices  in  FidoNet and WhatEverOtherNets that I  know  of). 
+     When I say "backwards compatible" I mean that problems it would 
+     create  already  exist  in the current  FTS-0001  system  (e.g. 
+     zone  conflicts when dealing with a non compliant  system).  In 
+     short   it  only  corrects  some  flaws  in  FTS-0001   WITHOUT 
+     generating new ones.
+
+     In  this document I have tried to stay as much as  possible  on 
+     the   paths   of  existing   practices.   Therefore   I   think 
+     implementation  of  the additions it proposes will not  be  too 
+     hard.
+
+!    Prologue to revision 2
+!    ======================
+
+!    Revision   2   of  this  document  reserves  a   bit   in   the 
+!    CapabilityWord  for one bundle type already in use  outside  of 
+!    FidoNet,  RFC-822.  A small change was made to the  "receiving" 
+!    flowchart  in order to ensure compatibility with  FSC-0039.004. 
+!    In  the process a lot of errors and omissions in the  spelling, 
+!    credits etc. were corrected.
+
+     ===============
+
+!    All  references in the following to FSC-0039 are to Revision  1 
+!    of that document.
+
+     My thoughts on FSC-0039 and FTS-0001 rev 12
+     ===========================================
+
+     First,  revision  12  of FTS-0001 introduced  the  term  "(some 
+     impls)"  to indicate that some implementations used  their  own 
+!    extensions  to FTS-0001 (Note that in later revisions this  was 
+!    changed to "optional"). The problem is that this info cannot be 
+     relied upon,  because there is no way to actually validate  the 
+     data. One can only check whether the values of these fields are 
+     in the range of valid values and hope for the best.
+
+     Second,  FSC-0039  introduced  the idea of  having  a  bitfield 
+     (called the Capability Word) indicating whether extension  data 
+     was  valid.  Through  the  Capability Word,  it  also  made  it 
+     possible to indicate the ability to support other,  non type 2, 
+     packets,  thus allowing for flexible migration towards type  3. 
+     It  also documented the addressing extensions used  by  various 
+     programs.
+
+     However, FSC-0039 has two flaws:
+
+     1. One  cannot  be  sure the bitfield  is  zero  because  other 
+        implementations might use this field for their own purposes. 
+        Therefore  this document includes a second  validation  copy 
+        for the Capability Word (CW hereafter). This copy allows the 
+        FSC-xxxx compliant software to validate the CW by  comparing 
+        the two.  The chance of some junk portraying itself as a  CW 
+        is significantly reduced by this.
+
+!       Please  note  that  the  validation  copy  is  byte  swapped 
+!       compared to the normal capability word.  While this  started 
+!       out  as a typo,  I decided to leave it in as  it  introduces 
+!       some extra safety, without requiring much extra code effort. 
+!       In later revisions of FSC-0039,  Mark adopted this idea of a 
+!       validation copy too and eliminated the problem.
+
+     2. Although  FSC-0039 provides a way to make packet headers  4D 
+        it  is not backwards compatible.  It cannot be used in  FTS-
+        0001 sessions to unknown systems,  making FidoNet still  not 
+        totally 4D capable.  Although it implements fields for  zone 
+        and point number,  an FTS-0001 compliant application is  not 
+        required to look at these fields.  When a point mails  using 
+        these  fields  to implement its 4D address,  a  system  only 
+        looking  at the net/node info,  as is required by  FTS-0001, 
+        still sees it as a boss node, causing the obvious problems.
+
+        This document provides a way for transparent point handling, 
+        using   a  technique  already  exploited  by  many   mailers 
+        internally.  It  will allow this document to be  implemented 
+        and used by mailers not supporting it.  At the same time the 
+        danger that a point is seen as the boss node is eliminated.
+ 
+        It does NOT provide full inter-zone backwards compatibility, 
+        but that is not needed as badly, as problems are not yet too 
+        great.  Any  measures to ensure backwards  compatibility  in 
+        this  area  might  harm  communication  with  non-supporting 
+        programs, when the old system could handle the situation.
+
+     Packet Header
+     =============
+
+     The "|" character is used to indicate extensions documented  in 
+     FTS-0001  revision  12,   the  ":"  character  indicates  those 
+     documented here and in FSC-0039.
+
+       Offset
+      dec hex
+              .-----------------------------------------------------.
+        0   0 | origNode     (low order) | origNode    (high order) |
+              +--------------------------+--------------------------+
+        2   2 | destNode     (low order) | destNode    (high order) |
+              +--------------------------+--------------------------+
+        4   4 | year         (low order) | year        (high order) |
+              +--------------------------+--------------------------+
+        6   6 | month        (low order) | month       (high order) |
+              +--------------------------+--------------------------+
+        8   8 | day          (low order) | day         (high order) |
+              +--------------------------+--------------------------+
+       10   A | hour         (low order) | hour        (high order) |
+              +--------------------------+--------------------------+
+       12   C | minute       (low order) | minute      (high order) |
+              +--------------------------+--------------------------+
+       14   E | second       (low order) | second      (high order) |
+              +--------------------------+--------------------------+
+       16  10 | baud         (low order) | baud        (high order) |
+              +--------------------------+--------------------------+
+       18  12 |      0      |      2     |      0      |      0     |
+              +--------------------------+--------------------------+
+       20  14 | origNet      (low order) | origNet     (high order) |
+:             |               Set to -1 if from point               |
+              +--------------------------+--------------------------+
+       22  16 | destNet      (low order) | destNet     (high order) |
+              +--------------------------+--------------------------+
+|      24  18 | ProductCode  (low order) | Revision         (major) |
+|             +--------------------------+--------------------------+
+|      26  1A |                      password                       |
+|             |               8 bytes, null padded                  |
+|             +--------------------------+--------------------------+
+|:     34  22 | origZone     (low order) | origZone    (high order) | }
+|             +--------------------------+--------------------------+ } As in
+|:     36  24 | destZone     (low order) | destZone    (high order) | } QMail
+:             +--------------------------+--------------------------+
+:      38  26 | AuxNet       (low order) | AuxNet      (high order) |
+:             +--------------------------+--------------------------+
+:      40  28 | CWvalidationCopy  (high) | CWvalidationCopy   (low) |
+:             +--------------------------+--------------------------+
+:      42  2A | ProductCode (high order) | Revision         (minor) |
+:             +--------------------------+--------------------------+
+:      44  2C | CapabilWord  (low order) | CapabilWord (high order) |
+:             +--------------------------+--------------------------+
+:      46  2E | origZone     (low order) | origZone    (high order) | }
+:             +--------------------------+--------------------------+ } As in
+:      48  30 | destZone     (low order) | destZone    (high order) | } FD etc
+:             +--------------------------+--------------------------+
+:      50  32 | origPoint    (low order) | origPoint   (high order) | }
+:             +--------------------------+--------------------------+ } As in
+:      52  34 | destPoint    (low order) | destPoint   (high order) | } FD etc
+:             +--------------------------+--------------------------+
+:      54  46 |                 Product Specific Data               |
+:             +                                                     +
+:             |                       4 Bytes                       |
+              +--------------------------+--------------------------+
+       58  3A |                     zero or more                    |
+              ~                        packed                       ~
+              |                       messages                      |
+              +--------------------------+--------------------------+
+              |      0      |      0     |      0      |      0     |
+              '-----------------------------------------------------'
+
+    Packet       = PacketHeader  { PakdMessage }  00H 00H
+
+    PacketHeader = origNode       (* of packet, not of messages in packet   *)
+                   destNode       (* of packet, not of messages in packet   *)
+                   year           (* of packet creation, e.g. 1986          *)
+                   month          (* of packet creation, 0-11 for Jan-Dec   *)
+                   day            (* of packet creation, 1-31               *)
+                   hour           (* of packet creation, 0-23               *)
+                   minute         (* of packet creation, 0-59               *)
+                   second         (* of packet creation, 0-59               *)
+                   baud           (* max baud rate of orig and dest         *)
+                   PacketType     (* old type-1 packets now obsolete        *)
+                   origNet        (* of packet, not of messages in packet
+                                     set to -1 if orig=point                *)
+                   destNet        (* of packet, not of messages in packet   *)
++                  productCode Lo (* 0 for Fido, write to FTSC for others   *)
+|+                 serialNo Maj   (* binary serial number (otherwise null)  *)
+|                  password       (* session pasword  (otherwise null)      *)
+|                  origZone       (* zone of pkt sender (otherwise null)    *)
+|                  destZone       (* zone of pkt receiver (otherwise null)  *)
+|                  auxNet         (* contains Orignet if Origin is a point  *)
++!        Bytesw.  CWvalidationCopy (* Must be equal to CW to be valid      *)
++                  ProductCode Hi
++                  revision Minor
++                  origZone       (* zone of pkt sender (otherwise null)    *)
++                  destZone       (* zone of pkt receiver (otherwise null)  *)
++                  ProdData       (* Product specific filler                *)
+
+     When  the two copies of the CW match they can be asumed  to  be 
+     valid and used.
+
+     Stone-Aged: Old FTS-0001
+     Type-2+   : Old FTS-0001 plus changes indicated by "|" and  ":" 
+                 are valid
+
+     A  Type-N Bundle will always advertise its capabilities in  the 
+     CW regardless of the type being sent.   As shown in the example 
+     below,  the CW allows Type-N processors to automatically  track 
+     the capability of your system.   Again, in cases where a stone-
+     age processor is being used, this field will be ignored, and in 
+     the  unusual  event  that it is not  ignored,  and  is  somehow 
+     harmful  to  the  far  system,  the  Type-N  processor  can  be 
+     configured to send a CW of 0.
+
+     The format of the Capability Word is designed to support up  to 
+     15  future bundle types,  and is bit-mapped to  facilitate  the 
+     easy  determination  of  the  maximum  common  level  supported 
+     between two nodes:
+
+                    msb           Capability Word               lsb
+     Node Supports  ------------FTSC Type Supported **)------------
+
+                     U 16 15 14 13 12 11 10  9  8  7  6  5  4  3 2+
+
+     2+,3, and 7     0  0  0  0  0  0  0  0  0  0  1  0  0  0  1  1
+     2+,3, and 5     0  0  0  0  0  0  0  0  0  0  0  0  1  0  1  1
+     2+ (this Doc)   0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  1
+     Stone Age       0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0
+
+!                    ^-- "U" Indicates nodes able to process RFC-822 
+!                        bundles.
+                    ** - In the example bit definitions only type 2, 
+                         and  the Stone-Age type,  are defined  now. 
+                         The rest are to be concidered "reserved  by 
+                         FTSC".
+
+     The receiving Type-N bundler would AND the two words, obtaining 
+     a  word  expressing  the Types which are  common  to  both  the 
+     receiving  and the sending system.   The most significant  Type 
+     will be used for future sessions,  by default. Please note that 
+     this assumes that new bundling Types will be increasingly  more 
+     efficient or in some way more beneficial.  Because this may not 
+     always  be  the  case,  there should be a  method  provided  to 
+     override the automatic upgrade,  as illustrated  above,  should 
+     this ever happen.
+
+!    N.B. The  one bit left over (Msb) is now used as indicator  for 
+!         RFC-822 type bundles. For info on RFC-822 please check out 
+!         the relevant documents themselves.
+
+!         For  a more explanatory text on using the CW to  its  full 
+!         potential,  refer  to  the FSC-0039 text by  Mark  Howard. 
+!         Mark also gives some more rationale for the origional idea 
+!         of the CW.
+
+     Generating Type-2+ bundles
+     ==========================
+
+      Do we have a CW              Does CW indicate
+     stored for dest?  YES ---->   higher packets  YES ---> Generate higher
+           NO                       we support?                packet
+           |                            NO
+          \|/                           |
+           +-----<----------------------+
+           |
+      Fill header with all info
+           |
+          \|/
+           |
+      Are we sending from a point? (origPoint != 0) YES --+
+           |                                              |
+          NO                                              |
+           |                                             \|/
+           |                                    set AuxNet = OrigNet
+          \|/                                  set OrigNet = -1
+           |                                              |
+           +-----<----------------------------------------+
+           |
+      Add Messages
+           |
+      Terminate packet
+           |
+       Send packet
+
+     Receiving Type-2+ bundles
+     =========================
+
+       Receive Packet
+           |
+       Packettype = 2  NO  -------------> Process Type-Other
+          YES
+           |
+           |
+       CWcopies match  NO --------+------> Treat as normal Stone-Age packet
+          YES                     |     |
+           |                      |     |
+       Store CW                  /|\    |
+           |                      |    /|\
+       CW is 0 YES  --------------+     |
+          NO                            |
+           |                            |
+           |                            |
+       CW indicates support for 2+ NO --+
+          YES
+           |
+           |
+!      OrigPoint is not 0 and OrigNet = -1 YES -------+
+           NO                                         |
+           |                                         \|/
+!         \|/                            Set OrigNet is AuxNet
+           |                                          |
+           +------<-----------------------------------+
+           |
+        Process using added info
+
+     Credits
+     =======
+
+     To Mark Howard,  for introducing the idea of a CW in his  FSC-
+     0039  document and quite rightly pointing out one big  omision 
+     in revision 1 of this document.
+
+     To  Rick Moore,  for doing a good job in processing all  these 
+     revisions by Mark and myself, and for his work for the FTSC in 
+     general.
+
+     To  Joaquim  Homrighausen,  for his contributions  to  FidoNet 
+     software  in general,  and especially for his time devoted  to 
+     reading,  discussing  and  implementing the ideas Mark  and  I 
+     introduced.
+
+     To  Andre van de Wijdeven,  for producing and letting me  beta 
+     test his TS-MM software, which in my opinion is the best point 
+     software around.  (I'm not saying available,  because it isn't 
+     :-()
+
+     To john lots, for shipping this stuff to the US.
+
+     To  Jon  Webb,  for doing a much needed grammar  and  spelling 
+     check.
+
+     To Bob Hartman, Vince Periello, Tom Jennings, Eelco de Graaff, 
+     aXel Horst,  Arjen van Loon,  jim nutt,  Odinn Sorensen, David 
+     Nugent,  Peter  Janssens and many others,  for making  FidoNet 
+     what it is now, for me and for everybody.
+
+     Epilog
+     ======
+
+     So  this it,  now it's up to you to decide whether or  not  to 
+     implement  it.  A  small  change was  made  in  the  receivers 
+     flowchart and a small incompatibility with the later revisions 
+     of  FSC-0039 was removed.  That will ensure that FSC-0048  and 
+     FSC-0039 mailers can happily talk to each other....
+
+     The best way to implement this would be to always support FSC-
+     0048  on inbound trafic and generate FSC-0048 on  outbound  by 
+     default. A switch on a per-node basis will force your software 
+     to be FSC-0039 or even FSC-0001 only,  and you will cover  all 
+     bases.
+
+     This can be done easily, as FSC-0048 is a superset of FSC-0039 
+     (The -1 thing on points being the difference) which in turn is 
+     a superset of FTS-0001 (CW). I'd be glad to get some feedback. 
+     You can put it in NET_DEV or netmail me.
+
+                              Jan Vroonhof (2:281/1.12@fidonet)
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0049.html b/html/ftsc/fsc-0049.html new file mode 100755 index 00000000..d4787917 --- /dev/null +++ b/html/ftsc/fsc-0049.html @@ -0,0 +1,103 @@ + + +A Proposal for Passing Domain Information During an FST-0006 Session. + + + + +
+Document: FSC-0049
+Version:  001
+Date:     03-Jul-90
+
+
+
+
+                               A Proposal for
+                         Passing Domain Information
+                         During an FTS-0006 Session
+
+                                     by
+                                Bob Hartman
+                           1:104/501@fidonet.org
+                                July 3, 1990
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+FSC-0045 proposes a method for sending five dimensional FidoNet addresses
+(ie, zone:net/node.point@domain) via the type 2 packet header.  This
+document describes a proposed method for sending the same five dimensional
+address in the Hello packet of an FTS-0006 session, with the additional
+advantage of being able to utilize the full Internet recognized domain name
+for various Fidonet technology networks.  This proposal, combined with
+FSC-0045 will help to solve one of FidoNet's most pressing problems: How to
+recognize alternative networks without the need of some centralized
+management looking at all of them and what they are doing with Zone numbers,
+etc.  Like FSC-0045, this proposal remains backwards compatible with what it
+is replacing.
+
+Currently FTS-0006 has provisions for zone, net, node, and point information
+to be passed in the Hello packet.  To extend this to allow the domain name
+to be passed, an extra capability bit is used.  This bit corresponds to the
+0x4000 bit, and will be called the DO_DOMAIN bit.  If this bit is set, it
+means that the sender is domain aware, and has enclosed his domain in the
+Hello packet.  The domain is stored in the system name field, after the null
+that terminates the real system name.  The system name field is a maximum of
+60 characters, so the sender must make the real system name, a null, the
+domain name, and another null byte fit within the 60 bytes.  The domain will
+start at the byte immediately after the first null byte.  The domain is
+arbitrary length and should correspond to the Internet assigned domain name.
+This is NOT the same as the FSC-0045 domain, and therefore there needs to be
+a mapping between real Internet domains, and the FSC-0045 style domain name,
+if FSC-0045 is accepted by the FTSC as a standard for use by all mailers.
+This mapping is normally straightforward (for example, Internet fidonet.org
+would correspond to FSC-0045 domain FidoNet).  Since most alternative nets
+do not have a registered Internet domain, the naming convention should be
+"known by" domain (ie, FSC-0045 domain name) followed by .ftn (for FidoNet
+Technology Network).  So, the FSC-0045 domain "Alternet" would be converted
+to alternet.ftn under this proposal.  This allows domains which are not
+normally FidoNet aware to use FTS-0006 to talk to FidoNet technology mail
+programs.  For example, a mailer located at Camex in Manchester, NH might
+send it's mail as 'man.camex.com' during an FTS-0006 session.  When parsing
+the domain name, the parsing should try to match the domain from right to
+left (Internet naming is hierarchical from right to left), so that if a
+mailer knew about man.camex.com, that could also match something of the form
+super.machine.silly.name.man.camex.com.  The domain name should be case
+INSENSITIVE, and the FSC-0045 abbreviation of it should be unique within the
+first 8 characters, and also should not include any periods ('.') or at-signs
+('@') since those characters are significant in the Internet domain naming
+scheme.
+
+In order for this proposal to be adopted, the FTSC would have to assign the
+DO_DOMAIN bit, and have it documented in FTS-0006.  This method is fully
+backwards compatible, since a domain aware mailer could send the domain
+information, and if the other end was not domain aware, it would ignore it.
+If the other end was domain aware, it would be able to extract the domain
+information easily and would then have a full five dimensional address
+available for the sender.  This proposal remains fully backward compatible
+with the current uses of all FTS-0006 fields, and should not affect operation
+of any mailer that has used reserved bytes in the Hello packet.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0050.html b/html/ftsc/fsc-0050.html new file mode 100755 index 00000000..a1a7cb0e --- /dev/null +++ b/html/ftsc/fsc-0050.html @@ -0,0 +1,98 @@ + + +A Character Set Identifier For FidoNet Message Editors. + + + + +
+Document: FSC-0050
+Version:  001
+Date:     14-Jul-90
+
+
+
+
+         A Character Set Identifier For FidoNet Message Editors
+
+                                Draft I
+
+                           Thomas Sundblom
+                          2:201/114@fidonet
+
+
+
+			  
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+   Purpose
+
+        This document should serve as a guide for the character set 
+        identifier, CHARSET hereafter, format for FidoNet message Editors.
+        The purpose behind CHARSET is related to my attempt to make it
+        easier for each reader of a FidoNet message to identify the 
+        characters used in the messages.
+
+        Since FidoNet messages aren't restricted to use any special character
+        sets in the messages, there will be differences between computer 
+        kinds and special country dependent characters. To avoid confusion
+        in such cases, I'm hereby introducing the CHARSET kludge.
+
+        There is no need that each FidoNet Message reader should be able
+        to understand every possible character set. If the reader can't
+        handle the special character set found in a message, then it should
+        use a default character set (as most readers do today).
+
+
+   Format
+
+        ^aCHARSET: 
+
+   Sample
+
+        ^aCHARSET: ISO-11
+
+        Would identify that the message is written using the ISO-11 
+        character set, which relates to the character set mainly used
+        in Sweden.
+
+
+   Supported character sets
+
+        No special character set is specified, but it is recomended to
+        use the ISO numbering of the different character sets. Where no
+        ISO number is available, an easy to understand code should by used.
+
+
+   Character set identifier examples
+
+        ISO-6       Relates to plain ASCII 7 bit character set.
+        ISO-11      Swedish character set, 7 bit.
+        ISO-21      Germany character set, 7 bit.
+        ISO-69      French character set, 7 bit.
+
+        Other character set identifiers could be
+        PC-8        IBM PC complete character set.
+        ATARI       ATARI ST complete character set
+        AMIGA       AMIGA complete character set
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0053.html b/html/ftsc/fsc-0053.html new file mode 100755 index 00000000..fe764e7a --- /dev/null +++ b/html/ftsc/fsc-0053.html @@ -0,0 +1,187 @@ + + +Specifications for the ^aFLAGS field. + + + + +
+Document: FSC-0053
+Version:  002
+Date:     08-Dec-92
+
+
+
+
+
+
+                    Specifications for the ^aFLAGS field
+
+                           Joaquim H. Homrighausen
+                       2:270/17@fidonet or joho@ae.lu
+
+                              December 8, 1992
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+     Purpose
+
+     To explain and document the existing usage of the ^aFLAGS field used
+     by many software packages, including FrontDoor, TosScan, and
+     D'Bridge. And to inform software authors of its proper usage.
+
+
+     Prologue
+
+     One of the problems with the FTS-1 (stored) message format is its
+     limitations in regards to message attributes. Several bits are used
+     (reserved) by SEAdog, another by several packers and editors - even
+     though most mailer authors don't support them, they remain. One
+     reason would be backward compatibility with older software.
+
+     Unfortunately, this presents a problem for software authors that
+     would like to pass extended message attributes for use and handling
+     by other software.
+
+     Some software packages have been using an alternate method called
+     "FLAGS" which is 7-bit ASCII placed behind FLAGS somewhere near
+     the beginning of a message. The various flags will now be described.
+
+
+     Flags
+
+     The FLAGS string should be placed somewhere near the beginning of
+     the message text, and is preceeded by a  (^a) character. There
+     is no need to support all or any of the below mentioned flags.
+
+     If flags are stripped when a message passes through a system, all
+     relevant and correct FTS-1 status bits should be updated to indicate
+     the original contents of the FLAGS field.
+
+
+     Flag      Brief          Long description
+     --------------------------------------------------------------------
+     PVT       Private        Indicates that the message may only be read
+                              by its addressee and author.
+
+     HLD       Hold           Message should be held for pickup by its
+                              destination system.
+
+     CRA       Crash          High-priority mail.
+
+     K/S       Kill/Sent      Remove message after it has been success-
+                              fully sent.
+
+     SNT       Sent           Message has been successfully sent (used
+                              for message without Kill/Sent status).
+
+     RCV       Received       Message has been read by its addressee.
+
+     A/S       Archive/Sent   Place message in "sent mail" archival
+                              system after it has been successfully sent.
+
+     DIR       Direct         Message must be sent directly to its
+                              destination and may not be routed.
+
+     ZON       Zonegate       Send message through zonegate (if
+                              possible).
+
+     HUB       Hub/Host-route Host- or Hub-route message (as
+                              appropriate).
+
+     FIL       File attach    Message has one or more files attached to
+                              it.
+
+     FRQ       File request   Message has one or more file requests in
+                              subject field.
+
+     IMM       Immediate      NOW!-priority mail. Send at first
+                              opportunity, override any transmission
+                              restrictions enforced by events, costs, or
+                              qualification.
+
+     XMA       Xmail          Message has alternate form of compressed
+                              mail attached.
+
+     KFS       Kill file      Remove attached file(s) after they have
+                              been successfully sent. Only valid for file
+                              attach message.
+
+     TFS       Truncate file  Truncate attached file(s) to zero length
+                              after they have been successfully sent.
+                              Only valid for file attach message.
+                              Primarily used by Conference Mail
+                              processors.
+
+     LOK       Lock           Prevent message from being processed.
+                              This includes sending, deleting,
+                              purging, and editing.
+
+     RRQ       Receipt REQ    When the mailer/packer at the message's
+                              final destination unpacks the message, it's
+                              asked to generate a receipt to the author
+                              of the message that indicates that the
+                              message arrived at its final destination.
+
+     CFM       Confirm REQ    When message is read by its addressee, a
+                              Confirmation Receipt should be generated to
+                              the author of the message.
+
+     HIR       HiRes          FAX: Hi-Resolution image.
+
+     COV       CoverLetter    FAX: Cover sheet.
+
+     SIG       Signature      FAX: Signature.
+
+     LET       LetterHead     FAX: LetterHead.
+
+|    FAX       Fax image      The filename specified in the message's
+|                             subject field contains a fax document that
+|                             should be viewed using software capable of
+|                             doing so.
+
+|    FPU       Force pickup   Treated as a message with an IMM flag. This
+|                             instructs the mailer to keep calling the
+|                             destination system, if the connection is
+|                             aborted for some reason, until a valid "End
+|                             of files" signal is received (i.e. no more
+|                             files remain to pick up).
+
+
+     Notes
+
+     Xmail is related to the ARCmail 0.60 standard as adopted by the FTSC.
+     The exception is that any type of compression method may be used and
+     the naming convention isn't necessarily limited to that of the
+     ARCmail 0.60 standard.
+
+
+     Epilogue
+
+     Feedback would be appreciated and can be sent to me at the addresses
+     specified on the title page. Please send feedback via netmail.
+
+ +Back Go Back + + + + + diff --git a/html/ftsc/fsc-0056.html b/html/ftsc/fsc-0056.html new file mode 100755 index 00000000..eeb6b3ad --- /dev/null +++ b/html/ftsc/fsc-0056.html @@ -0,0 +1,1078 @@ + + +EMSI/IEMSI Protocol Definitions. + + + + +
+Document: FSC-0056
+Version:  001
+Date:     03-May-1991
+
+
+
+
+
+                      EMSI/IEMSI Protocol Definitions
+                          Joaquim H. Homrighausen
+                               May 3, 1991
+ 
+
+
+
+    Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is subject to the restrictions
+     specified on the next page.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+
+      (Also known as EMSC-001; Electronic Mail Standards Document #001)
+    ---------------------------------------------------------------------
+      Copyright 1989-1991 Joaquim H. Homrighausen. All rights reserved.
+    ---------------------------------------------------------------------
+
+
+    Notice
+    =====================================================================
+    This document obsoletes EMSI_003 and any previous document describing
+    the EMSI, UZAP, and/or IEMSI handshake protocol. I apologize for the
+    lack of proper state charts. I am currently under a fairly heavy
+    work-load and thought it would be better to release something half-
+    decent than not to release anything at all.
+
+    Restrictions
+    =====================================================================
+    EMSI/IEMSI may be used by any developer as long as these
+    specifications are followed exactly. The IEMSI and EMSI specifications
+    may be implemented independently of each other.
+
+    EMSI/IEMSI may be used free-of-charge by any developer for any
+    purpose, commercially or otherwise. In creating EMSI/IEMSI, we are
+    taking the first step towards developing a clear protocol definition
+    for state-of-the-art E-Mail systems to follow.
+
+    This document and its NOTES file (EMSI.NOT) may be freely copied and
+    distributed, but must NEVER be distributed in a modified form. If you
+    have an enhancement request, please contact the author of this
+    document; do not change it yourself.
+
+    Permission is hereby granted to the FTSC (Fidonet Technical Standards
+    Committee) and other technical organisations to republish this
+    document in its entirety. Librarians may change the title page and
+    page headers to match their library format as long as all copyrights
+    and body text remain unaltered. The original document name and source
+    (EMSC) must be mentioned in any republished versions of this
+    document.
+
+    No organization, company, person, or other being may impose any fees
+    for any reason for providing this document. This document may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+    Layout
+    =====================================================================
+    This document consists of four major parts; A short introduction and
+    explanation of the EMSI/IEMSI handshake protocol, the EMSI
+    definitions, the IEMSI definitions, and finally various notes and
+    credits.
+
+
+    PART I
+
+    Introduction
+    =====================================================================
+    The EMSI/IEMSI handshake protocol allows for maximum flexibility in
+    E-Mail session start-up and control. The YooHoo (FTS-6) standard,
+    designed by Wynn Wagner III, was a good idea, but did not allow
+    sufficient room for growth and cannot be used in 7-bit environments.
+    EMSI/IEMSI should provide for virtually unlimited growth and
+    expansion of its own scope. By providing variable-length packets,
+    EMSI/IEMSI is capable of being as simple or as complex as necessary
+    and entirely backwards compatible when new features and/or protocols
+    are added.
+
+    All EMSI/IEMSI packets and sequences consists of 7-bit printable
+    ASCII characters. This format allows us to establish a universal
+    handshake between "PCs" and "mainframes" alike. The more complicated
+    the computer system, the more restrictions affect its I/O; there are
+    many I/O channels that cannot transmit control characters such as XON
+    and XOFF; for this, we have created a universal handshake protocol
+    that uses all printable characters.
+
+    EMSI/IEMSI does allow control and 8-bit ASCII characters to be
+    transmitted. This is, however, accomplished by escaping the data
+    and converting it to 7-bit printable ASCII characters.
+
+    Data layer
+    =====================================================================
+    EMSI/IEMSI is a protocol based on multi-character sequences rather
+    than single character flow control. There are several advantages of
+    using several characters rather than just one, but there is also a
+    drawback. On very poor-quality telephone lines, EMSI will most likely
+    require several retransmissions of packets since line noise usually
+    come in bursts. That aside, there is little advantage in using a
+    protocol based on single characters.
+
+    All EMSI/IEMSI sequences are terminated by a single  unless
+    otherwise specified. This is necessary to force some data collection
+    equipment to flush their buffers. Appending  to EMSI/IEMSI
+    sequences in a FidoNet environment is a delicate matter and it is
+    important that you follow the notes regarding this.
+
+    Note regarding file requests
+    ---------------------------------------------------------------------
+    The file request concept mentioned in the EMSI document refers to
+    WaZOO style file requests as specified in FTS-6. No other file
+    request mechanism is supported in the EMSI specifications.
+
+
+    Separator usage
+    ---------------------------------------------------------------------
+    To designate the fields within the EMSI/IEMSI packets and retain
+    complete transparency, both start and stop characters are used.
+
+    The ASCII1 type is used for all fields within the packet. This uses
+    the brace characters to delimit the fields. The '{' (ASCII 123)
+    character is the start byte and '}' (ASCII 125) is the stop byte.
+    If a stop byte is used as literal data within a field, it must be
+    transmitted twice. The end of a field is designated by a stop byte
+    that is not followed by another identical stop byte.
+
+    The ASCII2 fields are delimited in exactly the same way, but use the
+    square brackets as delimiters. The '[' (ASCII 91) is the start byte
+    and ']' (ASCII 93) is the stop byte. ASCII2 is used to delimit data
+    within the ASCII1 extra_field information.
+
+    7-bit data restriction
+    ---------------------------------------------------------------------
+    It is the developer's responsibility to ensure that the software
+    generates EMSI/IEMSI packets and sequences containing only 7-bit
+    (00H through 7eH) printable ASCII characters.
+
+    It is recommended that all EMSI/IEMSI implementations strip the high-
+    order bit of all received characters prior to processing the packet/
+    sequence and prior to calculating CRC values.
+
+    CRC values
+    ---------------------------------------------------------------------
+    The polynomial used to calculate a 16-bit CRC is the same polynomial
+    used in the Xmodem file transfer protocol. The polynomial used to
+    calculate a 32-bit CRC is the same polynomial used in the Zmodem file
+    transfer protocol.
+
+    Binary values
+    ---------------------------------------------------------------------
+    Since the EMSI environment specifies only 7-bit printable ASCII
+    characters to be used, binary values, such as CRC and length
+    descriptors are expressed as a four character hexadecimal string. The
+    only exception to this is a 32-bit CRC value which is expressed as an
+    eight character hexadecimal string.
+
+    The application must treat them case insensitive, eg. ffaa should be
+    treated identical to FFAA. 
+
+
+    Handling 8-bit data
+    ---------------------------------------------------------------------
+    Although EMSI only uses 7-bit printable ASCII characters, there is an
+    escape mechanism that allows systems to transmit control and 8-bit
+    ASCII characters without the requirement of an 8-bit data link. The
+    escape character is a backslash character ('\') and is followed by two
+    characters in hexadecimal notation. Eg. "\80" is the ASCII character
+    128. To insert an actual backslash character, two backslashes are used
+    ("\\"), or a backslash followed by the hexadecimal code for a
+    backslash, eg. "\5c".
+
+    The hexadecimal code following a backslash MUST always be two
+    characters, ie. to insert ASCII 15 (hexadecimail 'f'), the result
+    would be "0f". All hexadecimal sequences must be treated case
+    insensitively.
+
+
+    PART II - Electronic Mail Standard Idenfitication
+
+    Connecting two EMSI capable systems
+    =====================================================================
+    This assumes that the two systems are connected and that no data
+    has been transmitted by the Caller.
+
+    It should be mentioned that sending/monitoring for the "YooHoo",
+    "TSYNC", and other protocol start characters is optional and not
+    required for a strict EMSI implementation.
+
+    STEP 1, EMSI INIT    
+
+        Calling system                   Answering system
+    +-+-------------------------------+----------------------------------+
+    :1: Send  until ANY character : Send EMSI_REQ and possible       :
+    : : is received.                  : banner, etc.                     :
+    +-+-------------------------------+----------------------------------+
+    :2: Receive banner, etc. Monitor  : Monitor line for the EMSI_INQ    :
+    : : line for the EMSI_REQ         : sequence and if received,        :
+    : : sequence and if received,     : attempt to handshake immediately.:
+    : : transmit EMSI_INQ and attempt :                                  :
+    : : to handshake immediately.     :                                  :
+    +-+-------------------------------+----------------------------------+
+    :3: No EMSI_REQ sequence received,: Monitor line for EMSI_INQ and    :
+    : : send EMSI_INQ twice followed  : possible other protocol start    :
+    : : by possible other protocol    : characters and if received,      :
+    : : start characters.             : attempt to handshake immediately.:
+    : :                               :                                  :
+    : : Transmit                  : Go to step 3.                    :
+    +-+-------------------------------+----------------------------------+
+    :4: If EMSI_REQ sequence received,:
+    : : send EMSI_INQ and attempt to  :
+    : : handshake immediately,        :
+    : : otherwise repeat step 3.      :
+    +-+-------------------------------+
+
+    In steps 1 and 2, both the Calling and Answering system terminate all
+    sequences with . In step 3, the Calling system does not terminate
+    sequences with  as it is explicitly transmitted after possible
+    protocol start characters. In step 4, the Calling system once again
+    terminate all sequences with a .
+
+
+    STEP 2A, RECEIVE EMSI HANDSHAKE
+
+    At this point, all sequences are terminated with a .
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T1=20 seconds, T2=60 seconds                            :
+    +-+------------------------------------------------------------------+
+    :2: Increment Tries                                                  :
+    : :                                                                  :
+    : : Tries>6?                      Terminate, and report failure.     :
+    : +------------------------------------------------------------------+
+    : : Are we answering system?      Transmit EMSI_REQ, go to step 3.   :
+    : +------------------------------------------------------------------+
+    : : Tries>1?                      Transmit EMSI_NAK, go to step 3.   :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds                                                    :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI sequence until EMSI_HBT or EMSI_DAT or any of the  :
+    : : timers have expired.                                             :
+    : :                                                                  :
+    : : If T2 has expired, terminate call and report failure.            :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_HBT received, go to step 3.                              :
+    : +------------------------------------------------------------------+
+    : : If EMSI_DAT received, go to step 5.                              :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :5: Receive EMSI_DAT packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?                Transmit EMSI_ACK twice, and  :
+    : :                                    go to step 6.                 :
+    : +------------------------------------------------------------------+
+    : : Go to step 2.                                                    :
+    +-+------------------------------------------------------------------+
+    :6: Received EMSI_DAT packet OK, exit.                               :
+    +-+------------------------------------------------------------------+
+
+    All processing of the information in the EMSI_DAT packet must be done
+    after transmitting EMSI_ACK twice to the remote system. It is
+    recommended that an EMSI_HBT sequence is issued once every seven
+    seconds while such processing is taking place to avoid unnecessary
+    handshake collissions. Emitting EMSI_HBT should only be done when
+    it is obvious that the remote system is waiting for the second phase
+    of the EMSI handshake to take place.
+
+
+
+    STEP 2B, TRANSMIT EMSI HANDSHAKE
+
+    At this point, all sequences are terminated with a .
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T1=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_DAT packet and increment Tries                     :
+    : :                                                                  :
+    : +------------------------------------------------------------------+
+    : : Tries>6?                        Terminate, and report failure.   :
+    : +------------------------------------------------------------------+
+    : : Go to step 3.                                                    :
+    +-+------------------------------------------------------------------+
+    :3: T2=20 seconds                                                    :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI sequence until T1 has expired                      :
+    : :                                                                  :
+    : : If T1 has expired, terminate call and report failure.            :
+    : +------------------------------------------------------------------+
+    : : If T2 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_REQ received, go to step 4.                              :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ACK received, go to step 5.                              :
+    : +------------------------------------------------------------------+
+    : : If any other sequence received, go to step 2.                    :             :
+    +-+------------------------------------------------------------------+
+    :5: Received EMSI_ACK, exit.                                         :
+    +-+------------------------------------------------------------------+
+
+
+    EMSI packet and sequence definitions
+    =====================================================================
+
+    =====================================================================
+    EMSI Inquiry                                    **EMSI_INQ
+    ---------------------------------------------------------------------
+    EMSI Inquiry is transmitted by the calling system to identify it as
+    EMSI capable. If an EMSI_REQ sequence is received in response, it is
+    safe to assume the answering system to be EMSI capable.
+
+    =====================================================================
+    EMSI Request                                    **EMSI_REQ
+    ---------------------------------------------------------------------
+    EMSI Request is transmitted by the answering system in response to an
+    EMSI Inquiry sequence. It should also be transmitted prior to or
+    immediately following the answering system has identified itself by
+    transmitting its program name and/or banner. If the calling system
+    receives an EMSI Request sequence, it can safely assume that the
+    answering system is EMSI capable.
+    
+    =====================================================================
+    EMSI Client                                     **EMSI_CLI
+    ---------------------------------------------------------------------
+    EMSI Client is used by terminal emulation software to force a mailer
+    front-end to bypass any unnecessary mail session negotiation and
+    treat the call as an incoming human caller. The EMSI_CLI sequence may
+    not be issued by any software attempting to establish a mail session
+    between two systems and must only be acted upon by an answering
+    system.
+
+    =====================================================================
+    EMSI Heartbeat                                  **EMSI_HBT
+    ---------------------------------------------------------------------
+    EMSI Heartbeat is used to prevent unnecessary timeouts from occurring
+    while attempting to handshake. It is most commonly used when the
+    answering system turns around to transmit its EMSI_DAT packet. It is
+    quite normal that any of the timers of the calling system (which at
+    this stage is waiting for an EMSI_DAT packet) expires while the
+    answering system is processing the recently received EMSI_DAT packet.
+
+    =====================================================================
+    EMSI Data                      **EMSI_DAT
+    ---------------------------------------------------------------------
+    EMSI Data is transmitted by both the calling and answering system at
+    the appropriate time to exchange system information. Following the
+    header is a four byte number representing the length of 
+    excluding the CRC and terminating .
+
+    The EMSI_DAT packet is a variable length packet. Since this is a
+    synchronous protocol, the inbound data buffer should be purged
+    between transmission of the  and  fields to prevent
+    accidental EMSI_NAK sequences, etc.
+
+
+    =====================================================================
+    EMSI ACK                                        **EMSI_ACK
+    ---------------------------------------------------------------------
+    EMSI ACK is transmitted by either system as a positive
+    acknowledgement of the valid receipt of a EMSI_DAT packet. This should
+    only be used as a response to EMSI_DAT and not any other packet.
+    Redundant EMSI_ACK sequences should be ignored.
+
+    =====================================================================
+    EMSI NAK                                        **EMSI_NAK
+    ---------------------------------------------------------------------
+    EMSI NAK is transmitted by either system as a negative
+    acknowledgement of the valid receipt of a EMSI_DAT packet. This
+    should only be used as a response to EMSI_DAT and not any other
+    packet. Redundant EMSI_NAK packets should be ignored.
+
+    The EMSI_DAT packet
+    =====================================================================
+    The EMSI_DAT packet is the core of an EMSI negotiated session. It
+    contains information vital to the mail session. The following pseudo
+    structure shows the layout of the EMSI_DAT packet.
+
+    EMSI_DAT
+        fingerprint,            "EMSI"
+        system_address_list,
+        password,
+        link_codes,
+        compatibility_codes,
+        mailer_product_code,
+        mailer_name,
+        mailer_version,
+        mailer_serial_number:    ASCII1;
+        extra_field_1,
+            ..
+            ..
+        extra_field_n:            EMSI_addon; (optional fields)
+    end;
+
+    The EMSI_addon structure is defined as follows:
+
+    EMSI_addon
+        product_ID,
+        specific_data:            ASCII1;
+    end;
+
+
+    Following is an example of the actual data transmitted as an EMSI_DAT
+    packet:
+
+    {EMSI}{2:270/17}{}{8N1,PUA}{ZAP,ZMO,ARC,XMA}{44}{AirMail}{0.10}
+    {Beta-2}{IDENT}{[Advanced Engineering S.A.R.L.][Luxembourg]
+    [Joaquim Homrighausen][-Unpublished-][9600][MO,XA,HST,V32B,V42B]}
+
+    EMSI_DAT field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    Fingerprint                                                      EMSI
+    ---------------------------------------------------------------------
+    The constant "EMSI". There is no need for a revision level since this    
+    basic format cannot change and remain backward compatible.
+
+    =====================================================================
+    System address list
+    ---------------------------------------------------------------------
+    The system address list is a list of system-specific identifiers for
+    the E-Mail system separated by spaces.
+
+    For FidoNet-technology based networks, it is required that
+    Zone:Net/Node be presented, and .Point be omitted if zero. Zone and
+    Net must not be zero.
+
+    In other networks, an address such as "jhom@csource.oz.au" should be
+    considered valid.
+
+    =====================================================================
+    Password
+    ---------------------------------------------------------------------
+    For systems using a session level password, it would be passed in
+    this field. Note that the same password is used for all presented
+    addresses and that it must be treated case insensitive.
+
+    =====================================================================
+    Link codes
+    ---------------------------------------------------------------------
+    Link codes is a string of flags that specify desired connect
+    conditions. These codes are separated by commas. New codes may be
+    added with prior approval from the author of this document.
+
+    Calling system/answering system options:
+
+        8N1,
+        7E1,
+        7O2,
+        etc.       Communication parameters.
+
+    Calling system options:
+
+        PUA        Pickup mail for all presented addresses.
+        PUP        Pickup mail for primary address only.
+        NPU        No mail pickup desired.
+
+
+    Answering system options:
+
+        HAT        Hold ALL traffic.
+        HXT        Hold compressed mail traffic.
+        HRQ        Hold file requests (not processed at this time).
+
+    =====================================================================
+    Compatibility codes
+    ---------------------------------------------------------------------
+    Compatibility codes is a string of flags that specifies the
+    capabilities and enabled features of the mailer. These codes are
+    separated by commas. New codes may be added with prior approval from
+    the author of this document.
+     
+    The calling system must list supported protocols first and descending
+    order of preference (the most desirable protocol should be listed
+    first). The answering system should only present one protocol and it
+    should be the first item in the compatibility_codes field.
+
+        Protocols
+        -----------------------------------------------------------------
+        DZA*    DirectZAP (Zmodem variant).
+        ZAP     ZedZap (Zmodem variant).
+        ZMO**   Zmodem w/1,024 byte data packets.
+        JAN     Janus.
+        KER     Kermit.
+
+        Other codes
+        -----------------------------------------------------------------
+        NCP     No compatible protocols (failure).
+        NRQ     No file requests accepted by this system.
+        ARC     ARCmail 0.60-capable, as defined by the FTSC.
+        XMA     Supports other forms of compressed mail.
+        FNC     Filename conversion. This indicates that any transmitted
+                files must follow the MS-DOS restrictions of an eight
+                character file name followed by a three character
+                extension; eg. FILENAME.EXT
+
+    (*) DirectZAP is a variant of ZedZap. The difference is that the
+    transmitter only escapes CAN (18H). It is not recommended to use the
+    DirectZAP protocol when two systems are connected via a packet
+    switching network, or via another layer sensitive to control
+    characters such as XON and XOFF.
+
+    (**) The minimum protocol requirement for an EMSI implementation is
+    to support plain Zmodem (16- or 32-bit CRC, 1,024 byte packets) which
+    is represented by the ZMO flag in EMSI.
+
+    =====================================================================
+    Mailer product code
+    ---------------------------------------------------------------------
+    The hexadecimal representation of the EMSC product code assigned to
+    the mailer. Currently, the EMSC codes are the same as the FTSC
+    assigned codes.
+
+    =====================================================================
+    Mailer name
+    ---------------------------------------------------------------------
+    Specifies the name of the E-Mail system sending the EMSI packet.
+
+    =====================================================================
+    Mailer version
+    ---------------------------------------------------------------------
+    The version number of the mailer software, ie. "1.10", "2.00".
+
+    =====================================================================
+    Mailer serial number
+    ---------------------------------------------------------------------
+    The serial number, distribution source, version information, etc.
+    This field is usually displayed like:
+
+        NameVersion/Serial_number
+
+    eg.
+
+        AirMail 0.10/Beta-2
+
+    =====================================================================
+    Extra fields
+    ---------------------------------------------------------------------
+    The extra fields make the EMSI handshake protocol extremely flexible.
+    Any program or mailer may add fields to the end of the pre-defined
+    structure so that program-specific data may be passed without the
+    concern of interferring with other systems.
+
+    There may be any number of extra fields added to the end of this
+    structure. Each EXTRA_FIELD contains two ASCII1 strings:
+
+    PRODUCT_IDENTIFIER      A unique "tag" that defines a specific
+                            program (such as a mailer or a utility).
+
+    SPECIFIC_DATA           ASCII text that is specific data to the
+                            program defined in PRODUCT_IDENTIFIER. With
+                            this structure, any program can add its own
+                            data to the EMSI packet without affecting
+                            other applications.
+
+    It is recommended that you contact the author of this document should
+    you have any EXTRA_FIELDS that you may think worthwhile for other
+    developers to implement and support.
+
+    Predefined extra fields
+    ---------------------------------------------------------------------
+    The following extra fields have been defined to date.
+
+    PRODUCT_IDENTIFIER   :  IDENT
+
+    Purpose              :  General identification of system that
+                            includes all information to generate a St.
+                            Louis-format nodelist entry.
+
+    SPECIFIC_DATA        :  system_name,
+                            city,
+                            operator_name,
+                            phone_number,
+                            baud_rate,
+                            flags:            ASCII2;
+
+        SYSTEM_NAME         The name of the system given by the user.
+                            This would normally be a company name, BBS
+                            name or other identifying text.
+
+        CITY                The geographical location of the system.
+
+        OPERATOR_NAME       The name of the person primarily responsible
+                            for the system.
+
+        PHONE_NUMBER        The telephone number of the system, or
+                            "-Unpublished-" if the telephone number is
+                            unpublished. This MUST be in the standard
+                            format COUNTRY-CITY-NUMBER. Leading zeros
+                            should be stripped from the city code,
+                            ie. Stockholm (Sweden) has a city code of 08,
+                            included in an EMSI packet, it would read
+                            46-8-.
+
+        BAUD_RATE           The maximum baud rate supported by the
+                            system. This is NOT necessarily the same as
+                            the highest DTE rate.
+
+        FLAGS               The St. Louis (FTSC) nodelist flags
+                            associated with the system.
+
+
+    PART III - Interactive Electronic Mail Standard Idenfitication
+
+    Connecting two IEMSI capable systems
+    =====================================================================
+    Two specific labels are used when discussing the IEMSI definitions.
+    The Client, which in this case is the Terminal software, and the
+    Server, which in this case is the interactive on-line software,
+    such as a BBS package or database system. It is assumed that the
+    Client and the Server have established a data link and that no
+    data has been transmitted by the Server.
+
+    STEP 1, IEMSI INIT    
+
+    There is no specific sequence of events in the IEMSI definition. The
+    Client must monitor incoming data and if the EMSI_IRQ sequence is
+    detected, it attempts to negotiate an IEMSI session with the Server.
+    Under no circumstances is the Client allowed to transmit an EMSI_ICI
+    packet prior to receiving the EMSI_IRQ sequence from the Server.
+    All IEMSI sequences and EMSI sequences used during an IEMSI session
+    are terminated by a single . There are no exceptions to this.
+
+
+    STEP 2A, Server
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T2=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_IRQ sequence                                       :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds, increment Tries                                   :
+    : :                                                                  :
+    : : Tries>3?                        Discontinue IEMSI negotiation.   :
+    +-+------------------------------------------------------------------+
+    :4: Wait for EMSI_ICI packet until any of the timers have expired.   :
+    : :                                                                  :
+    : : If T2 has expired, discontinue IEMSI negotiation.                :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ICI seen, go to step 5.                                  :
+    : +------------------------------------------------------------------+
+    : : Go to step 4.                                                    :
+    +-+------------------------------------------------------------------+
+    :5: Receive EMSI_ICI packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?             Transmit EMSI_ISI packet, and    :
+    : :                                 go to step 6.                    :
+    : +------------------------------------------------------------------+
+    : : Packet not received OK?         Transmit EMSI_NAK and go to step :
+    : :                                 3.                               :
+    +-+------------------------------------------------------------------+
+    :6: Tries=0                                                          :
+    +-+------------------------------------------------------------------+
+    :7: T1=20 seconds, increment Tries                                   :
+    : :                                                                  :
+    : : Tries>3?                        Discontinue IEMSI negotiation.   :
+    +-+------------------------------------------------------------------+
+    :8: Wait for EMSI_ACK/EMSI_NAK until any of the timers have expired. :
+    : :                                                                  :
+    : : If T2 has expired, discontinue IEMSI negotiation.                :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired or EMSI_NAK received, transmit EMSI_ISI packet :
+    : : again and go to step 7.                                          :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ACK received, go to step 9.                              :
+    : +------------------------------------------------------------------+
+    : : Go to step 8.                                                    :
+    +-+------------------------------------------------------------------+
+    :9: IEMSI session successfully established, exit.                    :
+    +-+------------------------------------------------------------------+
+
+    The Server must monitor its incoming data channel for 'normal' data,
+    ie. data not transmitted as IEMSI sequences, to detect if the user is
+    attempting to log-in without the use of IEMSI. The only basic
+    restriction this imposes on the Server is that user names and/or IDs
+    may not start with the character '*' since all EMSI/IEMSI sequences
+    start with this character.
+
+    All processing of the information in the EMSI_ICI packet must be done
+    after transmitting the EMSI_ISI packet and receiving two EMSI_ACK
+    sequences in return.
+
+
+    STEP 2B, Client
+
+    Note that this assumes that the Client has seen the EMSI_IRQ sequence
+    transmitted by the Server and that the negotiation is ready to take
+    place.
+
+    +-+------------------------------------------------------------------+
+    :1: Tries=0, T2=60 seconds                                           :
+    +-+------------------------------------------------------------------+
+    :2: Transmit EMSI_ICI packet                                         :
+    +-+------------------------------------------------------------------+
+    :3: T1=20 seconds, increment Tries                                   :
+    +-+------------------------------------------------------------------+
+    :5: Tries>3 or T2 expired?            Discontinue IEMSI negotiation. :
+    : +------------------------------------------------------------------+
+    : : If T1 has expired, go to step 2.                                 :
+    : +------------------------------------------------------------------+
+    : : If EMSI_ISI seen, go to step 6.                                  :
+    : +------------------------------------------------------------------+
+    : : Go to step 5.                                                    :
+    +-+------------------------------------------------------------------+
+    :6: Receive EMSI_ISI packet                                          :
+    : +------------------------------------------------------------------+
+    : : Packet received OK?              Transmit EMSI_ACK packet twice, :
+    : :                                  and go to step 7.               :
+    : +------------------------------------------------------------------+
+    : : Packet not received OK?          Transmit EMSI_NAK and go to step:
+    : :                                  3.                              :
+    +-+------------------------------------------------------------------+
+    :7: IEMSI session successfully established, exit.                    :
+    +-+------------------------------------------------------------------+
+
+    All processing of the information in the EMSI_ISI packet must be done
+    after transmitting two EMSI_ACK sequences in return.
+
+    If either of the ICI or ISI packets are NAK'd three consecutive times,
+    the session negotiation attempt is terminated and the Client proceeds
+    as it would have done should the Server not have supported IEMSI.
+
+
+    IEMSI packet and sequence definitions
+    =====================================================================
+
+    =====================================================================
+    EMSI ACK                                        **EMSI_ACK
+    ---------------------------------------------------------------------
+    EMSI ACK is transmitted by either Client or Server as a positive
+    acknowledgement of the valid receipt of an IEMSI packet such as
+    EMSI_ISI and EMSI_ICI. During an IEMSI session, this sequence can,
+    however, be used as a positive acknowledgement for other IEMSI
+    packets. Redundant EMSI_ACK sequences should be ignored.
+
+    =====================================================================
+    EMSI NAK                                        **EMSI_NAK
+    ---------------------------------------------------------------------
+    EMSI NAK is transmitted by either Client or Server as a negative
+    acknowledgement of the valid receipt of an IEMSI packet such as
+    EMSI_ISI and EMSI_ICI. During an IEMSI session, this sequence can,
+    however, be used as a negative acknowledgement for other IEMSI
+    packets. Redundant EMSI_NAK sequences should be ignored.
+
+    =====================================================================
+    EMSI IRQ                                        **EMSI_IRQ
+    ---------------------------------------------------------------------
+    Similar to EMSI_REQ which is used by mailer software to negotiate a
+    mail session. IRQ identifies the Server as being capable of
+    negotiating an IEMSI session. When the Client detects an IRQ sequence
+    in its inbound data stream, it attempts to negotiate an IEMSI
+    session.
+
+    =====================================================================
+    EMSI IIR                                        **EMSI_IIR
+    ---------------------------------------------------------------------
+    The IIR (Interactive Interrupt Request) sequence is used by either
+    Client or Server to abort the current negotiation. This could be
+    during the initial IEMSI handshake or during other interactions
+    between the Client and the Server.
+
+    =====================================================================
+    EMSI ICI                             **EMSI_ICI
+    ---------------------------------------------------------------------
+    The ICI packet is used by the Client to transmit its configuration
+    and Server-related information to the Server. It contains Server
+    parameters, Client options, and Client capabilities.
+
+    =====================================================================
+    EMSI ISI                             **EMSI_ISI
+    ---------------------------------------------------------------------
+    The ISI packet is used by the Server to transmit its configuration
+    and Client-related information to the Client. It contains Server data
+    and capabilities.
+
+    =====================================================================
+    EMSI ISM                             **EMSI_ISM
+    ---------------------------------------------------------------------
+    The ISM packet is used to transfer ASCII images from the Server to
+    the Client. These images can then be recalled by the Client when
+    the Server needs to display a previously displayed image. This will
+    be further described in future revisions of this document.
+
+    =====================================================================
+    EMSI CHT                                        **EMSI_CHT
+    ---------------------------------------------------------------------
+    The CHT sequence is used by the Server to instruct the Client
+    software to enter its full-screen conversation mode function (CHAT).
+    Whether or not the Client software supports this is indicated in the
+    ICI packet.
+
+    If the Server transmits this sequence to the Client, it must wait for
+    an EMSI_ACK prior to engaging its conversation mode. If no EMSI_ACK
+    sequence is received with ten seconds, it is safe to assume that the
+    Client does not support EMSI_CHT. If, however, an EMSI_NAK sequence
+    is received from the Client, the Server must re-transmit the
+    EMSI_CHT sequence. Once the on-line conversation function has been
+    sucessfully activated, the Server must not echo any received
+    characters back to the Client.
+
+    =====================================================================
+    EMSI TCH                                        **EMSI_TCH
+    ---------------------------------------------------------------------
+    The TCH sequence is used by the Server to instruct the Client
+    software to terminate its full-screen conversation mode function
+    (CHAT).
+
+    If the Server transmits this sequence to the Client, it must wait for
+    an EMSI_ACK prior to leaving its conversation mode. If no EMSI_ACK
+    sequence is received with ten seconds, a second EMSI_TCH sequence
+    should be issued before the Server resumes operation. If, however, an
+    EMSI_NAK sequence is received from the Client, the Server must
+    re-transmit the EMSI_TCH sequence.
+
+
+    The EMSI_ICI packet
+    =====================================================================
+    The following pseudo structure shows the layout of the EMSI_ICI
+    packet. Note that the information in the EMSI_ICI packet may not
+    exceed 2,048 bytes.
+
+    EMSI_ICI
+        name,
+        alias,
+        location,
+        data#,
+        voice#,
+        password,
+        birthdate,
+        crtdef,
+        protocols,
+        capabilities,
+        requests,
+        software,
+        xlattabl:                ASCII1;
+    end;
+
+    EMSI_ICI field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    Name and Alias (or Handle)
+    ---------------------------------------------------------------------
+    The name and possible alias (AKA) of the user (Client). This must be
+    treated case insensitively by the Server.
+
+    =====================================================================
+    Location
+    ---------------------------------------------------------------------
+    The geographical location of the user, ie. Stockholm, Sweden.
+
+    =====================================================================
+    data# and voice#
+    ---------------------------------------------------------------------
+    Unformatted data and voice telephone numbers of the user. Unformatted
+    is defined as the full telephone number, including country and local
+    area code. Eg. 46-8-90510 is a telephone number in Stockholm, Sweden.
+
+    =====================================================================
+    Password
+    ---------------------------------------------------------------------
+    The password for the user. This must be treated case insensitively by
+    the Server.
+
+    =====================================================================
+    Birthdate
+    ---------------------------------------------------------------------
+    Hexadecimal string representing a long integer containing the birth-
+    date of the user in UNIX notation (number of seconds since midnight,
+    Jan 1 1970). This must be treated case insensitively by the Server.
+
+    =====================================================================
+    CrtDef
+    ---------------------------------------------------------------------
+    Consisting of four sub-fields separated by commas, this field
+    contains from left to right: The requested terminal emulation
+    protocol, the number of rows of the user's CRT, the number of columns
+    of the user's CRT, and the number of ASCII NUL (00H) characters the
+    user's software requires to be transmitted between each line of text.
+
+    The following terminal emulation protocols are defined:
+
+        AVT0    AVATAR/0+. Used in conjunction with ANSI. If AVT0 is
+                specified by the Client, support for ANSI X3.64 emulation
+                should be assumed to be present.
+        ANSI    ANSI X3.64
+        VT52    DEC VT52
+        VT100   DEC VT100
+        TTY     No terminal emulation, also referred to as RAW mode.
+
+    =====================================================================
+    Protocols
+    ---------------------------------------------------------------------
+    The file transfer protocol option specifies the preferred method of
+    transferring files between the Client and the Server in either
+    direction. The Client presents all transfer protocols it is capable
+    of supporting and the Server chooses the most appropriate protocol.
+
+        DZA*    DirectZAP (Zmodem variant)
+        ZAP     ZedZap (Zmodem variant)
+        ZMO     Zmodem w/1,024 byte data packets
+        SLK     SEAlink
+        KER     Kermit
+    
+    (*) DirectZAP is a variant of ZedZap. The difference is that the
+    transmitter only escapes CAN (18H). It is not recommended to use the
+    DirectZAP protocol when the Client and the Server are connected via a
+    packet switching network, or via another layer sensitive to control
+    characters such as XON and XOFF.
+
+
+    =====================================================================
+    Capabilities
+    ---------------------------------------------------------------------
+    The capabilities of the user's software. If more than one capability
+    is listed, each capability is separated by a comma.
+
+    The following capability codes are defined:
+
+        CHT     Can do full-screen on-line conversation (CHAT).
+        MNU     Can do ASCII image download (see ISM packet).
+        TAB     Can handle TAB (ASCII 09H) characters.
+        ASCII8  Can handle 8-bit IBM PC ASCII characters.
+
+    =====================================================================
+    Requests
+    ---------------------------------------------------------------------
+    The requests field specifies what the user wishes to do once the
+    initial IEMSI negotiation has been successfully completed. If more
+    than one capability is listed, each capability is separated by a
+    comma.
+
+    The following request codes are defined:
+
+        NEWS    Show bulletins, announcements, etc.
+        MAIL    Check for new mail.
+        FILE    Check for new files.
+        HOT     Hot-Keys.
+        CLR     Screen clearing.
+        HUSH    Do not disturb.
+        MORE    Page pausing, often referred to as "More".
+        FSED*   Full-screen editor.
+        XPRS    .
+
+    (*) Note that this allows the Client to request use of a full-screen
+    editor without requiring that it also supports a full-screen terminal
+    emulation protocol.
+
+    =====================================================================
+    Software
+    ---------------------------------------------------------------------
+    The name, version number, and optionally the serial number of the
+    user's software. Eg. {FrontDoor,2.00,AE000001}.
+
+    =====================================================================
+    XlatTabl
+    ---------------------------------------------------------------------
+    Used for character translation between the Server and the Client.
+    This field has not been completely defined yet and should always be
+    transmitted as {} (empty).
+
+
+    The EMSI_ISI packet
+    =====================================================================
+    The following pseudo structure shows the layout of the EMSI_ISI
+    packet. Note that the information in the EMSI_ISI packet may not
+    exceed 2,048 bytes.
+
+    EMSI_ISI
+        id,
+        name,
+        location,
+        operator,
+        localtime,
+        notice,
+        wait,
+        capabilities:            ASCII1;
+    end;
+
+    EMSI_ISI field definitions
+    ---------------------------------------------------------------------
+    
+    =====================================================================
+    ID
+    ---------------------------------------------------------------------
+    The name, version number, and optionally the serial number of the
+    Server software. Eg. {RemoteAccess,1.10/b5,CS000001}.
+
+    =====================================================================
+    Name
+    ---------------------------------------------------------------------
+    The name of the Server system. Eg. {Advanced Engineering S.A.R.L.}.
+
+    =====================================================================
+    Location
+    ---------------------------------------------------------------------
+    The geographical location of the user, ie. Stockholm, Sweden.
+
+    =====================================================================
+    Operator
+    ---------------------------------------------------------------------
+    The name of the primary operator of the Server software. Eg. {Joaquim
+    H. Homrighausen}.
+
+
+
+    =====================================================================
+    Localtime
+    ---------------------------------------------------------------------
+    Hexadecimal string representing a long integer containing the current
+    time of the Server in UNIX notation (number of seconds since midnight,
+    Jan 1 1970). This must be treated case insensitively by the Client.
+
+    =====================================================================
+    Notice
+    ---------------------------------------------------------------------
+    May contain copyright notices, system information, etc. This field
+    may optionally be displayed by the Client.
+
+    =====================================================================
+    Wait
+    ---------------------------------------------------------------------
+    A single character used by the Server to indicate that the user
+    has to press the  key to resume operation. This is used in
+    conjunction with ASCII Image Downloads (see ISM packet).
+
+    =====================================================================
+    Capabilities
+    ---------------------------------------------------------------------
+    The capabilities of the Server software. No Server software
+    capabilities have currently been defined.
+
+    Credits and other notes
+    =====================================================================
+    The original EMSI specifications were designed by Chris Irwin and
+    Joaquim H. Homrighausen. The original IEMSI specifications were
+    designed by Joaquim H. Homrighausen and Andrew Milner.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0057.html b/html/ftsc/fsc-0057.html new file mode 100755 index 00000000..1355fff7 --- /dev/null +++ b/html/ftsc/fsc-0057.html @@ -0,0 +1,533 @@ + + +Conference Managaers - Specifications for Requests. + + + + +
+Document: FSC-0057
+Version:  003
+Date:     07-Dec-92
+
+
+
+
+               Conference Managers - Specifications for Requests
+
+                               December 7, 1992
+
+                   Fabiano Fabris      Joaquim H. Homrighausen
+                2:285/304.100@fidonet      2:270/17@fidonet
+
+
+
+
+    Status of this document:
+
+    This FSC suggests a proposed protocol for the FidoNet(r) community, and
+    requests discussion and suggestions for improvements. Revision 3
+    presents several additions and enhancements over the previous revision.
+
+    Distribution of this document is unlimited.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido
+    Software.
+
+
+
+    1  Purpose
+
+       This document will explore the methods implemented by various
+       conference managers which process requests (in net mail form)
+       for changes to the conference mail links on the system on which
+       they are in use.
+
+       Until now, it would appear that no real standard exists, so most
+       software authors have either tried to emulate another program, or
+       to create a new method of their own, or both.
+
+       Here, an attempt will be made to define a standard, one which tries
+       to maintain compatibility with methods already in use, while also
+       extending them to provide new functions.
+
+
+
+    2  Conventions
+
+       The names of the commands described in the following paragraphs are
+       given in upper case, for legibility. However, a conference manager
+       should be able to interpret them even if they are given in lower
+       or mixed case.
+
+       Similarly, conference names, or tags, are given in upper case, but
+       the conference manager should be able to handle them even if typed
+       in lower or mixed case.
+
+       Optional information is enclosed with square brackets, while
+       variable information is enclosed with angle brackets. For example:
+
+          +CONF [,R=]
+
+       indicates that the section within square brackets is optional, and
+       if supplied, requires a parameter after the equals sign.
+
+       Some conference managers may allow commands to be abbreviated to the
+       shortest non-ambiguous string. For example, %LIST might be reduced
+       to %L.
+
+
+
+    3  Format of the request
+
+       A request to a conference manager is generally made in a net mail
+       message containing specific information in some of the fields. In
+       particular, the addressee is the name of the conference manager
+       itself, and the subject of the message is a password assigned by
+       the sysop of the system running the program.
+
+       For example:
+
+          From:     John Doe, on 2:123/56
+          To:       Program,  on 2:234/0
+          Subject:  password
+
+       Here the first problem is encountered. Each of the existing programs
+       recognizes a different addressee. For this reason it is proposed
+       that all such programs recognize requests made to a single,
+       "standard" addressee, besides any other they may wish to implement.
+       The term "ConfMgr" has been arbitrarily chosen, and should be used
+       by those programs which adhere fully to all the standards proposed
+       in this document.
+
+       The text of the message itself contains the request proper, and is
+       the subject of the following paragraphs.
+
+
+
+    4  Linking and Unlinking of conferences.
+
+       The current methods for requesting that a conference be linked are
+       basically two:
+
+          +CONFNAME
+          CONFNAME
+
+       For reasons of uniformity, it is proposed that all conference
+       manager programs recognize the first method.
+
+       Requests that a conference be unlinked are given by:
+
+          -CONFNAME
+
+       It might be interesting to implement some form of pattern matching,
+       similar to the unix shell. The following basic wildcards should be
+       considered:
+
+          *        matches zero or more characters
+          ?        matches any one (not zero) character
+
+       Since the requests are processed top-down, a request of the form
+
+          +CONFNAME
+          -*
+
+       would be redundant, since the ConfMgr would link CONFNAME from the
+       first line, and then immediately unlink it again because of the
+       second line, which requests that all linked conferenecs be unlinked.
+
+       It should also be possible to specify more than one conference tag
+       on the same line. For example:
+
+          +CONF1 CONF2 CONF3
+
+       would link the three conferences CONF1, CONF2 and CONF3.
+
+
+
+    5  Rescanning Conference Mail
+
+       Many conference managers currently allow a system to request that an
+       area be "rescanned". In other words, the system receiving the
+       request will export all mail in one or more areas to the requesting
+       system.
+
+       This may be accomplished by specifying the %RESCAN command in the
+       body of the request. This will force the ConfMgr to generate a scan
+       request for those areas which the remote system requested with the
+       message containing the %RESCAN command.
+
+       Rescans of a single area, newly linked, could be requested as
+       follows:
+
+          +CONFNAME, R[=]
+
+       where 'n' is the number of messages in that area to be rescanned.
+       (The space following the comma is optional, but allowed.)
+
+       Rescanning has one serious drawback: dupes! It is very possible for
+       the requesting system to have already set up the area with several
+       downlinks. Thus, when the rescanned mail is received, it could be
+       exported to other systems. In a tree-based topology, this is
+       harmless, but in circular topologies this would create dupes.
+
+       Thus, it is proposed that system receiving the rescan request add a
+       kludge to the messages, so that they can be recognized by the
+       requesting system and not re-exported.
+
+       The proposed kludge is:
+
+          ^ARESCANNED 
+
+       where  is the network address, including domain, of the
+       system from which the mail was rescanned.
+
+       In alternative to a rescan, a sysop might request a "sample",
+       consisting of a series of messages contained in a text file. The
+       ConfMgr would export some or all messages from an area to a plain
+       ASCII text file, and send it along with the reply, to the requesting
+       system. A "sample" request would be made as follows:
+
+          +CONFNAME, S[=]
+
+       where 'n' indicates how many messages should be sampled.
+
+       a) Updating Conferences
+
+          Update requests allow a sysop to rescan or "sample" an area
+          without having to first unlink from it, and then relink with the
+          rescan or "sample" parameter.
+
+          The format of this command is:
+
+             =CONFNAME, [=]
+
+          Thus a rescan request for the most recent 50 messages would be
+          specified as:
+
+             =CONFNAME, R=50
+
+
+
+    6  Information Requests
+
+       Requests for information have until now taken two forms. In one
+       case, they are given as switches after the password on the subject
+       line, while in the second they are given as "commands" within the
+       body of the message text. It is proposed that the second method be
+       chosen as standard, since it is considerably more flexible.
+
+       Below are listed the proposed commands:
+
+         %HELP                    Sends a (pre-defined) help text to the
+                                  requesting system, explaining how the
+                                  ConfMgr is to be used.
+
+         %LIST[,B]                Lists the conferences currently available
+                                  to the requesting system, on the basis
+                                  of a method internal to the conference
+                                  manager itself. This list would flag the
+                                  areas which are already linked. The 'B'
+                                  modifier would generate the list in
+                                  binary format (see section 8e).
+
+         %BLIST                   Equivalent to %LIST,B above.
+
+         %QUERY                   Lists the conferences currently linked to
+                                  the requesting system.
+
+         %UNLINKED                Lists the conferences which are available
+                                  to the requesting system, but not
+                                  currently linked. This is the logical
+                                  difference between a %LIST and a %QUERY.
+
+
+
+    7  Remote Maintenance
+
+       Besides these simple functions, it is becoming more and more
+       interesting to make handling of the conference mail flow even more
+       automatic. For this reason, for example, it might be useful to
+       allow another sysop control over your own system, adding and
+       removing conferences as need requires. Thus a hub or coordinator
+       could automatically have a new area added to their conference
+       lists, or discontinued ones removed.
+
+       Naturally, the ConfMgr must be able to distinguish which system has
+       the ability to make such changes, but that is beyond the scope of
+       this document.
+
+       It is proposed that a conference manager be able to automatically
+       add a new conference to the system's list if/when it is detected.
+       Thus no special commands would be required. The manager should be
+       able to determine a default list of down-links for the new area,
+       and also the "group" of systems which could then request it.
+
+       However, should it be desired to explicitly create a new conference
+       via remote, this could be done by including a line such as the
+       following in the message text:
+
+          &CONFNAME
+
+       In order to remote delete an area, the requesting sysop should
+       include a line like this in the body of the message text:
+
+          ~CONFNAME
+
+       Thus, if the system has remote privileges, the conference would be
+       deleted (and optionally, all systems linked to the conference could
+       be informed of this fact).
+
+       Similarly, it would also be possible to allow a system to change the
+       tag of a conference. This would be accomplished by a line such as:
+
+          # OLD_NAME  NEW_NAME
+
+       The ConfMgr should inform all downlinks of the change by sending a
+       net mail message.
+
+       It might also be desirable to allow a sysop to make changes on
+       behalf of another system. This could be done by inserting a special
+       command at the beginning of the request itself. For example:
+
+          From:     John Doe, on 2:123/1
+          To:       Program,  on 2:987/65
+          Subject:  password
+          Text:
+          %FROM: 2:234/56
+          +CONFNAME
+
+       The %FROM command would make the ConfMgr carry out the changes as if
+       the system 2:234/56 had requested them. The password should
+       nonetheless be the one assigned to 2:123/1.
+
+
+
+    8  Further Automation
+
+       In order to make the system more powerful, and to reduce the
+       necessity for human intervention, several extensions are feasible.
+
+       a) ARCmail Compression Method
+
+          One interesting application is the possibility of allowing a
+          remote system to change the compression program used to "pack"
+          mail bound for his system. This could be done with the following
+          command in the message to a ConfMgr:
+
+             %COMPRESS 
+
+          where  is one of the compression programs supported by
+          the system. Of course, the remote system should also be able to
+          determine which compression methods are available; this could be
+          done with
+
+             %COMPRESS ?
+
+          Requests for an unsupported compression method should also be
+          responded to with a list of those available.
+
+          From the practical point of view, only systems which pick up
+          their mail (as opposed to those to whom mail is sent) should be
+          allowed to change the compression method used. How this
+          distinction is achieved is beyond the scope of this document.
+
+       b) Passwords
+
+          A sysop should be able to change the password used to make
+          requests to a ConfMgr without requiring the intervention of the
+          other system's sysop. This could easily be done if the
+          conference manager implemented the following command:
+
+             %PWD 
+
+          The new password (case insensitive) would replace the current
+          one as of the next request.
+
+       c) Temporary Unlink
+
+          Should a system's sysop be absent for a prolonged period of time,
+          he might want to temporarily cut all conferences from his
+          uplink.  This could be accomplished with the
+
+             %PAUSE
+
+          command. This would tell the ConfMgr to temporarily stop sending
+          conferences to that system.  On his return, the sysop could
+          reactivate them all with the
+
+             %RESUME
+
+          command.
+
+       d) Forwarding Remote Requests
+
+          If a conference manager receives a remote request to delete an
+          area, it could very easily "forward" that request to all its
+          downlinks by producing a similar request.  In that way, a single
+          request originating from, for example, a Region Coordinator,
+          would result in the conference being deleted from all systems
+          "below" him.
+
+          Similarly, remote requests for conference name changes could
+          also be passed on to downlinks.
+
+       e) Automatic Requests for Conferences
+
+          A conference manager should also be able to automatically request
+          an area from an uplink. This would become necessary if, for
+          example, it processed a request for an area not currently
+          available on the system. In this case, it would scan a series of
+          conference lists for the requested area, and if found, would
+          send a request for that area.
+
+          In order to be able to do this, the ConfMgr would need to have
+          one or more lists of conferences from the uplinks. These lists
+          could be produced on request by the ConfMgr itself. In order to
+          simplify matters, a binary format is proposed. (Note that these
+          are C-style structures, with everything which that implies.)
+          This binary file is called a Binary Conference List (BCL).
+
+          The file starts with a header, containing some basic system
+          information:
+
+             struct bcl_header {
+               char    FingerPrint[4];     /* BCL */
+               char    ConfMgrName[31];    /* Name of "ConfMgr" */
+               char    Origin[51];         /* Originating network addr */
+               long    CreationTime;       /* UNIX-timestamp when created */
+               long    flags;              /* Options, see below */
+               char    Reserved[256];      /* Reserved data */
+             }
+
+          The currently defined flags for the header are:
+
+            BCLH_ISLIST     0x00000001L
+              File is complete list
+
+            BCLH_ISUPDATE   0x00000002L
+              File contains update/diff information
+
+          The BCL would then contain a series of entries having the
+          following format:
+
+             struct bcl {
+               int     EntryLength;      /* Length of entry data */
+               long    flags1, flags2;   /* Conference flags */
+               char    *AreaTag;         /* Area tag [51] */
+               char    *Description;     /* Description [51] */
+               char    *Administrator;   /* Administrator or contact [51] */
+             }
+
+          The flags currently defined are:
+
+             FLG1_READONLY   0x00000001L
+                Read only, software must not allow users to enter mail.
+
+             FLG1_PRIVATE    0x00000002L
+                Private attribute of messages is honored.
+
+             FLG1_FILECONF   0x00000004L
+                File conference.
+
+             FLG1_MAILCONF   0x00000008L
+                Mail conference.
+
+             FLG1_REMOVE     0x00000010L
+                Remove specified conference from list (otherwise add/upd).
+
+          Thus, instead of scanning an AREAS.BBS style list, the ConfMgr
+          would parse and use lists in the above format. Naturally, each
+          list would be in some way "attached" to a node number, and a
+          corresponding ConfMgr password.
+
+          Each system may only have one master file, called anything they
+          want. But when transmitted to other systems, this file must
+          always be named ????????.BCL.
+
+          The list would be generated in response to a
+
+            %LIST, B
+
+          command in the message text.
+
+       f) Receipts
+
+          It might be useful to have the ConfMgr generate a receipt to be
+          sent to another system, perhaps a co-sysop or a sysop point
+          node. This could be done with the command:
+
+            %RECEIPT ,
+ + embedded in the request message. For example: + + %RECEIPT JoHo,2:270/17 + + + + 9 Comments in the request + + It should be possible for a sysop to insert a comment in the request + made to a conference manager. These comments, naturally, would be + destined to the sysop of the system, and not to the conference + manager itself. Such comments should be placed at the end of the + message, following a %NOTE command. + + In all cases except the above, the request can be deleted by the + ConfMgr once processed, but messages containing comments should be + retained. + + Note: the current method used is to supply comments after a tear- + line. This practice is somewhat "messy", but it might be wise to + support it until such time as all conference managers have + implemented the %NOTE command. + + + + 10 Summary + + +CONFNAME[,R|S] Request to link to CONFNAME + -CONFNAME Request to unlink from CONFNAME + =CONFNAME,R|S Rescan or "sample" linked conference + &CONFNAME Request to create CONFNAME + ~CONFNAME Request to delete CONFNAME + #OLD NEW Name change request + + %LIST[,B] List available areas, flag linked + %QUERY Only list linked areas + %UNLINKED List available but unlinked areas + %HELP Send help text + %FROM Simulate request from another system + %RESCAN Rescan conferences linked in current request + %COMPRESS Change compression method + %PWD Change ConfMgr password + %PAUSE Suspend link + %RESUME Resume link + %RECEIPT , Send copy of receipt to another system + %NOTE Introduces comment to the sysop + + + + 11 Final Note + + This document is to be considered as a suggestion for software + developers to make their programs compatible with one another, so as + to make life easier for the average sysop when dealing with + conference managers. + + Feedback would be appreciated and can be sent to us at the addresses + specified on the title page. Please send feedback via netmail only. + +
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0059.html b/html/ftsc/fsc-0059.html new file mode 100755 index 00000000..1060f8e3 --- /dev/null +++ b/html/ftsc/fsc-0059.html @@ -0,0 +1,1622 @@ + + +Newsgroup Interchange within FidoNet. + + + + +
+Document: FSC-0059
+Version:  001
+Date:     08-Mar-1992
+
+
+
+
+                  Newsgroup Interchange within FidoNet
+                              Jack Decker
+                            1:154/8@fidonet
+
+  A proposed standard for the interchange of USENET News messages among
+                             FidoNet nodes.
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+Introduction:
+
+This document defines the standard format for the interchange of USENET
+news messages among FidoNet nodes.  It incorporates by reference the
+document RFC-1036, "Standard for Interchange of USENET Messages" by M.
+Horton of AT&T Bell Laboratories and R. Adams of the Center for Seismic
+Studies.  A copy of RFC-1036 should be included in the distribution
+archive of this standard.  However, RFC-1036 is NOT applicable in its
+entirety to FidoNet.  Therefore, unless specifically referenced
+elsewhere in this document, only section 2 of RFC-1036 should be
+considered part of this standard.  Section 3, which deals with "control
+messages", may be implemented in FidoNet on an optional basis, and if
+processing of control messages is included in a FidoNet implementation,
+it should be done in accordance with section 3 of RFC-1036 to the
+extent possible.  Section 4 of RFC-1036 is *NOT* applicable to FidoNet
+(except for section 4.3, which will be discussed later) and therefore
+is NOT included as part of this standard.  Section 5 of RFC-1036 is a
+treatise on the News Propagation Algorithm used within UseNet, and
+should be studied even though it is not directly applicable to FidoNet,
+in particular because it contains a discussion on the prevention of
+loops (what we in FidoNet commonly refer to as "dupe loops").
+
+Please note that FidoNet implementations do not recognize nor support
+what is referred to as the "old format" or the "A format" in section 2
+of RFC-1036.
+
+The goal of this document is to define a standard for the interchange
+of news messages between FidoNet nodes in a format that will also be
+acceptable to UseNet hosts.  In order to simplify the creation of
+software that conforms to this standard, we do not intend to support
+every news format that has ever existed in UseNet.  The standard
+described in RFC-1036 is used by the majority of UseNet hosts, and
+therefore it is the standard that will be adopted in this document.
+
+This standard will contain three sections:  General theory of newsgroup
+transmission, Format and protocols of batched newsgroups, and the
+translation of newsgroup messages to and from FidoNet message format.
+
+1. General theory of newsgroup transmission:
+
+Prior to the introduction of the DoveMail program, the usual method of
+gating a UseNet newsgroup into FidoNet was to convert it to FidoNet
+echomail, and then send it to "downstream" nodes in echomail format.
+This method is still used at the majority of gateway systems at this
+writing.  Unfortunately, no conversion process is perfect, and some
+useful control information is usually lost in the conversion.  In
+addition, most FidoNet echomail processors don't handle long messages
+(which are fairly common in newsgroups) well at all, and many gateway
+systems either try to split these messages into multiple parts (a
+somewhat awkward process) or discard them entirely.  Because the
+duplicate message detection algorithms used in many FidoNet echomail
+processors incorrectly identify some of the parts of a split message as
+duplicates, parts of long messages often get "lost" when transmitted as
+echomail.  Also, UseNet allows a message to be posted to multiple
+newsgroups, and when such messages are converted to echomail, it may be
+necessary to create multiple copies of the message (one for each
+echomail area that it would be placed in), thus increasing the
+transmission time for such messages.
+
+Even normal-length newsgroup messages may be falsely discarded as
+duplicates by some "downstream" echomail processors.  The reason this
+is a particular problem in newsgroups converted to echomail is because
+some echomail processors use a checksum of parts of FidoNet message
+headers to determine if messages are duplicates. Since all newsgroup
+messages are assumed to be addressed to "All", and since some gateway
+software uses the date and time that the message was converted to
+echomail rather than the original date and time from the message, it's
+quite possible that the remainder of the message header contains
+information that is similar enough to information in another message's
+header to cause it to be discarded as a duplicate message.  This
+happens far more frequently with converted newsgroup messages than with
+messages originally entered as echomail.
+
+Finally, when a BBS user enters a reply to a news message that has been
+converted to echomail, in many cases the information is simply not
+available in the original message to generate a proper "References:"
+line in the reply, as required by RFC-1036.  If the original message
+contained a "Followup-To:" line, which requires that replies be posted
+to a different newsgroup than the one in which the original message was
+entered, this line may not transmitted in the message as converted to
+echomail.  And even if this information is available, no echomail
+processor currently available will modify the reply message as required
+(to add the "References:" line where necessary, or to move the message
+to a different area if it is a reply to a message that contained a
+"Followup-To:" line).
+
+Under this proposed standard, none of the UseNet message header
+information is lost in transmission between nodes, and reply messages
+can be generated that conform to UseNet specifications.  If a message
+is posted to multiple newsgroups, it is only transmitted once (instead
+of multiple times as it might be if converted to echomail).  Also, long
+messages are not truncated or changed in transmission between nodes,
+and finally, there is no chance that a message will be improperly
+discarded as a duplicate.
+
+The main thing to remember is that under this standard, news messages
+are never converted to echomail.  Echomail is an irrelevant concept in
+this context, since we are not passing echomail between nodes.
+Instead, newsgroups are transmitted in the native format specified by
+RFC-1036, and tossed directly from batched newsgroup packets to the
+FidoNet message format (e.g. the *.msg format) if necessary.  Keep in
+mind that most FidoNet BBS software uses the same general format not
+only for echomail messages, but also for netmail and local message
+areas, so it is not necessary to transmit messages between nodes in
+echomail format if another format is more suitable for the type of
+message being transmitted.
+
+2. Format and protocols of batched newsgroups:
+
+When newsgroup messages are transmitted between systems, the individual
+messages must conform to the specifications of section 2 of RFC-1036,
+and section 3 of this document.  Where section 3 of this document
+defines a more restrictive standard than RFC-1036, this document shall
+take precedence.
+
+When transmitting news messages between FidoNet nodes, they must be
+sent in a batched newsgroup file (as described in section 4.3 of
+RFC-1036) unless some other format is agreed upon in advance.  The
+transmission of unbatched news messages, or the use of any batching
+method other than that described in section 4.3 of RFC-1036 shall be
+considered non-standard.  Please note that RFC-1036 section 4.3 refers
+to this batching process as combining several messages into "one large
+message", but we will refer to this "one large message" as a "batched
+newsgroup file", or a "UseNet format mail packet" rather than as a
+"large message", since FidoNet systems do not normally handle large
+"messages".
+
+When messages pass through a FidoNet system on their way to other
+nodes, the header lines in the message may be modified to conform with
+the standards given here.  However, the text (body) of a message should
+NEVER be altered (one exception: Carriage Returns MAY be converted to
+Line Feeds in order to conform to this standard, but this is neither
+required nor expected of software).
+
+The standard format for sending a batched newsgroup file to other
+FidoNet nodes is as follows:
+
+First, as will be noted in section 3 of this document, individual lines
+of the batched newsgroup file must be terminated with Line Feeds only,
+and the file must NOT contain Carriage Return characters (ASCII 13).
+
+Batched newsgroup files shall be transmitted between FidoNet nodes as
+files named using the filename ????????.PKU, where the eight character
+root name can be any of the hexadecimal digits 0 - 9 or A - F.  The
+.PKU extension (which stands for "PacKet - Usenet format") is the news
+equivalent of the .PKT file used to transmit FidoNet format netmail and
+echomail between nodes.
+
+Batched newsgroup files with the filespec ????????.PKU may be archived
+into a standard mail archive file (bearing the extension *.MO?, *.TU?,
+*.WE? ... *.SU?).  It is assumed that the receiver of batched newsgroup
+files will take any necessary steps to make sure that both *.PKU and
+*.PKT files are extracted from incoming mail archive files before the
+mail archive files are deleted.  In certain cases, this may mean that
+an external unarchive shell may have to be used, instead of allowing
+the echomail processor to call the unarchiver (typical external
+unarchive shell programs at this writing are GUS, POLYXARC, and SPAZ).
+
+A batched newsgroup file awaiting transmission may be stored in a
+FidoNet system's "outbound" area in uncompressed form, prior to being
+archived for transmission or sent in uncompressed form.  It is
+suggested that when a system uses the .OUT extension to indicate an
+uncompressed netmail or echomail packet, the .UUT extension be used to
+indicate an uncompressed batched newsgroup packet.  It is expected that
+a .UUT file in a system's "outbound" area will be treated in much the
+same way as an .OUT file, except it will be renamed to a file with an
+extension of .PKU (rather than .PKT) before being archived into the
+mail archive.  This implies that the root name of the .UUT file will
+contain the net number and node number of the destination system,
+expressed as four hexadecimal digits each for net and node numbers, in
+the same manner as the root name for a FidoNet .OUT file is
+constructed.
+
+The root filename of the *.PKU file should be an eight digit
+hexadecimal number, with leading zeroes used if necessary, in order to
+make an eight character root filename.  It is suggested that this
+hexadecimal number be based on time of year, with 00000000.PKU
+generated at exactly midnight on January 1 and FFFFFFFF.PKU generated
+at just a moment before midnight on December 31.  However, it is
+permissible to use the same algorithm that is used to generate the root
+filename for *.PKT files.
+
+The normal sequence for transmission of messages between FidoNet nodes
+might then be described as follows:
+
+a. Messages created on the originating system are placed into a batched
+newsgroup file conforming to the specifications of RFC-1036 section
+4.3.  When this batched newsgroup file is destined for another FidoNet
+node, it will have a filename of the format:
+
+     [4 hex digit net number][4 hex digit node number].UUT
+
+This file will then be placed in the outbound mail area for packing.
+
+b. A mail packing program will examine the outbound mail area and, upon
+finding the .UUT file, will rename it to a file with an extension of
+.PKU, and then shell to a compression program in order to place the
+*.PKU file into a new or existing mail archive file for the destination
+node.  Mail archive files bear extension names consisting of the first
+two letters of a day of the week (in the English language) plus a
+numeric character in the range 0 - 9 (for example, .MO5 or .TH7).  The
+method of compression for the mail archive is as agreed upon between
+the originating and destination nodes.  No "standard" method of
+compression for the mail archive is specified in this document.  NOTE:
+If the compression program fails for any reason (such as running out of
+disk space), the mail packing program MUST rename the .PKU file back to
+the original *.UUT filename before exiting.  Since batched newsgroup
+files do not contain a header that indicates the destination node,
+there would be no way to determine the proper destination node if the
+file were not renamed back to the original filename.
+
+c. The mail archive is transmitted in the usual manner by a FidoNet
+compatible mailer, or such other means as may be agreed upon in advance
+by the sysops of the originating and destination nodes.
+
+d. At the destination system, the individual files are extracted from
+the mail archive.  *.PKT files are processed in the usual manner to
+extract any netmail or echomail messages, while *.PKU files are
+processed by software designed to handle batched newsgroup files.  In
+this context, such files could be "handled" by re-processing the
+messages and batching them to be sent on to one or more additional
+node(s), or by tossing the messages to the local message base, or both.
+
+Please note that this standard does not anticipate that batched
+newsgroup files will be converted to FidoNet echomail at any point
+along the way.  It is realized that this may indeed happen, but such
+conversions should be considered as something to be avoided if at all
+possible due to the problems discussed in section 1 of this document.
+
+3. Translation of newsgroup messages to and from FidoNet message
+format:
+
+NOTE: Where applicable, the standards defined in this section for
+messages shall apply not only to locally created messages, but also to
+all messages sent to "downstream" FidoNet nodes.
+
+In this context, "FidoNet message format" means that format in which
+messages commonly reside on a FidoNet BBS.  At this writing, there are
+three formats commonly used for message storage on FidoNet systems, but
+other formats may be in use as well.  The three most common formats are
+the "*.msg" format as used by the original Fido program (and a host of
+programs since), also commonly referred to as the "single message per
+file format"; the "Hudson" format, used by QuickBBS, Remote Access, and
+some other products; and the "Squish" format used by the Maximus BBS
+and the "Squish" echomail processor.
+
+Because there are so many message formats, some other programs have
+taken the approach of trying to convert UseNet news into echomail,
+creating *.PKT files which can theoretically be processed by any
+FidoNet system.  However, since the *.PKT files are processed by the
+echomail processor, all the limitations and pitfalls associated with
+converting newsgroup messages to echomail come into play.
+
+The preferred way of handling incoming messages would be to have the
+BBS (or message reader/editor) software directly read batched newsgroup
+files.  In this way, the files would not have to be "processed" per se.
+As new batched newsgroup files arrived on a system, they could simply
+be concatenated to the existing message base, and then a utility could
+be run that would build an index to the message base, in a manner
+somewhat similar to the way "flat file" message bases are currently
+implemented on some BBS's.  Of course, you'd need to occasionally run a
+utility to delete old messages in order to keep the message base from
+growing too large, and new messages entered on the system would have to
+be exported from the system in a separate batched newsgroup file.
+However, at this writing no FidoNet-compatible BBS or message editor is
+capable of directly reading a batched newsgroup file.
+
+The second most preferable method is to convert news messages directly
+to the message format used by that system.  At this writing the
+DoveMail software includes utilities (NewsToss and NewsScan) that can
+convert batched newsgroup files to and from messages in the *.msg
+(single message per file) format.  It should be possible to convert
+batched newsgroup files to and from other FidoNet message formats as
+well.
+
+The method in which messages are stored on a BBS, and the method in
+which it is determined which new (locally-entered) messages need to be
+exported from the system will necessarily be implementation-specific.
+One method that can be used with *.msg type message bases is to
+maintain a "high water mark" in 1.msg, similar to the "high water mark"
+used for echomail messages, and additionally to mark messages received
+from other nodes as "sent" when they arrive, and locally-entered
+messages as "sent" when they have been exported, and to never re-send a
+message marked as "sent".
+
+When tossing incoming messages, duplicate messages can be detected by
+comparing the contents of the "Message-ID:" line with those of
+previously received messages.  This may be slow processing
+considerably, however, and would require storage of a history file of
+"previously seen" messages.  Another method is to look in the "Path"
+line and see if we are already listed in the path; if so, the message
+is a duplicate and should be deleted.  This method is faster and does
+not require maintenance of a history file, but will not guard against
+duplicate messages arriving from one's feed that have not passed
+through the system twice (for example, a message that arrived from two
+different paths).  Fortunately, UseNet folks seem to understand the
+need for proper topology, so those types of dupes are relatively rare.
+FidoNet sysops taking UseNet feeds must understand that it is
+IMPERATIVE that a feed of any one newsgroup be obtained from only ONE
+source, especially if they are then passing that newsgroup to any
+"downstream" nodes.  This absolutely does NOT imply that geographic
+restrictions on newsgroup distribution are necessary or desirable!
+
+Additional comments on preventing "loops" can be found in section 5 of
+RFC-1036, in the discussion of the News Propagation Algorithm.  Please
+note that only two methods of loop prevention are included in this
+standard:
+
+1) The history mechanism.  Each host keeps track of all messages it has
+seen (by their Message-ID) and whenever a message comes in that it has
+already seen, the incoming message is discarded immediately.
+
+2) Not sending a message to a system listed in the "Path" line of the
+header, or to the system that originated the message (which, in
+practice, should be listed in the Path line).
+
+No other methods of dupe loop prevention are acceptable.  In
+particular, checksums of portions of the message header or message
+itself are NOT permitted to be used for loop prevention, except perhaps
+as a method to quickly identify POTENTIAL duplicate messages before
+doing a full string comparison with the Message-ID data in the history
+file.  In no case should a checksum be used as the SOLE method of
+determining whether a message is a duplicate.
+
+When newsgroup messages are created for transmission to other systems,
+or when received messages are transmitted other systems, the individual
+messages must conform to the specifications of section 2 of RFC-1036.
+However, in order to simply programming of software designed to handle
+such messages, the following modifications to the standard are proposed
+for use within FidoNet.  Please note that these are slightly more
+restrictive than the standard permitted by RFC-1036:
+
+a. The "old format" or "A format" described in section 2 of RFC-1036 is
+NOT supported in FidoNet.  Only the format detailed in RFC-1036
+(sometimes referred to as the "B" News format) is supported.  The vast
+majority of UseNet sites currently use the "B" News format.
+
+b. The UseNet standard permits the use of "white space" to separate
+certain items in the message header, with "white space" defined as
+blanks or tabs.  It also states that "the Internet convention of
+continuation header lines (beginning with a blank or tab) is allowed."
+However, it should NOT be ASSUMED that "continuation header lines" will
+be used in any message.  It is suggested that when creating newsgroup
+messages for transmission to other systems, the use of tab characters
+be avoided in header lines, and that "continuation header lines" NOT be
+used, even if this means that a header line will be considerably longer
+than the length of a screen line.  Software that creates FidoNet-format
+messages (for display to BBS callers) from batched newsgroup files
+(that is, newsgroup message tossers) should break up such extra-long
+header lines, using a single space character ONLY (NOT a tab!) at the
+start of "continuation header lines."  Since batched newsgroup files
+received from a UseNet site may contain "continuation header lines"
+and/or tabs as "white space" in header lines, it is necessary to be
+able to decode such header lines properly, but it is strongly suggested
+that FidoNet software not CREATE messages with tabs or "continuation
+header lines" for transmission through the network.
+
+c. All lines in news messages, including header lines, shall be
+terminated with a LINE FEED (ASCII 10 decimal) ONLY.  Under NO
+circumstances shall a CARRIAGE RETURN (ASCII 13 decimal) appear in news
+messages transmitted through FidoNet (if a Carriage Return is found in
+an in-transit message it MAY be changed to a Line Feed, this being the
+sole exception to the rule about not changing the body of a message,
+but the expectation is that no Carriage Returns will appear in a news
+message).  Also, spaces appearing at the end of lines (just prior to
+the Line Feed character) are strongly discouraged since they convey no
+useful information.  Finally, there should be only a single line feed
+at the end of each message (blank lines following the last line of a
+message are not allowed, again because they convey no useful
+information).  Please note that the use of the Line Feed as a line
+terminator is fairly standard throughout UseNet, and when a news
+message is converted to a FidoNet format message it is a simple matter
+to replace Line Feeds with Carriage Returns so that the message will
+display properly.
+
+d. When constructing or adding to "Path" lines, RFC-1036 (section
+2.1.6) states that "The names may be separated by any punctuation
+character or characters (except '.' which is considered part of the
+hostname)."  However, in actual practice, only the "!" (exclamation
+point or "bang" character) is commonly used to separate names.
+Therefore, the "!" character will be considered the "standard"
+separator for system names in Path lines in messages generated in
+FidoNet.  Also, RFC-1036 states that "Normally, the rightmost name will
+be the name of the originating system.  However, it is also permissible
+to include an extra entry on the right, which is the name of the
+sender.  This is for upward compatibility with older systems." In
+actual practice, it appears that most Path lines originating in UseNet
+have a user name as the rightmost entry.  Therefore, when a Path line
+is created for a message originating in FidoNet, it is suggested that
+the following format be used (assuming a message entered by user John
+Smith at node 1:123/456):
+
+     Path: f456.n123.z1.fidonet.org!john.smith
+
+When a user name is placed in the path, all spaces in the user name
+must be replaced with periods, and all uppercase characters in the name
+should be converted to lowercase.  It is permissible to use an alias in
+place of a user's real name if the originating system runs software
+that will recognize that alias in incoming netmail messages, and remap
+such messages to the proper user if necessary.  Also, note the
+restrictions on prohibited characters in the user name as specified in
+RFC-1036 section 2.1.1.  Although section 2.1.1. deals with the "From"
+line, common sense would indicate that these same restrictions on
+prohibited characters should apply if the user name is placed in the
+Path line (with the obvious exception of the use of the period to
+replace spaces in the user name, which is required).
+
+e. Header lines defined as "optional" may be more or less optional
+depending on the keyword.  For example, the "Reply-To" and
+"Followup-To" lines should be automatically honored, if at all
+possible, when reply messages are created, and the "References" line,
+even though listed as an "optional" line, is "required for all
+follow-up messages" (replies).  On the other hand, lines such as
+"Control" and "Distribution" may have little meaning to FidoNet nodes
+(in particular, "Distribution" is meant to control distribution of a
+message along hierarchial lines, but since FidoNet topology has little
+relation to UseNet hierarchies, it is probably best to just ignore
+"Distribution" lines on in-transit messages).
+
+Additional specifications for messages, including required and optional
+header lines, are detailed in section 2 of RFC-1036.
+
+When a newsgroup is moderated, it is the responsibility of the sysop of
+each participating BBS to prevent users from entering messages in that
+area (unless the message exporting software is capable of sending any
+locally-entered messages to the conference moderator via MAIL).
+However, if a software newsgroup processor is written that both imports
+(tosses) messages to a FidoNet-format message base, and exports locally
+entered messages, and if the software does not have a way to send
+replies to the moderator via mail, then some mechanism must be provided
+to prevent the export of messages from a moderated area, so that in the
+unlikely event that there is no easy way to prevent users from posting
+messages in the moderated area, such messages will still not be sent
+out.  Since this standard does not deal with the transport of UseNet
+MAIL within FidoNet, the method for transmission of replies in
+moderated newsgroups is undefined by this document.  However, software
+authors are encouraged to provide some mechanism for private mail
+replies to newsgroup messages, in both moderated and unmoderated areas.
+
+Note that if a moderated newsgroup is carried on a system, it is the
+responsibility of the sysop to provide mail access to users so that
+replies can be (manually) sent to the conference moderator, especially
+if replies in the newsgroup area cannot be automatically routed to the
+conference moderator.
+
+One point that needs to be emphasized is there is NO message length
+limit on UseNet messages.  If a FidoNet node passes newsgroup messages
+to, or on behalf of other FidoNet nodes, it is NOT permissible to
+discard or truncate messages that exceed a preset length limit.  Note
+that in a batched newsgroup file, each message is preceded by a header
+of the form "#! rnews ".  Since the message text
+length is never changed in processing, it is possible to determine the
+length of a message after processing by reading in all the header
+lines, calculating the combined length of the header lines prior to
+making changes in the header (e.g. the Path line), then calculating the
+combined length of the header lines after making changes.  The
+difference between the original and the new length of the header lines
+can then be applied to the value given in the "#! rnews" line to
+determine the new message length, when is then used in the "#! rnews"
+header of the modified message.  Also, the number of bytes given in the
+"#! rnews" line, MINUS the length of the message header lines, is the
+length of the body of the message.  Once this length is known, the body
+of the message can be copied from the input file to the output file(s)
+in "chunks" small enough to fit in memory, until the end of the message
+is reached.
+
+The following comments are implementation suggestions applicable to
+current FidoNet-compatible BBS systems, though not necessarily to
+software that may be written in the future:
+
+It should be noted that when a BBS user enters a reply message, most
+FidoNet BBS software will "link" the reply message to the original by
+placing the message number of the original message in the message
+header (this is almost always the case if messages are stored in the
+"*.msg" format, in which case the number of the message being replied
+to is found at bytes 185-186 in the message header).  If the
+appropriate header lines have been stored in the text of the original
+message, it is possible to construct a reply message that meets all
+RFC-1036 specifications.  For example, a "References" line can be
+constructed from the "Message-ID" line (and the "References" line, if
+any) of the original message.  Similarly, if the original message
+contains a "Followup-To:" line, the reply can be posted to the
+newsgroup(s) specified in that line.  This may not work as expected if
+a message renumbering program or similar program messes with the
+message base before reply message is exported, so it is highly
+recommended that locally-entered newsgroup messages be exported as soon
+as practicable after they are entered.
+
+Since the user of a BBS may reply to a message entered by another user
+of the same BBS, it is recommended that when a message is exported, any
+UseNet format header lines created for the exported message also be
+written back to the original message if possible.  This will permit
+reply linking to remain intact even if two or more users of the same
+BBS participate in the same message thread.
+
+If a message is received that specifies more than one newsgroup in the
+"Newsgroups" header line, and corresponding message areas are available
+on the local system, one copy of the message should be placed in each
+such area.  For example, if the message is posted to four different
+newsgroups, and two of those groups are carried on the local BBS, then
+a copy of the message should be placed in the message base for each of
+those groups.  If users of a BBS are allowed to post a message to
+multiple newsgroups, then any message thus posted should be copied to
+the message bases of any of the other areas that are also carried on
+that system (and that the message was posted to) at the time the
+message is exported.
+
+Corrections and Additions to this document:
+
+Proposed corrections and additions to this document should be submitted
+to Jack Decker at 1:154/8, or jack.decker@f8.n154.z1.fidonet.org
+
+ +
+ +
+Network Working Group                                          M. Horton
+Request for Comments:  1036                       AT&T Bell Laboratories
+Obsoletes: RFC-850                                              R. Adams
+                                              Center for Seismic Studies
+                                                           December 1987
+
+
+              Standard for Interchange of USENET Messages
+
+
+
+STATUS OF THIS MEMO
+
+    This document defines the standard format for the interchange of
+    network News messages among USENET hosts.  It updates and replaces
+    RFC-850, reflecting version B2.11 of the News program.  This memo is
+    disributed as an RFC to make this information easily accessible to
+    the Internet community.  It does not specify an Internet standard.
+    Distribution of this memo is unlimited.
+
+1.  Introduction
+
+    This document defines the standard format for the interchange of
+    network News messages among USENET hosts.  It describes the format
+    for messages themselves and gives partial standards for transmission
+    of news.  The news transmission is not entirely in order to give a
+    good deal of flexibility to the hosts to choose transmission
+    hardware and software, to batch news, and so on.
+
+    There are five sections to this document.  Section two defines the
+    format.  Section three defines the valid control messages.  Section
+    four specifies some valid transmission methods.  Section five
+    describes the overall news propagation algorithm.
+
+2.  Message Format
+
+    The primary consideration in choosing a message format is that it
+    fit in with existing tools as well as possible.  Existing tools
+    include implementations of both mail and news.  (The notesfiles
+    system from the University of Illinois is considered a news
+    implementation.)  A standard format for mail messages has existed
+    for many years on the Internet, and this format meets most of the
+    needs of USENET.  Since the Internet format is extensible,
+    extensions to meet the additional needs of USENET are easily made
+    within the Internet standard.  Therefore, the rule is adopted that
+    all USENET news messages must be formatted as valid Internet mail
+    messages, according to the Internet standard RFC-822.  The USENET
+    News standard is more restrictive than the Internet standard,
+
+
+
+Horton & Adams                                                  [Page 1]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    placing additional requirements on each message and forbidding use
+    of certain Internet features.  However, it should always be possible
+    to use a tool expecting an Internet message to process a news
+    message.  In any situation where this standard conflicts with the
+    Internet standard, RFC-822 should be considered correct and this
+    standard in error.
+
+    Here is an example USENET message to illustrate the fields.
+
+              From: jerry@eagle.ATT.COM (Jerry Schwarz)
+              Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+              Newsgroups: news.announce
+              Subject: Usenet Etiquette -- Please Read
+              Message-ID: <642@eagle.ATT.COM>
+              Date: Fri, 19 Nov 82 16:14:55 GMT
+              Followup-To: news.misc
+              Expires: Sat, 1 Jan 83 00:00:00 -0500
+              Organization: AT&T Bell Laboratories, Murray Hill
+
+              The body of the message comes here, after a blank line.
+
+      Here is an example of a message in the old format (before the
+      existence of this standard). It is recommended that
+      implementations also accept messages in this format to ease upward
+      conversion.
+
+               From: cbosgd!mhuxj!mhuxt!eagle!jerry (Jerry Schwarz)
+               Newsgroups: news.misc
+               Title: Usenet Etiquette -- Please Read
+               Article-I.D.: eagle.642
+               Posted: Fri Nov 19 16:14:55 1982
+               Received: Fri Nov 19 16:59:30 1982
+               Expires: Mon Jan 1 00:00:00 1990
+
+               The body of the message comes here, after a blank line.
+
+      Some news systems transmit news in the A format, which looks like
+      this:
+
+                Aeagle.642
+                news.misc
+                cbosgd!mhuxj!mhuxt!eagle!jerry
+                Fri Nov 19 16:14:55 1982
+                Usenet Etiquette - Please Read
+                The body of the message comes here, with no blank line.
+
+    A standard USENET message consists of several header lines, followed
+    by a blank line, followed by the body of the message.  Each header
+
+
+
+Horton & Adams                                                  [Page 2]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    line consist of a keyword, a colon, a blank, and some additional
+    information.  This is a subset of the Internet standard, simplified
+    to allow simpler software to handle it.  The "From" line may
+    optionally include a full name, in the format above, or use the
+    Internet angle bracket syntax.  To keep the implementations simple,
+    other formats (for example, with part of the machine address after
+    the close parenthesis) are not allowed.  The Internet convention of
+    continuation header lines (beginning with a blank or tab) is
+    allowed.
+
+    Certain headers are required, and certain other headers are
+    optional.  Any unrecognized headers are allowed, and will be passed
+    through unchanged.  The required header lines are "From", "Date",
+    "Newsgroups", "Subject", "Message-ID", and "Path".  The optional
+    header lines are "Followup-To", "Expires", "Reply-To", "Sender",
+    "References", "Control", "Distribution", "Keywords", "Summary",
+    "Approved", "Lines", "Xref", and "Organization".  Each of these
+    header lines will be described below.
+
+2.1.  Required Header lines
+
+2.1.1.  From
+
+    The "From" line contains the electronic mailing address of the
+    person who sent the message, in the Internet syntax.  It may
+    optionally also contain the full name of the person, in parentheses,
+    after the electronic address.  The electronic address is the same as
+    the entity responsible for originating the message, unless the
+    "Sender" header is present, in which case the "From" header might
+    not be verified.  Note that in all host and domain names, upper and
+    lower case are considered the same, thus "mark@cbosgd.ATT.COM",
+    "mark@cbosgd.att.com", and "mark@CBosgD.ATt.COm" are all equivalent.
+    User names may or may not be case sensitive, for example,
+    "Billy@cbosgd.ATT.COM" might be different from
+    "BillY@cbosgd.ATT.COM".  Programs should avoid changing the case of
+    electronic addresses when forwarding news or mail.
+
+    RFC-822 specifies that all text in parentheses is to be interpreted
+    as a comment.  It is common in Internet mail to place the full name
+    of the user in a comment at the end of the "From" line.  This
+    standard specifies a more rigid syntax.  The full name is not
+    considered a comment, but an optional part of the header line.
+    Either the full name is omitted, or it appears in parentheses after
+    the electronic address of the person posting the message, or it
+    appears before an electronic address which is enclosed in angle
+    brackets.  Thus, the three permissible forms are:
+
+
+
+
+
+Horton & Adams                                                  [Page 3]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+              From: mark@cbosgd.ATT.COM
+              From: mark@cbosgd.ATT.COM (Mark Horton)
+              From: Mark Horton 
+
+    Full names may contain any printing ASCII characters from space
+    through tilde, except that they may not contain "(" (left
+    parenthesis), ")" (right parenthesis), "<" (left angle bracket), or
+    ">" (right angle bracket).  Additional restrictions may be placed on
+    full names by the mail standard, in particular, the characters ","
+    (comma), ":" (colon), "@" (at), "!" (bang), "/" (slash), "="
+    (equal), and ";" (semicolon) are inadvisable in full names.
+
+2.1.2.  Date
+
+    The "Date" line (formerly "Posted") is the date that the message was
+    originally posted to the network.  Its format must be acceptable
+    both in RFC-822 and to the getdate(3) routine that is provided with
+    the Usenet software.  This date remains unchanged as the message is
+    propagated throughout the network.  One format that is acceptable to
+    both is:
+
+                      Wdy, DD Mon YY HH:MM:SS TIMEZONE
+
+    Several examples of valid dates appear in the sample message above.
+    Note in particular that ctime(3) format:
+
+                          Wdy Mon DD HH:MM:SS YYYY
+
+    is not acceptable because it is not a valid RFC-822 date.  However,
+    since older software still generates this format, news
+    implementations are encouraged to accept this format and translate
+    it into an acceptable format.
+
+    There is no hope of having a complete list of timezones.  Universal
+    Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST,
+    CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be
+    supported.  It is recommended that times in message headers be
+    transmitted in GMT and displayed in the local time zone.
+
+2.1.3.  Newsgroups
+
+    The "Newsgroups" line specifies the newsgroup or newsgroups in which
+    the message belongs.  Multiple newsgroups may be specified,
+    separated by a comma.  Newsgroups specified must all be the names of
+    existing newsgroups, as no new newsgroups will be created by simply
+    posting to them.
+
+
+
+
+
+Horton & Adams                                                  [Page 4]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    Wildcards (e.g., the word "all") are never allowed in a "News-
+    groups" line.  For example, a newsgroup comp.all is illegal,
+    although a newsgroup rec.sport.football is permitted.
+
+    If a message is received with a "Newsgroups" line listing some valid
+    newsgroups and some invalid newsgroups, a host should not remove
+    invalid newsgroups from the list.  Instead, the invalid newsgroups
+    should be ignored.  For example, suppose host A subscribes to the
+    classes btl.all and comp.all, and exchanges news messages with host
+    B, which subscribes to comp.all but not btl.all.  Suppose A receives
+    a message with Newsgroups: comp.unix,btl.general.
+
+    This message is passed on to B because B receives comp.unix, but B
+    does not receive btl.general.  A must leave the "Newsgroups" line
+    unchanged.  If it were to remove btl.general, the edited header
+    could eventually re-enter the btl.all class, resulting in a message
+    that is not shown to users subscribing to btl.general.  Also,
+    follow-ups from outside btl.all would not be shown to such users.
+
+2.1.4.  Subject
+
+    The "Subject" line (formerly "Title") tells what the message is
+    about.  It should be suggestive enough of the contents of the
+    message to enable a reader to make a decision whether to read the
+    message based on the subject alone.  If the message is submitted in
+    response to another message (e.g., is a follow-up) the default
+    subject should begin with the four characters "Re:", and the
+    "References" line is required.  For follow-ups, the use of the
+    "Summary" line is encouraged.
+
+2.1.5.  Message-ID
+
+    The "Message-ID" line gives the message a unique identifier.  The
+    Message-ID may not be reused during the lifetime of any previous
+    message with the same Message-ID.  (It is recommended that no
+    Message-ID be reused for at least two years.)  Message-ID's have the
+    syntax:
+
+                     ">
+
+    In order to conform to RFC-822, the Message-ID must have the format:
+
+                          
+
+    where full_domain_name is the full name of the host at which the
+    message entered the network, including a domain that host is in, and
+    unique is any string of printing ASCII characters, not including "<"
+    (left angle bracket), ">" (right angle bracket), or "@" (at sign).
+
+
+
+Horton & Adams                                                  [Page 5]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    For example, the unique part could be an integer representing a
+    sequence number for messages submitted to the network, or a short
+    string derived from the date and time the message was created.  For
+    example, a valid Message-ID for a message submitted from host ucbvax
+    in domain "Berkeley.EDU" would be "<4123@ucbvax.Berkeley.EDU>".
+    Programmers are urged not to make assumptions about the content of
+    Message-ID fields from other hosts, but to treat them as unknown
+    character strings.  It is not safe, for example, to assume that a
+    Message-ID will be under 14 characters, that it is unique in the
+    first 14 characters, nor that is does not contain a "/".
+
+    The angle brackets are considered part of the Message-ID.  Thus, in
+    references to the Message-ID, such as the ihave/sendme and cancel
+    control messages, the angle brackets are included.  White space
+    characters (e.g., blank and tab) are not allowed in a Message-ID.
+    Slashes ("/") are strongly discouraged.  All characters between the
+    angle brackets must be printing ASCII characters.
+
+2.1.6.  Path
+
+    This line shows the path the message took to reach the current
+    system.  When a system forwards the message, it should add its own
+    name to the list of systems in the "Path" line.  The names may be
+    separated by any punctuation character or characters (except "."
+    which is considered part of the hostname).  Thus, the following are
+    valid entries:
+
+                   cbosgd!mhuxj!mhuxt
+                   cbosgd, mhuxj, mhuxt
+                   @cbosgd.ATT.COM,@mhuxj.ATT.COM,@mhuxt.ATT.COM
+                   teklabs, zehntel, sri-unix@cca!decvax
+
+    (The latter path indicates a message that passed through decvax,
+    cca, sri-unix, zehntel, and teklabs, in that order.) Additional
+    names should be added from the left.  For example, the most recently
+    added name in the fourth example was teklabs.  Letters, digits,
+    periods and hyphens are considered part of host names; other
+    punctuation, including blanks, are considered separators.
+
+    Normally, the rightmost name will be the name of the originating
+    system.  However, it is also permissible to include an extra entry
+    on the right, which is the name of the sender.  This is for upward
+    compatibility with older systems.
+
+    The "Path" line is not used for replies, and should not be taken as
+    a mailing address.  It is intended to show the route the message
+    traveled to reach the local host.  There are several uses for this
+    information.  One is to monitor USENET routing for performance
+
+
+
+Horton & Adams                                                  [Page 6]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    reasons.  Another is to establish a path to reach new hosts.
+    Perhaps the most important use is to cut down on redundant USENET
+    traffic by failing to forward a message to a host that is known to
+    have already received it.  In particular, when host A sends a
+    message to host B, the "Path" line includes A, so that host B will
+    not immediately send the message back to host A.  The name each host
+    uses to identify itself should be the same as the name by which its
+    neighbors know it, in order to make this optimization possible.
+
+    A host adds its own name to the front of a path when it receives a
+    message from another host.  Thus, if a message with path "A!X!Y!Z"
+    is passed from host A to host B, B will add its own name to the path
+    when it receives the message from A, e.g., "B!A!X!Y!Z".  If B then
+    passes the message on to C, the message sent to C will contain the
+    path "B!A!X!Y!Z", and when C receives it, C will change it to
+    "C!B!A!X!Y!Z".
+
+    Special upward compatibility note:  Since the "From", "Sender", and
+    "Reply-To" lines are in Internet format, and since many USENET hosts
+    do not yet have mailers capable of understanding Internet format, it
+    would break the reply capability to completely sever the connection
+    between the "Path" header and the reply function.  It is recognized
+    that the path is not always a valid reply string in older
+    implementations, and no requirement to fix this problem is placed on
+    implementations.  However, the existing convention of placing the
+    host name and an "!"  at the front of the path, and of starting the
+    path with the host name, an "!", and the user name, should be
+    maintained when possible.
+
+2.2.  Optional Headers
+
+2.2.1.  Reply-To
+
+    This line has the same format as "From".  If present, mailed replies
+    to the author should be sent to the name given here.  Otherwise,
+    replies are mailed to the name on the "From" line. (This does not
+    prevent additional copies from being sent to recipients named by the
+    replier, or on "To" or "Cc" lines.)  The full name may be optionally
+    given, in parentheses, as in the "From" line.
+
+2.2.2.  Sender
+
+    This field is present only if the submitter manually enters a "From"
+    line.  It is intended to record the entity responsible for
+    submitting the message to the network.  It should be verified by the
+    software at the submitting host.
+
+
+
+
+
+Horton & Adams                                                  [Page 7]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    For example, if John Smith is visiting CCA and wishes to post a
+    message to the network, using friend Sarah Jones' account, the
+    message might read:
+
+              From: smith@ucbvax.Berkeley.EDU (John Smith)
+              Sender: jones@cca.COM (Sarah Jones)
+
+    If a gateway program enters a mail message into the network at host
+    unix.SRI.COM, the lines might read:
+
+              From: John.Doe@A.CS.CMU.EDU
+              Sender: network@unix.SRI.COM
+
+    The primary purpose of this field is to be able to track down
+    messages to determine how they were entered into the network.  The
+    full name may be optionally given, in parentheses, as in the "From"
+    line.
+
+2.2.3.  Followup-To
+
+    This line has the same format as "Newsgroups".  If present, follow-
+    up messages are to be posted to the newsgroup or newsgroups listed
+    here.  If this line is not present, follow-ups are posted to the
+    newsgroup or newsgroups listed in the "Newsgroups" line.
+
+    If the keyword poster is present, follow-up messages are not
+    permitted.  The message should be mailed to the submitter of the
+    message via mail.
+
+2.2.4.  Expires
+
+    This line, if present, is in a legal USENET date format.  It
+    specifies a suggested expiration date for the message.  If not
+    present, the local default expiration date is used.  This field is
+    intended to be used to clean up messages with a limited usefulness,
+    or to keep important messages around for longer than usual.  For
+    example, a message announcing an upcoming seminar could have an
+    expiration date the day after the seminar, since the message is not
+    useful after the seminar is over.  Since local hosts have local
+    policies for expiration of news (depending on available disk space,
+    for instance), users are discouraged from providing expiration dates
+    for messages unless there is a natural expiration date associated
+    with the topic.  System software should almost never provide a
+    default "Expires" line.  Leave it out and allow local policies to be
+    used unless there is a good reason not to.
+
+
+
+
+
+
+Horton & Adams                                                  [Page 8]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+2.2.5.  References
+
+    This field lists the Message-ID's of any messages prompting the
+    submission of this message.  It is required for all follow-up
+    messages, and forbidden when a new subject is raised.
+    Implementations should provide a follow-up command, which allows a
+    user to post a follow-up message.  This command should generate a
+    "Subject" line which is the same as the original message, except
+    that if the original subject does not begin with "Re:" or "re:", the
+    four characters "Re:" are inserted before the subject.  If there is
+    no "References" line on the original header, the "References" line
+    should contain the Message-ID of the original message (including the
+    angle brackets).  If the original message does have a "References"
+    line, the follow-up message should have a "References" line
+    containing the text of the original "References" line, a blank, and
+    the Message-ID of the original message.
+
+    The purpose of the "References" header is to allow messages to be
+    grouped into conversations by the user interface program.  This
+    allows conversations within a newsgroup to be kept together, and
+    potentially users might shut off entire conversations without
+    unsubscribing to a newsgroup.  User interfaces need not make use of
+    this header, but all automatically generated follow-ups should
+    generate the "References" line for the benefit of systems that do
+    use it, and manually generated follow-ups (e.g., typed in well after
+    the original message has been printed by the machine) should be
+    encouraged to include them as well.
+
+    It is permissible to not include the entire previous "References"
+    line if it is too long.  An attempt should be made to include a
+    reasonable number of backwards references.
+
+2.2.6.  Control
+
+    If a message contains a "Control" line, the message is a control
+    message.  Control messages are used for communication among USENET
+    host machines, not to be read by users.  Control messages are
+    distributed by the same newsgroup mechanism as ordinary messages.
+    The body of the "Control" header line is the message to the host.
+
+    For upward compatibility, messages that match the newsgroup pattern
+    "all.all.ctl" should also be interpreted as control messages.  If no
+    "Control" header is present on such messages, the subject is used as
+    the control message.  However, messages on newsgroups matching this
+    pattern do not conform to this standard.
+
+
+
+
+
+
+Horton & Adams                                                  [Page 9]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    Also for upward compatibility, if the first 4 characters of the
+    "Subject:" line are "cmsg", the rest of the "Subject:" line should
+    be interpreted as a control message.
+
+2.2.7.  Distribution
+
+    This line is used to alter the distribution scope of the message.
+    It is a comma separated list similar to the "Newsgroups" line.  User
+    subscriptions are still controlled by "Newsgroups", but the message
+    is sent to all systems subscribing to the newsgroups on the
+    "Distribution" line in addition to the "Newsgroups" line.  For the
+    message to be transmitted, the receiving site must normally receive
+    one of the specified newsgroups AND must receive one of the
+    specified distributions.  Thus, a message concerning a car for sale
+    in New Jersey might have headers including:
+
+                   Newsgroups: rec.auto,misc.forsale
+                   Distribution: nj,ny
+
+    so that it would only go to persons subscribing to rec.auto or misc.
+    for sale within New Jersey or New York.  The intent of this header
+    is to restrict the distribution of a newsgroup further, not to
+    increase it.  A local newsgroup, such as nj.crazy-eddie, will
+    probably not be propagated by hosts outside New Jersey that do not
+    show such a newsgroup as valid.  A follow-up message should default
+    to the same "Distribution" line as the original message, but the
+    user can change it to a more limited one, or escalate the
+    distribution if it was originally restricted and a more widely
+    distributed reply is appropriate.
+
+2.2.8.  Organization
+
+    The text of this line is a short phrase describing the organization
+    to which the sender belongs, or to which the machine belongs.  The
+    intent of this line is to help identify the person posting the
+    message, since host names are often cryptic enough to make it hard
+    to recognize the organization by the electronic address.
+
+2.2.9.  Keywords
+
+    A few well-selected keywords identifying the message should be on
+    this line.  This is used as an aid in determining if this message is
+    interesting to the reader.
+
+2.2.10.  Summary
+
+    This line should contain a brief summary of the message.  It is
+    usually used as part of a follow-up to another message.  Again, it
+
+
+
+Horton & Adams                                                 [Page 10]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    is very useful to the reader in determining whether to read the
+    message.
+
+2.2.11.  Approved
+
+    This line is required for any message posted to a moderated
+    newsgroup.  It should be added by the moderator and consist of his
+    mail address.  It is also required with certain control messages.
+
+2.2.12.  Lines
+
+    This contains a count of the number of lines in the body of the
+    message.
+
+2.2.13.  Xref
+
+    This line contains the name of the host (with domains omitted) and a
+    white space separated list of colon-separated pairs of newsgroup
+    names and message numbers.  These are the newsgroups listed in the
+    "Newsgroups" line and the corresponding message numbers from the
+    spool directory.
+
+    This is only of value to the local system, so it should not be
+    transmitted.  For example, in:
+
+               Path: seismo!lll-crg!lll-lcc!pyramid!decwrl!reid
+               From: reid@decwrl.DEC.COM (Brian Reid)
+               Newsgroups: news.lists,news.groups
+               Subject: USENET READERSHIP SUMMARY REPORT FOR SEP 86
+               Message-ID: <5658@decwrl.DEC.COM>
+               Date: 1 Oct 86 11:26:15 GMT
+               Organization: DEC Western Research Laboratory
+               Lines: 441
+               Approved: reid@decwrl.UUCP
+               Xref: seismo news.lists:461 news.groups:6378
+
+    the "Xref" line shows that the message is message number 461 in the
+    newsgroup news.lists, and message number 6378 in the newsgroup
+    news.groups, on host seismo.  This information may be used by
+    certain user interfaces.
+
+3.  Control Messages
+
+    This section lists the control messages currently defined.  The body
+    of the "Control" header line is the control message.  Messages are a
+    sequence of zero or more words, separated by white space (blanks or
+    tabs).  The first word is the name of the control message, remaining
+    words are parameters to the message.  The remainder of the header
+
+
+
+Horton & Adams                                                 [Page 11]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    and the body of the message are also potential parameters; for
+    example, the "From" line might suggest an address to which a
+    response is to be mailed.
+
+    Implementors and administrators may choose to allow control messages
+    to be carried out automatically, or to queue them for annual
+    processing.  However, manually processed messages should be dealt
+    with promptly.
+
+    Failed control messages should NOT be mailed to the originator of
+    the message, but to the local "usenet" account.
+
+3.1.  Cancel
+
+                     cancel 
+
+
+    If a message with the given Message-ID is present on the local
+    system, the message is cancelled.  This mechanism allows a user to
+    cancel a message after the message has been distributed over the
+    network.
+
+    If the system is unable to cancel the message as requested, it
+    should not forward the cancellation request to its neighbor systems.
+
+    Only the author of the message or the local news administrator is
+    allowed to send this message.  The verified sender of a message is
+    the "Sender" line, or if no "Sender" line is present, the "From"
+    line.  The verified sender of the cancel message must be the same as
+    either the "Sender" or "From" field of the original message.  A
+    verified sender in the cancel message is allowed to match an
+    unverified "From" in the original message.
+
+3.2.  Ihave/Sendme
+
+                   ihave  []
+                   sendme  []
+
+    This message is part of the ihave/sendme protocol, which allows one
+    host (say A) to tell another host (B) that a particular message has
+    been received on A.  Suppose that host A receives message
+    "<1234@ucbvax.Berkeley.edu>", and wishes to transmit the message to
+    host B.
+
+    A sends the control message "ihave <1234@ucbvax.Berkeley.edu> A" to
+    host B (by posting it to newsgroup to.B).  B responds with the
+    control message "sendme <1234@ucbvax.Berkeley.edu> B" (on newsgroup
+    to.A), if it has not already received the message.  Upon receiving
+
+
+
+Horton & Adams                                                 [Page 12]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    the sendme message, A sends the message to B.
+
+    This protocol can be used to cut down on redundant traffic between
+    hosts.  It is optional and should be used only if the particular
+    situation makes it worthwhile.  Frequently, the outcome is that,
+    since most original messages are short, and since there is a high
+    overhead to start sending a new message with UUCP, it costs as much
+    to send the ihave as it would cost to send the message itself.
+
+    One possible solution to this overhead problem is to batch requests.
+    Several Message-ID's may be announced or requested in one message.
+    If no Message-ID's are listed in the control message, the body of
+    the message should be scanned for Message-ID's, one per line.
+
+3.3.  Newgroup
+
+                      newgroup  [moderated]
+
+    This control message creates a new newsgroup with the given name.
+    Since no messages may be posted or forwarded until a newsgroup is
+    created, this message is required before a newsgroup can be used.
+    The body of the message is expected to be a short paragraph
+    describing the intended use of the newsgroup.
+
+    If the second argument is present and it is the keyword moderated,
+    the group should be created moderated instead of the default of
+    unmoderated.  The newgroup message should be ignored unless there is
+    an "Approved" line in the same message header.
+
+3.4.  Rmgroup
+
+                            rmgroup 
+
+    This message removes a newsgroup with the given name.  Since the
+    newsgroup is removed from every host on the network, this command
+    should be used carefully by a responsible administrator.  The
+    rmgroup message should be ignored unless there is an "Approved:"
+    line in the same message header.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 13]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+3.5.  Sendsys
+                           sendsys (no arguments)
+
+    The sys file, listing all neighbors and the newsgroups to be sent to
+    each neighbor, will be mailed to the author of the control message
+    ("Reply-To", if present, otherwise "From").  This information is
+    considered public information, and it is a requirement of membership
+    in USENET that this information be provided on request, either
+    automatically in response to this control message, or manually, by
+    mailing the requested information to the author of the message.
+    This information is used to keep the map of USENET up to date, and
+    to determine where netnews is sent.
+
+    The format of the file mailed back to the author should be the same
+    as that of the sys file.  This format has one line per neighboring
+    host (plus one line for the local host), containing four colon
+    separated fields.  The first field has the host name of the
+    neighbor, the second field has a newsgroup pattern describing the
+    newsgroups sent to the neighbor.  The third and fourth fields are
+    not defined by this standard.  The sys file is not the same as the
+    UUCP L.sys file.  A sample response is:
+
+      From: cbosgd!mark  (Mark Horton)
+      Date: Sun, 27 Mar 83 20:39:37 -0500
+      Subject: response to your sendsys request
+      To: mark@cbosgd.ATT.COM
+
+      Responding-System: cbosgd.ATT.COM
+      cbosgd:osg,cb,btl,bell,world,comp,sci,rec,talk,misc,news,soc,to,
+            test
+      ucbvax:world,comp,to.ucbvax:L:
+      cbosg:world,comp,bell,btl,cb,osg,to.cbosg:F:/usr/spool/outnews
+            /cbosg
+      cbosgb:osg,to.cbosgb:F:/usr/spool/outnews/cbosgb
+      sescent:world,comp,bell,btl,cb,to.sescent:F:/usr/spool/outnews
+            /sescent
+      npois:world,comp,bell,btl,ug,to.npois:F:/usr/spool/outnews/npois
+      mhuxi:world,comp,bell,btl,ug,to.mhuxi:F:/usr/spool/outnews/mhuxi
+
+3.6.  Version
+
+                           version (no arguments)
+
+    The name and version of the software running on the local system is
+    to be mailed back to the author of the message ("Reply-to" if
+    present, otherwise "From").
+
+3.7.  Checkgroups
+
+
+
+Horton & Adams                                                 [Page 14]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    The message body is a list of "official" newsgroups and their
+    description, one group per line.  They are compared against the list
+    of active newsgroups on the current host.  The names of any obsolete
+    or new newsgroups are mailed to the user "usenet" and descriptions
+    of the new newsgroups are added to the help file used when posting
+    news.
+
+4.  Transmission Methods
+
+    USENET is not a physical network, but rather a logical network
+    resting on top of several existing physical networks.  These
+    networks include, but are not limited to, UUCP, the Internet, an
+    Ethernet, the BLICN network, an NSC Hyperchannel, and a BERKNET.
+    What is important is that two neighboring systems on USENET have
+    some method to get a new message, in the format listed here, from
+    one system to the other, and once on the receiving system, processed
+    by the netnews software on that system.  (On UNIX systems, this
+    usually means the rnews program being run with the message on the
+    standard input. <1>)
+
+    It is not a requirement that USENET hosts have mail systems capable
+    of understanding the Internet mail syntax, but it is strongly
+    recommended.  Since "From", "Reply-To", and "Sender" lines use the
+    Internet syntax, replies will be difficult or impossible without an
+    Internet mailer.  A host without an Internet mailer can attempt to
+    use the "Path" header line for replies, but this field is not
+    guaranteed to be a working path for replies.  In any event, any host
+    generating or forwarding news messages must have an Internet address
+    that allows them to receive mail from hosts with Internet mailers,
+    and they must include their Internet address on their From line.
+
+4.1.  Remote Execution
+
+    Some networks permit direct remote command execution.  On these
+    networks, news may be forwarded by spooling the rnews command with
+    the message on the standard input.  For example, if the remote
+    system is called remote, news would be sent over a UUCP link
+    with the command:
+
+                              uux - remote!rnews
+
+    and on a Berknet:
+
+                              net -mremote rnews
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 15]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    It is important that the message be sent via a reliable mechanism,
+    normally involving the possibility of spooling, rather than direct
+    real-time remote execution.  This is because, if the remote system
+    is down, a direct execution command will fail, and the message will
+    never be delivered.  If the message is spooled, it will eventually
+    be delivered when both systems are up.
+
+4.2.  Transfer by Mail
+
+    On some systems, direct remote spooled execution is not possible.
+    However, most systems support electronic mail, and a news message
+    can be sent as mail.  One approach is to send a mail message which
+    is identical to the news message: the mail headers are the news
+    headers, and the mail body is the news body.  By convention, this
+    mail is sent to the user newsmail on the remote machine.
+
+    One problem with this method is that it may not be possible to
+    convince the mail system that the "From" line of the message is
+    valid, since the mail message was generated by a program on a
+    system different from the source of the news message.  Another
+    problem is that error messages caused by the mail transmission
+    would be sent to the originator of the news message, who has no
+    control over news transmission between two cooperating hosts
+    and does not know whom to contact.  Transmission error messages
+    should be directed to a responsible contact person on the
+    sending machine.
+
+    A solution to this problem is to encapsulate the news message into a
+    mail message, such that the entire message (headers and body) are
+    part of the body of the mail message.  The convention here is that
+    such mail is sent to user rnews on the remote system.  A mail
+    message body is generated by prepending the letter N to each line of
+    the news message, and then attaching whatever mail headers are
+    convenient to generate.  The N's are attached to prevent any special
+    lines in the news message from interfering with mail transmission,
+    and to prevent any extra lines inserted by the mailer (headers,
+    blank lines, etc.) from becoming part of the news message.  A
+    program on the receiving machine receives mail to rnews, extracting
+    the message itself and invoking the rnews program.  An example in
+    this format might look like this:
+
+
+
+
+
+
+
+
+
+
+
+Horton & Adams                                                 [Page 16]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+                Date: Mon, 3 Jan 83 08:33:47 MST
+                From: news@cbosgd.ATT.COM
+                Subject: network news message
+                To: rnews@npois.ATT.COM
+
+                NPath: cbosgd!mhuxj!harpo!utah-cs!sask!derek
+                NFrom: derek@sask.UUCP (Derek Andrew)
+                NNewsgroups: misc.test
+                NSubject: necessary test
+                NMessage-ID: <176@sask.UUCP>
+                NDate: Mon, 3 Jan 83 00:59:15 MST
+                N
+                NThis really is a test.  If anyone out there more than 6
+                Nhops away would kindly confirm this note I would
+                Nappreciate it.  We suspect that our news postings
+                Nare not getting out into the world.
+                N
+
+    Using mail solves the spooling problem, since mail must always be
+    spooled if the destination host is down.  However, it adds more
+    overhead to the transmission process (to encapsulate and extract the
+    message) and makes it harder for software to give different
+    priorities to news and mail.
+
+4.3.  Batching
+
+    Since news messages are usually short, and since a large number of
+    messages are often sent between two hosts in a day, it may make
+    sense to batch news messages.  Several messages can be combined into
+    one large message, using conventions agreed upon in advance by the
+    two hosts.  One such batching scheme is described here; its use is
+    highly recommended.
+
+    News messages are combined into a script, separated by a header of
+    the form:
+
+
+                   #! rnews 1234
+
+    where 1234 is the length of the message in bytes.  Each such line is
+    followed by a message containing the given number of bytes.  (The
+    newline at the end of each line of the message is counted as one
+    byte, for purposes of this count, even if it is stored as .)  For example, a batch of message might look
+    like this:
+
+
+
+
+
+
+Horton & Adams                                                 [Page 17]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+                #! rnews 239
+                From: jerry@eagle.ATT.COM (Jerry Schwarz)
+                Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+                Newsgroups: news.announce
+                Subject: Usenet Etiquette -- Please Read
+                Message-ID: <642@eagle.ATT.COM>
+                Date: Fri, 19 Nov 82 16:14:55 EST
+                Approved: mark@cbosgd.ATT.COM
+
+                Here is an important message about USENET Etiquette.
+                #! rnews 234
+                From: jerry@eagle.ATT.COM (Jerry Schwarz)
+                Path: cbosgd!mhuxj!mhuxt!eagle!jerry
+                Newsgroups: news.announce
+                Subject: Notes on Etiquette message
+                Message-ID: <643@eagle.ATT.COM>
+                Date: Fri, 19 Nov 82 17:24:12 EST
+                Approved: mark@cbosgd.ATT.COM
+
+                There was something I forgot to mention in the last
+                message.
+
+    Batched news is recognized because the first character in the
+    message is #.  The message is then passed to the unbatcher for
+    interpretation.
+
+    The second argument (in this example rnews) determines which
+    batching scheme is being used.  Cooperating hosts may use whatever
+    scheme is appropriate for them.
+
+5.  The News Propagation Algorithm
+
+    This section describes the overall scheme of USENET and the
+    algorithm followed by hosts in propagating news to the entire
+    logical network.  Since all hosts are affected by incorrectly
+    formatted messages and by propagation errors, it is important
+    for the method to be standardized.
+
+    USENET is a directed graph.  Each node in the graph is a host
+    computer, and each arc in the graph is a transmission path from
+    one host to another host.  Each arc is labeled with a newsgroup
+    pattern, specifying which newsgroup classes are forwarded along
+    that link.  Most arcs are bidirectional, that is, if host A
+    sends a class of newsgroups to host B, then host B usually sends
+    the same class of newsgroups to host A.  This bidirectionality
+    is not, however, required.
+
+    USENET is made up of many subnetworks.  Each subnet has a name, such
+
+
+
+Horton & Adams                                                 [Page 18]
+
+RFC 1036              Standard for USENET Messages         December 1987
+
+
+    as comp or btl.  Each subnet is a connected graph, that is, a path
+    exists from every node to every other node in the subnet.  In
+    addition, the entire graph is (theoretically) connected.  (In
+    practice, some political considerations have caused some hosts to be
+    unable to post messages reaching the rest of the network.)
+
+    A message is posted on one machine to a list of newsgroups. That
+    machine accepts it locally, then forwards it to all its neighbors
+    that are interested in at least one of the newsgroups of the
+    message.  (Site A deems host B to be "interested" in a newsgroup if
+    the newsgroup matches the pattern on the arc from A to B.  This
+    pattern is stored in a file on the A machine.)  The hosts receiving
+    the incoming message examine it to make sure they really want the
+    message, accept it locally, and then in turn forward the message to
+    all their interested neighbors.  This process continues until the
+    entire network has seen the message.
+
+    An important part of the algorithm is the prevention of loops.  The
+    above process would cause a message to loop along a cycle forever.
+    In particular, when host A sends a message to host B, host B will
+    send it back to host A, which will send it to host B, and so on.
+    One solution to this is the history mechanism.  Each host keeps
+    track of all messages it has seen (by their Message-ID) and
+    whenever a message comes in that it has already seen, the incoming
+    message is discarded immediately.  This solution is sufficient to
+    prevent loops, but additional optimizations can be made to avoid
+    sending messages to hosts that will simply throw them away.
+
+    One optimization is that a message should never be sent to a machine
+    listed in the "Path" line of the header.  When a machine name is
+    in the "Path" line, the message is known to have passed through the
+    machine.  Another optimization is that, if the message originated
+    on host A, then host A has already seen the message.  Thus, if a
+    message is posted to newsgroup misc.misc, it will match the pattern
+    misc.all (where all is a metasymbol that matches any string), and
+    will be forwarded to all hosts that subscribe to misc.all (as
+    determined by what their neighbors send them).  These hosts make up
+    the misc subnetwork.  A message posted to btl.general will reach all
+    hosts receiving btl.all, but will not reach hosts that do not get
+    btl.all.  In effect, the messages reaches the btl subnetwork.  A
+    messages posted to newsgroups misc.misc,btl.general will reach all
+    hosts subscribing to either of the two classes.
+
+Notes
+
+    <1>  UNIX is a registered trademark of AT&T.
+
+
+
+
+
+Horton & Adams                                                 [Page 19]
+
+Back Go Back + + + + diff --git a/html/ftsc/fsc-0062.html b/html/ftsc/fsc-0062.html new file mode 100755 index 00000000..aacd685a --- /dev/null +++ b/html/ftsc/fsc-0062.html @@ -0,0 +1,363 @@ + + +A Proposed Nodelist flag indicating Online Times of a Node. + + + + +
+ | Document: FSC-0062
+ | Version:  003
+ | Date:     April 14, 1996
+ | Author:   David J. Thomas
+
+
+
+
+	  A Proposed Nodelist flag indicating Online Times of a Node
+                               David J. Thomas
+                            2:442/600@fidonet.org
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+  Note
+  ----
+
+  Changes in content between the previous edition of this document, and this
+  edition, are signified by bars (|) in the left margin, except where
+  otherwise specified. I have changed the format of the document slightly to
+  allow this. Where the format of the document has changed, but the actual
+  text has not, bars are not present.
+
+  Purpose
+  -------
+
+  There are currently several systems within FidoNet that offer file request
+  or mail holding capabilities but are not continuously online. The only time
+  during which these nodes can be contacted with reference to the nodelist is
+  currently the Zone Mail Hour of the zone to which the systems belong. In
+  theory, mailers can only use the zone mail hour(s) specified by the system
+  in question to contact these nodes, which does not provide for any method
+  of file requesting or calling for echomail that does not conflict with the
+  Policy requirement that no echomail or files be transferred during the zone
+  mail hour. This means that, in practice, if it is known that a particular
+  node is online for more time than ZMH alone, but less than 24 hours a day,
+  it is necessary to "kludge," or set this up as a special situation, in most
+  mailers whenever a node has to be contacted a number of times, whether
+  regularly or irregularly. The proposed flag would benefit the mailers in
+  such a way as to provide for them the online times that the node is usually
+  online for, thus cutting on the costs of calling a non-continuous mail
+  node, only to find that it is not available; and also, hopefully preventing
+  annoyance for a sysop whose mailer is being called whilst it is not online,
+  for example in the case of a voice/data shared line.
+
+  Compatibility
+  -------------
+
+  Since the current nodelist format is always being extended and nodelist
+  processors look only for the flags that they know about, there are no
+  expected compatibility problems with the suggestion outlined below.
+
+  Format of additional nodelist flag
+  ----------------------------------
+
+  The proposed nodelist flag has the following form:
+
+    Txy
+
+  where x represents the startup time, and y the end time, in the following
+  format:
+
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+   |Letter|Time|  |Letter|Time|  |Letter|Time|  |Letter|Time|  |Letter|Time|
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+   |   A  |0000|  |   F  |0500|  |   K  |1000|  |   P  |1500|  |   U  |2000|
+   |   a  |0030|  |   f  |0530|  |   k  |1030|  |   p  |1530|  |   u  |2030|
+   |   B  |0100|  |   G  |0600|  |   L  |1100|  |   Q  |1600|  |   V  |2100|
+   |   b  |0130|  |   g  |0630|  |   l  |1130|  |   q  |1630|  |   v  |2130|
+   |   C  |0200|  |   H  |0700|  |   M  |1200|  |   R  |1700|  |   W  |2200|
+   |   c  |0230|  |   h  |0730|  |   m  |1230|  |   r  |1730|  |   w  |2230|
+   |   D  |0300|  |   I  |0800|  |   N  |1300|  |   S  |1800|  |   X  |2300|
+   |   d  |0330|  |   i  |0830|  |   n  |1330|  |   s  |1830|  |   x  |2330|
+   |   E  |0400|  |   J  |0900|  |   O  |1400|  |   T  |1900|  |      |    |
+   |   e  |0430|  |   j  |0930|  |   o  |1430|  |   t  |1930|  |      |    |
+   +------+----+  +------+----+  +------+----+  +------+----+  +------+----+
+
+| This flag is not intended to be a user flag. The flag is intended to provide
+| information to computerised mailer processes, and is not easily read by
+| human beings (although they can of course interpret the meaning of the
+| flag); most mailers however do not attempt to interpret any information that
+| is specified as a user flag, assuming that it is there for the benefit of
+| human beings. Such mailers would not be able to make use of the information
+| provided, which is the purpose of the flag.
+
+| This flag is of course not specified in FTS-0005 at the time of writing, but
+| this is not regarded by FidoNet as a problem because other flags in current
+| use are not specified in FTS-0005.
+
+  The case of the letter could be relevant. Whereas the case is currently not
+  used by any flags in the document describing the current format of the
+  nodelist, there exists the potential for the case of a letter to have
+  relevant meaning. The case has to be correct for the CRC check calculation
+  to prove correct, and this would be a good use for the case of the letter.
+  If it is necessary to ignore the case, then the upper on-the-hour time
+  should be used, i.e. the time that is listed after the upper-case letter.
+
+| These times are expressed in UTC so that the flag is useful for systems all
+  around the world, without the need for specific time zone information to be
+  included in the nodelist. They do not adjust with daylight saving time for a
+  similar reason. Note the section on daylight saving time for information
+  about handling adjustments without changing the flag; this is important.
+
+  Where necessary, the times can wrap around midnight, so for example, for a
+| node that is online between the hours of 1800 and 0600 UTC, the flag TSG
+  would be a valid indication of this time.
+
+  This nodelist entry is not required by any node. It is supplementary to the
+  #01, #02, #08, #09, #18, #20 flags and their !xx counterparts, though its
+  meaning is different. It has been suggested to me about the possibility of
+  an additional flag with the same meaning, but having a W as the first
+  letter, indicating that the node is also available for all hours during
+  weekends; however, I believe that the simple inclusion of the single flag
+  indicated above will solve most problems, as it does indicate a period for
+  non-CM nodes during which the node is available, which is all that is
+  really required.
+
+  Daylight saving time
+  --------------------
+
+  If a node changes online times with respect to UTC when daylight saving
+  time becomes effective (which would be the case with most part time nodes),
+  then this is to be taken into account when assigning this flag. An online
+  times flag assigned to a node should not be altered for the specific
+  purpose of adjusting due to daylight saving time, since large difference
+  files (NODEDIFF's) would result if every node was allowed to do this, e.g.
+  my node used to be online from 2300 to 0800 in local time, which in winter
+| is UTC, but in the summer it becomes BST (British Summer Time). This is one
+| hour ahead of UTC, and the corresponding availability times of my node
+| during the summer period were 2200 to 0700 UTC. Therefore my online times
+  flag would have indicated availability between the hours of 2300 and 0700
+| UTC, the daily time period encompassing both times, so the flag would be
+  TXH.
+
+  Policy considerations
+  ---------------------
+
+  This is a technical document. However, since the flag could make for an
+  increase in the size of difference files, the author feels that the
+  following guidelines should be adopted concerning the use of the flag.
+
+  The online times flag does not replace the requirement for exclusivity of
+  zone mail hour to be maintained. It is still annoying behaviour to have
+  this flag and be unavailable during ZMH, just as it is annoying behaviour
+  to have the CM (continuous mail) flag in one's entry, and disregard ZMH.
+
+  Except for during ZMH, the sysop of a node using this flag finding that
+  they need to take their mailer offline during the specified times to
+  perform system maintenance, or for any other reason, would not be acting in
+  an annoying manner to do so, unless the practice is found to be continuous,
+  in which case the flag's times could be reduced, or the flag itself could
+  be removed from their node entry.
+
+  It should be noted that this flag is present for the benefit of mailers,
+  not human beings. This means that the flag should be used only to indicate
+  when a mailer is ready to receive calls. A system that uses a FidoNet-
+  technology mailer in ZMH, and a human-access only system during other
+  period(s) of the day that cannot receive mail, should not use this flag.
+  This flag does not explicitly specify online times of a public access BBS,
+  although for presumably most nodes with FidoNet-capable software, a public
+  access BBS will be available during the times indicated.
+
+  Where the flag is used, it should not often be changed. If a situation
+  exists, for example, where a node uses a certain set of times during the
+  first two weeks of a month, and a different set of times during the
+  remainder period, the flag should be set to a time during each day of the
+  month when the node is online. For example, if a node is online during
+  1800-0800 for the first two weeks, and then during 2200-1000 for the
+  remainder, the time flag should specify 2200-0800 only. If there is no such
+  time (other than ZMH) then no flag should be used. Of course, any permanent
+  changes, and any necessary reductions in the times, should be permitted at
+  any time, but changes owing only to daylight saving time should certainly
+  be expressly forbidden.
+
+  File requests and user access are of course permitted during the online
+  times indicated (except ZMH).
+
+  The above list may seem rather frightening! Please note that they are
+  guidelines rather than rules, unless FidoNet policy has included them as
+  rules. In the vast majority of situations where a node is online for a
+  fixed set of hours per day, the only thing to watch out for is that you get
+  the daylight saving time period right. Then you don't have to worry about
+  changing it at any time, except when your own online times change.
+
+  Example
+  -------
+
+  With regard to time zones now; this is a complicated topic, so I wish to
+  express an example. Imagine a node in Indiana, USA. It is online for the
+  time period beginning 6 o'clock pm (1800) and ending 8 o'clock am (0800).
+  This changes with daylight saving time, so the times expressed effectively
+| become an hour earlier with respect to UTC during daylight saving time.
+
+| Indiana is in the Central time zone, which is 6 hours behind UTC. Therefore,
+| the online times in UTC can be expressed as 0000-1400 UTC during winter.
+| During daylight saving time, however, the local time for Indiana is 5 hours
+| behind UTC. The online times during this period are 0100-1500 UTC. The
+| subset should be used, so that the online times flag for the node should
+| indicate availability between 0100 and 1400 UTC, which is indicated
+| by the flag TBO.
+
+| (Thanks to a few people for pointing out that the previous example was in
+| error; it assumed that Indiana was ahead of UTC, and not behind as is
+| actually the case.)
+
+  ANSI C routines to Calculate the Online Times Flag
+  --------------------------------------------------
+
+  These were not provided in the first edition. Change bars will not be used
+  here, since they would interfere with the syntax of the presented routines.
+
+  The first program calculates the online times flag from the user's entry of
+  the online times of a system, expressed in the local time zone, and the
+  offset to UTC used by the user's country. It takes into account that the
+  clock is put forward and back once a year by reducing the end time by one
+  hour. The program should work on any platform, and has been tested.
+
+=== start of code ===
+/* TIMEFLAG.C
+   Calculates FSC-0062 time flag requirement from user input */
+
+#include 
+
+char *onlineflag(char *on, char *off, int utc_diff);
+
+void main()
+{
+   char on[6], off[6]; int utc_diff;
+
+   printf("\nPlease specify the time you come online [HH:MM]: ");
+   scanf("%s", on);
+   printf("\nPlease specify the time you come offline [HH:MM]: ");
+   scanf("%s", off);
+   printf("\nSpecify the difference between your local time zone in winter\n"
+      "time and UTC (e.g. if your time zone is 6 hours behind UTC,\n"
+      "enter 6): ");
+   scanf("%d", &utc_diff);
+   printf("\nYour online time flag is %s\n\n",
+      onlineflag(on, off, utc_diff));
+}
+
+char *onlineflag(char *ontime, char *offtime, int utcdiff)
+{
+   int onhour, onmin, offhour, offmin;
+   static char flag[4]="T  ";
+
+   sscanf(ontime, "%d:%d", &onhour, &onmin);
+   sscanf(offtime, "%d:%d", &offhour, &offmin);
+
+   if(onmin>30) ++onhour;
+   --offhour; /* to correct for daylight saving time */
+   onhour = (onhour+24+utcdiff) % 24;
+   offhour = (offhour+24+utcdiff) % 24;
+
+   flag[1]='A'+onhour;
+   flag[2]='A'+offhour;
+
+   if(onmin>0 && onmin<31) flag[1] += 'a'-'A';
+   if(offmin>29) flag[2] += 'a'-'A';
+
+   return flag;
+}
+=== end of code ===
+
+  The second program calculates the online times from the time flag, input
+  as a pointer to char to the routine (this being of the format "Txy"). It
+  returns a pointer to a structure which contains the on- and off-times in
+  UTC. This is not a complete program; it is designed to be used by mailers
+  to determine the valid online times. It has also been tested.
+
+=== start of code ===
+/* INTFLAG.C
+   Interprets online time flags and converts them to a set of UTC times */
+
+struct TIMES {
+   int on_hour;
+   int on_min;
+   int off_hour;
+   int off_min;
+};
+
+struct TIMES *interpret_flag(char *time_flag);
+
+struct TIMES *interpret_flag(char *timeflag)
+{
+   static struct TIMES times;
+
+   times.on_min=0;
+   times.off_min=0;
+
+   times.on_hour=timeflag[1]-'A';
+   if(times.on_hour>23) {
+      times.on_hour -= 'a'-'A';
+      times.on_min=30;
+   }
+   times.off_hour=timeflag[2]-'A';
+   if(times.off_hour>23) {
+      times.off_hour -= 'a'-'A';
+      times.off_min=30;
+   }
+   return ×
+}
+=== end of code ===
+
+| The above routines can be copied and re-used as desired. I am now an
+| amazing C programmer, but I still make no guarantees about them! :-)
+
+  Summary
+  -------
+
+  I believe this to be a neat and compact solution to, what is in my opinion,
+  one of the gravest problems currently facing FidoNet. In FidoNet, most
+  nodes are continuous mail, but it is important for the growth and
+  popularity of FidoNet that non-CM nodes do not receive many mailer calls at
+  times when they are off line. Users are bad enough in this respect. It is
+  also useful for people wishing to contact hubs that are non-CM with mail
+  for a downlink, and for people wishing to file request from a node that is
+  not CM. There is no need for systems that are only online in zone mail hour
+  to adopt this flag; also, there is no need for CM systems to adopt this
+  flag.
+
+  Contacting the Author
+  ---------------------
+
+  My board is now online continuously, except for periods of down time during
+| which the board is maintained (few and far between now that Linux is used).
+  Netmail contact is therefore possible at any time. I went CM because of a
+  certain number of nodes calling at the wrong times, and also users. Users
+  weren't too bad, but I dislike 0600 am wake-up calls, repeated at regular
+  three-minute intervals for an hour, by mailers, rather intensely :-)
+
+End of document.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0070.html b/html/ftsc/fsc-0070.html new file mode 100755 index 00000000..a21682a1 --- /dev/null +++ b/html/ftsc/fsc-0070.html @@ -0,0 +1,122 @@ + + +Improving FidoNet/UseNet gating and Dupe Checking. + + + + +
+Document:   FSC-0070
+Date:       15-Jul-94
+Revision:   002
+
+              Improving Fidonet/Usenet gating and Dupe Checking
+                              
+                    Franck Arnaud, Fidonet 2:320/213.666
+
+
+
+  Status of this document
+  -----------------------
+
+ This FSC suggests a proposed standard for the FidoNet(r) community,
+ and invites discussion and suggestions for improvements. Distribution of
+ this document is unlimited.
+
+ Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+   
+
+  Introduction
+  ------------
+
+ The complexity of Usenet/Fidonet gating and the large number of gateways
+ has led to a non-negligible quantity of duplicates appearing regularly in 
+ both the Usenet and Fidonet worlds. This proposal defines a standard method 
+ for gateway software to deal with conversion of message identifiers between 
+ both worlds, so that we can improve the reliability of Usenet/Fidonet 
+ gateways.
+
+ In this document "^" means  (character 01h).
+
+
+  History
+  -------
+
+ Revision 002 adds details and makes the Fidonet to Usenet sheme FTS-0009
+ compliant.
+
+
+  Usenet To Fidonet Message Identifier Conversion
+  -----------------------------------------------
+
+ A major problem is preventing messages gated into Fidonet from RFC822 from
+ being gated back to Usenet at another gateway with a new message id. The
+ easy way to solve that is simply to store the RFC message ID in a kludge 
+ line. This kludge line could also allow identifying messages gated from 
+ Usenet (this could be used by message editors to allow private replies to 
+ the nearest uucp gateway for example).
+
+ It is proposed that the ^RFCID: kludge is used to store the RFC Message-ID:
+ in Fidonet messages. Of course, the use of the RFCID kludge doesn't replace
+ the standard fts-0009 Message-ID:.
+
+       (Usenet)  Message-ID: <92_feb_10_19192012901@prep.ai.mit.edu>
+    to (Fido)    ^MSGID: 2:300/400.5 6789fedc
+                 ^RFCID: 92_feb_10_19192012901@prep.ai.mit.edu
+
+ Note ^RFCID does not include the Message-ID enclosing "<" and ">".
+
+ Then if a gateway finds a ^RFCID line in a Fido message, it will use it in
+ the Usenet message ID, instead of converting the ^MSGID.
+
+
+  Fidonet to Usenet Message Identifiers Conversion
+  ------------------------------------------------
+
+ The dupe checking in Usenet is based on the message ID. Fidonet now has its
+ own standard message identification standard (fts-0009).
+
+ So it would be interesting if the same Fidonet message gated at different
+ gateways had the same ID in Usenet to help news processing programs in
+ stopping dupes.
+
+ The proposed fido ^MSGID: to RFC1036 Message-ID: conversion method is 
+ defined as below:
+
+ The ^MSGID: value (a string) is not parsed and converted as below to the ID
+ part of Usenet's Message-ID. The Message-ID domain is the fidonet domain,
+ "fidonet.org" if the gated echomail comes from the Fidonet(tm) network.
+
+ To convert the MSGID string, the following rules are applied:
+ - Alphanumeric (a-z,A-Z,0-9) characters are kept intact (case preserved).
+ - Non-alphanumeric characters - including the space beetwen the origin
+   address and the serial number - are converted to '-'.
+
+ Some examples:
+
+    (Fido)   ^MSGID: 2:300/400 12345AbC
+ to (Usenet) Message-ID: <2-300-400-12345AbC@fidonet.org>
+
+    (Fido)   ^MSGID: 15:300/400.50@somenet abcd6789
+ to (Usenet) Message-ID: <15-300-400-50-somenet-abcd6789@fidonet.org>
+
+    (Fido)   ^MSGID: Internet.Domain.org aBcD1234
+ to (Usenet) Message-ID: 
+
+    (Fido)   ^MSGID: "LZKkoe$1982 98a" 45678bcd
+ to (Usenet) Message-ID: <-LZKkoe-1982-98a--45678bcd@fidonet.org>
+
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0072.html b/html/ftsc/fsc-0072.html new file mode 100755 index 00000000..aff543f1 --- /dev/null +++ b/html/ftsc/fsc-0072.html @@ -0,0 +1,1925 @@ + + +The HYDRA file transfer protocol. + + + + +
+Document: FSC-0072
+Version:  001
+Date:     21-Feb-1993
+
+
+
+
+                    The HYDRA file transfer protocol
+
+               Joaquim H. Homrighausen and Arjen G. Lentz
+
+
+
+
+Status of this document:
+
+     This FSC suggests a proposed protocol for the FidoNet(r) community,
+     and requests discussion and suggestions for improvements.
+     Distribution of this document is subject to the restrictions listed
+     below.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+
+
+    ---------------------------------------------------------------------
+     Copyright 1991-1993 Joaquim H. Homrighausen. All rights reserved.
+     Copyright 1991-1993 Lentz Software Development. All rights reserved.
+    ---------------------------------------------------------------------
+
+
+    Restrictions
+    =====================================================================
+    You are granted a license to implement the HYDRA file transfer
+    protocol, HYDRA hereafter, in your own programs and/or use the sample
+    source code and adapt these to your particular situation and needs;
+    subject to the following conditions:
+
+    o You must refer to it as the HYDRA file transfer protocol, and you
+      must give credit to the authors of HYDRA in any information screens
+      or literature pertaining to your programs that contains other such
+      information (credits, your own copyrights, etc.).
+
+    o HYDRA will always remain backwards compatible with previous
+      revisions. HYDRA allows for expansion of its features without
+      interfering with previous revisions. It is, however, important that
+      different people do not expand the protocol in different directions.
+      We therefore ask you to contact us if you have any needs/ideas
+      regarding HYDRA, so development can be synchronized and beneficial
+      to all.
+
+    o If your implementation cannot converse with past or future revisions
+      as supplied by us, then you must refer to it as "HYDRA derived", or
+      as "a variation of HYDRA", or words to that effect.
+
+    Permission is hereby granted to the FTSC (FidoNet Technical Standards
+    Committee) and other technical organisations to republish this
+    document in its entirety. Librarians may change the title page and
+    page headers to match their library format as long as all copyrights
+    and body text remain unaltered. The original document name and source
+    must be mentioned in any republished versions of this document.
+
+    No organization, company, person, or other being may impose any fees
+    for any reason for providing this document. This document may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+
+    Disclaimer
+    =====================================================================
+    This information is provided "as is" and comes with no warranties of
+    any kind, either expressed or implied. There is no support available
+    for this package. It's intended to be used by programmers and
+    developers.
+
+    In no event shall the authors be liable to you or anyone else for any
+    damages, including any lost profits, lost savings or other incidental
+    or consequential damages arising out of the use or inability to use
+    this information.
+
+
+    Revision timestamps
+    =====================================================================
+    001                           0x2b1aab00                 Dec 01, 1992
+
+
+    Introduction
+    =====================================================================
+    This document will not attempt to convince the reader that HYDRA is
+    of value to him/her or that it is better than other file transfer
+    protocols, it will simply describe the protocol. Just to get it out
+    of the way, HYDRA is not the ultimate file transfer protocol.
+
+    The authors do, however, feel that it offers an significant
+    improvement over those file transfer protocols available today. HYDRA
+    is a bi-directional protocol with the ability to receive and send
+    files simultaneously. There are other bi-directional file transfer
+    protocols, but to the authors' knowledge no public specifications
+    exist.
+
+    HYDRA owes much to Zmodem and its designer, Chuck Forsberg as well as
+    to Janus, designed by Rick Huebner. We would like to think of HYDRA
+    as a combination of both with a few extra options installed.
+
+    The basic concept of a bi-directional file transfer protocol is
+    simple. Both data channels are utilized to transmit and receive files
+    simultaneously. I.e. two 100 kb files can be exchanged between two
+    parties in the time it takes a fully streaming uni-directional file
+    transfer protocol to transmit one of the files.
+
+
+    Protocol design
+    =====================================================================
+    The ultimate goal when designing HYDRA was to design a protocol that
+    is as simple and robust as possible; complexity increase the problem
+    of faulty implementations.
+
+    The obvious function of a file transfer protocol is to transport a
+    collection of data from its source to its destination as efficient
+    possible and without jeopardizing the integrity of the data.
+
+    The lack of data compression and lost packet management (as used in
+    Kermit and Super Kermit) is intentional. The authors feel that this
+    unnecessarily increases the complexity of the protocol.
+
+    While HYDRA performs to its best on full duplex links, it should be
+    possible to use it on links using proprietary protocols such as the
+    US Robotics HST protocol which features one 14.4 kbps data channel
+    and one 450 bps back channel.
+
+    The protocol design should be flexible enough for future enhancements
+    while maintaining backward compatibility.
+
+
+    Protocol requirements and restrictions
+    =====================================================================
+    HYDRA require that the link can handle ASCII character 24 (DLE) as
+    well as all ASCII characters in the range 32 through 126. All other
+    characters can be escaped or encoded by the protocol as required by
+    the link.
+
+    Capability of the computer to perform simultaneous serial I/O as well
+    as simultaneous serial I/O combined with disk access is preferred,
+    but can be circumvented by opting for windowed transmission instead
+    of full streaming.
+
+    HYDRA calls for the ability to check whether there is anything in the
+    serial input buffer (i.e. "peek-ahead"), but it doesn't mind if it
+    has to wait for a second if there is no data available (using for
+    instance the UNIX alarm() mechanism).
+
+    The protocol is extremely tolerant with timeouts (i.e. satellite or
+    network delays) while still maintaining maximum reliability,
+    robustness, and throughput.
+
+
+    Terms and definitions
+    =====================================================================
+    A BYTE                   An 8-bit unsigned character.
+    A WORD                   A 16-bit unsigned integer.
+    A DWORD                  A 32-bit unsigned integer.
+    A LONG                   A 32-bit SIGNED integer.
+    FILE OFFSETS (position)  A long.
+    NUL                      The ASCII character 0.
+    BS                       The ASCII character 8.
+    CR                       The ASCII character 13.
+    XOFF                     The ASCII character 17.
+    XON                      The ASCII character 19.
+    H_DLE                    The HYDRA link escape character, ASCII 24
+                             (^X).
+    SP or SPACE              The ASCII character 32.
+    UNIX timestamp           A specific time and date expressed as the
+                             number of seconds since midnight, January
+                             1st, 1970. All UNIX timestamps used in HYDRA
+                             are expressed in local time.
+
+    Multi-byte items are transmitted in "low-byte first" order, so big-
+    endian CPUs (like 680xx) need to do some byteswapping, depending on
+    the implementation.
+
+    Values preceded by '0x' are in hexadecimal notation (base 16, 0..9
+    a..f). All values transmitted in hexadecimal notation must be
+    converted to lowercase characters and left-padded to their full
+    size with '0' prior to transmission. E.g. a WORD with the value 255
+    (decimal) is expressed as 00ff. A LONG with the value 255 (decmial)
+    is expressed as 000000ff.
+
+    In formulas, "AND" means bitwise AND, "XOR" means bitwise Exclusive
+    OR, "NOT" is ones complement (i.e. all zeros become ones, all ones
+    become zeros). The ">>" is a shift operation to the right, "R >> 3"
+    means shift R three bits to the right.
+
+
+    General packet format
+    =====================================================================
+    All data exchange is done with framed packets protected by 16 or 32
+    bit CRC values appended to the packet data and packet type (low-
+    byte first). The only exception to this is the cancel sequence of 5
+    consecutive H_DLE characters.
+
+    All packets except those with the type DATA are followed by a CR
+    (ASCII 13) to help get through some buffered environments and aid
+    possible debugging and/or tracing. If requested by the other side in
+    its INIT packet, packets can also be prefixed by a specific data
+    string which can include NULs, delays or break signals. Refer to the
+    section on the INIT packet for more information.
+
+
+                          Format of unframed packet
+
+                +------------------------------------------+
+                ~ Zero or more bytes packet dependent data ~
+                +------------------------------------------+
+                | Packet type byte                         |
+                +------------------------------------------+
+                | CRC-16/32 of packet data and packet type |
+                +------------------------------------------+
+
+
+                            Table of packet types
+
+         +--------+---------+-----+--------------------------------+
+         |Name    |Character|ASCII|Description                     |
+         +--------+---------+-----+--------------------------------+
+         |START   |   'A'   |  65 |Startup sequence                |
+         |INIT    |   'B'   |  66 |Session initialisation          |
+         |INITACK |   'C'   |  67 |Response to INIT packet         |
+         |FINFO   |   'D'   |  68 |File information                |
+         |FINFOACK|   'E'   |  69 |Response to FINFO packet        |
+         |DATA    |   'F'   |  70 |File data packet                |
+         |DATAACK |   'G'   |  71 |File data position ACK packet   |
+         |RPOS    |   'H'   |  72 |Reposition request packet       |
+         |EOF     |   'I'   |  73 |End of file packet              |
+         |EOFACK  |   'J'   |  74 |Response to EOF packet          |
+         |END     |   'K'   |  75 |End of session                  |
+         |IDLE    |   'L'   |  76 |Idle (just saying I'm alive)    |
+         |DEVDATA |   'M'   |  77 |Data to specified device     (1)|
+         |DEVDACK |   'N'   |  78 |Response to DEVDATA packet   (1)|
+         +--------+---------+-----+--------------------------------+
+
+    (1) Support for DEVDATA and DEVDACK types is optional and indicated
+        in INIT state of a HYDRA session.
+
+
+                           Format of framed packet
+
+               +----------------------+--------------------+
+               |        H_DLE         |Packet format byte  |
+               +----------------------+--------------------+
+               ~               Encoded packet              ~
+               +----------------------+--------------------+
+               |        H_DLE         |End of framed packet|
+               +----------------------+--------------------+
+
+
+                            Table of packet formats
+
+           +----+---------+-----+--------------------------------+
+           |Name|Character|ASCII|Description                     |
+           +----+---------+-----+--------------------------------+
+           |END |   'a'   |  97 |End of framed packet            |
+           |BIN |   'b'   |  98 |Binary packet                   |
+           |HEX |   'c'   |  99 |Hex encoded packet              |
+           |ASC |   'd'   | 100 |Shifted 7-bit encoded packet (1)|
+           |UUE |   'e'   | 101 |UUencoded packet             (1)|
+           +----+---------+-----+--------------------------------+
+
+    (1) Support for ASC and/or UUE formats is optional and indicated in
+        the INIT state of a HYDRA session.
+
+
+    Packet sender and receiver state charts
+    ---------------------------------------------------------------------
+
+TXPKT (Sender)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|Begin   |1|pkttype == START or         |format = HEXPKT           |Format    |
+|        | |pkttype == INIT or          |                          |          |
+|        | |pkttype == INITACK or       |                          |          |
+|        | |pkttype == END or           |                          |          |
+|        | |pkttype == IDLE             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape 8th bit (7 bit link) |                          |Coding    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (no spc.pkt, 8bit link)|format = BINPKT           |Format    |
++--------+-+----------------------------+--------------------------+----------+
+|Coding  |1|escape all control chars &  |format = UUEPKT           |Format    |
+|        | |UUENCODED packets allowed   |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|ASCII packets allowed       |format = ASCPKT           |Format    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|7 bit link &                |format = HEXPKT           |Format    |
+|        | |escape all control chars &  |                          |          |
+|        | |UUE/ASC pkts not allowed    |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+|Format  |                              |Append format byte to data|CRC       |
++--------+-+----------------------------+--------------------------+----------+
+|CRC     |1|format != HEXPKT &          |Calc CRC-32 (data,pkttype)|Encode    |
+|        | |CRC-32 allowed              |Append one's complement of|          |
+|        | |                            |CRC to data, lowbyte first|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (HEXPKT or no CRC-32)  |Calc CRC-16 (data,pkttype)|Encode    |
+|        | |                            |Append one's complement of|          |
+|        | |                            |CRC to data, lowbyte first|          |
++--------+-+----------------------------+--------------------------+----------+
+|Encode  |1|format == BINPKT            |BIN escape databuf        |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|format == HEXPKT            |HEX encode databuf        |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|format == ASCPKT            |ASC encode/escape databuf |Prefix    |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|format == UUEPKT            |UUE encode databuf        |Prefix    |
++--------+-+----------------------------+--------------------------+----------+
+|Prefix  |1|No more prefix characters   |                          |Transmit  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Prefix character ASCII 221  |Send 1 second break signal|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Prefix character ASCII 222  |1 second delay            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Prefix character ASCII 223  |Transmit NUL (ASCII 0)    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |Transmit character        |          |
++--------+-+----------------------------+--------------------------+----------+
+|Transmit|                              |Transmit H_DLE,format byte|Suffix    |
+|        |                              |Transmit encoded buffer   |          |
+|        |                              |Transmit H_DLE,pktend byte|          |
++--------+-+----------------------------+--------------------------+----------+
+|Suffix  |1|pkttype != DATA &           |Transmit CR,LF (ASC 13,10)|Done      |
+|        | |pktformat != BINPKT         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (pkttype == DATA or    |                          |Done      |
+|        | |      pktformat == BINPKT)  |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+RXPKT (Receiver)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Reset   |                              |rxdle = 0                 |NextByte  |
+|        |                              |format = 0                |          |
+|        |                              |pktlen = 0                |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|User wishes to abort session|Report reason for abort   |Abort     |
+|        | |or carrier lost             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Byte available in inputbuf  |                          |StripIn   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|braintimer expired          |Report braindead situation|Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Any other timer expired     |Tell responsible party    |          |
++--------+-+----------------------------+--------------------------+----------+
+|StripIn |1|Escape 8th bit (7 bit link) |c = c AND 0x7f (strip 8th)|StripC    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (8 bit link)           |                          |StripC    |
++--------+-+----------------------------+--------------------------+----------+
+|StripC  |1|Escape ctlchars with 8th set|n = c AND 0x7f (strip 8th)|Process   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (let 8 bit ctl through)|n = c                     |Process   |
++--------+-+----------------------------+--------------------------+----------+
+|Process |1|c == H_DLE                  |increment rxdle           |DLE       |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape XON/XOFF &           |Eat these                 |NextByte  |
+|        | |n == XON or n == XOFF       |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Escape all control chars &  |Eat these                 |NextByte  |
+|        | |n < 32 or n == 127          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxdle > 0                   |                          |Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (no eating or escaping)|                          |Store     |
++--------+-+----------------------------+--------------------------+----------+
+|DLE     |1|rxdle == 5                  |Report remote wants abort |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (rxdle < 5)            |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|c == PKTEND                 |                          |PktEnd    |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == BINPKT                 |format = BINPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c == HEXPKT                 |format = HEXPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|c == ASCPKT                 |format = ASCPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|c == UUEPKT                 |format = UUEPKT           |PktStart  |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|else (normal escaped char)  |c = c XOR 0x40            |Store     |
+|        | |                            |rxdle = 0                 |Store     |
++--------+-+----------------------------+--------------------------+----------+
+|Store   |1|format == 0                 |Garbage                   |NextByte  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|pktlen >= maximum           |Pkt too long / lost PKTEND|Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (fmt > 0 & len < max)  |Append c to databuffer    |NextByte  |
+|        | |                            |increment pktlen          |          |
++--------+-+----------------------------+--------------------------+----------+
+|PktStart|                              |rxdle = 0                 |NextByte  |
+|        |                              |pktlen = 0                |          |
++--------+-+----------------------------+--------------------------+----------+
+|PktEnd  |1|format == 0                 |End without start, garbage|Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|format == BINPKT            |(No more decoding needed) |CalcCRC   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|format == HEXPKT            |ok = Decode HEXPKT        |CheckDec  |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|format == ASCPKT            |ok = Decode ASCPKT        |CheckDec  |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|format == UUEPKT            |ok = Decode UUEPKT        |CheckDec  |
++--------+-+----------------------------+--------------------------+----------+
+|CheckDec|1|ok (no errors during decode)|                          |CalcCRC   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (errors in decoding)   |Bad encoding, ignore pkt  |Reset     |
++--------+-+----------------------------+--------------------------+----------+
+|CalcCRC |1|format != HEXPKT &          |Calc CRC-32 over databuf  |CheckCRC  |
+|        | |CRC-32 allowed              |ok = (crc == 0xdebb20e3)  |          |
+|        | |                            |pktlen = pktlen - 4       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (HEXPKT or no CRC-32)  |Calc CRC-16 over databuf  |CheckCRC  |
+|        | |                            |ok = (crc == 0xf0b8)      |          |
+|        | |                            |pktlen = pktlen - 2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|CheckCRC|1|ok (CRC matched magic)      |pkttype = last byte of buf|Reset     |
+|        | |                            |pktlen = pktlen - 1       |          |
+|        | |                            |Hand pkt to higher level  |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (CRC check failed)     |Bad CRC, ignore packet    |Reset     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    BIN packet format
+    ---------------------------------------------------------------------
+    The binary packet format require an 8-bit data channel. If requested
+    by either side, one or more sets of control characters are escaped.
+    In this case, when one of these characters appears in an unframed
+    packet, a H_DLE is sent followed by the character XOR 0x40. The H_DLE
+    character itself is always transmitted in this fashion. On the
+    receiver side, if the character after a H_DLE is not one of the
+    packet format bytes, this character is decoded using XOR 0x40 again.
+
+
+BINPKT Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |txlastc = 0               |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape ctlchars with 8th set|n = c AND 0x7f (strip 8th)|Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (let 8 bit ctl through)|n = c                     |Escape    |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|n == H_DLE                  |Output H_DLE              |Output    |
+|        | |                            |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Escape XON/XOFF &           |Output H_DLE              |Output    |
+|        | |n == XON or n == XOFF       |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Escape Telenet &            |Output H_DLE              |Output    |
+|        | |n == CR &                   |c = c XOR 0x40            |          |
+|        | |txlasc == '@'               |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|Escape all control chars &  |Output H_DLE              |Output    |
+|        | |n < 32 or n == 127          |c = c XOR 0x40            |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |                          |Output    |
++--------+-+----------------------------+--------------------------+----------+
+|Output  |                              |Store c                   |NextByte  |
+|        |                              |txlastc = c               |          |
++--------+------------------------------+--------------------------+----------+
+
+
+
+    HEX packet format
+    ---------------------------------------------------------------------
+    Supported by all implementations, this packet format is used in
+    worst-case situations and upon startup of a session when it is not
+    yet known what restrictions the line and the other side will place on
+    the link.
+
+    Packet types always transmitted in HEX format are: START, INIT,
+    INITACK, IDLE, END.
+
+    HEX format packets always use a 16-bit CRC.
+
+    HEX packets assume a 7-bit link, escaping all control characters and
+    filtering all control characters upon receipt.
+
+    ASCII characters in the range 128-255 (high bit set) are encoded by
+    first transmitting a backslash ('\') character (ASCII 92), followed
+    by the character in two lowercase hex-digits (bits 4-7 in first
+    digit, bits 0-3 in second).
+
+    Uppercase hex-digits are not permitted.
+
+    The backslash character itself is transmitted as two backslashes.
+
+    ASCII characters in the range 0-31 and 127 (all control characters)
+    are escaped with H_DLE in the same fashion as in binary (BIN)
+    packets.
+
+    Decoded  byte 1
+            +------+
+            76543210
+            +--++--+
+    Encoded  h1  h2
+
+
+HEXPKT Encoding/Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|High bit of c set           |Output \ (backslash)      |          |
+|        | |                            |Output hexdigit(c bit 4-7)|          |
+|        | |                            |Output hexdigit(c bit 0-3)|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c < 32 or c == 127          |Output H_DLE              |          |
+|        | |                            |Output (c XOR 0x40)       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|c == \ (backslash)          |Output \ (backslash)      |          |
+|        | |                            |Output \ (backslash)      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|else (any other character)  |Output c                  |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+HEXPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done OK   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == \ (backslash)          |                          |Escape    |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (any other character)  |Output c                  |Escape    |
++--------+-+----------------------------+--------------------------+----------+
+|Escape  |1|No more bytes to process    |Premature end of data     |Error     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == \ (backslash)          |Output \ (backslash)      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|c == lowercase hexdigit     |Save c, move ptr to next  |NextHex   |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (all other characters) |Invalid character         |Error     |
++--------+-+----------------------------+--------------------------+----------+
+|NextHex |1|No more bytes to process    |Premature end of data     |Error     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|c == lowercase hexdigit     |Output (1st << 4 OR 2nd)  |NextByte  |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (all other characters) |Invalid character         |Error     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+    ASC packet format
+    ---------------------------------------------------------------------
+    Support of this packet format is optional and signalled in the INIT
+    packet with the ASC flag in the "Supported options" field. 8-bit data
+    is transformed into 7-bit data by a simple shift operation. Each byte
+    is inserted at the top of a shift register, the lower seven bits are
+    moved out. So seven 8-bit bytes are encoded into eight 7-bit
+    characters.
+
+    The end of the packet is padded by a maximum of six bits of 0 to make
+    the number of bits a multiple of seven and thereby creating
+    complete characters (so the receiver stops decoding when there are
+    less than seven bits left). The output can contain control
+    characters, so if escaping of these characters is required, this is
+    done as in BIN packets using the H_DLE method.
+
+
+    Decoded  byte 7  byte 6  byte 5  byte 4  byte 3  byte 2  byte 1
+            +------++------++------++------++------++------++------+
+            76543210765432107654321076543210765432107654321076543210
+            +-----++-----++-----++-----++-----++-----++-----++-----+
+    Encoded   c8     c7      c6    c5     c4     c3     c2     c1
+
+
+ASCPKT Encoding/Escaping
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Reset   |                              |n = 0 (16 bit wide!)      |NextByte  |
+|        |                              |bitshift = 0              |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (more bytes to process)|n = n OR (c << bitshift)  |Shift     |
+|        | |                            |BINPKT escape (n & 0x7f)  |          |
+|        | |                            |n = n >> 7                |          |
+|        | |                            |increment bitshift        |          |
++--------+-+----------------------------+--------------------------+----------+
+|Shift   |1|bitshift == 7               |BINPKT escape (n & 0x7f)  |Reset     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift < 7)         |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|bitshift > 0                |BINPKT escape (n & 0x7f)  |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift == 0)        |                          |Done      |
++--------+-+----------------------------+--------------------------+----------+
+
+ASCPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |n = 0 (16 bit wide!)      |NextByte  |
+|        |                              |bitshift = 0              |          |
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|No more bytes to process    |                          |Done OK   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (more bytes to process)|c = c AND 0x7f            |Shift     |
+|        | |                            |n = n OR (c << bitshift)  |          |
+|        | |                            |bitshift = bitshift + 7   |          |
++--------+-+----------------------------+--------------------------+----------+
+|Shift   |1|bitshift >= 8               |Output (n AND 0xff)       |NextByte  |
+|        | |                            |n = n >> 8                |          |
+|        | |                            |bitshift = bitshift - 8   |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (bitshift < 8)         |                          |NextByte  |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    UUE packet format
+    ---------------------------------------------------------------------
+    Support of this packet format is optional and signalled in the INIT
+    packet with the UUE flag in the "Supported options" field. The 8-bit
+    data is transformed into printable ASCII using the UUENCODE
+    algorithm. Three 8-bit bytes are encoded into four printable ASCII
+    characters. This done by taking the bottom six bits left and adding
+    '!' (ASCII 33) to move this character value into printable ASCII
+    range.
+
+    The end of the packet is padded by a maximum of five bits of 0 to
+    make the number of bits a multiple of six and thereby creating 
+    complete characters (so the receiver stops decoding when there are
+    less than six bits left). The output of this coding scheme does not
+    need any further escaping before transmission.
+
+    Decoded  byte 3  byte 2  byte 1
+            +------++------++------+
+            765432107654321076543210
+            +----++----++----++----+
+    Encoded   c4    c3    c2    c1
+
+
+UUEPKT Encoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|Less than three bytes left  |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (three or more left)   |UUE(in[0]>>2)             |          |
+|        | |                            |UUE(in[0]<<4 OR in[1]>>4) |          |
+|        | |                            |UUE(in[1]<<2 OR in[2]>>6) |          |
+|        | |                            |UUE(in[2])                |          |
+|        | |                            |(UUE: (c AND 0x3f) + '!') |          |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|No more bytes left          |                          |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|One byte left               |UUE(in[0]>>2)             |Done      |
+|        | |                            |UUE(in[0]<<4)             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Two bytes left              |UUE(in[0]>>2)             |Done      |
+|        | |                            |UUE(in[0]<<4 OR in[1]>>4) |          |
+|        | |                            |UUE(in[1]<<2)             |          |
++--------+-+----------------------------+--------------------------+----------+
+
+UUEPKT Decoding
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+-+----------------------------+--------------------------+----------+
+|NextByte|1|Less than four bytes left   |                          |Flush     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (four or more left) &  |UD(i[0])<<2 OR UD(i[1])>>4|          |
+|        | |(c AND 0x7f) is in UUE range|UD(i[1])<<4 OR UD(i[2])>>2|          |
+|        | |                            |UD(i[2])<<6 OR UD(i[3])   |          |
+|        | |                            |(UD: (c - '!') AND 0x3f)  |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (all other characters) |Invalid character(s)      |Error     |
++--------+-+----------------------------+--------------------------+----------+
+|Flush   |1|No bytes left or            |                          |Done OK   |
+|        | |Less than two bytes left    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Two bytes left &            |UD(i[0])<<2 OR UD(i[1])>>4|Done OK   |
+|        | |(c AND 0x7f) is in UUE range|                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Three bytes left &          |UD(i[0])<<2 OR UD(i[1])>>4|Done OK   |
+|        | |(c AND 0x7f) is in UUE range|UD(i[1])<<4 OR UD(i[2])>>2|          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (all other characters) |Invalid character(s)      |Error     |
++--------+-+----------------------------+--------------------------+----------+
+
+
+
+    START packet                                             (HEX format)
+    ---------------------------------------------------------------------
+    This packet is sent to tell the remote to initiate a HYDRA session.
+
+    The complete framed packet as transmitted looks like:
+
+        ASCII values   24    99  65  92 102  53  92  97  51    24    97
+                    +-------+---+---+---+---+---+---+---+---+-------+---+
+        Characters  | H_DLE | c | A | \ | f | 5 | \ | a | 3 | H_DLE | a |
+                    +-------+---+---+---+---+---+---+---+---+-------+---+
+
+    Applications may scan for this sequence to automatically start HYDRA
+    when the remote transmits this packet (AutoStart). Prior to the START
+    packet, a special string is transmitted to enable remote starting
+    from a command prompt, hydra (the word hydra in lowercase):
+
+        ASCII values 104 121 100 114  97  13
+                    +---+---+---+---+---+----+
+        Characters  | h | y | d | r | a | CR |
+                    +---+---+---+---+---+----+
+
+    The special string combined with the START packet is transmitted at
+    five second intervals until either a START or INIT packet is received
+    from the remote, or the maximum number of retries is reached. Any
+    other packet types received in this stage must be ignored as they
+    could be remains of a previous session.
+
+
+    INIT packet                                              (HEX format)
+    ---------------------------------------------------------------------
+    The INIT packet contains file transfer session options. The remote
+    acknowledges this packet by returning an INITACK packet.
+
+
+                              INIT packet data
+
+                 +---------------------------------------+
+                 ~ Application ID string, NUL terminated ~
+                 +---------------------------------------+
+                 ~ Supported options, NUL terminated     ~
+                 +---------------------------------------+
+                 ~ Desired options, NUL terminated       ~
+                 +---------------------------------------+
+                 | Desired transmitter window size or 0  |
+                 +---------------------------------------+
+                 | Desired receiver window size or 0     |
+                 +---------------------------------------+
+                 ~ Other general options, NUL terminated ~
+                 +---------------------------------------+
+                 ~ Packet prefix string, NUL terminated  ~
+                 +---------------------------------------+
+
+    The application ID string contains a printable ASCII string with the
+    document revision date, product name, product revision number, and
+    optionally the product serial number. The format of the string is:
+
+        <,>[<,>]
+
+    RevDate is the UNIX timestamp (the hour, minute, and second portion
+    is assumed to be zero), in hexadecimal notation, of the HYDRA
+    document that the application is supposed to support. None of the
+    following three fields should exceed thirty characters in length and
+    must not contain any control characters (ASCII 0-31) or the comma
+    character (ASCII 44). The field separator is a comma (ASCII 44)
+    character.
+
+    Capability flags
+
+        XON        Escape  and  characters.
+        TLN        Escape the @ sequence (Telenet escape).
+        CTL        Escape ASCII characters 0-31 and 127.
+        HIC        Escape above three with high bit set.
+        HI8        Escape ASCII characters 128-255 and strip the high bit.
+        BRK        Can transmit a break signal.
+        ASC        Can handle ASC packets.
+        UUE        Can handle UUE packets.
+        C32        Can receive packets with 32-bit CRC error detection.
+        DEV        Can receive device packets.
+        FPT        Can receive filenames with paths.
+
+    Capability flags are always three characters long, in uppercase, and
+    seperated by a comma character (ASCII 44). Please note that the first
+    five flags must be supported by all applications that implement the
+    HYDRA specifications.
+
+    The "Supported options" string contain the capability flags of the
+    options that the application support. The "Desired options" string
+    contain the capability flags of the options that the application
+    would like to use/enable for the session. Some flags do not have to
+    be specified in both strings. E.g. if the C32 flag is present in the
+    "Supported options" string and the remote system indicates support
+    for the same flag, 32-bit CRC error detection will be used. An
+    application may not ask for an option it does not support.
+
+    Escaping certain characters or bits also means filtering any
+    occurrence of them in the incoming data stream. At the start of a
+    session, it is assumed that the first five capability flags are in
+    effect, i.e. the high bit is stripped off every received character
+    and all control characters are filtered out.
+
+    The "Desired transmitter/receiver window size" fields are long
+    integers expressed in hexadecimal notation. With these options each
+    side tells the other to use window management of the requested size
+    when transmitting file data, instead of using full streaming (0).
+    The window setting is completely seperate for both directions.
+    If one side requests a smaller window size than the other, that
+    smaller size will be used for that direction; also, a window of any
+    size takes precedence over no window (0).
+    Please note that the terms 'transmitter' and 'receiver' used for the
+    fields in the INIT packet are from the view of the side transmitting
+    that packet, so the other side should merge the 'transmitter' window
+    field from the received INIT packet with its own 'receiver' window
+    field.
+
+    The "General options" string currently has no other fields than
+    "Desired tx/rx window size"; the string is NUL terminated.
+
+    The packet prefix string is normally empty, but may be provided by
+    the remote if required. The maximum length of a packet prefix string
+    is 30 characters. All characters should be transmitted as specified,
+    with the following exceptions:
+
+    
+                Table of special packet prefix string chars
+
+               +-----+--------------------------------------+
+               |ASCII|Description                           |
+               +-----+--------------------------------------+
+               | 221 |Transmit a break signal for one second|
+               | 222 |Delay one second before next character|
+               | 223 |Transmit a NUL (ASCII 0) character    |
+               +-----+--------------------------------------+
+
+
+    INITACK packet                                           (HEX format)
+    ---------------------------------------------------------------------
+    The INITACK packet is used to acknowledge the receipt of the remote's
+    INIT packet.
+
+    Duplicate INIT packets should be acknowledged too, as the remote may
+    have missed previous INITACK packets; the reception of such a
+    duplicate packet should not however reset the braindead timer, as it
+    does not mean a change of state and is not actual file data.
+
+
+    FINFO packet
+    ---------------------------------------------------------------------
+    File information packet, sent to notify the remote that another file
+    is to be transmitted, or to signal end of batch. After the FINFO
+    packet has been transmitted, the timer is set to the normal timeout
+    value. The sender then waits for an FINFOACK packet from the remote
+    or for the timer to expire. In the event of a timeout, the transmit/
+    wait sequence is repeated with half the normal timeout value until
+    the maximum number of retries has been reached.
+
+
+                              FINFO packet data
+                   +-------------------------------------+
+                   ~ File information, NUL terminated    ~
+                   +-------------------------------------+
+
+
+                   File information        End of batch
+                  +-----------------+   +-----------------+
+                  | Timestamp or 0  |   |       NUL       | 
+                  +-----------------+   +-----------------+ 
+                  | Filesize or 0   |
+                  +-----------------+
+                  | Reserved (0)    |
+                  +-----------------+
+                  | Transaction #   |
+                  +-----------------+
+                  | File count or 0 |
+                  +-----------------+
+                  ~ Short filename  ~
+                  +-----------------+
+                  ~ Real filename   ~
+                  +-----------------+
+                  |     NUL         |
+                  +-----------------+
+                     
+    End of batch is signalled by an empty string (only the terminating
+    NUL).
+
+    The first five fields are long integers expressed in hexadecimal
+    notation.
+
+    Timestamp is a UNIX timestamp representing the creation time of the
+    file. If the creation time is not known, this is zero.
+
+    Filesize is the size of the file in bytes. If the size of the file is
+    not known, this is zero. This field should not be used as an exact
+    measure of the size of the file. It is safe to assume that you should
+    not receive less data than specified in this field, but the file may
+    grow while it is being transferred (e.g. the result of a background
+    process).
+
+    Transaction # is a unique number for each set of files being sent
+    during the session. This is primarily used to allow the receiving
+    application to group several files together and store them in
+    specific directories as a result of automated file requests. If the
+    file being sent is not a result of an automated file request, this
+    field must be set to zero.
+
+    File count is the session file counter. For the first file in a
+    session, this field contains the total number of files to be sent
+    during the session; for subsequent files, it contains the file number
+    in the session, starting with two (2). If the total number of files
+    is not known, this field contains zero for all files.
+
+    The first filename field must be specified in lowercase characters.
+    It must conform to MS-DOS filename conventions and not exceed 12
+    characters in length (excluding the terminating NUL character). The
+    second field, real filename, is the actual filename on the sending
+    system. If this field is not present, the short filename field is
+    used.
+
+    No directory paths may be specified in the short filename. Directory
+    paths may be specified in the real filename field if the "Desired
+    options" of the receiver contains FPT. If the real filename field
+    contains a path, it may include any ASCII character in the range 32
+    (0x20) through 255 (0xff) with \ characters translated to /. A drive
+    specifier may be present in the : (e.g. c:) format. If both
+    the short and real filename fields are present, they are separated
+    by a NUL character. There is never more than one NUL character
+    terminating the packet.
+    
+
+    FINFOACK packet
+    ---------------------------------------------------------------------
+    Sent in response to an FINFO packet. If the FINFO packet contained
+    file information, the FINFOACK packet is also used to instruct the
+    remote how to proceed with the transfer.
+
+
+                            FINFOACK packet data
+                 +---------------------------------------+
+                 | Long file offset, special code, or 0  |
+                 +---------------------------------------+
+
+    The only data in this packet is a long integer. In response to an
+    an end of batch FINFO packet, the file offset is set to zero (0). In
+    all other cases, file offset is one of the following:
+
+
+                       File offsets and special values
+           +------+----------------------------------------------+
+           |Offset|Description                                   |
+           +------+----------------------------------------------+
+           | >=0  |Seek to specified offset and start sending (1)|
+           |  -1  |Already have file                          (2)|
+           |  -2  |Send file during another batch (not now)      |
+           +------+----------------------------------------------+
+
+    (1) This can only be something other than zero if the FINFO packet
+        specified a filesize other than zero (i.e. the size of the file
+        is known to the receiver).
+
+    (2) The sending application should consider the file as having been
+        sent successfully. This is primarily used to prevent duplicate
+        files from being transmitted.
+
+
+    DATA packet
+    ---------------------------------------------------------------------
+    Packet containing actual file data.
+
+
+                                  DATA packet
+                  +-----------------------------------------+
+                  | Long file offset of file data block     |
+                  +-----------------------------------------+
+                  ~ Variable length data block 0-2048 bytes ~
+                  +-----------------------------------------+
+
+    If the file offset corresponds with what is expected by the receiver,
+    the data block is saved and the file position increased accordingly.
+    If the file offset is not correct, DATA packets may have been lost or
+    failed the CRC check. Bad packets are ignored because it is not
+    certain that the bad packet was an actual DATA packet and not some
+    other type of packet. The file offset comparison is therefore the
+    only way to find out about lost or bad data.
+
+    When a bad data packet is detected, an RPOS packet is transmitted by
+    the receiver to force the sender to seek to the desired file offset
+    and resume transmission from it. After transmitting the RPOS packet,
+    the receiver initializes a timer and continues to monitor received
+    DATA packets while comparing their file offset with its desired
+    offset.
+
+    If the offset of a newly received DATA packet is greater than the
+    offset received in the last DATA packet prior to transmitting the
+    RPOS packet, the sender has not yet seen the RPOS packet, or the
+    DATA packet was already in the data stream when the RPOS packet was
+    transmitted.
+
+    If the received offset matches the requested offset, the transfer is
+    resumed, otherwise, a new RPOS packet is transmitted by the receiver
+    and the timer restarted.
+
+    If the timer expires, another RPOS packet is transmitted by the
+    receiver. This is repeated until the maximum number of retries has
+    been reached.
+
+    If the receiver encounters more missing or invalid DATA packets at
+    the same offset than it finds acceptable and it is not the originator
+    of the session, it may decide to revert to a one-way transfer and
+    wait with sending the remainder of its own files until the remote has
+    transmitted its end of batch signal. It is possible that some hard-
+    ware is not capable or well suited for a bi-directional file transfer
+    involving large volumes of data (see description of the IDLE packet).
+
+
+    DATAACK packet
+    ---------------------------------------------------------------------
+    Transmitted by the receiver with its current file offset after
+    receiving a valid DATA packet.
+
+
+                              DATAACK packet data
+                          +------------------------+
+                          |    Long file offset    |
+                          +------------------------+
+
+    This packet is only transmitted if there is a window in operation
+    for that direction (selected in the INIT stage of the session), in
+    which case the sender uses the DATAACK file offsets to manage its
+    transmit window. If the sender's file offset is greater than or equal
+    to the last DATAACK offset received plus the window size, no more
+    data is transmitted by the sender until a DATAACK packet is received
+    which allows the sender to proceed without exceeding the window size.
+
+    While waiting for the DATAACK packet, the sender checks its timer
+    and retry counter. If the timer expires before a valid DATAACK packet
+    is received, the next DATA packet is transmitted, the retry counter
+    incremented, and the timer restarted with half the normal timeout.
+    This system ensures that the two sides do not end up waiting for
+    each other in case packets are lost; the receiver will respond with
+    either a DATAACK or RPOS packet. Receipt of a DATAACK packet does not
+    reset the braindead timer.
+
+    There are two windowing systems the receiver can use: sliding window
+    or segmented streaming.
+
+    If the receiver is capable of simultaneous serial and disk I/O, it
+    will transmit a DATAACK packet for every received DATA packet, or
+    every few DATA packets if it wants to be more economical with line
+    capacity.
+    Sliding window transmission is just a method of keeping the runahaid
+    of the transmitter within reasonable limits (for sattelite or network
+    links with long delays), thereby allowing for faster error recovery.
+    Because of Hydra's tolerancy to delays and method of error recovery,
+    sliding windows transmission is not normally required and full
+    streaming can be used.
+
+    If however the receiver is not capable of simultaneous serial and
+    disk I/O, it will will process received DATA packets until the window
+    size is reached (or slightly exceeded), write the received packets to
+    disk, and then transmit one DATAACK packet to signal that it can
+    receive the next segment of data.
+
+    If the sender cannot handle simultaneous serial and disk I/O, it can
+    apply the segmented streaming technique for reading data segments of
+    the negotiated window size from disk.
+
+
+    RPOS packet
+    ---------------------------------------------------------------------
+    Transmitted by the receiver to force the sender to seek to a specific
+    position in the file and resume the transfer (as described above).
+
+    The RPOS packet is also used by the receiver to skip a file once the
+    transfer has been initiated. This is done by transmitting a RPOS
+    packet with -2 as the desired offset and then waiting for a EOF
+    packet with the same offset (-2). Once the EOF packet is received,
+    the receiver responds to it by transmitting a EOFACK packet and then
+    proceeds to wait for the next FINFO packet.
+
+
+                          RPOS packet dependent data
+                  +----------------------------------------+
+                  | Long file offset                       |
+                  +----------------------------------------+
+                  | Desired datablock size (word, 64-2048) |
+                  +----------------------------------------+
+                  | Long RPOS packet ID                    |
+                  +----------------------------------------+
+
+
+                                 File offsets 
+             +------+-------------------------------------------+
+             |Offset|Description                                |
+             +------+-------------------------------------------+
+             | >=0  |Seek to specified offset and resume sending|
+             |  -2  |Send file during another batch (not now)   |
+             +------+-------------------------------------------+
+
+    The desired data blocksize field tells the sender what blocksize
+    to use when it resumes transmitting from the specified file offset.
+
+    Each new RPOS packet should be given a different packet ID. This
+    allows the sender to identify and ignore duplicate RPOS packets.
+    The ID need not be sequential, but it must not have the same value as
+    any other RPOS packet sent during the transmission of the same file.
+    A RPOS ID value of zero (0) is not permitted. The same ID value is
+    only used when sending multiple RPOS packets due to an expired RPOS
+    packet timer as described above (DATA packet).
+
+
+    EOF packet
+    ---------------------------------------------------------------------
+    Indicates that the end of the file has been reached by the sender.
+    The packet is transmitted after the last DATA packet with file data.
+    The EOF packet only contains one field which holds the current file
+    offset of the sender (i.e. the actual size of the file).
+
+    After the EOF packet has been transmitted, the timer is set to the
+    normal timeout value. The sender then waits for an EOFACK packet
+    from the remote or for the timer to expire. In the event of a
+    timeout, the transmit/wait sequence is repeated with half the normal
+    timeout value until the maximum number of retries has been reached.
+
+    In the event that the receiver requests to skip the file by
+    transmitting a RPOS(-2) packet (see RPOS packet), the EOF packet
+    contains the same value (-2). If the sender wants to skip the file
+    currently being transmitted, it issues an EOF packet with -2 as the
+    offset value.
+
+    EOF packets with an incorrect offset should be treated by the
+    receiver as if it was an incorrect DATA packet (i.e. transmitting an
+    RPOS packet). Accepted EOF packets are acknowledged by transmitting
+    an EOFACK packet.
+
+
+                                EOF packet data
+                     +----------------------------------+
+                     | Long file offset or special code |
+                     +----------------------------------+
+
+
+                         File offsets and special value
+               +------+----------------------------------------+
+               |Offset|Description                             |
+               +------+----------------------------------------+
+               | >=0  |Final offset in file (size of file)     |
+               |  -2  |Send file during another batch (not now)|
+               +------+----------------------------------------+
+
+
+    EOFACK packet
+    ---------------------------------------------------------------------
+    Transmitted in response to an accepted EOF packet. After transmitting
+    this packet, the receiver waits for the FINFO packet of the next file
+    or end of batch.
+
+
+    END packet                                               (HEX format)
+    ---------------------------------------------------------------------
+    Once all files have been transmitted by both sides and no device
+    packets remain to be transmitted, the end of session sequence is
+    initiated. END packets are always sent in HEX format.
+
+    Two END packets are transmitted and the transmit timer set to half
+    the normal timeout. The application then waits for an END packet from
+    the remote or for the transmit timer to expire. In the event of a
+    timeout, the transmit/wait sequence is repeated until the maximum
+    number of retries has been reached. At this point, the HYDRA session
+    may be considered to be successful as both batches were completed.
+
+    If an END packet is received before timeout, another three (3) END
+    packets are transmitted and the protocol exits. Both sides need to
+    transmit END packets and receive at least one from the remote.
+
+
+    IDLE packet                                              (HEX format)
+    ---------------------------------------------------------------------
+    The IDLE packet is used to let the remote know that the application
+    is still alive. This is only applicable in uni-directional transfer
+    mode to let the remote know that your application is still alive when
+    it is receiving files, and after having transmitted an end of batch
+    signal to the remote and not having any more files to send for the
+    remainder of the session.
+
+    When applicable, the IDLE packet is transmitted every 20 seconds. The
+    remote resets its braindead timer upon receipt of an IDLE packet. If
+    an application receives an IDLE packet while it is in a state where
+    it is transmitting IDLE packets to the remote, something is wrong.
+    This could occur if both sides have accidentally switched to one-way
+    mode waiting for the remote to finish its batch. In this situation,
+    one-way should be disabled to prevent a complete deadlock. Note that
+    if both sides have finished their batch, the end of session sequence
+    (see END packet) should be initiated.
+
+
+    DEVDATA packet
+    ---------------------------------------------------------------------
+    Support for the DEVDATA and DEVDACK packets is optional and indicated
+    in the INIT packet with the DEV flag in the "Supported options"
+    field. The ID value is a long, different for each new device data
+    packet sent. A value of zero (0) is not permitted.
+
+    Only one DEVDATA packet may be transmitted at a time; the side
+    issuing it then waits either for a timeout of the device transmit
+    timer, or for a DEVDACK packet with the correct ID value to be
+    received from the remote. If the timer expires before a correct
+    DEVDACK packet is received, the DEVDATA packet is again transmitted,
+    and the nnumber of device transmit retries incremented. If the
+    maximum number of retries is reached, the HYDRA session is aborted;
+    apparently the other is not functioning properly, or data is not
+    getting through. In either case, the normal operation of the
+    protocol (transferring files) will also fail.
+
+    The name of the device to which the data is addressed is transmitted
+    as an uppercase fixed-length three character NUL terminated string.
+    There are two pre-defined device names as described below. If an
+    unknown device name is specified, or a duplicate DEVDATA packet is
+    received (one with the same ID value as a previously received and
+    acknowledged DEVDATA packet), the packet is simply discarded after
+    transmitting a DEVDACK packet with the corresponding ID value.
+
+    DEVDATA and DEVDACK packets do not reset the braindead timer. They
+    operate independently from the normal protocol. Device packets may
+    only be transmitted after the initialization sequence, and before
+    both sides have completed their batch. If a DEVDATA packet has not
+    yet been acknowledged, the end of session sequence is delayed until
+    a DEVDACK packet has been sent in response.
+
+
+                       DEVDATA packet dependent data
+           +--------------------------------------------------+
+           | Long DEVDATA packet ID value                     |
+           +--------------------------------------------------+
+           | 3 character uppercase device name, NUL terminated|
+           +--------------------------------------------------+
+           ~ Variable length device data block (0-2048)       ~
+           +--------------------------------------------------+
+
+
+                           Predefined device names
+                +---+-------------------------------------+
+                |Dev|Description                          |
+                +---+-------------------------------------+
+                |MSG|Print data in protocol message window|
+                |CON|Print data to user console           |
+                +---+-------------------------------------+
+
+    The MSG device may be used to notify the remote of protocol-specific
+    issues, i.e. "One-way transfer mode". Such messages may be logged,
+    but should not be considered to be machine-readable.
+
+    The CON device may be used to implement a "chat" or conversation
+    feature. This is a special case in which a session *can* be prolonged
+    after end of batch, but not against the remote's will.
+    While chat is enabled, there is no transition from the REND to the
+    END transmitter state. When a CON device packet is transmitted in
+    chat mode and the txstate is REND, the own braindead timer is reset.
+    If the other side does initiate the end sequence by sending an END
+    packet, the chat mode is immediately terminated and the session ended
+    in a clean manner. If one side does not want to (continue) chat, and
+    the other side does not comply, the one side will abort after a
+    braindead timeout, so this chat system does not mean a security flaw.
+    Each side is responsible for keeping the session going on his end
+    until its own user has finished chatting. It is suggested that the
+    software apply a timeout of say 1 minute to keyboard input, ending
+    the chat automatically if the user stops typing but does not exit
+    chat mode. Also, the chat mode should be initiated with a special key
+    so that it can not erronously be started or prolonged.
+
+
+    DEVDACK packet
+    ---------------------------------------------------------------------
+    Transmitted in response to a DEVDATA packet. The device data ID value
+    must correspond to the ID of the previously received DEVDATA packet.
+
+
+                              DEVDACK packet data
+                         +---------------------------+
+                         | Long device data ID value |
+                         +---------------------------+
+
+
+
+DEVICE sender (devtxstate HTD_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |devtxid = 0               |DONE      |
+|        |                              |reset devtxtimer          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|wish to send device data &  |increase devtxid          |DATA      |
+|        | |other side allows DEV pkts  |devtxretries = 0          |          |
+|        | |                            |reset devtxtimer          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|wish to send device data &  |Tell calling function     |          |
+|        | |other doesn't allow DEV pkts|it's not on...            |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|devtxretries == 10          |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (devtxretries < 10)    |txpkt DEVDATA(id,dev,data)|DACK      |
+|        | |                            |devtxtimer = timeout      |          |
++--------+-+----------------------------+--------------------------+----------+
+|DACK    |1|rxpkt DACK &                |reset devtxtimer          |DONE      |
+|        | |DACK(id) == devtxid         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|devtxtimer expired          |Report devtx timeout      |DATA      |
+|        | |                            |increase devtxretries     |          |
++--------+-+----------------------------+--------------------------+----------+
+ 
+DEVICE RECEIVER
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |devrxid = 0               |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|rxpkt DEVDATA               |txpkt DEVDACK(id)         |CheckID   |
++--------+-+----------------------------+--------------------------+----------+
+|CheckID |1|DEVDATA(id) != devrxid      |devrxid = DEVDATA(id)     |Process   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (apparent duplicate)   |                          |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+|Process |1|DEVDATA(dev) == MSG         |Print protocol message    |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|DEVDATA(dev) == CON         |Output to user console    |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|DEVDATA(dev) == known&ok    |Call processing routine   |DONE      |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|else (unknown/not-ok device)|One-way into bitbucket    |DONE      |
++--------+-+----------------------------+--------------------------+----------+
+
+ 
+    Packet length and data block size
+    ---------------------------------------------------------------------
+    The maximum length of a source data block (i.e. raw, non processed
+    input file or device data) is 2048 bytes. The maximum allowed length
+    of the packet data is 2048 + 8 = 2056 bytes. The eight bytes are to
+    provide sufficient room for the additional fields in the DATA and
+    DEVDATA packets. Packetizing adds an additional three to five bytes.
+    The maximum length of a framed packet being transmitted can be three
+    times the size of its source data depending on what type of encoding
+    scheme is used (ASC, HEX, UUE, BIN). The minimum length of a data
+    block is 64 bytes.
+
+    The block size of DATA packets is based on the physical (DCE) link
+    speed and is established as follows:
+
+            +---------+------------------+-------------------+
+            |DCE speed|Maximum block size|Starting block size|
+            +---------+------------------+-------------------+
+            |  300 bps|     256 bytes    |     256 bytes     |
+            | 1200 bps|     512 bytes    |     256 bytes     |
+            | 2400 bps|    1024 bytes    |     512 bytes     |
+            |>2400 bps|    2048 bytes    |     512 bytes     |
+            +---------+------------------+-------------------+
+
+    The blocksize is initialized to the starting blocksize when a session
+    is first started. After each kilobyte of file data transmitted, the
+    blocksize is doubled until it reaches the maximum allowed blocksize.
+
+    When the maximum allowed blocksize has been reached, the variable
+    keeping track of how many bytes are needed to increase the blocksize
+    is reset to zero.
+
+    If a request for retransmission (RPOS packet) is received from the
+    receiver, the blocksize is immediately set to that specified in the
+    retransmission request. Every time this occurs, the number of bytes
+    needed to double the blocksize is increased by 1024 with a maximum of
+    of 8192 bytes. The end result is that more data has to be
+    successfully transmitted before the blocksize is increased for each
+    error that occurs.
+
+    The length of a data block is dynamic and always in the range 0-2048
+    bytes. A data block is never padded. If there is insufficient data
+    to fill a block of the current blocksize, the blocksize is adjusted
+    to the amount of remaining data.
+
+    The blocksize logic is not reset between files in a session.
+
+
+    Timers and retry counters
+    =====================================================================
+    Each process in the protocol (transmit, receive and device transmit)
+    has its own timer and retry counter, and there is one overall
+    braindead timer. Allowed are 10 tries, the braindead timeout is 120
+    seconds, and the other timeouts are based on the speed of the line
+    and the state of the protocol. It can be calculated as (40960/DCE
+    rate), with a minimum of 10 seconds and a maximum of 60 seconds.
+
+                     +---------+----------+----------+
+                     |DCE speed|Timeout   |Half      |
+                     +---------+----------+----------+
+                     |  300 bps|60 seconds|30 seconds|
+                     | 1200 bps|34 seconds|17 seconds|
+                     | 2400 bps|17 seconds| 8 seconds|
+                     |>2400 bps|10 seconds| 5 seconds|
+                     +---------+----------+----------+
+
+    If the output buffer is empty, the timeout value is halved. In
+    general, this is the case if the number of tries is greater than zero
+    and during the init and end sequences. These timeouts are not fatal
+    situations, they just give the remote a reasonable amount of time to
+    receive and respond to a packet before a retry occurs. Duplicate
+    packets are always identified and ignored. A retry counter is reset
+    if there is a change of state, or a reposition different from the
+    previous file offset occurs.
+
+    The braindead timer monitors useful data from the other side: a first
+    response to a transmitted supervisiory packet, or a received packet
+    with file data at the correct offset. Device packets and packets that
+    do not signify any progress of the protocol do not affect the
+    braindead timer.
+
+    No other timers (such as one between characters in a packet) are
+    necessary.
+
+
+    Aborting a session
+    =====================================================================
+    A session is aborted with five consequetive CAN (^X or ASCII 24)
+    characters. Whenever a state table mentions "Abort", the following
+    procedure is to be followed:
+
+    Clear the output buffer and transmit eight CAN characters followed by
+    ten BS (^H or ASCII 8) characters; wait a few seconds for the data to
+    be transmitted to the remote, purge the input buffer and exit the
+    protocol code.
+
+
+GENERAL sender (txstate HTX_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |txretries = 0             |START     |
+|        |                              |reset txtimer             |          |
+|        |                              |blksize = startblksize    |          |
+|        |                              |goodbytes = 0             |          |
+|        |                              |goodneeded = 1024         |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|START   |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txstr AutoStart           |SWAIT     |
+|        | |                            |txpkt START               |          |
+|        | |                            |txtimer = 5               |          |
++--------+-+----------------------------+--------------------------+----------+
+|SWAIT   |1|rxpkt START or              |txretries = 0             |INIT      |
+|        | |rxpkt INIT                  |reset txtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |START     |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|INIT    |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txpkt INIT(linkinfo)      |INITACK   |
+|        | |                            |txtimer = timeout/2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|INITACK |1|rxpkt INITACK               |txretries = 0             |RINIT     |
+|        | |                            |reset txtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |INIT      |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|RINIT   |1|rxstate != INIT             |                          |NextFile  |
++--------+-+----------------------------+--------------------------+----------+
+|NextFile|1|No files left?              |Report end of batch       |ToFName   |
+|        | |                            |Set NULL fileinfo         |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|Can access next file?       |Set up fileinfo           |ToFName   |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|Can't access file?          |Report access failure     |NextFile  |
++--------+-+----------------------------+--------------------------+----------+
+|ToFName |                              |txsyncid = 0              |FINFO     |
+|        |                              |txretries = 0             |          |
+|        |                              |reset txtimer             |          |
++--------+-+----------------------------+--------------------------+----------+
+|FINFO   |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txretries > 0               |txpkt FINFO(fileinfo)     |FINFOACK  |
+|        | |                            |txtimer = timeout/2       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (txretries == 0)       |txpkt FINFO(fileinfo)     |FINFOACK  |
+|        | |                            |txtimer = timeout         |          |
++--------+-+----------------------------+--------------------------+----------+
+|FINFOACK|1|NULL fname (end of batch) & |txtimer = idletimeout     |REND      |
+|        | |rxpkt FINFOACK              |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt FINFOACK &            |txpos = FINFOACK(pos)     |DATA      |
+|        | |FINFOACK(pos) >= 0          |txretries = 0             |          |
+|        | |                            |txlastack = 0             |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt FINFOACK &            |They already have file    |NextFile  |
+|        | |FINFOACK(pos) == -1)        |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt FINFOACK &            |Skip this file for now    |NextFile  |
+|        | |FINFOACK(pos) == -2)        |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |Report tx timeout         |FINFO     |
+|        | |                            |inrease txretries         |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|rxstate != Done &           |txtimer = idletimeout     |XWAIT     |
+|        | |hdxlink == True             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS &                |Skip this file for now    |SkipFile  |
+|        | |RPOS(pos) < 0               |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt RPOS &                |Report too many errors    |Abort     |
+|        | |RPOS(id) == txsyncid &      |                          |          |
+|        | |inc txretries == 10         |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt RPOS &                |txpos = RPOS(pos)         |          |
+|        | |RPOS(id) != txsyncid &      |txsyncid = RPOS(id)       |          |
+|        | |RPOS(pos) >= 0              |txretries = 1             |          |
+|        | |                            |blksize = RPOS(blksize)   |          |
+|        | |                            |goodbytes = 0             |          |
+|        | |                            |inc goodneeded + 1024     |          |
+|        | |                            |if (goodneeded > 8192)    |          |
+|        | |                            |   goodneeded = 8192      |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|File seek/read error or     |Skip this file for now    |SkipFile  |
+|        | |user wishes to skip file    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|txwindow &                  |if (txretries > 0)        |DATAACK   |
+|        | |txpos >= txlastack+txwindow |   txtimer = timeout/2    |          |
+|        | |                            |else                      |          |
+|        | |                            |   txtimer = timeout      |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |8|Enough room in output &     |txpkt DATA(pos,data)      |          |
+|        | |more filedata(blksize) to go|txpos += datalen          |          |
+|        | |                            |inc goodbytes + datalen   |          |
+|        | |                            |if goodbytes > goodneeded |          |
+|        | |                            |   Store txpos,blksize    |          |
+|        | |                            |   blksize * 2 (max.2048) |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |9|End of filedata reached     |                          |EOF       |
++--------+-+----------------------------+--------------------------+----------+
+|SkipFile|                              |txpos = -1                |EOF       |
+|        |                              |txretries = 0             |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATAACK |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |DATA      |
+|        | |DATAACK(pos) > txlastack &  |txretries = 0             |          |
+|        | |txpos < DATAACK(pos) + txwin|reset txtimer             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS                  |Handle RPOS in state DATA |          |
+|        | |                            |but stay in this state    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|txtimer expired             |Report tx timeout         |DATA      |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|XWAIT   |1|rxstate == Done             |reset txtimer             |DATA      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS                  |Handle RPOS in state DATA |          |
+|        | |                            |but stay in this state    |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt IDLE                  |hdxlink = False           |DATA      |
+|        | |                            |reset txtimer             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |txpkt IDLE                |          |
+|        | |                            |txtimer = idletimeout     |          |
++--------+-+----------------------------+--------------------------+----------+
+|EOF     |1|txretries == 10             |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txretries > 0               |txpkt EOF(txpos)          |EOFACK    |
+|        | |                            |txtimer = timeout/2       |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (txretries == 0)       |txpkt EOF(txpos)          |EOFACK    |
+|        | |                            |txtimer = timeout         |          |
++--------+-+----------------------------+--------------------------+----------+
+|EOFACK  |1|rxpkt EOFACK                |braintimer = 120          |NextFile  |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATAACK &             |txlastack = DATAACK(pos)  |          |
+|        | |DATAACK(pos) > txlastack    |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt RPOS &                |rxpos == -2               |EOF       |
+|        | |RPOS(pos) == -2 &           |                          |          |
+|        | |rxpos != -2                 |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt RPOS &                |Handle as in state DATA   |DATA      |
+|        | |RPOS(pos) >= 0              |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|txtimer expired             |Report tx timeout         |EOF       |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+|REND    |1|rxstate == DONE &           |txretries = 0             |END       |
+|        | |devtxstate == DONE          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |txpkt IDLE                |          |
+|        | |                            |txtimer = idletimeout     |          |
++--------+-+----------------------------+--------------------------+----------+
+|END     |1|txretries == 10             |                          |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (txretries < 10)       |txpkt END (twice)         |ENDACK    |
+|        | |                            |txtimer = timeout/2       |          |
++--------+-+----------------------------+--------------------------+----------+
+|ENDACK  |1|rxpkt END                   |txpkt END (thrice)        |Done      |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|txtimer expired             |Report tx timeout         |END       |
+|        | |                            |increment txretries       |          |
++--------+-+----------------------------+--------------------------+----------+
+
+ 
+ 
+GENERAL RECEIVER (rxstate HRX_...)
++--------+------------------------------+--------------------------+----------+
+|State   |Predicate(s)                  |Action(s)                 |Next state|
++--------+------------------------------+--------------------------+----------+
+|Begin   |                              |reset rxtimer             |START     |
+|        |                              |lastrxdlen = startblksize |          |
+|        |                              |(tx handles braintimer)   |          |
++--------+-+----------------------------+--------------------------+----------+
+|INIT    |1|rxpkt INIT &                |txpkt INITACK             |FINFO     |
+|        | |INIT(options) are compatible|Set options               |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|INIT(options) not compatible|Report link failure       |Abort     |
++--------+-+----------------------------+--------------------------+----------+
+|FINFO   |1|rxpkt INIT (apparent dup)   |txpkt INITACK             |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt FINFO &               |Report end of batch       |          |
+|        | |FINFO(fileinfo) == Empty    |txpkt FINFOACK            |DONE      |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt FINFO &               |do not want this file     |          |
+|        | |we already have file        |txpkt FINFOACK(-1)        |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt FINFO &               |Skip this file for now    |          |
+|        | |open/diskspace error        |txpkt FINFOACK(-2)        |          |
+|        | |                            |braintimer = 120          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt FINFO &               |rxpos = resume offset     |ToData    |
+|        | |file we want to resume      |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|rxpkt FINFO &               |rxpos = 0                 |ToData    |
+|        | |new file for us             |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|rxpkt EOF (apparent dup)    |txpkt EOFACK              |          |
++--------+-+----------------------------+--------------------------+----------+
+|ToData  |                              |txpkt FINFOACK(rxpos)     |DATA      |
+|        |                              |rxsyncid = 0              |          |
+|        |                              |rxlastsync = 0;           |          |
+|        |                              |rxretries = 0             |          |
+|        |                              |reset rxtimer             |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DATA    |1|rxpkt FINFO (apparent dup)  |txpkt FINFOACK(rxpos)     |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxpkt DATA &                |Store data                |          |
+|        | |DATA(pos) == rxpos          |rxpos += datalen          |          |
+|        | |                            |rxretries = 0             |          |
+|        | |                            |rxlastsync = rxpos        |          |
+|        | |                            |reset rxtimer             |          |
+|        | |                            |braintimer = 120          |          |
+|        | |                            |if (rxwindow)             |          |
+|        | |                            |   txpkt DATAACK(rxpos)   |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|rxpkt DATA &                |Report bad rxpos          |BadPos    |
+|        | |DATA(pos) != rxpos          |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |4|rxpkt EOF &                 |Close file, received ok   |OkEOF     |
+|        | |EOF(pos) == rxpos           |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |5|rxpkt EOF &                 |Close, save for resume    |OkEOF     |
+|        | |EOF(pos) == -2              |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |6|rxpkt EOF &                 |Report bad EOF            |BadPos    |
+|        | |EOF(pos) != rxpos           |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |7|File write error or         |Close, save for resume    |          |
+|        | |user wishes to skip file    |rxpos = -2                |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |8|rxpkt IDLE &                |braintimer = 120          |          |
+|        | |hdxlink == False            |                          |          |
++--------+-+----------------------------+--------------------------+----------+
+|BadPos  |1|DATA/EOF(pos) <= rxlastsync |rxretries = 0             |Timer     |
+|        | |                            |reset rxtimer             |          |
+|        | |                            |rxlastsync = pos          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|DATA/EOF(pos) > rxlastsync  |rxlastsync = pos          |Timer     |
++--------+-+----------------------------+--------------------------+----------+
+|Timer   |1|rxtimer expired             |                          |HdxLink   |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (rxtimer not expired)  |                          |DATA      |
++--------+-+----------------------------+--------------------------+----------+
+|HdxLink |1|rxretries > 4 &             |hdxlink = True            |Retries   |
+|        | |txstate < REND &            |rxretries = 0             |          |
+|        | |originator == False &       |                          |          |
+|        | |hdxlink == False            |                          |          |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|else (above not the case)   |                          |Retries   |
++--------+-+----------------------------+--------------------------+----------+
+|Retries |1|inc rxretries == 10         |Report too many errors    |Abort     |
+|        +-+----------------------------+--------------------------+----------+
+|        |2|rxretries == 1              |increase rxsyncid         |RPos      |
+|        +-+----------------------------+--------------------------+----------+
+|        |3|else (rxretries > 1)        |                          |RPos      |
++--------+-+----------------------------+--------------------------+----------+
+|RPos    |                              |lastrxdatalen/=2 (min.64) |DATA      |
+|        |                              |txpkt RPOS (rxpos,        |          |
+|        |                              |   lastrxdatalen,rxsyncid)|          |
+|        |                              |rxtimer = timeout         |          |
++--------+------------------------------+--------------------------+----------+
+|OkEOF   |                              |txpkt EOFACK              |FINFO     |
+|        |                              |reset rxtimer             |          |
+|        |                              |braintimer = 120          |          |
++--------+-+----------------------------+--------------------------+----------+
+|DONE    |1|rxpkt FINFO (apparent dup)  |txpkt FINFOACK(-2)        |          |
++--------+-+----------------------------+--------------------------+----------+
+
+
+    HYDRA in FidoNet technology mailers
+    =====================================================================
+    HYDRA is suitable for use in FidoNet mailers. It can be implemented
+    for EMSI and FTS-6 mail sessions. The FTS-6 (YooHoo) capability bit
+    for HYDRA is 0x0020 (DOES_HYDRA). The EMSI and IEMSI protocol
+    capability flag is HYD.
+
+    When utilizing HYDRA in a mail session, two complete batches are
+    always performed. Little else differs from a normal FTS-6 ZedZap mail
+    session. The first batch is used to transmit all mail, files, and
+    file requests by both sides. The second batch is always performed,
+    sending nothing if there are no file requests to honor. The data
+    buffers are not purged between the two batches since HYDRA ignores
+    any leftovers from the previous batch (END packets, etc.).
+
+    To integrate HYDRA into an existing mailer, the same code used for
+    the ZedZap session flow can be used, but instead of one transmit and
+    one receive session, two transmit sessions (or batches) are used.
+    When the HYDRA end of batch is initiated it will not be terminated
+    until an end of batch has been received from the remote and the end
+    of session sequence has been finished.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido
+    Software.
+
+
+    Error detection using CRCs
+    =====================================================================
+    CRC (Cyclic Redundancy Check) values only provide their promised
+    maximum error detection capability when properly applied, which
+    involves calculating and transmitting low-bit first, presetting the
+    CRC with all ones, and transmitting the ones' complement of the
+    result. The receiver also initializes to all ones, processes all of
+    the data AND the following CRC, and the result should match a "magic
+    value" which is 0xf0b8 for the 16-bit CRC and 0xdebb20e3 for the
+    32-bit CRC.
+
+    The easiest and fastest way to perform CRC calculations is by using a
+    table that does the algorithm's shift-operations in 8-bits at a time.
+
+
+    CRC-16 error detection
+    ---------------------------------------------------------------------
+    16-bit CRC using the CCITT CRC-16 polynomial. This is the default at
+    startup, and always used for HEX packets even if both sides are
+    capable of handling 32-bit CRCs.
+
+    This CRC-16 is not identical to the one used by the Xmodem and Zmodem
+    file transfer protocols. The polynomial is the same
+    (X^16+X^12+X^5+X^0 or 0x8408) but the bit-ordering is the opposite,
+    and preconditioning and postconditioning is used as in 32-bit CRCs.
+    This method is also used by the European version of X.25.
+
+    The 16-bit CRC table is created as follows (pseudocode, the variable
+    CRC16 and the table of 256 entries are 16-bit unsigned integers):
+
+        FOR (i=0 TO 255)
+            {
+            CRC16=i
+            FOR (N=1 TO 8)
+                {
+                IF (CRC16 AND 1)
+                    CRC16=(CRC16 >> 1) XOR 0x8408
+                ELSE
+                    CRC16=CRC16 >> 1
+                }
+            CRC16TAB[i]=CRC16;
+            }
+
+    When processing data, each byte is run through the CRC calculation
+    routine as follows (variable CRC stores the 16-bit CRC value/result,
+    C is the next 8-bit char):
+
+        CRC=CRC16TAB[(CRC XOR C) AND 0xff] XOR ((CRC>>8) AND 0x00ff)
+
+
+    CRC-32 error detection
+    ---------------------------------------------------------------------
+    32-bit CRC using the CCITT CRC-32 polynomial. Support of CRC-32 is
+    optional and signalled in the INIT packet.
+
+    If both sides indicate they can handle CRC-32, all packets except
+    those transmitted in HEX format use this algorithm instead of CRC-16
+    to improve error detection.
+
+    This CRC-32 is identical to the one used by the Zmodem protocol.
+    The polynomial is (0xedb88320):
+
+    X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+
+    The principal method of calculation, transmission, and checking is
+    identical to CRC-16 as described above, but the "magic value" for
+    32-bit CRC is 0xdebb20e3.
+
+    The CRC-32 table is created as follows (pseudocode, the variable
+    CRC32 and the table of 256 entries are 32-bit unsigned integers):
+
+    FOR (i=0 TO 255)
+        {
+        CRC32=i
+        FOR (N=1 TO 8)
+            {
+            IF (CRC32 AND 1)
+                CRC32 = (CRC32 >> 1) XOR 0xedb88320
+            ELSE
+                CRC32 = CRC32 >> 1
+            }
+        CRC32TAB[i] = CRC32;
+        }
+
+    When processing data, each byte is run through the CRC calculation
+    routine as follows (variable CRC stores the 32-bit CRC value/result,
+    C is the next 8-bit character):
+
+        CRC=CRC32TAB[(CRC XOR C) AND 0xFF] XOR ((CRC>>8) AND 0x00ffffff)
+
+
+    The authors
+    =====================================================================
+    The authors can be reached at the following addresses:
+
+    Joaquim H. Homrighausen                    Arjen G. Lentz
+    389, route d'Arlon                         Lentz Software Development
+    L-8011 Strassen                            Langegracht 7B
+    Luxembourg                                 3811 BT Amersfoort
+                                               The Netherlands
+	joho@ae.lu
+    FidoNet 2:270/17                           aglentz@fido.lu
+                                               FidoNet 2:283/512
+
+
+    The name HYDRA
+    =====================================================================
+    Hydra is a greek mythological creature (the watersnake). Like the
+    Nemeic lion, Hydra is the daughter of the giant Typhon and the snake
+    Echidna.
+
+    She grew up in the marshes of Lerna near/in Argolis (Argos). There
+    she ate entire herds of cattle and destroyed large cropfields. Later,
+    she lived in caves on a hill near the spring of Amymone.
+
+    Hydra is a monstrous large snake with nine heads: eight mortal ones,
+    and one (the middle one) immortal. She was defeated and killed by
+    Heracles (Hercules) - son of Zeus and Alcemene, grandson of Perseus -
+    as the second of his twelve tasks, with the help of his cousin
+    Iolaos. Every time he cut of one of the heads with his sword, two new
+    heads grew in its place. So Iolaos scorched the wound of each cut off
+    head with burning branches so the head couldn't grow on again.
+
+    Heracles buried the last and immortal head under a stone nearby. He
+    also dipped his arrows in Hydra's poisonous blood, thereafter the
+    wounds caused by those arrows were incurable.
+
+
+    Also star constellation (sign of the watersnake) in the equatorial
+    zone.
+
+
+    Also a type of sweetwater polip (the Hydroidea Thin, tubeshaped body
+    can be full contracted, just like the six (or more) tentacles. There
+    is no generation change, the gender-products grow directly on the
+    body.
+
+    The animals catch their prey with nettlecells, and are very verocious.
+    They can be found in various stilstanding and flowing water and were
+    first described by Anthonie van Leeuwenhoek in the year 1704.
+
+
+    Also small island (spelled Idhra in modern Greek) of the Sargonic
+    group in the Aegean Sea, just of the eastern tip of the Argolis
+    peninsula of the Peloponesus (Attika). Its length (NE/SW) is 21 km,
+    with a total area of 49,6 square km. Its highest point is 597 meters
+    above sea level. Population of 2794 (latest census: 1981). Only one
+    real city with the same name as the island. Once quite wooded and
+    well watered, now denuded and dry, with almost no arable land
+    (infertile limestone). Certain times of the year the people have to
+    ship in water from the main land. Its Turkish name is Camliza which
+    means "Place of Pines".
+
+    References:
+         Dutch:  Oosthoeks Encyclopedie
+                 Grote Winklerprins Encyclopedie
+       English:  Encyclopaedia Brittannica
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0087.html b/html/ftsc/fsc-0087.html new file mode 100755 index 00000000..714a8ac7 --- /dev/null +++ b/html/ftsc/fsc-0087.html @@ -0,0 +1,305 @@ + + +File Forwarding in Fidonet Technology Networks. + + + + +
+  | Document: FSC-0087
+  | Version:  001
+  | Date:     31 October, 1995
+  |
+  | Robert Williamson FidoNet#1:167/104.0
+
+    File Forwarding in Fidonet Technology Networks
+    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+    Purpose: 
+        To  document  current practices in File Forwarding and the minimum
+    requirements and known extensions of the TIC file format.
+
+    Acknowledgements:
+        The  TIC  file  format  was introduced by Barry Geller, in the MSDOS
+    File Forwarder, Tick.  Useful extensions to this format were introduced
+    by Harald Helms, in the MSDOS FileForwarder, AllFix.
+    
+    Terminology:
+    FTN - Fidonet Technolgy Network, such as FIDONET, AMIGANET or IBMNET.
+          Sometimes used interchangably with the term DOMAIN.
+
+    FNC - FileName Conversion, process of converting filenames to msdos 8.3
+          format for transmission.
+
+    FQFA - Fully Qualified FTN Address, the format is
+              FTN#Zone:Net/Node.Point
+
+    CRC - Cyclic Redundancy Check, method to determine whether some data
+          has been altered. CRC-32 is used in File Forwarding.
+
+    TIC - a file that contains control information for the File Forwarding
+        system.   These  files  are  named  xxSTAMP.TIC,  where  xx  is  an
+        abbreviation  representing  the  File  Forwarding  program name and
+        stamp  is  a  unixdate  stamp  truncated  to 6 characters.  
+
+    UTC  -  Universal  Time  Coordinated,  the  time  at  the  0o  meridian
+        (Greenwich); previously called GMT
+
+
+    forwarding  -  the  process  of  creating and sending tic files and the
+                   associated  file to one's downlinks.
+
+    ticking - the processing of reading and verifying a tic file and it's
+              associated file.
+
+    hatching - the process of introducing a new file into a fileecho
+
+    cross-hatching - the process of forwarding a file from one fileecho
+                     (ususally restricted) to another
+
+    Associated File - The file listed in the FILE field of the TIC file.
+
+
+        Note that use of UPPERCASE on tic file keywords in this document in
+        for display purposes only.
+
+  Format of a TIC file:
+
+    Addressing:
+        In  a  tic  file  any form of FTN address representation from 3d to
+        FQFA  may  be  used.   All  File  Forwarders  must  understand  the
+        following formats:
+          zone:net/node                 - 3D 
+          zone:net/node.point           - 4D
+          zone:net/node@ftn             - 5D - point 0 assumed
+          zone:net/node.point@ftn       - 5D 
+          ftn#zone:net/node.point       - fqfa
+
+        File Forwarders should have configurable options per site as to the
+        type of addressing each of it's downlinks can understand.
+
+    Dates:
+        All dates are expressed in UTC.
+
+    TimeDateStamps:
+        All  TimeDateStamps are unix TimeDateStamps (# of seconds since Jan
+        1, 1960) in UTC and expressed in hexadecimal notation.
+
+    Case Insensitivity:
+        the  format is completely case-insensitive.  It is general practice
+        that  the  first  letter  of a keyword is uppercase.  This is not a
+        requirement.
+
+    Order Dependancy:
+        keywords are not order dependant.
+        Order  dependancy  is required in some groupings of a keyword, such
+        as PATH, VIA, DESC and APP.
+
+    Modification of address fields on PassThrough:
+        The  forwarding  site may modify the addresses in any keyword field
+        to  make  them  compliant  with  the addressing limitations of each
+        downlink.  
+
+    Stripping of SeenBys:
+        The  forwarding site may strip seenbys to current FTN, ZONE or NET,
+        when not forwarding outside of current FTN, ZONE or NET.  This does
+        not imply nor permit the stripping of of a direct downlink which is
+        outside the current strip filter.
+
+
+    Keywords:
+      There are no colons on keywords.
+
+      Each keyword line is terminated with CR LF pair.
+
+      The maximum length of a keyword line is 256 characters, including the
+      CRLF termination. Some keyword lines may have a shorter limit.
+
+      Keywords  are  separated from their data by a single space.  There is
+      no space if there is no data associated with the keyword.
+        eg:  ReturnReceipt
+
+      Keywords are case-insensitive and order independant.
+
+      Keywords not understood are to be passed-though.
+
+      Known Keywords that are blank should not be passed though.
+        For  example,  an  empty  AREADESC,  could be either dropped or the
+        blank  replaced with the proper description.
+
+      Most Keywords are passed through when processing.
+        There  are  exceptions.  In some cases, a site-specific replacement
+        may be created.
+        Keywords marked with a ^ should not be passed-through.
+
+      Keywords marked with a * are REQUIRED when processing a TIC file.
+        If  any  of these are missing, the tic file should be considered as
+        BAD and the associated file not forwarded to downlinks.
+
+      Keywords marked with a # are CREATED when hatching or forwarding.
+
+
+    *#  AREA [AreaName]
+          the TagName of the file area.
+
+        AREADESC [description of area]                    OPTIONAL
+          a  short  (80 chars) description of the file area.  This could be
+          the description found in FileBone.NA
+
+    *#  FILE [File being sent]
+          the name of the file being sent, no path
+          the filename must conform to msdos 8.3 format, unless it is known
+          that the receiving site can handle longer filenames.
+     
+    ^#  FULLNAME [original filename before FNC]           OPTIONAL FNC only
+          the original filename (no path) before FileName Conversion    
+
+    *#  CRC [CRC-32 in hex]
+          crc of the file being sent, 8 hexadecimal characters
+
+    ^   MAGIC [MagicName]               OPTIONAL
+          Name  under  which the file can be FREQed from the site listed in
+          FROM.   This  is  NOT  passed  though when forwarding, unless the
+          MAGIC  name  is  the  same  on  the  forwarding  site.  It can be
+          replaced by the appropriate name.
+
+        REPLACES [FileName]               OPTIONAL
+          Filename  (no  path)  of  a  file  hatched  in  the AREA that the
+          associated file replaces.  If the site expects FNC files, and the
+          filename  does  not confrom to msdos 8.3 convention, the REPLACES
+          name should also be FNC.
+
+     #  DESC [Description]
+          Description of the file, limited to 80 characters per line,
+          including CRLF termination.
+          If  multiple LDESC lines are used, the DESC line must provide the
+          maximum information.  No File Forwadrer is required to passthough
+          or make use of any extra DESC line after the first.
+
+     # LDESC [multiple lines]
+          A  long description of the file.  LDESC does NOT replace DESC, it
+          is  used IN ADDITION to the short description.  No File Forwarder
+          is required make use of LESC lines.
+
+     #  SIZE [Bytes]              OPTIONAL, SHOULD be required
+          Length of the file in bytes
+
+        DATE [TimeDateStamp]
+          TimeDateStamp of the file. Can be date of creation of archive.
+
+       RELEASE [TimeDateStamp]
+          Date  when file is TO BE released.  Usually used by SDS, but can
+          be used by ADS as well.
+
+       AUTHOR [name]
+          Name  of  the author of the software package being hatched.  This
+          field  is  obviously not applicable to Newsletters, Nodelists and
+          Diffs and the like.
+
+       SOURCE [authors_address]
+          FTN  address of the Author of the software package being hatched.
+          Not  necessary  the same as the ORIGIN hatch site.  Does not have
+          to be an FTN address.
+
+     ^ APP [program] [Application Specific Information]
+          The  APP  keyword  is  a  keyword  known  to programs of the name
+          indicated.  APP'S are order dependent and must be passed though.
+  
+    *#  ORIGIN [Address]
+          Site where file entered the fileecho
+
+    *^# FROM [Address] [Pwd]
+          Site  that  is  forwarding  the  file  to  the next site.  Pwd is
+          optional and rarely used, IF AT ALL.  Pwd is NEVER passed through.
+
+    ^   TO [Address]                        OPTIONAL
+          Site  to  which  this TIC and the assocaited file are being sent.
+          This keyword is included in the .TIC file when:
+            a)  the file is being routed via another system which permits
+                such routing.  
+            b)  the  platform  in  use  does  not  have  any  FTN  software
+                independant   method   of   associating   a  file  nd  it's
+                destination.   eg.   platforms  that  do not have filenotes
+                that   could  contain  this  information  as  part  of  the
+                filesystem.
+
+          If  the address in the TO line is that of the receiving site, the
+          field  is  not passed through when forwarding.  If the address in
+          the  TO  lines  IS  NOT  that of the receiving site, it should be
+          forwarded to the TO site, if a routing agreement is in place with
+          the sending site.
+
+    *^# CREATED [by] [Program Banner]
+          File  Forwarder which created the TIC file.  This is generally in
+          the form:  
+            Created [by] program_name version [copyright_info]
+
+        VIA [FROM CREATED]                  OPTIONAL (tracking)
+          Copy  of  CREATED  line of FROM, with 'Created [by]' stripped and
+          FROM  prepended.   Always passed though.  The VIA is only created
+          by the receiving site when forwarding. It is never created by the
+          hatching  site.  Therefore, in any TIC file, the addresses in the
+          FROM and VIA should never be the same.
+          examples:
+          Via 1:167/100 ALLFIX+ 4.31 Copyright (C) 1992,95 Harald Harms (2:281/910)
+          Via FIDONET#1:167/104.0 XTick 3 Copyright (c) 1995 Robert Williamson FIDONET#1:167/104.0
+
+    *#  PATH [Address] [TimeDateStamp] [date and time]
+          Address  of  Site  which  has forwarded the file.  TimeDateStamp,
+          date and time is that of when the Site received and Processed the
+          file.
+
+    * # SEENBY [Address]
+          Site  which  has  received the file.  There are multiple lines of
+          Seenby and they are unordered.
+
+    *   PW [password]
+          Site or Area password.  This is case-insensitive and should be at
+          least 5 characters in length. 
+
+        PGP [signature]
+          PrettyGoodPrivacy signature. To be discussed. 
+
+    ^    ReceiptRequest -no data-               OPTIONAL
+          A  request  to the receiving system to generate a IsReturnReceipt
+          (attribute  word bit 13) messsage, in the same manner it would if
+          it  had  received  a message with the FileAttach an ReturnReceipt
+          attributes and a subject of the filename.
+          There  is  NO  requirement  to recognize this keyword.  It should
+          never be passed through.
+
+  Transmission of Files:
+
+    The  associated file, that is, the file Listed in the FILE field of the
+  TIC  file, should always be sent FIRST.  In the case of a failed session,
+  sending  the  FILE  first  prevents  the  orphaning  of  the file that is
+  normally caused by the deletion or movement of the TIC file to BAD. 
+
+    File  Forwarders should not move or delete orphaned TIC files, but this
+  can neither be relied upon nor mandated.
+
+    File  Forwaders  should  be  transparent  to  the  renaming  of file by
+  mailers.   This  means  that  if  the  mailer renames a duplicate file by
+  renaming  or  bumpinmg  a numeric extension, the File Forwarder should be
+  able  to  use  the  size  and  crc fields of the TIC to find and properly
+  rename the associated file referred to in the TIC.
+
+  File  Forwaders  should  always  delete and dequeue unsent TIC files when
+  re-hatching  the  same  or  updated  version  of an associated file.  The
+  implementor  may  wish  to  allow  exceptions  for  periodicals  such  as
+  nodediffs and newsletters.
+
+ -to be continued-
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0088.html b/html/ftsc/fsc-0088.html new file mode 100755 index 00000000..8231eaf1 --- /dev/null +++ b/html/ftsc/fsc-0088.html @@ -0,0 +1,326 @@ + + +Compatibility and Link Qualifier Extensions for EMSI Sessions + + + + +
+  | Document: FSC-0088
+  | Version:  001
+  | Date:     31 October, 1995
+  |
+  | Robert Williamson FidoNet#1:167/104.0
+
+    Compatibility and Link Qualifier Extensions for EMSI Sessions
+    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+    Purpose:
+
+    The  basic  purpose of this document is to start discussions which will
+    hopefully result in an improved handshake negotiation protocol.
+
+    Scope:
+
+    Relation of flags to Types of files transferred:
+
+    The  FSC-0056  EMSI  specification  (hereafter  referred  to as EMSI-I)
+    makes  little  distinction  between  ARCmail/packets and other types of
+    files,  such  as  files attached and TIC'ed files.  In EMSI-I, the term
+    'Mail'  when  not  used  in  conjunction with the term 'compressed', is
+    interpreted to mean ANY file.
+
+    This  extension  (hereafter  referred to as EMSI-II) makes reference to
+    and  allows control of types of files in addition to 'compressed mail'.
+    References  to  'Mail'  are  changed to 'File' where common practice so
+    indicates.   The  additional qualifier flags described provide for more
+    control as to the types of files a system is prepared to receive.
+
+
+    Relation of flags to presented addresses:
+
+    The  EMSI-I  specification does not allow qualification for any address
+    other than the PRIMARY address.  This means that Link flags are limited
+    in  application  to  either  all  presented addresses or to the primary
+    presented address only.
+
+    This  extension  also  allows  application  of  Link  flags to specific
+    addresses other than the primary.
+
+
+    Distinctions between Calling and Answering System:
+
+    In  the EMSI-I spec, the type of flags that may be presented is limited
+    by  the  status  of the site.  Certain flags may only be presented when
+    the  site  is the caller and other flags may only be presented when the
+    site   is   the   answerer.    This  proposed  extension  removes  this
+    distinction.
+
+    In the EMSI-I spec, certain Link and Capability (a.k.a:  Compatibility)
+    flags  are  caller-driven, while others are controlled by the answering
+    system.  This specification attempts to harmonize these discrepancies.
+
+    A  attempt  is made to remain somewhat backwards compatible and to have
+    new  flags  follow the original flag naming convention.  However, IMHO,
+    it  would  be preferable to harmonize the flags; reducing the number of
+    them  while retaining the fine type control, so that the same codes are
+    used in all sessions.
+
+    Under  both  EMSI-I and EMSI-II, any flags that are not understood, are
+    to  be  ignored.   Therfore,  if  a site presents it's flags in EMSI-II
+    format  and  the  other site does not do EMSI-II, it is permissable for
+    that site to interpret all flags according to EMSI-I specifications.
+
+
+    Specifics:
+
+    Compatibility flags:
+
+    Compatibility  flags  consist of a string of codes that specify the
+    PROTOCOL CAPABILITIES and ENABLED FEATURES of the mailer.
+
+    ARC, XMA
+    These  EMSI-I  compatibility  flags  have  no  meaning  relavant to the
+    transfer  of  files  and  are  not  to  be presented under EMSI-II.  If
+    received, they are to be ignored.
+
+
+    FNC    
+    The FNC EMSI-I compatibility flag has been identified as a 'mistake' by
+    the  author  of EMSI-I.  This is agreeable as that specification called
+    for   the   creation   of   a   filename   that  was  ALWAYS  8.3,  not
+    up-to-8.up-to-3.
+    It   is   not  to  be  presented  under  EMSI-II.   If  received  as  a
+    compatibility flag, it is to be ignored.
+
+
+    Protocol Selection:
+
+    In  the EMSI-I spec, a requirement is placed upon the calling system to
+    present  it's  available  protocols  in  order  of preference.  A quote
+    follows:
+
+        The calling system must list supported protocols first and
+        descending order of preference (the most desirable protocol
+        should be listed first).
+        The answering system should only present one protocol and it
+        should be the first item in the compatibility_codes field.
+
+    Some mailer authors have interpreted 'the compatibility_codes field' in
+    the  second  sentence  to  mean  that  of the answering system, thereby
+    making  protocol  selection RECEIVER-PREFS driven.  This interpretation
+    makes  unnecessary  the  'decending  order' requirement placed upon the
+    calling   system,   so  shall  be  considered  in  conflict  with  that
+    requirement.
+
+     Most   mailer  authors  have  interpreted  that  phrase  to  mean  the
+    'compatibility_codes  field'  OF  THE  CALLER,  thereby making protocol
+    selection  CALLER-PREFS  driven.   Since  EMSI-I  was intended to be "a
+    clear  protocol  definition  for  state-of-the-art  E-Mail  systems  to
+    follow",  they  cannot  be  faulted  for  interpretation.  Caller-prefs
+    driven  selection  is state-of-the-art, receiver-prefs driven selection
+    is older technolgy, such as Wazoo.
+
+    This   specification   requires   that   the   second  interpretation,
+    CALLER-PREFS driven, be mandatory.
+
+
+    New Compatibilty Flags:
+    ----------------------
+
+    EII
+    Indicates   that   the   system   will   interpret   flags  under  this
+    specification, if other end also presents this flag.  IF either or both
+    systems  do  not  present  this  flag,  all  interpretations  are  done
+    according to EMSI-I.
+
+    DFB
+    Indicates  that  the  system  presenting  is  capabable of fall-back to
+    FTS1/WAZOO  negotiation  in the case of failure of EMSI handshake or no
+    common  protocol.   Since  ZMO  is  the  minimum required protocol, NCP
+    should  only  occur  if  the  answering  system  presents more than one
+    protocol..  (ie. it's broken)
+
+    FRQ
+    Indicates  that  the  system  will  accept  and  process  file requests
+    received  during  outbound  calls.   In other words, the calling system
+    will  do a second turnaround for uni-directional protocols, to send the
+    files requested, at his cost.
+
+    NRQ
+    NRQ should be presented ONLY IF the mailer does not have a file request
+    server, task or function and cannot accept requests..  It should NOT be
+    used to indicate that the  function  is  temporarly disabled. 
+
+    When  examined,  No  requests will be sent.  It would be advisable that
+    the  mailer  alert  the  system  operator  of this occurance to prevent
+    continued polling of the remote site.
+
+
+    Protocol Capabilities:
+
+    Protocol   capability   flags  are  presented  in  decending  order  of
+    preference  by  the  caller.  The answering system selects and presents
+    the  FIRST  protocol  from  the  callers  list  that  it supports.  The
+    answering system must present only ONE protocol.
+
+    HYD  Hydra bi-directional    (link flags define parameters)
+    JAN  Janus bi-directional
+    TZA  DirectZap               (TrapDoor DirectZap varient)
+    DZA  DirectZap               (Zmodem variant, reduced escape set)
+    ZAP  ZedZap                  (Zmodem variant, upe 8K blocks)
+    ZMO  Zmodem w/1,024 packets  (Wazoo ZedZip)
+    SLK  SeaLink                 (no TYSNC, No MDM7, No TeLink)
+                                 (8-32k window/ReSync/OverDrive/LongNames)
+
+    NCP
+    This  is  presented  if  no compatible protocol can be negotiated under
+    EMSI.   Since  in  most  FTN  networks,  a  common protocol DOES exist,
+    fallback   to  WaZoo  and  FTS1  negotiation  is  expected.   If  these
+    negotiation methods are not available, the session is terminated.
+
+    This  condition  should  never  occur  under  normal circumstances.  It
+    should  be  considered as a problem with the design or configuration of
+    one of the mailers involved.
+
+    Link flags:
+    ----------
+
+    Link  flags  consist  of a string of codes that specify DESIRED CONNECT
+    CONDITIONS.   They  apply  to  the CURRENT SESSION ONLY.  Under EMSI-I,
+    there are four TYPES of link flags:  communications parameters, session
+    parameters, pickup options and hold options.  Under EMSI-II, only three
+    types  are  used,  the communications parameters type is REMOVED, as it
+    serves no purpose whatsoever in FTN operations.
+
+
+    Link Session options:
+
+    FNC
+    If  either  system  presents  this  flag,  it is an indication that the
+    presenting   system   requires   filename   conversion   to  cp/m-msdos
+    conventions.  The other system will convert filenames to cp/m cpm/msdos
+    8.3 conventions before sending. 
+    The   convention   is   defined   as   a  filename  consisting  of  two
+    parts,  the  filepart  and  extension.   The filepart and extension are
+    separated  by a period ".".  The filepart may be from 1 to 8 characters
+    in  length  and  the  extension  may  be  from  0 to 3 characters.  The
+    character set shall be any uppercase character in the range A-Z and any
+    numeric  character  in  the  range  0-9.   If  the extension is of zero
+    length, the period may or may not be present.
+
+
+    RMA
+    Indicates that the presenting site is able to send and process multiple
+    file  requests.   If both sites present this flag, the caller will send
+    any REQ files found for each AKA presented by the answering system.
+    The answering system will process each received REQ.
+
+    RH1
+    Indicates  that  under  the  Hydra  protocol,  batch  one contains file
+    requests only, while batch 2 is reserved for all other files.
+    
+
+    (others to be defined)
+
+    Pickup and Hold Flags:
+
+    Under  the  EMSI-I  specification, Link Pickup flags are only presented
+    when  calling (an Outbound Session) and are examined and processed only
+    when  answering  (an  Inbound  Session)  and  Link  Hold flags are only
+    presented  when  answering  (an  Inbound  Session) and are examined and
+    processed only when calling (an Outbound Session).
+
+    With  EMSI-II,  BOTH  Pickup and Hold flags are presented by both sites
+    during  a  session.   This  allows  more control for those systems, for
+    example,  which  cannot  modify  addresses  presented or rotate akas to
+    change  the  primary  address  presented  on  a per-session or per-site
+    basis.
+
+
+    Link Pickup and Hold:
+
+    Each  system can present one of three (or more) Link options related to
+    application of addresses.  If neither of these flags are presented, PUA
+    is to be assumed.
+
+    Neither  PUA  nor  PUP  is  to  be  presented  if  only one address was
+    presented.
+
+             PUP     Pickup FILES for primary address only
+          /  PUA     Pickup FILES for all presented addresses
+         /   PUn     Pickup FILES for address number n in AKA list
+ one of |
+         \
+          \  NPU     No FILE pickup desired. (calling system)
+             HAT     Hold all FILES          (answering system)    
+             HAn     Hold all FILES for address number n in AKA list
+
+
+    Qualifiers:
+
+    Qualifiers  are  processed  in  the  order presented, with any conflict
+    being  resolved  by  subsequent  qualifiers overridding any conflicting
+    previous qualifier in the list.
+
+    Qualifiers may be not be presented with either NPU or HAT and should be
+    ignored if received with NPU or HAT.
+
+    PickUp:
+
+        PMO     PickUp Mail (ARCmail and Packets) ONLY 
+        PMn     PickUp Mail ONLY for address number n in AKA list
+
+        NFE     No TIC'S, associated files or files 
+                attachs desired
+        NFn     No TIC'S, associated files or file attaches, 
+                for address number n in AKA list
+
+        NXP     No compressed mail pickup desired 
+        NXn     No compressed mail pickup desired, 
+                for address number n in AKA list
+
+        NRQ     File requests not accepted by caller
+                This  flag is presented if file request processing
+                is disabled TEMPORARILY for any reason
+        NRn     File requests not accepted by caller
+                for address number n in AKA list
+
+     Note that NFE,NPX,NRQ != NPU
+
+    Hold:
+
+        HNM     Hold all traffic EXCEPT Mail (ARCmail and Packets)
+        HNn     Hold all traffic EXCEPT Mail (ARCmail and Packets)
+                for address number n in AKA list
+
+        HXT     Hold compressed mail traffic.
+        HXn     Hold compressed mail traffic.
+                for address number n in AKA list
+
+        HFE     Hold tic's and associated files
+                and file attaches other than mail 
+        HFn     Hold tic's and associated files
+                and file attaches other than mail 
+                for address number n in AKA list
+
+        HRQ     Hold file requests (not processed at this time)
+                This  flag is presented if file request processing
+                is disabled TEMPORARILY for any reason
+        HRn     Hold file requests (not processed at this time)
+                for address number n in AKA list
+
+     Note that HXT,HRQ,HFE == HAT
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0091.html b/html/ftsc/fsc-0091.html new file mode 100755 index 00000000..7be686be --- /dev/null +++ b/html/ftsc/fsc-0091.html @@ -0,0 +1,60 @@ + + +ISDN nodelist flags (rev.002). + + + + +
+ | Document: fsc-0091
+ | Version:  001
+ | Date:     01 Jun 1996
+ | Arjen Lentz, 2:283/512
+
+ISDN nodelist flags (rev.002)                   Arjen Lentz (agl@bitbike.com)
+addendum to FTS-0005                                        FidoNet 2:283/512
+superceding FSC-0075                                       October 30th, 1995
+
+Input from Michael Buenter, Jan Ceuleers, Chris Lueders, and others. Thanks!
+
+The proposed new information text in nodelist trailer is as follows:
+
+   Nodelist  Specification of minimal support required for this flag;
+   flag      any additional support to be arranged via agreement between users
+   ========  =================================================================
+   V110L     ITU-T V.110 19k2 async ('low').
+   V110H     ITU-T V.110 38k4 async ('high').
+   V120L     ITU-T V.120 56k async, layer 2 framesize 259, window 7, modulo 8.
+   V120H     ITU-T V.120 64k async, layer 2 framesize 259, window 7, modulo 8.
+   X75       ITU-T X.75 SLP (single link procedure) with 64kbit/s B channel;
+               layer 2 max.framesize 2048, window 2, non-ext.mode (modulo 8);
+               layer 3 transparent (no packet layer).
+   ISDN      Other configurations. Use *only* if none of the above fits.
+   ===========================================================================
+   NOTE: No flag implies another. Each capability MUST be specifically listed.
+   If no modem connects are support, the nodelist speed field should be 300.
+
+   Conversion from old to new ISDN capability flags:
+   - Nodes in the USA currently use the 'ISDN' flag.
+     Most will be able to change to V120H (64k lines).
+     Also many to V120L,V120H (64k lines) with autodetecting equipment.
+     Some to only V120L (still with 56k lines).
+   - Nodes in Europe currently use the ISDNA, ISDNB and ISDNC flags.
+     A simple translation will do the trick here.
+     ISDNA -> V110L
+     ISDNB -> V110H
+     ISDNC -> X75
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0092.html b/html/ftsc/fsc-0092.html new file mode 100755 index 00000000..74462c06 --- /dev/null +++ b/html/ftsc/fsc-0092.html @@ -0,0 +1,243 @@ + + +New control lines for forwarded messages. + + + + +
+ | Document: FSC-0092
+ | Version:  001
+ | Date:     September 12th 1996
+ | Author:   Michael Hohner
+
+
+                                 New control lines
+                              for forwarded messages
+
+                                        by
+                                  Michael Hohner
+                                  2:2490/2520.17
+
+                                  September 1996
+
+   Status of this document:
+
+         This document proposes a standard for the Fidonet(tm) community
+         and for other networks using Fido technology. It may be freely
+         distributed if unchanged.
+
+         You can reach the author at one of the addresses listed at the end
+         of the document.
+
+
+   Abstract:
+
+         Most fidonet message editors offer a "forward" function. Using
+         this function a user A can sort of "redirect" a message from user B
+         to another user C, maybe because A is not the correct recipient or
+         because C is a better person to answer the message. The name and
+         address of B are usually included in the forward in free-text format.
+         The message text is included in non-quoted format.
+
+         A problem arises when the final recipient C wants to reply to sender B
+         of the forwarded message. The forward contains the intermediate user A
+         as the sender. So user C must insert the name and address of B
+         manually, using the information contained in the message text. The
+         message editor of C can't do this automatically because of the
+         free-text format. The editor will also use incorrect quote initials,
+         which is at least irritating.
+
+         This document introduces 6 new control lines which contain the header
+         information of the original message. With these control lines the
+         message editor can use the original header information automatically.
+
+
+   Specifications:
+
+         There are 7 new control lines: FWDFROM, FWDTO, FWDORIG, FWDDEST,
+         FWDSUBJ, FWDAREA, FWDMSGID. As all control lines they start with an
+         ASCII 01 character followed by the control line name followed by
+         whitespace followed by the control line's content followed by ASCII 13.
+
+         Please note that all these control lines do not have a colon (like the
+         control lines in FTS-0001). This would be just waste of space.
+
+         FWDFROM
+         -------
+
+         This control line contains the name of the original sender as found in
+         the FROM field of the original message. Leading and trailing
+         whitespace should be removed. This control line should be omitted
+         altogether if the FROM field is empty.
+
+         FWDTO
+         -----
+
+         This control line contains the name of the original recipient as found
+         in the TO field of the original message. Leading and trailing
+         whitespace should be removed. This control line should be omitted
+         altogether if the TO field is empty.
+
+         FWDORIG
+         -------
+
+         This control line contains the address of the original sender as found
+         in the ORIG field of the original message. The usual 5D ASCII notation
+         (zone:net/node.point@domain) should be used. This control line should
+         be omitted altogether if the address is not known.
+
+         FWDDEST
+         -------
+
+         This control line contains the address of the original recipient as
+         found in the DEST field of the original message. The usual 5D ASCII
+         notation (zone:net/node.point@domain) should be used. This control line
+         should be omitted altogether if the address is not known or unsure
+         (as it is the case with forwarded echomail messages).
+
+         FWDSUBJ
+         -------
+
+         This control line contains the subject line of the original message.
+         This control line should be omitted altogether if the SUBJ field is
+         empty.
+         This control line should by made optional for security reasons. Echo
+         manager passwords are too easily revealed with it.
+
+
+         FWDAREA
+         -------
+
+         This control line contains the name of the echomail area where the
+         original message was forwarded from. It should be omitted altogether
+         if the original message was not forwarded from an echomail area.
+
+         FWDMSGID
+         --------
+
+         This control line contains the MSGID control line of the original
+         message. It should be omitted altogether if a MSGID control line is not
+         present in the original message.
+
+
+   Usage:
+
+         When the "forward" function of the message editor is invoked, the
+         editor program should generate the proposed control lines from the
+         header of the original message. If the original message already was
+         a forwarded one (indicated by the presence of at least a FWDORIG
+         control line), the editor should keep all FWD* control lines and should
+         not add any FWD* control lines. This preserves the FWD* control lines
+         of the first forwarder, containing the header data of the author of
+         the original message.
+
+         The editor should not generate FWD* control lines, if the message isn't
+         to be forwarded. A mail forwarding robot may also generate these
+         control lines, if it not just readdresses the message.
+
+         When the "reply" function of the editor is invoked the program should
+         use the control lines' contents instead of the header information. The
+         control lines should not be included in the reply.
+
+         Since it may not be immediately clear whether the user wants to reply
+         to the forwarder or to the original sender, the editor should offer a
+         means to ignore the proposed control lines and start a "normal" reply
+         instead, e.g. by two distinct functions, user preference or dialog.
+
+
+         Pseudo code:
+
+         forwarding_message:
+            if is_forwarded_message then
+               don't change FWD* control lines
+            else
+               add FWD* control lines
+
+         quoting_message:
+            if is_forwarded_message then
+               if reply_to_forwarder then
+                  use header data (normal quoting)
+               else
+                  use FWD* control lines
+               remove FWD* control lines from reply
+            else
+               use header data (normal quoting)
+
+         other_functions:
+            remove/ignore FWD* control lines
+
+
+   Example:
+
+         Message from Joe User to my boss node:
+
+            From: Joe User 1:234/567
+            To:   Harry Herrmannsdoerfer 2:2490/2520
+            Subj: Some questions
+            @MSGID: 1:234/567 12345678
+            Text: Hello Harry!
+                  ...
+
+         Harry forwards the message to me:
+
+            From: Harry Herrmannsdoerfer 2:2490/2520
+            To:   Michael Hohner 2:2490/2520.17
+            Subj: Joe's message
+            @FWDFROM Joe User
+            @FWDORIG 1:234/567
+            @FWDTO   Harry Herrmannsdoerfer
+            @FWDDEST 2:2490/2520
+            @FWDSUBJ Some questions
+            @FWDMSGID 1:234/567 12345678
+            Text: Hi Michael!
+                  ...
+
+         My answer using the new control lines:
+
+            From: Michael Hohner 2:2490/2520.17
+            To:   Joe User 1:234/567
+            Subj: Some questions
+            @REPLY: 1:234/567 12345678
+            Text: Hi Joe!
+
+                  JU> ...
+                  ...
+
+
+   Compatiblity:
+
+         Editor programs which are not prepared for the proposed control lines
+         usually just ignore them and remove them from a reply. A reply goes
+         to the forwarder. Nothing gained and nothing lost.
+
+
+   Implementations:
+
+         This proposal is implemented in the author's Fidonet editor
+         "FleetStreet for OS/2" (versions 1.17 and above).
+
+
+   Contacting the author:
+
+         The author may be contacted electronically at the following addresses:
+
+         Fidonet:    2:2490/2520.17
+         Internet:   miho@osn.de
+         CompuServe: 100425,1754
+
+         Suggestions, comments and corrections are always welcome.
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsc-0093.html b/html/ftsc/fsc-0093.html new file mode 100755 index 00000000..ea3f2302 --- /dev/null +++ b/html/ftsc/fsc-0093.html @@ -0,0 +1,156 @@ + + +Reduced seen-by lines. + + + + +
+ | Document: FSC-0093
+ | Version:  001
+ | Date:     13 September, 1996
+ | Title:    Reduced seen-by lines
+ | Author:   Frank Ellermann, 2:240/5815.1
+
+
+  Reduced seen-by lines
+  Frank Ellermann, 2:240/5815.1
+
+
+  Abstract
+  --------
+  A way to save great amounts (estimated 10 %) of echo mail traffic by
+  reducing "seen by" informations, compatible with existing echo mail
+  tossers conforming to FTS-0004.
+
+
+  Definitions
+  -----------
+  A thorough understanding of FTS-0004 is required, the reader should
+  be familiar with PATH and SEEN-BY lines in echo mail, illegal and
+  legal echo mail distribution topologies, i.e. dup-rings, as well
+  as with some pre-requisite knowledge of zones, 4D and 2D addresses,
+  and the "sticky" 2D notation in PATH and SEEN-BY lines.
+
+  PATH: path lines as specified in FTS-0004
+  FSB:  full seen-by informations as specified in FTS-0004
+  TSB:  tiny seen-by informations as mentioned in FTS-0004, see below
+  RSB:  reduced seen-by informations specified below
+  dupe: multiple arrival of the same echo mail (e.g. different paths)
+
+
+  Examples of echo mail distribution topologies
+  ---------------------------------------------
+  In all examples a) to d) echo mail entered at system 1 is sent to
+  systems 2 and 3 with FSB 1 2 3. Therefore system 2 (3) knows, that
+  system 3 (2) already got this mail, topology a) is perfectly legal.
+
+  a) 1 - 3  b) 1 - 3  c) 1 - 3  d) 1 - 2
+     | /       |   |     | / |     | X |
+     2         2 - 4     2 - 4     2 - 4
+
+  In the exanmples b) and c) both systems 2 and 3 forward all mails
+  from system 1 to system 4, these topologies contain a dup-ring and
+  are therefore illegal following FTS-0004.
+
+  The examples a) and d) show fully connected polygons with three or
+  four nodes. In example d) a mail entered at system 1 is sent to
+  systems 2, 3, and 4 with FSB 1 2 3 4. The topologies a) and d) are
+  perfectly legal, there are no dupes caused by distribution.
+
+  In example b) each mail entered at system 1 reaching system 4 via
+  system 2 carries FSB 1 2 3 4, therefore system 4 will not forward
+  such mails to 3. Using TSB at system 2 the same mails would carry
+  TSB 2 4, therefore system 4 would forward them to 3 as dupes.
+
+  Note that illegal topologies as in example b) and c) cause dupes
+  with either FSB or TSB. The real problem with TSB is example b),
+  as it allows for loop mails on the dup-ring 1 - 2 - 3 - 4 - ...
+  and vice versa, if no additional checks for dupes are employed.
+
+  With RSB (specified below) systems contained in the PATH are not
+  stripped from the seen-by informations, therefore RSB avoid loop
+  mail much like FSB.
+
+
+  FSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the FSB qualify as recipients.
+  3) add own address(es) to the FSB set if not already contained.
+  4) add recipients to FSB, sort FSB, forward mail to recipients.
+
+
+  TSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the TSB qualify as recipients.
+  3) strip old TSB and start new TSB with own address(es).
+  4) add recipients to TSB, sort TSB and forward mail to recipients.
+
+
+  RSB algorithm
+  -------------
+  1) add own system to the PATH.
+  2) all area links not contained in the RSB qualify as recipients.
+  3) strip RSB addresses not matching an address in the PATH, then
+     add own address(es) to the RSB set if not already contained.
+  4) add recipients to RSB, sort RSB and forward mail to recipients.
+
+
+  PATH considerations
+  -------------------
+  There are 2 problems with the PATH kludge as specified in FTS-0004:
+
+  First like in the FSB the addresses in the PATH are 2D, and having
+  the same 2D address in different zones is possible. Therefore zone
+  gates are required to use the TSB algorithm. Unfortunately the PATH
+  is forwarded without regarding zone gating, therefore detection of
+  loop mail based solely on the PATH could be erroneous.
+
+  Further FTS-0004 (written 1989) expects future echo mail tossers to
+  implement PATH support, but doesn't require this support from old
+  implementations. Strictly spoken the PATH is still only an option.
+
+  In some areas of FidoNet (e.g. in zone 2) at least all non-terminal
+  nodes are required to fully support the PATH line, therefore this
+  problem will probably not show up in praxis. Of course any tosser
+  implementing the RSB feature is required to fully support the PATH.
+
+
+  Summary
+  -------
+  To show the benfits of RSB compared with FSB assume the following:
+
+  An echo mail travels from node to echo hub, host, major star, echo
+  host, hub, and finally arrives at a recipient. Each routing system
+  has 10 links, i.e. FSB at the recipient contain 51 addresses, about
+  400 characters, but RSB only 15 addresses in about 150 characters.
+
+  Therefore in an echo mail with 2500 characters about 10 % of its
+  size can be reduced using RSB in favour of FSB. If this estimation
+  is applicable on world wide FidoNet echo mail traffic, RSB can save
+  us an immense amount of costs.
+
+  This document can be adopted by the FTSC as FTS, in this case it
+  has to be regarded as an addition to FTS-0004 with the extension,
+  that all non-terminal nodes are required to support PATH lines as
+  specified in FTS-0004.
+
+  For additional informations (e.g. aspects of zone gating) feel free
+  to send mails to Frank Ellermann 2:240/5815 or leo@bfispc.hanse.de
+
+- eof -
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1001.html b/html/ftsc/fsp-1001.html new file mode 100755 index 00000000..9faa08a6 --- /dev/null +++ b/html/ftsc/fsp-1001.html @@ -0,0 +1,210 @@ + + +Timezone information in FTN messages. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1001
+Revision:       2
+Title:          Timezone information in FTN messages
+Author:         Odinn Sorensen, 2:236/77
+Revision Date:  27 September 1997
+Expiry Date:    13 September 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Current practice
+                3. Kludge specification
+                4. Timezone table
+                5. Examples
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Current practice for Fidonet Technology Network (FTN) messages is to
+  store dates in local time. Timezone information (if known) is
+  usually lost. This document specifies a standard for storage of
+  timezone information in FTN messages, in the form of a kludge named
+  TZUTC.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN messages in any form where
+  timezone information is not integrated in the message storage or
+  transport format. Specifically any form where the information would
+  be lost if not stored in a kludge, such as in FTS-1 stored messages
+  or packets.
+
+
+2. Current practice
+-------------------
+
+  Some kludges already exist to specify the timezone of messages,
+  notably "TZUTC" and "TZUTCINFO". Other kludges may exist.
+
+  To the authors knowledge, no official specification exists for any
+  of these kludges.
+
+  From observations of these kludges in actual messages, TZUTC and
+  TZUTCINFO are identical except for the name. TZUTCINFO is probably
+  named after the JAM msgbase subfield of the same name.
+
+  This document adopts and documents the TZUTC kludge because it is
+  the shortest of them.
+
+
+3. Kludge specification
+-----------------------
+
+  Messages which conform to this specification must add the kludge:
+
+    ^aTZUTC: 
+
+  The offset has the format <[-]hhmm>, where hhmm is the number of
+  hours and minutes that local time is offset from UTC. If local time
+  is WEST of UTC (Greenwich), then the offset is NEGATIVE. See the
+  table below for typical offsets.
+
+  Note that the hh in a timezone offset is not limited to a maximum of
+  12. This is because the International Date Line does not run exactly
+  along the boundary between zone -1200 and +1200. The minutes part is
+  00 for most timezones.
+
+  All four digits must be present. If the offset is negative, there
+  must be a minus ('-', ASCII 45, 2Dh) in front of the offset.
+
+  Implementations must NOT put a plus ('+', ASCII 43, 2Bh) in front of
+  the offset for positive numbers, but robust implementations should
+  be prepared to find (and ignore) a plus if it exists.
+
+  If local time changes as a result of, for example, daylight savings
+  time, then the offset in TZUTC need to be changed to reflect this.
+
+  When this kludge is present in a message, the "date written" field
+  in the stored message is guaranteed to be in local time for the
+  given timezone. Note that this specification does not specify the
+  timezone for any other date fields. Other date fields (such as "date
+  received, arrived, processed, etc.") are usually in local time for
+  the system on which the messages are stored.
+
+
+4. Timezone table
+-----------------
+
+  This table gives examples of typical timezones.
+
+  -1000   Alaska-Hawaii Standard Time
+  -0900   Hawaii Daylight Time
+  -0800   Pacific Standard Time
+  -0700   Pacific Daylight Time
+  -0700   Mountain Standard Time
+  -0600   Mountain Daylight Time
+  -0600   Central Standard Time
+  -0500   Central Daylight Time
+  -0500   Eastern Standard Time
+  -0400   Eastern Daylight Time
+  -0400   Atlantic Standard Time
+  -0330   Newfoundland Standard Time
+  -0300   Atlantic Daylight Time
+  -0100   West Africa Time
+   0000   Greenwich Mean Time
+   0100   Central European Time
+   0100   British Summer Time
+   0200   Central European Summer Time
+   0200   Eastern European Time
+   0800   Australian Western Time
+   0800   China Coast Time
+   0900   Japan Standard Time
+   0900   Australian Western Daylight Time
+   0930   Australian Central Standard Time
+   1000   Australian Eastern Standard Time
+   1030   Australian Central Daylight Time
+   1100   Australian Eastern Daylight Time
+   1200   New Zealand Standard Time
+   1300   New Zealand Daylight Time
+
+
+5. Examples
+-----------
+
+  ^aTZUTC: 0000
+  ^aTZUTC: 0200
+  ^aTZUTC: -0700
+
+
+6. Redundancy
+-------------
+
+  If the TZUTC data duplicates a field in a storage format in such a
+  way that no information is lost in conversion to or from the field,
+  then it is recommended that the kludge is not stored in the message.
+  However, implementations are allowed to store the TZUTC even when
+  redundant.
+
+
+A. References
+-------------
+
+  [FTS-1] "A Basic FidoNet(r) Technical Standard Revision 16", Randy
+  Bush. September 1995.
+
+  [JAM] "The JAM message base proposal", Joaquim Homrighausen, Andrew
+  Milner, Mats Birch and Mats Wallin. July 1993.
+
+
+B. Author contact data
+----------------------
+
+  Odinn Sorensen
+  Fidonet: 2:236/77
+  E-mail:  odinn@goldware.dk
+  WWW:     http://www.goldware.dk
+
+
+C. History
+----------
+
+  Rev.1, 970913: First release.
+  Rev.2, 970927: Updated the timezone table. Added section about
+                 redundancy. Clarified what happens when local time
+                 changes. Clarified some of what the specification
+                 doesn't cover.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1002.html b/html/ftsc/fsp-1002.html new file mode 100755 index 00000000..808b7da2 --- /dev/null +++ b/html/ftsc/fsp-1002.html @@ -0,0 +1,140 @@ + + +Numeric reply indication in FTN subject lines. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1002
+Revision:       2
+Title:          Numeric reply indication in FTN subject lines
+Author:         Odinn Sorensen, 2:236/77
+Revision Date:  19 October 1997
+Expiry Date:    11 October 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Format
+                3. Reply procedure
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  When making a reply to a message, there are currently three common
+  ways to handle the subject line:
+
+  1. Don't change it.
+  2. Insert the string "Re: " in front of it.
+  3. Insert the string "Re^n: " in front of it, where 'n' is increased
+     by one if the original subject was already a reply.
+
+  This document concerns itself with specifying the third variant.
+
+
+1. Scope
+--------
+
+  This standard is specified for all FTN messages. Implementations
+  will typically be message editors and other software that creates
+  replies to messages.
+
+
+2. Format
+---------
+
+  The format is "Re^n: ", where n is an unsigned integer number with
+  one or more digits. The range of the number must be at least 0 to
+  255. Negative numbers are not allowed. Note that there must be a
+  space after the colon. The letters are not case sensitive, but
+  uppercase 'R' and lowercase 'e' is recommended.
+
+
+3. Reply procedure
+------------------
+
+  When making a reply that conforms to this specification, this
+  procedure, or a functionally identical one, must be followed:
+
+  1. If the original subject does not have a leading "Re: " or
+     "Re^n: ", put the string "Re: " in front of it. Don't use a
+     number here.
+
+     Example:   "Hello world"  ->  "Re: Hello world"
+
+  2. If the original subject has a leading "Re: ", put the string
+     "Re^2: " in front of the subject.
+
+     Example:   "Re: Hello world"  ->  "Re^2: Hello world"
+
+  3. If the original subject has a leading "Re^n: ", increase the
+     number 'n' by one and modify the subject accordingly.
+
+     Example:   "Re^4: Hello world"  ->  "Re^5: Hello world"
+
+  Notes:
+
+  * The numbers 0 and 1 should not occur in the "Re^n: " string under
+    normal circumstances, but a robust implementation should just
+    increase the number in any case.
+
+  * The number should not be increased beyond the range of the number
+    type used in the implementation, or in other words, it should not
+    roll around to zero. If it can't be increased, leave it alone.
+
+  * When inserting the "Re: " or "Re^n: " string in front of the
+    subject, information from the end might be lost, because the
+    message storage or packet formats use fixed length subject fields.
+    Intelligent subject-based reply linking software should be aware
+    of this and try to link correctly anyway.
+
+
+A. Author contact data
+----------------------
+
+  Odinn Sorensen
+  Fidonet: 2:236/77
+  E-mail:  odinn@goldware.dk
+  WWW:     http://www.goldware.dk
+
+
+B. History
+----------
+
+  Rev.1, 971011: First release.
+  Rev.2, 971019: Added note that "Re" is not case sensitive.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1003.html b/html/ftsc/fsp-1003.html new file mode 100755 index 00000000..f7ed6040 --- /dev/null +++ b/html/ftsc/fsp-1003.html @@ -0,0 +1,116 @@ + + +Suggested use of Nodelist Fields. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1003
+Revision:       1
+Title:          Suggested use of Nodelist Fields
+Author:         Lee Kindness
+Revision Date:  15 May 1997
+Expiry Date:    15 May 1999
+----------------------------------------------------------------------
+Contents:
+                1. Field 3, Node Name
+                2. Field 4, Location
+                3. Field 5, Sysop Name
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Introduction
+------------
+
+  This document makes recommendations on the use of various fields in
+  the distribution nodelist (St. Louis nodelist format", fts-0005).
+  Naturally it is the choice of the *C's if they want to use them.
+  Remember the fts-0005 requirements should still be adhered to.
+
+
+1. Field 3, Node Name
+---------------------
+
+  The node name field should be no more than 20 characters long. For
+  comparison in nodelist.122'1997 the minimum entry was 1, maximum 51!
+  and the average was 14.
+
+  For zone entries this field should contain a description of the
+  zones area, (eg North America, Europe). For region entries it should
+  contain the country/state, for host entries the local area name and
+  for hub entries a description of the area the hub serves.
+
+
+2. Field 4, Location
+--------------------
+
+  This field contains the location of the node. It should usually be
+  expressed as the primary local location (town, suburb, city, etc.)
+  plus an identifier of the regional geopolitical administrative
+  district (state, province, department, county, etc.). Wherever
+  possible, standard postal abbreviations for the major regional
+  district should be used (IL, BC, NSW, UK, etc.).
+
+  For zone and region entries this field should also have the julian
+  day of segment creation appended to it (eg "Somearea_(122)") to aid
+  checks on the validity of the nodelist.
+
+
+3. Field 5, Sysop Name
+----------------------
+
+  This field contains the name of the system operator. Entries such as
+  "postmaster" and "uucp" should not be used. Aliases should not be
+  permitted in this field (as they give Fidonet a 'less respectable'
+  image).
+
+
+A. Author contact data
+----------------------
+
+  Lee Kindness
+  Fidonet: n/a
+  E-mail:  wangi@earthling.net
+  WWW:     http://www.scms.rgu.ac.uk/students/cs_yr94/lk/fido.html
+
+
+B. History
+----------
+
+  Rev.1, 971101: First release as FSP, based on the Fidonews 14/20
+                 article. Transformed into FSP document by Odinn
+                 Sorensen.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1004.html b/html/ftsc/fsp-1004.html new file mode 100755 index 00000000..df485037 --- /dev/null +++ b/html/ftsc/fsp-1004.html @@ -0,0 +1,257 @@ + + +Standard FidoNet Addressing. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1004
+Revision:       1
+Title:          Standard Fidonet Addressing
+Author:         Lee Kindness
+Revision Date:  15 May 1997
+Expiry Date:    15 May 1999
+----------------------------------------------------------------------
+Contents:
+                1. Standard Fidonet Addressing
+                2. Internet Gateway Addressing
+                3. Routing Address Syntax
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Introduction
+------------
+
+  This document describes the standard form of addressing in Fidonet
+  today along with the common method of addressing via internet
+  gateways. In addition it proposes an extended addressing syntax,
+  useful for routing purposes. This is a draft for comments and
+  suggestions.
+
+
+1. Standard Fidonet Addressing
+------------------------------
+
+  Fidonet addressing uses the following format:
+
+    ZZ:NN/FF.PP@DO
+
+  where the fields refer to...
+
+  ZZ - Zone Number:  The zone the node is part of.
+                     Min: 1 Max: 32767
+                     If 'ZZ:' is missing then assume 1 as the zone.
+
+  NN - Net Number:   The network the node is a member of.
+                     Min: 1 Max: 32767
+                     Must be present.
+
+  FF - Node Number:  The actual node number.
+                     Min: -1 Max: 32767
+                     Must be present.
+
+  PP - Point Number: If the system is a point rather than a node then
+                     this is their point number off the node.
+                     Min: 0 Max: 32767
+                     If '.PP' is missing then assume 0 (ie not a
+                     point) as the point number.
+
+  DO - Domain:       The name of the 'Fidonet Technology Network'.
+                     Maximum length of 8 characters. The domain
+                     should not include periods, thus 'fidonet.org'
+                     is invalid (should be fidonet).
+                     If '@DO' is missing then fidonet can be assumed.
+
+  The following are all valid examples:
+      1:234/5.6@fidonet  (a '5D' address)   => 1:234/5.6@fidonet
+      2:34/6.78          (a '4D' address)   => 2:34/6.78@fidonet
+      4:610/34           (a '3D' address)   => 4:610/34.0@fidonet
+      123/45             (a '2D' address)   => 1:123/45.0@fidonet
+      955:95/2@othernet  (another FTN)      => 955:95/2.0@othernet
+      2:259/-1           (node application) => 2:259/-1.0@fidonet
+
+  The limits on each various part of the address are a result of
+  fts-0005 (zone, net, node, point), fsc-0045 (domain) and Policy 4
+  (-1 node address for node application).
+
+
+2. Internet Gateway Addressing
+------------------------------
+
+  An internet user can send email/netmail to a fidonet user via one of
+  the fidonet->internet gateway systems (it's out-with the scope of
+  this document to describe the semantics of posting). The internet
+  user would send an email to a Fidonet user by using an email address
+  of the following syntax:
+
+    user.name@pPP.fFF.nNN.zZZ.gateway.domain
+
+  where the fields refer to...
+
+  user.name - Name:         Name of the user the email is being sent
+                            to, spaces replaced by periods.
+
+  PP        - Point Number: As Fidonet address (FA)
+                            If '.pPP' is missing 0 is assumed.
+
+  FF        - Node Number:  As FA
+                            Must be present.
+
+  NN        - Net Number:   As FA
+                            Must be present.
+
+  ZZ        - Zone Number:  As FA
+                            Must be present.
+
+  gate.way  - Gateway:      Internet domain of the gateway, for
+                            example 'fidonet.org'.
+                            Must be present.
+
+  The following are all valid examples (assuming 'fidonet.org' is an
+  internet gateway):
+
+    joe.bloggs@p6.f5.n234.z1.fidonet.org  => 1:234/5.6@fidonet
+    harry.cat@p78.f6.n34.z2.fidonet.org   => 2:34/6.78@fidonet
+    i.be.jolly@f34.n610.z4.fidonet.org    => 4:610/34.0@fidonet
+
+  and if 'foo.bar.org.uk' is a gateway for 'othernet':
+
+    louise.hat@f2.n95.z955.foo.bar.org.uk => 955:95/2.0@othernet
+
+
+3. Routing Address Syntax
+-------------------------
+
+  The two previous address types (Fidonet and Internet->Fidonet
+  gateway) are common practice, this however is a suggested standard
+  of addressing for routing tables. The routing address has the
+  following syntax:
+
+    DD:ZZ:RR:NN:HH:FF:PP
+
+  where the fields refer to:
+
+  DD - Domain:        As FA
+                      Must be present, even if blank (ie a leading
+                      ':') to ensure we always have 6 ':'s in an
+                      address to aid pattern matching.
+
+  ZZ - Zone Number:   As FA
+                      Must be present.
+
+  RR - Region Number: The region (from fts-0005 nodelist) that the
+                      following network is in.
+                      Min: 1 Max: 32767
+                      Must be present.
+
+  NN - Net Number:    As FA
+                      Must be present.
+
+  HH - Hub:           The hub (from fts-0005 nodelist) that the node
+                      is under, or 0 (host hub).
+                      Min: 1 Max: 32767
+                      Must be present.
+
+  FF - Node Number:   As FA
+                      Must be present.
+
+  PP - Point Number:  As FA
+                      Must be present.
+
+  ':' has been chosen as the separator as it is not a POSIX regular
+  expression character or globing character (where as '.' is) and thus
+  always easy use of wildcards on the address. The following points
+  should be noted:
+
+    1. All addresses have 6 ':'s
+    2. The domain is at the front, the address gets more specific to
+       the right
+    3. Nodes have 0 as their point number
+    4. A zone net has identical zone, region and net fields
+    5. A region net has identical region and net fields
+
+  Example fidonet addresses converted to routing addresses:
+
+    fidonet:2:25:259:0:7:0 => 2:259/7.0@fidonet, region 25, hub 0
+    fidonet:1:1:1:0:23:0   => 1:1/23.0@fidonet, zone 1 net
+    :955:9551:95:300:45:0  => 955:95/45.0, region 9551, hub 300
+    fidonet:2:25:25:0:0:0  => 2:25/0.0@fidonet, R25C
+    cnet:12:34:341:100:1:7 => 12:341/1.7@cnet, region 34, hub 100
+    :2:25:259:300:300:0    => 2:259/300.0, region 25, hub 300
+
+  Example POSIX regular expression patterns on routing addresses:
+
+    [a-z]*:[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+:[0-9]+ (any address)
+    [a-z]*(:[0-9]+)+                                 (any address)
+    fidonet:2:25:[0-9]+:[0-9]+:[0-9]+:[0-9]+      (region 25 node)
+    fidonet:2:25(:[0-9]+)+                        (region 25 node)
+    fidonet:1:12:125(:[0-9]+)+               (all net 1:125 nodes)
+    fidonet:1:12:125:200(:[0-9]+)+   (all hub 1:125/200 downlinks)
+    fidonet:1:12:125:200:2:[0-9]+             (all 1:125/2 points)
+    fidonet:1:12:125:[0-9]+:(25|34|56):0
+                     (nodes 1:125/25.0, 1:125/34.0 and 1:125/56.0)
+
+  Example 'DOS style' patterns on routing addresses:
+
+    *:*:*:*:*:*:*                                    (any address)
+    fidonet:2:25:*:*:*:*                          (region 25 node)
+    fidonet:1:12:125:*:*:*                   (all net 1:125 nodes)
+    fidonet:1:12:125:200:*:*         (all hub 1:125/200 downlinks)
+    fidonet:1:12:125:200:2:*                  (all 1:125/2 points)
+    fidonet:1:12:125:*:3*:0  (any net 1:125 nodes starting with 3)
+    fidonet:1:12:125:*:3?:0           (net 1:125 nodes 30 thru 39)
+
+  The standard doesn't define which standard of pattern matching to
+  use, only the format of the addresses. These routing addresses would
+  be used in routing tables and configurations.
+
+
+A. Author contact data
+----------------------
+
+  Lee Kindness
+  Fidonet: n/a
+  E-mail:  wangi@earthling.net
+  WWW:     http://www.scms.rgu.ac.uk/students/cs_yr94/lk/fido.html
+
+
+B. History
+----------
+
+  Rev.1, 971101: First release as FSP, based on the Fidonews 14/20
+                 article. Transformed into FSP document by Odinn
+                 Sorensen.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1005.html b/html/ftsc/fsp-1005.html new file mode 100755 index 00000000..5c035533 --- /dev/null +++ b/html/ftsc/fsp-1005.html @@ -0,0 +1,450 @@ + + +Zone 2 nodelist flags. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1005
+Revision:       6
+Title:          Zone 2 nodelist flags
+Author:         Frank Ellermann, 2:240/5815.1
+Revision Date:  27 November 1997
+Expiry Date:    27 November 1999
+---------------------------------------------------------------------
+Contents:
+                1. Introduction
+                2. FTS-0005 flags
+                3. User flags
+                4. Approved zone 2 user flags
+                5. Flag implications
+                6. Invalid combinations
+                7. Baud rate field
+                8. Thanks to...
+---------------------------------------------------------------------
+
+
+1. Introduction
+---------------
+   This document informs about known differences of FidoNet zone 2
+   nodelist flags from FTS-0005.003.  The ultimate sources for these
+   informations are the current Z2 nodelist epilogue and the setup
+   for flag corrections at Z2C, but it may be difficult to get these
+   sources for readers in other zones.
+
+|  All changes since version 5 are marked by a bar at the left edge.
+   It is (again) possible to list V32b and V42b in zone 2, upper case
+   V32B or V42B is not more enforced.  Currently new flags needed for
+   IP-connectivity are under test in zone 2 (only internally), e.g.
+
+   ->   VM      VModem, default port  3141, dummy country code 000-
+   ->   IFC     IFCico, default port 60179, dummy country code 000-
+   ->   BND     BinkP,  default port 24544, dummy country code 000-
+   ->   IP      general IP connectivity,    dummy country code 000-
+   ->   TELN    Telnet                      dummy country code 000-
+
+
+2. FTS-0005 flags
+-----------------
+   The following flags are used as specified in FTS-0005.003:
+
+        CM      Continuous Mail, node accepts mail 24 hours a day
+        MO      Mailer Only (no BBS)
+        LO      Listed Only, node accepts calls only from listed
+                node numbers in the current FidoNet nodelist
+
+   ->   V21     ITU-T V21      300 bps full duplex (obsolete)
+        V22     ITU-T V22     1200 bps full duplex (obsolescent)
+
+|  In zone 2 the value 1200 in the baud rate field implies V22.  Only
+|  two nodes not supporting at least V22bis, ISDN, or IP still exist
+|  in the zone 2 segment.  Flag V22 is almost obsolete, and V21 is
+|  already removed in Z2.  Both flags should be dropped from the next
+|  FTS-0005 version.
+
+        V29     ITU-T V29     9600 bps half duplex (obsolescent)
+   ->   V33     ITU-T V33    14400 bps half duplex (obsolete)
+
+   V33 cannot be used in connecting FidoNet nodes over public dial-up
+   lines and is most probably a historical error in FTS-0005.  A very
+   similar argument is applicable on V29, all nodes flying this flag
+   support at least V32.  Today only one node in Z2 still flies V29,
+   and V33 is already removed in Z2.  Both flags should be dropped in
+   the next FTS-0005 version.
+
+        V32     ITU-T V32     9600 bps full duplex
+        V32b    ITU-T V32bis 14400 bps full duplex (implies V32)
+|       V34     ITU-T V34    28800 bps full duplex (33600 bps option)
+
+   FTS-0005 specifies V32b and V42b (capital V and small b), current
+   nodelist practice in FidoNet shows all combinations of small and
+   capital letters for flags.  This was no problem before FSC-0062
+   introduced case-sensitive flags.  The best solution is to stick to
+   the current practice and treat all old flags as case-insensitive.
+
+        H96     Hayes V9600
+        HST     USR Courier HST up to 9600  (implies MNP)
+        H14     USR Courier HST up to 14400 (implies HST)
+   ->   H16     USR Courier HST up to 16800 (implies H14 and V42b)
+        MAX     Microcom AX/96xx series (almost obsolete)
+        PEP     Packet Ensemble Protocol
+        CSP     Compucom Speedmodem
+   ->   ZYX     Zyxel series 16800 bps (implies V32b and V42b)
+   ->   V32T    V.32 Terbo   19200 bps (implies V32b)
+        VFC     V.Fast Class 28800 bps (should imply V32b and V42b)
+
+   If a flag directly or indirectly implies other flags, then these
+   other flags are not shown in a nodelist entry, because this would
+   be redundant.  Unfortunately the rules for redundancies in zone 2
+   and FTS-0005 are different.  Zone 2 continued to avoid redundancy
+   with most "new" flags, but FTS-0005.003 specified no redundancies
+   for "new" flags like ZYX, H16, V32T, or VFC.  "New" flags in this
+   context are flags approved by FidoNet International Coordinators
+   since 1989, when FTS-0005.TXT, the predecesssor of FTS-0005.003,
+   was published.
+
+   For details see the chapter "implications" below, for now only
+   note, that in zone 2 H16 implies V42b, ZYX implies V32b and V42b,
+   and V32T implies V32b.
+
+   Zone 1 and zone 2 have introduced a user flag Z19 approved by the
+   corresponding Zone Coordinator.  User flags are discussed later,
+   for now only note, that in zone 2 ZYX is specified as Zyxel 16k8,
+   while FTS-0005.003 not knowing Z19 specifies ZYX as generic flag
+   for all Zyxel protocol speeds.
+
+   Today only one node in FidoNet still really flies MAX, this flag
+   is obsolete and should be dropped from FTS-0005.  The flags CSP
+   (7 nodes worldwide) and H96 should be marked as obsolescent.
+
+|       MNP     Microcom Networking Protocol 2-4 error correction
+|       V42     ITU-T LAP-M error correction w/ fallback to MNP 2-4
+|       V42b    ITU-T V.42bis BTLZ data compression over V.42 LAP-M
+
+   The next version of FTS-0005 should adopt the better V42b and
+   MNP definitions of the zone 3 nodelist epilogue.  FTS-0005.003
+   specifies an implication of V42 by V42b, but the exact meaning of
+   the flag MNP is unclear.  Most probably this flag was meant to
+|  indicate support of MNP 2-4, and in this sense V42 implies MNP.
+
+|  Note the difference between the flag V42b (implying V42) and the
+|  standard V.42bis (not necessarily based on LAP-M as data link
+|  layer protocol), without this difference the flag V42b would be
+|  ambiguous for combined modem and ISDN node entries.
+
+        MN      No compression supported in insecure inbound
+
+        XA      Bark and WaZOO file/update requests
+        XB      Bark file/update requests, WaZOO file requests
+        XC      Bark file requests, WaZOO file/update requests
+        XP      Bark file/update requests
+        XR      Bark and WaZOO file requests
+        XW      WaZOO file requests
+        XX      WaZOO file/update requests
+
+   These flags are equivalent in FTS-0005 and in the zone 2 segment.
+
+        Gx..x   Gateway to domain 'x..x'
+
+   Valid values for this flag are assigned by the Fido International
+   Coordinator, FTS-0005.003 explicitly mentions GUUCP.  In zone 2
+   only GUUCP gateways are flagged.
+
+        #01     Zone 5 mail hour (01:00 - 02:00 UTC) w/ Bell 212A
+        #02     Zone 2 mail hour (02:30 - 03:30 UTC) w/ Bell 212A
+   ->   #08     Zone 4 mail hour (08:00 - 09:00 UTC) w/ Bell 212A
+        #09     Zone 1 mail hour (09:00 - 10:00 UTC) w/ Bell 212A
+        #18     Zone 3 mail hour (18:00 - 19:00 UTC) w/ Bell 212A
+        #20     Zone 6 mail hour (20:00 - 21:00 UTC) w/ Bell 212A
+
+   The variants !01, !02, !08, !09, !18, and !20 indicate missing
+   Bell 212A support.  In zone 2 #02 or !02 would be obviously
+   redundant.
+
+   Today less than four 1200 modems (V22 or Bell 212A) are listed.
+   A future version of FTS-0005 should drop !mn variants together
+   with V21 and V22 flags.
+
+   Further most non-CM systems flagging #mn or !mn today probably
+   want to show additional online times instead of additional mail
+   hours.  As soon as FSC-0062 flags have been approved by the IC
+   or adopted as FTS by the FTSC, the following version of FTS-0005
+   should mark #mn as obsolescent and recommend the more flexible
+   FSC-0062 flags (see below).
+
+
+3. User flags
+-------------
+   An example for one of several problems in zone 2 with user flags:
+
+        ...,U,Z19,V110H,V120L,V120H,X75,ENC,NEC
+
+   These flags indicate a modern Zyxel ISDN-modem and two additional
+   user flags ENC and NEC.  This possible user flags string contains
+   34 characters, but at most 32 characters are allowed in FTS-0005.
+
+        ...,U,Z19,V110L,V110H,X75,ISDNA,ISDNB,ISDNC
+
+   During the period for the replacement of old by new ISDN flags
+   (several months !) many nodes listed both old and new flags for
+   maximal compatibility, and no problems with nodelist compilers
+   or mailers caused by too long user flags strings were reported.
+
+   Therefore the length limit in FTS-0005 is probably unnecessary
+   and at least inconsequent:  Other nodelist fields like the system
+   name are unlimited, so why only restrict the user flags string ?
+   To help developpers an upper limit of e.g. 255 characters for a
+   nodelist line and 63 characters for fields 3 to 6 would be more
+   useful.
+
+   The next problem with user flag strings as specified in FTS-0005
+   is their introduction by the letter U with no comma following:
+
+   Nodelist compilers could parse ...,UISDN,USR in user flags ISDN
+   and USR.  But USR cannot be approved as "real" flag, because the
+   combination ...,USR,UISDN would then be parsed in SR and UISDN.
+
+   Other side effects of the FTS-0005 specification are additional
+   difficulties in finding flags.  Almost all flags are separated
+   by a comma, only the first user flag can be an exception to this
+   simple rule.  If the order of user flags has no meaning, then...
+
+        ...,UV120L,V120H
+        ...,UV120H,V120L
+
+   ... are equivalent.  A "simple" solution of this problem could be
+   to treat UV120L as synonym for V120L, and UV120H as synonym for
+   V120H.  Similar problems show up, if user flags are counted, etc.
+
+   Obviously a nodelist compiler looking for user flags has always
+   to consider the case "user flag separated by comma".  In zone 2
+   this idea was simply extended to the first user flag:
+
+   All flags are separated by commas.  Flags not yet approved by the
+   International Coordinator or the FTSC (i.e. user flags only used
+   experimentally or locally) are separated by a new pseudo flag U.
+
+   ->   U       pseudo flag to the left of at least one user flag
+
+   All flags following this pseudo flag U are user flags, all flags
+   before this pseudo flag are "real" flags specified in FTS-0005 or
+   approved by the International Coordinator.
+
+   Because this definition should be compatible with any reasonable
+   software implementation based on FTS-0005.003, and simplifies the
+   handling of user flags significantly, a future FTS-0005 version
+   will hopefully adopt it.
+
+
+4. Approved zone 2 user flags
+-----------------------------
+   In zone 2 user flags have to be approved by the Zone Coordinator.
+   Currently the following zone 2 user flags exist:
+
+   ->   V110L   ITU-T V.110 19k2 async 'Low'    (former ISDNA)
+   ->   V110H   ITU-T V.110 38k4 async 'High'   (former ISDNB)
+   ->   V120L   ITU-T V.120 56k6 async, N1 = 259, W = 7, modulo 8
+   ->   V120H   ITU-T V.120 64k  async, N1 = 259, W = 7, modulo 8
+   ->   X75     ITU-T X.75 SLP (single link procedure),
+                64kbit/s B channel; layer 2 max. framesize N1 = 2048,
+                window size W = 2, frame numbering modulo 8;
+                layer 3 transparent (no packet layer)
+   ->   ISDN    Other configuration, used only if none of above fits
+
+   These ISDN flags follow the specification in FSC-0091.
+
+   ->   Tyz     Online time flags as specified in FSC-0062
+
+   The flag Tyz is used by non-CM nodes online not only during ZMH,
+   y is a letter indicating the start and z a letter indicating the
+   end of the online period as defined below (times in UTC):
+
+        A  0:00,  a  0:30,   B  1:00,  b  1:30,   C  2:00,  c  2:30,
+        D  3:00,  d  3:30,   E  4:00,  e  4:30,   F  5:00,  f  5:30,
+        G  6:00,  g  6:30,   H  7:00,  h  7:30,   I  8:00,  i  8:30,
+        J  9:00,  j  9:30,   K 10:00,  k 10:30,   L 11:00,  l 11:30,
+        M 12:00,  m 12:30,   N 13:00,  n 13:30,   O 14:00,  o 14:30,
+        P 15:00,  p 15:30,   Q 16:00,  q 16:30,   R 17:00,  r 17:30,
+        S 18:00,  s 18:30,   T 19:00,  t 19:30,   U 20:00,  u 20:30,
+        V 21:00,  v 21:30,   W 20:00,  w 20:30,   X 23:00,  x 23:30.
+
+   For example TuB shows an online period from 20:30 until 1:00 UTC.
+
+   ->   Z19     Zyxel series 19200 bps (implies ZYX)
+   ->   X2C     x2 client w/ 56000 bps (should imply V34 and V42b)
+   ->   X2S     x2 server w/ 64000 bps (should imply V34 and V42b)
+
+   ->   K12     Systems offering all educational K12-conferences
+   ->   ENC     The node accepts inbound encrypted mail
+
+   ->   NC      Network Coordinator (only if the NC is not the host)
+   ->   NEC     Net Echomail Coordinator    (at most one per net)
+   ->   REC     Region Echomail Coordinator (at most one per region)
+
+   Redundant AKAs used to indicate echomail coordination in zone 2
+   are no longer permitted.  One *EC flag is valid for all AKAs of
+   a given sysop.
+
+
+5. Flag implications
+--------------------
+   Flag implications directly or indirectly specified in FTS-0005:
+
+        HST     => MNP
+        H14     => MNP HST
+        H16     => MNP HST H14
+        V42b    => V42 (MNP ?)
+        V32b    => V32
+
+   Flag implications specified in the zone 2 nodelist epilogue:
+
+        HST     => MNP
+        H14     => HST MNP
+   ->   H16     => V42 MNP V42b H14 HST
+   ->   V42b    => V42 MNP
+   ->   ZYX     => V42 MNP V42b V32 V32b
+   ->   Z19     => V42 MNP V42b V32 V32b ZYX
+        V32b    => V32
+   ->   V32T    => V32 V32b
+
+   ->   V110L   => ISDN
+   ->   V110H   => ISDN
+   ->   V120L   => ISDN
+   ->   V120H   => ISDN
+   ->   X75     => ISDN
+
+   The latter ISDN flag redundancies are a consequence of FSC-0091.
+   Maybe some of the following implications could be added in zone 2:
+
+        VFC     => V32 V32b MNP V42 V42b
+        X2C     => V34 MNP V42 V42b
+        X2S     => V34 MNP V42 V42b
+
+   Flag implications (i.e. not listing redundant flags) have several
+   advantages:  Some old nodelist tools are unable to handle too long
+   lines.  Old flags like HST, MNP, V42, or V32 vanish automatically,
+   if they are implied by H16, V42b, V32b, or better.  Redundancies
+   defined globally for the whole nodelist help to avoid flag errors.
+
+
+6. Invalid combinations
+-----------------------
+   All file request flags exclude each other (at most 1 is possible):
+   XA, XB, XC, XP, XR, XW, and XX.  For flag checkers only supporting
+   implications a good approximation based on FTS-0005 definitions is
+
+|       XA      => XW XR XP XB XC XX,
+|       XB      => XW XR XP,
+|       XC      => XW XR XX,
+|       XR      => XW,
+|       XX      => XW.
+
+   Further X2C cannot be combined with X2S, and FSC-62 Tyz-flags are
+   not possible with CM.  Also Tyz with y = z is of course incorrect.
+
+   Some modem protocols are "proprietary" in a sense, that all today
+   known modems can fly at most one of the corresponding modem flags:
+   MAX, CSP, H96, PEP, HST, H14, H16, ZYX, and Z19.
+
+   A few "old" modem protocol flags are known to be invalid if used
+   together with "new" protocol flags, i.e. each "old" flag excludes
+   all "new" flags and vice versa:
+
+   "Old" in this sense are MAX, CSP, H96, HST, H14, V32, and PEP.
+   "New" in this sense are X2S, X2C, V34, VFC, V32T, and H16.
+
+   For Z2 add ZYX as "old" and Z19 as "new".  A simple REXX script to
+   test some known inconsistencies is available as NLSCHECK.REX at
+   the site of the author.  While erroneously listing redundant flags
+   causes no harm, other errors like combining V34 with HST or Z19
+   with H16 indicate serious problems, which can result in connection
+   failures or other damage.
+
+
+7. Baud rate field
+------------------
+   The baud rate field 7 in the nodelist as specified in FTS-0005 is
+   nearly useless today:  Except from a few remaining 1200 and 2400
+   nodes almost all nodelist entries show either 9600 for all modem
+   protocols better than V22bis or 300 for ISDN (or IP) only nodes.
+   No more V21 or Bell 103 modems are listed for more than 2 years.
+
+   The baud rate values 19200 and 38400 specified in FTS-0005.003
+   have not been used in the FidoNet nodelist.  So all a reasonable
+   nodelist compiler can do today, is treat 300 as indicator for
+   ISDN or IP only, and treat unknown or missing values in field 7
+   like 9600.
+
+   A new meaning for field 7 as speed field could be really useful.
+   An example is ZYX, if we would have 16800, 19200, 28800, and 33600
+   as speed values, then their combination with ZYX is all we need
+   technically, Z19 would be unnecessary.  Another example is HST,
+   flags H14 and H16 are unnecessary, if HST is combined with 9600,
+   14400, 16800, 28800, or better.  Variants of PEP could be shown in
+   the speed field without new flags.  "Enhanced V32.terbo" could be
+   shown by 21600.
+
+   Most important:  V34 may have the famous bug not allowing connects
+   from new "V34+", unless the caller disabled symbol rate 3429.  If
+   "V34+" is indicated by speed 33600 or better, then an appropriate
+   setup for all kinds of V34 connects is possible.
+
+   A future version of FTS-0005 hopefully allows the following speed
+   values in field 7:
+
+          300   reserved for ISDN or IP only (for historical reasons)
+         1200   obsolete (either V.22 in Z2 / Z3, or Bell 212A in Z1)
+         2400   implies V22bis, qualifies as least common denominator
+         9600   default, used with PEP, V32, HST, H96, (CSP), (MAX)
+        12000   rare variant of V32
+        14400   used with V32b or HST (obsoleting H14)
+        16800   used with ZYX  or HST (obsoleting H16)
+        19200   used with V32T or ZYX (obsoleting Z19)
+        21600   rare variant of V32T (no "H21" needed)
+        28800   used with VFC or V34
+        33600   used with V34 (no V34+ or V34b needed)
+|       56000   used with X2C, X2S, or V.PCM
+
+   Allowing more than 12 speed values or allowing speed values above
+   64000 could break existing software (MakeNL, V7).  Therefore the
+   next step in FidoNet could be, to add 12000, 14400, 16800, 19200,
+   21600, 28800, 33600, and 56000, where 19200 is already specified
+   in FTS-5 since 1989.
+
+
+8. Thanks to...
+---------------
+   Ben Baker            St. Louis nodelist format
+   Rick Moore           FTS-0005.TXT
+   David Nugent         FTS-0005.003 and NLTOOLS
+   Jonny Bergdahl       ERRFLAGS 2.6
+   Ward Dossche         Zone 2 nodelist epilogue
+   David J. Thomas      FSC-0062.003 (FRL-0062)
+   Jan Ceuleers         FSC-0075.001 (FRL-0075)
+   Arjen Lentz          FSC-0091.001 (FRL-0091)
+   Leonard Erickson     CHECKNL 2.14 and many discussions in NET_DEV
+   Jim Barchuk          LNDL 2.7
+   Marius Ellen         FASTV7 2.04
+|  Jan Vermeulen, Ian Smith, Gisbert Rudolph, Carlos Fernandez Sanz,
+|  Tom Schlangen, Craig Ford, Pedro Lima, and many others...
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1006.html b/html/ftsc/fsp-1006.html new file mode 100755 index 00000000..ac3bb301 --- /dev/null +++ b/html/ftsc/fsp-1006.html @@ -0,0 +1,159 @@ + + +Kludge for specifying addition e-mail reply addresses. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1006
+Revision:       1
+Title:          Kludge for specifying addition e-mail reply addresses
+Author:         Ramon van der Winkel, 1:320/42.46
+                ramon@wsd.wline.se
+Revision Date:  12 December 1997
+Expiry Date:    12 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Background
+                3. Format
+                4. Implementation notes
+                5. Example
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  An Internet message can have several reply addresses. After gating
+  to FidoNet, the recipient is only presented with one of the reply
+  addresses. The others are lost. This is a suggestion for an
+  additional kludge to FSC-0035 to change that.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN netmail messages sent by a
+  FidoNet-to-Internet gateway to a recipient. Message editors will
+  have to support this to allow the user to select the reply address
+  to use.
+
+
+2. Background
+-------------
+
+  An Internet message has three headers to indicate where to send a
+  reply. These are, in order of priority, Reply-To:, Sender: and
+  From:. When a message is distributed by a mailing list, then one of
+  the headers could contain the e-mail address of the poster and one
+  of the other headers the address of the mailing list.
+
+  When the message is gated to FidoNet, the gateway currently selects
+  of the reply addresses and creates the message so that a reply will
+  return at the gateway and sent to this one address. The other
+  addresses are lost.
+
+  The FSC-0035 kludges REPLYTO and REPLYADDR allow for one return
+  address only. This is a proposal for an additional kludge inserted
+  by the gateway to specify an addtional reply address. The message
+  editor used by the recipient will present a list of all reply
+  addresses and allows the user to select the appropriate address.
+
+  This way, the user can send a message back to the mailing list (for
+  distribution), or to the e-mail address of the poster only.
+
+
+3. Format
+---------
+
+  Following the REPLYTO and REPLYADDR kludges, one or more kludges
+  with the name REPLYALSO can be inserted, each listing one possible
+  reply address.
+
+  @REPLYALSO 
+
+  Where  is in the form of
+
+     ramon@wsd.wline.se
+  or
+     wsd.wline.se!ramon
+
+  Each line MUST contain one address only.
+
+
+4. Implementation notes
+-----------------------
+
+  Gateways supporting the REPLYALSO kludge MUST put the the reply
+  address with the highest priority in the REPLYADDR kludge. The order
+  of priority is Reply-To:, Sender: and From: header. The other
+  addresses may be listed in any priority.
+
+
+5. Example
+----------
+
+  From: odinn@goldware.dk, 1:320/42
+  To:   Ramon van der Winkel, 1:320/42.46
+  Subj: Another test
+  ---------------------------------------
+  @INTL 1:320/42 1:320/42
+  @TOPT 46
+  @MSGID: wgmid$<123455@goldware.dk> 45AB23CD
+  @REPLYTO UUCP 1:320/42
+  @REPLYADDR odinn@goldware.dk
+  @REPLYALSO newftsc-l@brazerko.com
+  This message was distributed by the mailing list "New FTSC"
+  at brazerko.com.
+
+  ...
+
+
+A. Author contact data
+----------------------
+
+  Ramon van der Winkel
+  Fidonet: 1:320/42.46
+  E-mail:  ramon@wsd.wline.se
+  WWW:     http://www2.sbbs.se/hp/ramon
+
+
+B. History
+----------
+
+  Rev.1, 971212: First release.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1007.html b/html/ftsc/fsp-1007.html new file mode 100755 index 00000000..2b2e8fb0 --- /dev/null +++ b/html/ftsc/fsp-1007.html @@ -0,0 +1,162 @@ + + +Multiple recipient address specification to gateway. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1007
+Revision:       1
+Title:          Multiple recipient address specification to gateway
+Author:         Ramon van der Winkel, 1:320/42.46
+                ramon@wsd.wline.se
+Revision Date:  12 December 1997
+Expiry Date:    12 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Scope
+                2. Background
+                3. Format
+                4. Implementation notes for gateways
+                5. Example
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Private messages within FidoNet only have one recipient address.
+  Multiple copies of the same message have to be sent to a FidoNet-
+  to-Internet gateway in order to address multiple recipients. This is
+  a proposal to indicate the addresses of multiple recipients in the
+  body of the message sent to the gateway.
+
+
+1. Scope
+--------
+
+  This standard is specified for FTN netmail messages sent to a
+  FidoNet-to-Internet gateway. Users are able to add this information
+  manually, although message editors could support this and make it
+  transparent to the user.
+
+
+2. Background
+-------------
+
+  Three types of recipient addresses can be specified on the Internet
+  and are reflected in this suggestion: To, Cc and Bcc. "To" are the
+  primary recipient(s) of the message. "Cc" is short for Carbon Copy
+  and lists the recipients that are intended to receive the message as
+  "informational". The last option "Bcc" is short for Blind Carbon
+  Copy. Recipients lists as Bcc recipients will not show up in the
+  headers of the Internet message, but get a copy anyway.
+
+
+3. Format
+---------
+
+  Immediately following the kludge lines, one or more of the following
+  lines can be inserted in the message. If a To: line is present, then
+  these lines follow the To: line.
+
+  GW-To: [,[...]]
+  GW-Cc: [,[...]]
+  GW-Bcc: [,[...]]
+
+  Where  is in the form of
+
+     ramon@wsd.wline.se
+  or
+     wsd.wline.se!ramon
+
+  Multiple addresses can be specified on the same line, separated by a
+  comma with optionally spaces around the comma. There is no limit
+  regarding the length of the line. The line must be terminated by a
+  single carriage return.
+
+  The GW-To: line replaces the To: lines.
+
+  The reason for GW-Cc is that "Cc:" by itself is expanded by some
+  editors and used to generate multiple copies of a message.
+
+
+4. Implementation notes for gateways
+------------------------------------
+
+  Gateways supporting this format add the e-mail addresses mentioned
+  in any of these three headers to the envelope file and create on
+  outbound (probably UUCP or SMTP) body text message. Rules for the
+  maximum length of envelope files (if any) apply.
+
+  The headers section of the RFC822 message will list the e-mail
+  addresses under the To: and Cc: headers. A Bcc: header must not be
+  added!
+
+
+5. Example
+----------
+
+  From: Ramon van der Winkel, 1:320/42.46
+  To:   UUCP, 1:320/42
+  Subj: New header test
+  ---------------------------------------
+  @INTL 1:320/42 1:320/42
+  @FMPT 46
+  GW-To: groupElist@newftsc.org
+  GW-Cc: odinn@goldware.dk
+  GW-Bcc: groupAadmin@newftsc.org
+  Hi!
+
+  This is a test
+
+  Ramon
+
+
+A. Author contact data
+----------------------
+
+  Ramon van der Winkel
+  Fidonet: 1:320/42.46
+  E-mail:  ramon@wsd.wline.se
+  WWW:     http://www2.sbbs.se/hp/ramon
+
+
+B. History
+----------
+
+  Rev.1, 971212: First release.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1008.html b/html/ftsc/fsp-1008.html new file mode 100755 index 00000000..ba98118d --- /dev/null +++ b/html/ftsc/fsp-1008.html @@ -0,0 +1,275 @@ + + +New control lines for forwarding messages. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1008
+Revision:       2
+Title:          New control lines for forwarded messages
+Author:         Michael Hohner, 2:2490/2520.17
+Revision Date:  29 December 1997
+Expiry Date:    29 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Specifications
+                2. Usage
+                3. Compatiblity
+                4. Known implementations
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+  This revision is an update to FRL-0092.001. The basic specifications
+  are unchanged.
+
+
+Abstract
+--------
+
+  Most fidonet message editors offer a "forward" function. Using this
+  function a user A ("forwarder") can sort of "redirect" a message
+  from user B ("author") to another user C ("final recipient"), maybe
+  because the forwarder is not the correct recipient, or because the
+  final recipient is a better person to answer the message. The name
+  and address of the author are usually included in the forward in
+  free-text format. The message text is included in non-quoted format.
+
+  A problem arises when the final recipient wants to reply to the
+  author of the forwarded message. The forward contains the forwarder
+  as the sender. So the final recipient must insert the name and
+  address of the author manually, using the information contained in
+  the message text. The message editor of the final recipient can't do
+  this automatically because of the free-text format. The editor will
+  also use incorrect quote initials, which is at least irritating.
+
+  This document introduces 7 new control lines which contain the
+  header information of the original message. With these control lines
+  the message editor can use the original header information
+  automatically.
+
+
+1. Specifications
+-----------------
+
+  There are 7 new control lines: FWDFROM, FWDTO, FWDORIG, FWDDEST,
+  FWDSUBJ, FWDAREA, FWDMSGID. As all control lines they start with an
+  ASCII 01 character (SOH) followed by the control line name followed
+  by whitespace followed by the control line's content followed by
+  ASCII 13 (CR).
+
+  Please note that all these control lines do not have a colon (like
+  the control lines in FTS-0001). This would be just waste of space.
+
+  FWDFROM
+  -------
+
+  This control line contains the name of the original sender as found
+  in the FROM field of the original message. Leading and trailing
+  whitespace should be removed. This control line should be omitted
+  altogether if the FROM field is empty.
+
+  FWDTO
+  -----
+
+  This control line contains the name of the original recipient as
+  found in the TO field of the original message. Leading and trailing
+  whitespace should be removed. This control line should be omitted
+  altogether if the TO field is empty.
+
+  FWDORIG
+  -------
+
+  This control line contains the address of the original sender as
+  found in the ORIG field of the original message. The usual 5D ASCII
+  notation (zone:net/node.point@domain) should be used. This control
+  line should be omitted altogether if the address is not known.
+
+  FWDDEST
+  -------
+
+  This control line contains the address of the original recipient as
+  found in the DEST field of the original message. The usual 5D ASCII
+  notation (zone:net/node.point@domain) should be used. This control
+  line should be omitted altogether if the address is not known or
+  unsure (as it is the case with forwarded echomail messages).
+
+  FWDSUBJ
+  -------
+
+  This control line contains the subject line of the original message.
+  This control line should be omitted altogether if the SUBJ field is
+  empty.
+
+  This control line should by made optional for security reasons. Echo
+  manager passwords are too easily revealed with it.
+
+  FWDAREA
+  -------
+
+  This control line contains the name of the echomail area where the
+  original message was forwarded from. It should be omitted altogether
+  if the original message was not forwarded from an echomail area.
+
+  FWDMSGID
+  --------
+
+  This control line contains the MSGID control line of the original
+  message. It should be omitted altogether if a MSGID control line is
+  not present in the original message.
+
+
+2. Usage
+--------
+
+  When the "forward" function of the message editor is invoked, the
+  editor program should generate the proposed control lines from the
+  header of the original message. If the original message already was
+  a forwarded one (indicated by the presence of at least a FWDORIG
+  control line), the editor should keep all FWD* control lines and
+  should not add any FWD* control lines. This preserves the FWD*
+  control lines of the first forwarder, containing the header data of
+  the author of the original message.
+
+  The editor should not generate FWD* control lines, if the message
+  isn't to be forwarded. A mail forwarding robot may also generate
+  these control lines, if it not just readdresses the message.
+
+  When the "reply" function of the editor is invoked the program
+  should use the control lines' contents instead of the header
+  information. The control lines should not be included in the reply.
+
+  Since it may not be immediately clear whether the user wants to
+  reply to the forwarder or to the original sender, the editor should
+  offer a means to ignore the proposed control lines and start a
+  "normal" reply instead, e.g. by two distinct functions, by user
+  preference or a dialog.
+
+
+  Pseudo code:
+
+  forwarding_message:
+     if is_forwarded_message then
+        don't change FWD* control lines
+     else
+        add FWD* control lines
+
+  quoting_message:
+     if is_forwarded_message then
+        if reply_to_forwarder then
+           use header data (normal quoting)
+        else
+           use FWD* control lines
+        remove FWD* control lines from reply
+     else
+        use header data (normal quoting)
+
+  other_functions:
+     remove/ignore FWD* control lines
+
+
+  Example:
+
+  Message from Joe User to my boss node:
+
+     From: Joe User 1:234/567
+     To:   Harry Herrmannsdoerfer 2:2490/2520
+     Subj: Some questions
+     @MSGID: 1:234/567 12345678
+     Text: Hello Harry!
+           ...
+
+  Harry forwards the message to me:
+
+     From: Harry Herrmannsdoerfer 2:2490/2520
+     To:   Michael Hohner 2:2490/2520.17
+     Subj: Joe's message
+     @FWDFROM Joe User
+     @FWDORIG 1:234/567
+     @FWDTO Harry Herrmannsdoerfer
+     @FWDDEST 2:2490/2520
+     @FWDSUBJ Some questions
+     @FWDMSGID 1:234/567 12345678
+     Text: Hi Michael!
+           ...
+
+  My answer using the new control lines:
+
+     From: Michael Hohner 2:2490/2520.17
+     To:   Joe User 1:234/567
+     Subj: Some questions
+     @REPLY: 1:234/567 12345678
+     Text: Hi Joe!
+
+           JU> ...
+           ...
+
+
+3. Compatiblity
+---------------
+
+  Editor programs which are not prepared for these proposed control
+  lines usually just ignore them and remove them from a reply. A reply
+  goes to the forwarder. Nothing gained and nothing lost.
+
+
+4. Known implementations
+------------------------
+
+  This proposal is implemented in the author's Fidonet editor
+  "FleetStreet for OS/2" (versions 1.17 and newer).
+
+  Also implemented in Odinn Sorensens Fidonet editor "GoldED"
+  (versions 3.00.Alpha5 and newer).
+
+
+A. Contacting the author
+------------------------
+
+  The author may be contacted electronically at the following
+  addresses:
+
+  Fidonet:    2:2490/2520.17
+  Internet:   miho@osn.de
+
+  Suggestions, comments and corrections are always welcome.
+
+
+B. History
+----------
+
+  Rev.1, 19960912: First release as FSC-0092.001.
+  Rev.2, 19971229: Submitted as FSP.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1009.html b/html/ftsc/fsp-1009.html new file mode 100755 index 00000000..b7f5795a --- /dev/null +++ b/html/ftsc/fsp-1009.html @@ -0,0 +1,142 @@ + + +Year 2000 issues in FTN software. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1009
+Revision:       1
+Title:          Year 2000 issues in FTN software
+Author:         Michael Hohner, 2:2490/2520.17
+Revision Date:  29 December 1997
+Expiry Date:    29 December 1999
+----------------------------------------------------------------------
+Contents:
+                1. Introduction
+                2. Generating Fidonet timestamps
+                3. Interpreting Fidonet timestamps
+----------------------------------------------------------------------
+
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  The year 2000 causes problems in many computer programs which use
+  two-digit year numbers. Current Fidonet software faces the very same
+  problems. This FSP specifies procedures which enable FTN software to
+  run without problems after the year 2000.
+
+
+1. Introduction
+---------------
+
+  Software using two-digit year numbers may cause problems in the year
+  2000. When the year number rolls over from "99" to "00", some
+  software may interpret the resulting year number as "1900" instead
+  of "2000". Such programs may contain code like this:
+
+     calendar_year = year_number + 1900;  /* wrong! */
+
+  Fidonet software faces the very same problem: the year number in
+  packed messages (see FTS-0001) has only two digits. Some programs
+  interpreting this number incorrectly may decide that messages from
+  the year 1900 are too old and discard them. Other programs probably
+  just display a wrong calendar year.
+
+  The long-term solution would be a transition to four-digit year
+  numbers. However, this would require new data formats and cause
+  every existing software to fail. So a short-term solution is
+  required, resulting in only minimal changes in software. This FSP
+  contains guidelines for proper year-number interpretation. The
+  author encourages all FTN software authors to check their software
+  for possible year-2000 problems (and release fixed versions during
+  the next three years).
+
+
+2. Generating Fidonet timestamps
+--------------------------------
+
+  This should not cause much headache. However, some software may use
+  the following algorithm:
+
+     year_number = calendar_year - 1900  /* wrong! */
+
+  This will result in a three-digit year number in 2000 and lead to
+  incorrect Fidonet timestamps.
+
+  One correct algorithm is:
+
+     year_number = calendar_year mod 100  /* correct! */
+
+
+3. Interpreting Fidonet timestamps
+----------------------------------
+
+  We can make use of the fact that Fidonet didn't exist before 1980,
+  i.e. no messages were created before 1980. So any year number
+  smaller than 80 can't mean "year 19xx", but can only mean "year
+  20xx". One algorithm for correct year number interpretation is:
+
+     if year_number < 80 then
+        calendar_year = 2000 + year_number
+     else
+        calendar_year = 1900 + year_number
+
+  Fidonet software should only use the calendar year for further
+  processing, not the year number from the timestamp.
+
+  This solution will work until 2080, giving us another 80+ years to
+  finally let some innovation happen in Fidonet.
+
+
+A. Contacting the author
+------------------------
+
+  The author may be contacted electronically at the following
+  addresses:
+
+  Fidonet:    2:2490/2520.17
+  Internet:   miho@osn.de
+
+  Suggestions, comments and corrections are always welcome.
+
+
+B. History
+----------
+
+  Rev.1, 19971229: Submitted as FSP.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fsp-1010.html b/html/ftsc/fsp-1010.html new file mode 100755 index 00000000..3be37d24 --- /dev/null +++ b/html/ftsc/fsp-1010.html @@ -0,0 +1,242 @@ + + +FTSC Document FSP-1010, Revision 001 + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1010
+Revision:       1
+Title:          Via kludge specification
+Author:         Colin Turner,
+                Joaquim Homrighausen
+Revision Date:  26 April 1999
+Expiry Date:    26 April 2001
+----------------------------------------------------------------------
+Contents:
+                1. Current practice
+                2. Kludge specification
+                3. Examples
+                4. Deprecated formats
+----------------------------------------------------------------------
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standards Proposal (FSP).
+
+  This document specifies an optional Fidonet standard protocol for
+  the Fidonet community, and requests discussion and suggestions for
+  improvements.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+Abstract
+--------
+
+  Current practice for Fidonet Technology Network (FTN) NetMail
+  messages is to track their progress through the network and
+  programs by using control lines. These control lines are in
+  the form of a kludge named Via.
+  
+
+1. Current practice
+-------------------
+
+  As NetMail messages are routed through a FidoNet Technology Network
+  or as they are processed on a system, Via control lines are used to
+  track their progress.
+  
+  A single NetMail message may have any number of Via control lines.
+  
+  The Via control lines are stored in a block which starts after any
+  message text. New Via lines should be added to the end of the block
+  separated from the preceding control line by a single ASCII <CR>
+  character (0Dh).
+  
+  A Via control line is typically added:
+  
+    when a netmail packer packs the NetMail for transmission to
+    another system;
+    
+    when a netmail tracker inspects a NetMail.
+
+2. Kludge specification
+-----------------------
+
+  The Via control line is formatted as a number of fields, separated
+  by single space (20h) characters, as follows
+  
+    ^AVia: <FTN Address> @YYYYMMDD.HHMMSS[.Precise][.Time Zone] 
+    <Program Name> <Version> [Serial Number]<CR>
+    
+  Where ^A denotes the ASCII <SOH> (01h) character, and <CR> is the
+  character (0Dh).
+  
+  The fields are defined as follows:
+  
+  FTN Address
+  -----------
+
+  This field is mandatory and is the FidoNet Technology address of 
+  the system inserting the kludge. This may or may not include a
+  domain indicator.
+  
+  @YYYYMMDD.HHMMSS
+  ----------------
+  
+  This field is mandatory and consists of a time stamp. This is the
+  time at which the stamp was placed. The subcomponents are
+  
+  YYYY, the calendar year, in full four digit, decimal form;
+  MM,   the calendar month, in the range 01 to 12, this must be a
+        zero padded, two digit decimal number;
+  DD,   the day of the month, in the range 01 to 31, this must be a
+        zero padded, two digit decimal number;
+  HH,   hours, in the range 00 to 23, this must be a zero padded,
+        two digit decimal number;
+  MM,   minutes, in the range 00 to 59, this must be a zero padded,
+        two digit decimal number;
+  SS.   seconds, in the range 00 to 59, this must be a zero padded,
+        two digit decimal number.
+        
+  Precise
+  -------
+  
+  This field is optional and takes the form of extra precision in the
+  time stamp.
+  
+  If this field is present:
+  
+    it must begin with a single period character;
+    
+    this period must be followed by one or more decimal digits;
+    
+    the field has ended when another period or space is encountered;
+    
+    each decimal digit in the field following this character
+    represents the time of the via line in fractions of a second,
+    such that the the first digit represents tenths of a second,
+    the second digit represents hundreds of a second and so on.
+        
+  Time Zone
+  ---------
+
+  This field is optional, and must be a short, widely accepted
+  alphabetical abbreviation of the time zone that the time stamp
+  in the Via line pertains to.
+  
+  The use of various Time Zone values is deprecated, implementations
+  should attempt to convert the timestamp in the kludge to Universal
+  Time (GMT or UTC) and use the "UTC" Time Zone indicator, where
+  possible.
+  
+  The Time Zone field may only be ommitted when it is not possible
+  for the implementation to determine the correct offset from UTC,
+  and in this case the time stamp must represent local time on the
+  generating system.
+  
+  Program Name
+  ------------
+  
+  This field is mandatory, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+  
+  Version
+  -------
+
+  This field is mandatory, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+  
+  Serial Number
+  -------------
+  
+  This field is optional, and must follow the format used in the PID
+  control line (detailed in FSC-46).
+
+  Note that unlike many kludges, the "Via" text of the kludge itself
+  is in mixed, and not all upper case.
+  
+3. Examples
+-----------
+
+  Example of valid usage are
+  
+  ^AVia 2:443/13 @19990305.043212.UTC O/T-Track+ 2.69
+  ^AVia 2:443/13@fidonet @19980331.231202.UTC FrontDoor 2.32.mL
+  ^AVia 2:443/13.0 @19990101.002102.UTC FastEcho 1.46.1 21321
+  ^AVia 2:443/13 @19990323.230132 FakeMail 1.2
+  ^AVia 2:2480/18@fidonet @19990307.182128.47.UTC ITrack+ 1.3/G6 FP000069
+  
+4. Deprecated formats
+---------------------
+
+  Some other formats for the Via line are in use today, but these
+  formats are rather variable and inconsistent in nature, while
+  the format specified above is both more widespread and more
+  consistent.
+  
+  New implentations may need to parse these formats, but must not
+  generate them.
+  
+  The formats in use include, but are not limited to
+  
+  <NAME> [VERSION] [SERIAL] <ADDRESS> <TIMESTAMP> <TIMEZONE>
+  <NAME> <ADDRESS>, <TIMESTAMP> <TIMEZONE> <VERSION>
+  
+  Not that the time stamp in the above formats is also widely
+  variable, and takes forms which include, but may not be limited to
+  
+  <Day> <Month> <Year> AT <Hour>:<Min>:[Sec]
+  <Day of Week> <Month> <Day of Month> <Year>  <Hour>:<Min>:<Sec>
+  ON <Day of Month> <Month> <Year>  <Hour>:<Min>:<Sec>
+  <Month>/<Day> <Hour>:<Min>
+  @YYMMDDHHMMSS
+  
+  In the last listed format, observe in particular the two digit year
+  and lack of period to seperate the date from time.
+
+A. References
+-------------
+
+  [FTS-1] "A Basic FidoNet(r) Technical Standard Revision 16", Randy
+  Bush. September 1995.
+
+  [FSC-46] "A Product Identifier for FidoNet Message Handlers",
+  Joaquim Homrighausen, August 1994.
+
+
+B. Author contact data
+----------------------
+
+  Colin Turner
+  Fidonet: 2:443/13
+  E-mail:  ct@piglets.com
+  WWW:     http://www.piglets.com
+  
+  Joaquim Homrighausen
+  Fidonet: 2:201/330
+  E-mail:  joho@defsol.se
+  WWW:     http://www.defsol.se
+
+
+C. History
+----------
+
+  Rev.1, 990426: First release.
+
+**********************************************************************
+
+Back Go Back + + diff --git a/html/ftsc/fsp-1011.html b/html/ftsc/fsp-1011.html new file mode 100755 index 00000000..eaabefa8 --- /dev/null +++ b/html/ftsc/fsp-1011.html @@ -0,0 +1,1756 @@ + + +FTSC Document FSP-1011, Revision 003 + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FSP-1011
+Revision:       3
+Title:          Binkp - a protocol for transferring FidoNet mail over
+                reliable connections
+Authors:        Dima Maloff
+                Nick Soveiko
+                Maxim Masiutin
+Revision Date:  31 July 2000
+Expiry Date:    31 July 2002
+
+----------------------------------------------------------------------
+
+Abstract
+--------
+
+   This specification defines binkp - a protocol to handle a session
+   between two Fidonet Technology systems over a reliable connection.
+   Assumption that the connection is reliable makes possible to
+   eliminate error-checking and unnecessary synchronization steps,
+   achieving both ease of implementation and major performance
+   improvement over connections with large unpredictable delays (e.g.
+   Internet).
+
+Status of this document
+-----------------------
+
+   This document is a Fidonet Standards Proposal (FSP).
+
+   This document specifies an optional Fidonet standard protocol for
+   the Fidonet community, and requests discussion and suggestions for
+   improvements.
+
+   This document is released to the public domain, and may be used,
+   copied or modified for any purpose whatever.
+
+Available formats
+-----------------
+
+   Binkp Specification is also available in HTML format at
+   http://www.ritlabs.com/binkp/
+
+Table of contents
+-----------------
+
+    1. Background
+         1. Objectives
+         2. Motivation for a New Protocol
+    2. Definitions
+    3. Protocol Overview
+    4. Frame Format
+         1. Notation
+         2. Examples
+    5. Protocol Commands and Their Arguments
+         1. Classification
+         2. File Name Issues
+         3. Non-ASCII Characters in Command Argument symbol string
+         4. Binkp Commands
+         5. Example of Frame Exchange in a Simple binkp Session
+    6. Protocol States
+         1. Session Setup Stage
+              1. Originating Side
+              2. Answering Side
+         2. File Transfer Stage
+         3. Session Termination
+    7. Recommended Protocol Extensions
+         1. Non-Reliable Mode
+         2. Multiple Batch Mode
+         3. Multiple Passwords Mode
+         4. Keyed Hashing Challenge-Response Authentication Mechanism
+              1. Overview
+              2. Sequence of Steps
+              3. Generating and Transmitting Challenge Data
+              4. Producing and Transmitting a Digest
+              5. Indicating CRAM Capabilities
+              6. Example of Frame Exchange During CRAM Authentication
+              7. Notes on Hash Function Algorithms
+    8. License
+    9. Glossary
+   10. References
+   11. Acknowledgements
+    A. Author Contact Data
+    B. History
+
+     ---------------------------------------------------------------
+
+1. Background
+-------------
+
+  1.1 Objectives
+  --------------
+
+   It's been a long time since a new Fidonet protocol has been
+   developed, [EMSI] definitions being published last time in 1991,
+   not speaking about basic standards, [FTS-0001] and [FTS-0006].
+   Fidonet is evolving everyday and new transport layers are being
+   introduced into practice. This led to a situation when in certain
+   Fidonet Regions a visible portion of traffic, especially long
+   distance traffic generating high toll, is being carried by means of
+   protocols that formally are not Fidonet standards. This creates an
+   ambiguity for such systems in indicating their additional
+   capabilities in Fidonet nodelist and in some instances, from being
+   listed in the nodelist at all.
+
+   This document attempts to document the current practice for
+   communication between two Fidonet systems via a reliable channel,
+   provide technical reference for Fidonet software developers and
+   eventually improve Fidonet connectivity.
+
+  1.2 Motivation for a new protocol
+  ---------------------------------
+
+   Existing Fidonet Technical Standards and Fidonet Reference Library
+   documents [FTS-0001], [FTS-0006], [EMSI] specify both session
+   handshake procedures and transmission capabilities that imply:
+     * non-reliable communication channel between mailers
+     * low round-trip times in the communication channel between
+       mailers.
+
+   This was commonplace a few years ago, when Fidonet systems were not
+   using transport other than direct dial-up on a visible basis.
+   Things have changed today, when other communication media becomes
+   widely available on a day-to-day basis. This communication media
+   typically provides implementation of Physical, Data Link, Network
+   and Transport layers of the ISO/OSI Reference Model and facilitates
+   relieving Session layer of inappropriate functions, such as error
+   control, flow control, call management and data transparency
+   [Halsall95]. Examples of such communication media are TCP/IP socket
+   connection and HDLC family protocol connection.
+
+   New communication media can be generally characterized by the
+   reliable transmission service offered by it to the Session layer
+   protocol. Reliable transmission implies that:
+     * Data link and/or Transport layer protocols are responsible for
+       error control and delivery of frames in correct sequence
+     * Session layer and higher layer protocols are operating on top
+       of connection-oriented mode
+     * Quality of Service provisions (if any) result in unspecified
+       delays between transmitter and receiver
+     * connections are rarely aborted.
+
+   Combination of these factors imposed the following requirements for
+   the new Fidonet protocol:
+     * error control can be eliminated throughout the session layer
+       protocol for both handshake and default file transfer method
+     * session setup procedure should minimize number of
+       synchronization points for fast handshake
+     * protocol should be insensitive to delays and robust with
+       respect to timeouts
+     * application flow control should be moved to file level;
+       individual data frames do not need to be error checked nor
+       acknowledged
+     * protocol should be independent from both higher and lower layer
+       protocols
+     * protocol should be reasonably easy to implement and allow
+       future extensions.
+
+2. Definitions
+--------------
+
+   The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT" and "MAY"
+   in this document are to be interpreted as specified in [FTA-0006].
+   However, for readability, these words may sometimes not appear in
+   all uppercase letters in this specification. Although it should not
+   impact minimal realization of binkp protocol, it must be noted that
+   Protocol Extensions may override, update or obsolete requirement
+   levels indicated by the above keywords in chapters from 3 to 6
+   inclusive.
+
+   Calling party in this document is referred to as the Originating
+   side and called party is referred to as the Answering side.
+   Originating side here is the party that initiates the connection
+   between two systems.
+
+   Mailer in this document is a software that implements the protocol.
+
+   Words "frame", "packet", and "block" when used in this document
+   refer to binkp's Frames, unless explicitly stated otherwise.
+
+   Other definitions that are not local to this document can be found
+   in the Glossary.
+
+   This document is organized as following:
+
+   Frames section defines binkp's frames. Binkp/1.0 commands and their
+   arguments section provides detailed description of all defined
+   protocol commands together with recommendations for their usage.
+   Actual binkp implementation may match it's own diagrams provided
+   that such implementation remains fully compatible with current
+   specification. Protocol states section gives rigorous state
+   diagrams for the minimum realization of binkp. All mailers MUST
+   support this minimum realization. Recommended Protocol Extensions
+   section documents most important extensions to the basic protocol
+   that are in use as of the time of this writing. The License,
+   Glossary and References sections can be found at the end of this
+   document.
+
+3. Protocol Overview
+--------------------
+
+   Binkp is a Fidonet session layer protocol intended for use over
+   data transparent bi-directional channels with reliable
+   transmission. There are no other requirements for the service
+   provided by the underlying protocol suite. Presentation and
+   application layer protocols are not discussed here. Whenever TCP/IP
+   socket is used, IANA registered port number for binkp 24554 SHOULD
+   be used (as registered with the Internet Assigned Numbers
+   Authority).
+
+   Functionality of the minimum protocol realization makes provision
+   for:
+     * password protected sessions
+     * 4D/5D addressing for Fidonet and technology compatible networks
+     * exchange of Type 2 [FTS-0001], Type 2.2 [FSC-0045], Type 2+
+       [FSC-0039] and [FSC-0048], Type 3 [FSC-0081] packets and
+       [FTS-0006] arcmail in both directions, including poll and mail
+       pickup, as well as transfer of any binary or ASCII files
+     * handling WaZOO [FTS-0006] file requests
+     * ensuring integrity of transmitted mail and files
+     * simultaneous bi-directional transmission
+     * maximizing performance over packet switched data networks
+
+   Binkp uses only one synchronization point during session startup,
+   that is password exchange. This feature facilitates fast session
+   startup for high latency links. Sliding window flow control is
+   incorporated on the file level. This ensures that a batch of small
+   files is transmitted with the same efficiency as a one large file.
+
+4. Frame Format
+---------------
+
+   Binkp is defined in terms of sending and receiving specifically
+   formatted data blocks. We call them frames.
+
+   Command frames carry protocol commands and may change protocol
+   state. Data frames are usually appended to files being received by
+   mailers or may be discarded, depending on the protocol state.
+
+   The particular way of mapping an octet stream or a datagram stream
+   of the transport layer into binkp frames may depend on the
+   underlying protocol suite. At this time, we define such mapping for
+   TCP/IP socket connection which can also be used for similar
+   transports as well.
+
+   The socket stream is being split into binkp frames in the following
+   manner:
+
+     7 6543210 76543210
+    +-+-------+--------+--- ................ ---+
+    |T|      SIZE      |          DATA          |
+    +-+-------+--------+--- ................ ---+
+    |<-   2 octets   ->|<- up to 32767 octets ->|
+       (frame header)          (frame data)
+
+   If T bit is 0, this is a data frame.
+
+   If T bit is 1, this is a command frame.
+
+   15 bits marked SIZE carry the size of the DATA part of the frame in
+   octets (with the bit marked 0 being the least significant). That
+   is, the actual length of a binkp frame is SIZE+2.
+
+   The size of the DATA part may vary between 1 and 32767 octets. A
+   correct realization should never set SIZE to 0. Upon receiving of a
+   packet header with the SIZE field set to 0, the total length of the
+   incoming packet must be treated as 2, this packet must be dropped,
+   and the event should be logged.
+
+   The first octet of a command frame data is the command ID. The ID
+   must be between 0 and 127 inclusive.
+
+   Other octets carry command arguments. Command arguments are an
+   arbitrary symbol string that may be null-terminated. Treating of a
+   null character in the middle of a command depends on realization
+   (with the options being "treat as whitespace" or "treat as
+   end-of-line"). The terminating null character (if any) is either
+   stripped or used by mailers internally as an end-of-line marker.
+
+  4.1 Notation
+  ------------
+
+   As stated before, command ID is a small number between 0 and 127.
+   Every binkp command defined in this document has a symbolic name in
+   the form M_XXX. Symbolic names are defined in binkp commands
+   section. We will use symbolic names and not numeric command IDs to
+   refer to commands everywhere in this document.
+
+   The following notation is used to describe binkp's command frames:
+
+         M_XXX "Data string"
+
+   The actual numeric command ID for the command with the symbolic
+   name of M_XXX should be written into the first octet of the DATA
+   area of a binkp frame. "Data string" is a string to be copied into
+   DATA area starting at second octet. SIZE should be set to the total
+   length of "Data string" plus one for the octet to store the command
+   number. T bit should be set to 1.
+
+  4.2 Examples
+  ------------
+
+   M_OK "":
+
+     7 6543210 76543210 76543210
+    +-+-------+--------+--------+
+    |1|      0        1|       4|
+    +-+-------+--------+--------+
+     |                |        +----- command ID (no arguments)
+     |                +-------- frame length
+     +- command frame flag
+
+   M_NUL "TEST":
+
+    +-+-------+--------+--------+-------+--------+--------+--------+
+    |1|      0        5|       0|   T        E        S       T    |
+    +-+-------+--------+--------+-------+--------+--------+--------+
+
+5. Protocol Commands and Their Arguments
+----------------------------------------
+
+  5.1 Classification
+  ------------------
+
+   Protocol commands may be classified the following way:
+
+     * By argument type:
+                    M_SKIP. Mailer MUST parse these commands and it is not
+            recommended to log arguments of these commands as they
+            are. Mailer-parseable commands can be further subdivided
+            by containment of a file name in the argument.
+                              commands contain a file name in their arguments.
+                                 MAY ignore and/or log arguments of these commands.
+     * By protocol stage:
+                    M_PWD (must not be sent by the Answering side), M_OK (must
+            not be sent by the Originating side). These commands MUST
+            never be sent during the file transfer stage.
+                    These commands MUST NOT be sent session setup stage.
+                    any time during the session.
+
+  5.2 File Name Issues
+  --------------------
+
+   In Mailer-parseable commands that contain a file name, the file
+   name MUST NOT include a whitespace (ASCII value 20 hex). The file
+   name SHOULD NOT include symbols other than alphanumeric
+   (A-Z,a-z,0-9) and safe characters as defined below in BNF. All
+   other symbols are to be considered unsafe and SHOULD be escaped in
+   the form of two hexadecimal digits preceded by a backslash (e.g. a
+   whitespace must be transmitted as "\20").
+
+   filename        = *pchar
+   pchar           = unreserved | escape
+   unreserved      = ALPHA | DIGIT | safe
+   safe            = "@" | "&" | "=" | "+" | "%" | "$" | "-" | "_" |
+                     "." | "!" | "(" | ")" | "#" | "|"
+   escape          = "\" HEX HEX
+
+   National characters should not be escaped, but rather transmitted
+   using [UTF8] encoding (see section discussing non-ASCII characters
+   below).
+
+   The best current practice is that Mailer does not alter a file name
+   without sysop's intention. If the mailer does provide such a
+   mechanism, it MUST BE optional and it SHOULD BE off by default.
+
+   The protocol does not impose limitations on the file name length
+   other than those arising from the finite length of the binkp frame
+   itself.
+
+  5.3 Non-ASCII Characters in Command Argument Symbol String
+  ----------------------------------------------------------
+
+   Generally, mailer SHOULD use only characters from the ASCII range
+   [32...126] in the symbol strings for command arguments. In case
+   when there is a necessity to use non-ASCII characters, mailer
+   SHOULD use the [UTF8] format of the multioctet Universal Character
+   Set [ISO10646]. Mailer SHOULD use non-ASCII characters only if the
+   other side have indicated it's support by transmitting M_NUL "OPT
+   UTF8" frame during the session setup stage. Otherwise, mailer
+   SHOULD assume that the remote does not support non-ASCII characters
+   and SHOULD NOT use them in command arguments.
+
+  5.4 Binkp Commands
+  ------------------
+
+   Format: symbolic_command_name command_ID
+
+   M_NUL 0
+
+           Command arguments contain human-readable information, such
+           as nodelist info, sysop name, etc. This frame can also be
+           used by some Mailers to exchange protocol options. Mailer
+           MAY ignore and/or log arguments of M_NUL.
+
+           e.g. "ZYZ Dima Maloff"
+
+           The following format of M_NUL argument is recommended for
+           compatibility purposes:
+
+              * M_NUL "SYS system_name"
+              * M_NUL "ZYZ sysop's_name"
+              * M_NUL "LOC system_location"
+              * M_NUL "NDL system_capabilities"
+              * M_NUL "TIME remote_date_time"
+                remote_date_time format is described in [RFC822].
+                Example of valid remote_date_time is
+                Sun, 06 Nov 1994 08:49:37 GMT
+              * M_NUL "VER mailer_version protocol_version"
+                note: binkp/1.0 mailers should send "binkp/1.0" string
+                for protocol_version.
+              * M_NUL "TRF netmail_bytes arcmail_bytes"
+                traffic prognosis (in bytes) for the netmail
+                (netmail_bytes) and arcmail and files (arcmail_bytes),
+                both are decimal ASCII strings
+              * M_NUL "OPT protocol options"
+                here protocol options is a space separated list of
+                binkp options and extensions supported by the mailer.
+              * M_NUL "PHN string"
+                phone number, ip address or other network layer
+                addressing ID
+              * M_NUL "OPM string"
+                string is a message for the system operator that may
+                require manual attention
+
+   M_ADR 1
+
+           List of 4D/5D addresses (space separated).
+
+           e.g. "2:5047/13@fidonet 2:5047/0@fidonet"
+
+   M_PWD 2
+
+           Session password, case sensitive. After successful password
+           authentication of the remote, originating side proceeds to
+           the file transfer stage. This command MUST never be sent by
+           the Answering side.
+
+           e.g. "pAsSwOrD"
+
+   M_OK 4
+
+           Acknowledgement for a correct password. Upon receiving of
+           this command, originating side goes to file transfer stage.
+           This command MUST never be sent by the Originating side.
+           Arguments may be ignored.
+
+           e.g. ""
+
+   M_FILE 3
+
+           Space separated list of parameters for the next file to be
+           transmitted: filename; size in bytes; unixtime; file
+           transmission offset.
+
+           In protocol extensions, negative values for the offset may
+           have special meaning (see non-reliable mode for an example
+           of such usage), basic implementation may treat negative
+           values as an error.
+
+           Size, time and offset parameters are decimal. Until the
+           next M_FILE command is received, all data frames must carry
+           data from this file in consecutive manner. There is no end
+           of file identifier as the file size is known beforehand. If
+           there are "extra" data frames, Mailer may append this data
+           to the file. By default, transmission of each file should
+           be started from offset 0. M_GET command sent by the remote
+           MUST force the mailer to start transmission from the
+           specified offset.
+
+           e.g. "config.sys 125 2476327846 0"
+
+           or, answering to M_GET with offset 100:
+
+           "config.sys 125 2476327846 100"
+
+   M_EOB 5
+
+           End-of-Batch. M_EOB command must be transmitted after all
+           the files have been sent.
+
+           Arguments of the command may be ignored.
+
+           e.g. ""
+
+   M_GOT 6
+
+           File acknowledgement, that must be transmitted upon
+           receiving of the last data frame for current file.
+           Arguments for this command shall be the same as for the
+           M_FILE sent by remote, excluding the last argument, file
+           offset, which is not transmitted back to the system which
+           have sent M_FILE. M_GOT can also be transmitted while
+           receiving a file, in which case transmitting party may
+           interpret it as a destructive skip.
+
+           e.g. "config.sys 125 2476327846"
+
+   M_ERR 7
+
+           This command indicates a fatal error. A party sending M_ERR
+           should abort the session. Argument should contain an error
+           explanation and may be logged. Mailer sends M_ERR in
+           response for an incorrect password. Mailer NUST NOT abort a
+           session without sending a M_ERR or a M_BSY frame (though
+           state machine tables, for simplicity, may not include
+           "transmit M_ERR" instructions).
+
+           e.g. "Incorrect password"
+
+   M_BSY 8
+
+           M_BSY command is transmitted when the system encounters a
+           non-fatal error typically due to temporary lack of
+           resources to proceed with the session. The argument should
+           contain an explanation of the situation and may be logged
+           by remote. M_BSY may be sent at any time during the session
+           (including session setup stage), not only the stages
+           explicitly indicated in the finite state machine. The side,
+           which have sent M_BSY, is in legal position to abort the
+           session. Mailer MUST be able to accept M_BSY at any time.
+           Though state machine tables, for simplicity, may not
+           include handling of M_BSY command, Mailer MUST NOT be
+           confused by reception of M_BSY command.
+
+           e.g. "Too many servers are running already"
+
+           If a mailer wishes to suggest the remote a time interval
+           before the next session attempt, it may choose to transmit
+           it in the following format:
+
+           M_BSY "RETRY NNNN: explanation"
+
+           where NNNN is interval in seconds (decimal string) and
+           explanation is an arbitrary string containing explanation
+           of the matter (optional).
+
+   M_GET 9
+
+           M_GET command is a request to (re)send files. Arguments of
+           the command are the same as for the M_FILE command and
+           refer to a file which we'd like to receive from the remote.
+
+           Mailer may send M_GET when it doesn't like transmission
+           file offset (e.g. file was partially received during one of
+           the previous sessions).
+
+           e.g. "config.sys 125 2476327846 100"
+
+           Mailer reacts to this command as follows: according to the
+           first three arguments (filename/size/unixtime), it
+           determines whether the M_GET argument is the current file
+           being transmitted to the remote (or a file that have been
+           transmitted, but we are still waiting an M_GOT ack for it).
+           If this is the case, it should
+
+              * discard transmission in progress as soon as possible
+              * perform seek() to the specified offset
+              * proceed with transmission of the file requested
+                starting with an appropriate M_FILE.
+
+           For the example above, corresponding M_FILE will have the
+           following arguments: "config.sys 125 2476327846 100"
+
+           When the mailer is finished with transmitting data of the
+           requested file it may proceed with transmission of other
+           files it has for the remote.
+
+   M_SKIP 10
+
+           Non destructive skip. Parameter is a space separated list
+           of filename, size and unixtime. This command indicates that
+           the remote should postpone sending the file until next
+           session.
+
+           e.g. "config.sys 125 2476327846"
+
+  5.5 Example of Frame Exchange in a Simple Binkp Session
+  -------------------------------------------------------
+
+   +-----------------------------------------------------------------+
+   | Originating side                | Answering side                |
+   |---------------------------------+-------------------------------|
+   | M_NUL "SYS ..."                 | M_NUL "SYS ..."               |
+   | M_NUL "ZYZ ..."                 | M_NUL "ZYZ ..."               |
+   | M_NUL "LOC ..."                 | M_NUL "LOC ..."               |
+   | M_NUL "VER ..."                 | M_NUL "VER ..."               |
+   | M_ADR "2:2/2.2@fidonet"         | M_ADR "3:3/3.3@fidonet"       |
+   | M_PWD "password"                | (waiting for a password from  |
+   |                                 | remote)                       |
+   |---------------------------------+-------------------------------|
+   | (waiting for password           | M_OK "" (or M_ERR "Bad        |
+   | acknowledgement)                | password")                    |
+   |---------------------------------+-------------------------------|
+   | (got M_OK)                      | M_FILE "file2 200 42342434 0" |
+   |---------------------------------+-------------------------------|
+   | M_FILE "file1 100 423424244 0"  | data                          |
+   |---------------------------------+-------------------------------|
+   | data                            | data                          |
+   |---------------------------------+-------------------------------|
+   | data                            | data                          |
+   |---------------------------------+-------------------------------|
+   | M_EOB                           | (got file1, acknowledging it) |
+   |---------------------------------+-------------------------------|
+   | (got file2, acknowledging it)   | M_GOT "file1 100 423424244"   |
+   |---------------------------------+-------------------------------|
+   | M_GOT "file2 200 42342434"      | data                          |
+   |---------------------------------+-------------------------------|
+   |                                 | M_EOB                         |
+   +-----------------------------------------------------------------+
+
+6. Protocol States
+------------------
+
+   The protocol has two major stages: session setup (different for
+   originating side and answering side) and file transfer (where state
+   machined for both sides are the same). Methods for initiating
+   connection as well as numerical values for particular timeouts are
+   dependent on the underlying layer's protocol suite and are not
+   considered here. Mailer MAY allow configuration of timeouts in
+   reasonably wide range to cover all supported transport protocols.
+
+   The Finite State Machine notation is used throughout this section
+   as defined by [FTS-0001].
+
+  6.1 Session Setup Stage
+  -----------------------
+
+   Originating side should initiate a binkp session according to Table
+   1. Answering side should be able to act according to Table 2. Any
+   optional extensions of the handshake procedure MUST NOT confuse the
+   other side, which may choose at it's discretion to follow this
+   minimal implementation. Upon successful handshake, both sides
+   follow Table 3 (file transfer stage). That's why terms Answering
+   side and Originating side were chosen for this specification
+   instead of Client and Server - both sides play the same roles, and
+   their state machines differ in session setup stage only.
+
+   Session setup stage has the following roles
+
+     * Authentication (REQUIRED). Answering side, upon reception of a
+       password (common secret word) from Originating side, decides
+       whether the password really matches the list of presented
+       addresses, and either acknowledges it by sending M_OK frame or
+       rejects by sending M_ERR frame. This mechanism is called Basic
+       Authentication Scheme and MUST be supported by all Mailers.
+       Basic Authentication Scheme has the following limitations:
+          * If Originating side presented multiple addresses, the
+            password for all of the addresses must be the same (may be
+            solved by Multiple passwords extension).
+          * Cleartext reusable passwords are passed over a network
+            (may be solved by CRAM extension).
+          * Verification is made on Answering side only, thus
+            Originating side has no way to verify Answering side (may
+            be solved by dual CRAM or public-key cryptography, not
+            discussed in this document).
+     * Indicating protocol options (OPTIONAL). Sides may exchange
+       specially formatted M_NUL messages to indicate supported
+       extensions. Sides MAY use another technique to indicate
+       extensions.
+
+    6.1.1 Originating Side
+    ----------------------
+
+   Originating side sends M_ADR and M_PWD frames, waits for successful
+   authentication acknowledgement from the Answering side (M_OK frame)
+   and goes to file transfer stage. Originating side MUST NOT wait
+   before sending M_ADR frame, i.e. this frame should be send just
+   after setting up a connection on underlying layer. Originating side
+   MUST NOT wait before sending M_PWD except after reception of M_ADR
+   frame. The term wait in this paragraph means do not send anything
+   while expecting data from remote.
+
+                Table 1: Session setup, originating side
+   +-----------------------------------------------------------------+
+   | #  | Name       | Predicate(s)     | Action(s)           | Next |
+   |----+------------+------------------+---------------------+------|
+   | S0 | ConnInit   |                  | Attempt to          | S1   |
+   |    |            |                  | establish           |      |
+   |    |            |                  | connection          |      |
+   |----+------------+------------------+---------------------+------|
+   | S1 | WaitConn   | Connection       | Send M_NUL frames   | S2   |
+   |    |            | established      | with system info    |      |
+   |    |            |                  | (at least one M_NUL |      |
+   |    |            |                  | "SYS ..." frame     |      |
+   |    |            |                  | should be sent      |      |
+   |    |            |                  | before M_ADR)       |      |
+   |    |            |                  | Send M_ADR frame    |      |
+   |    |            |                  | with system         |      |
+   |    |            |                  | addresses           |      |
+   |    |            |                  | Set Timer           |      |
+   |    |            |                  | See if we have      |      |
+   |    |            |                  | password for the    |      |
+   |    |            |                  | remote              |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Connection       | Report no           | exit |
+   |    |            | refused          | connection          |      |
+   |----+------------+------------------+---------------------+------|
+   | S2 | SendPasswd | Yes, we have a   | Send M_PWD          | S3   |
+   |    |            | password         | "password" frame    |      |
+   |    |            |                  | Reset Timer         |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, there's no   | Send M_PWD "-"      | S3   |
+   |    |            | password         | frame               |      |
+   |----+------------+------------------+---------------------+------|
+   | S3 | WaitAddr   | M_ADR frame      | See if answering    | S4   |
+   |    |            | received         | side presented the  |      |
+   |    |            |                  | address we've       |      |
+   |    |            |                  | called              |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_BSY frame      | Report remote is    | exit |
+   |    |            | received         | busy                |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_ERR frame      | Report error        | exit |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_NUL frame      | Ignore (optionally, | S3   |
+   |    |            | received         | log frame argument) |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Other known      | Report unexpected   | exit |
+   |    |            | frame received   | frame               |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Unknown frame    | Ignore              | S3   |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Nothing happens  | Wait                | S3   |
+   |    |            |------------------+---------------------+------|
+   |    |            | Timer Expired    | Report timeout      | exit |
+   |----+------------+------------------+---------------------+------|
+   | S4 | AuthRemote | Yes, the address | See if we've sent a | S5   |
+   |    |            | was presented    | password for this   |      |
+   |    |            |                  | address             |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, the address  | Report we called    | exit |
+   |    |            | was not          | the wrong system    |      |
+   |    |            | presented        |                     |      |
+   |----+------------+------------------+---------------------+------|
+   | S5 | IfSecure   | Yes, we've sent  | Wait for M_OK frame | S6   |
+   |    |            | a password       |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | No, there was no | Report non-secure   | T0   |
+   |    |            | password         | session             |      |
+   |----+------------+------------------+---------------------+------|
+   | S6 | WaitOk     | M_OK frame       | report secure       | T0   |
+   |    |            | received         | session             |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_BSY frame      | Report remote is    | exit |
+   |    |            | received         | busy (Answering     |      |
+   |    |            |                  | size MAY report     |      |
+   |    |            |                  | busy after          |      |
+   |    |            |                  | reception of        |      |
+   |    |            |                  | caller's address)   |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_ERR frame      | Report error        | exit |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | M_NUL frame      | Ignore (optionally, | S6   |
+   |    |            | received         | log arguments)      |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Other known      | Report unexpected   | exit |
+   |    |            | frame received   | frame               |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Unknown frame    | Ignore              | S6   |
+   |    |            | received         |                     |      |
+   |    |            |------------------+---------------------+------|
+   |    |            | Nothing happens  | Wait                | S6   |
+   |    |            |------------------+---------------------+------|
+   |    |            | Timer Expired    | Report timeout      | exit |
+   +-----------------------------------------------------------------+
+
+    6.1.2 Answering Side
+    --------------------
+
+   Originating side sends M_ADR and waits for M_ADR and M_PWD frames
+   from remote. Upon receptions of these frames, it decides whether
+   the password really matches the list of presented addresses, and
+   either acknowledges it by sending M_OK frame (and goes to file
+   transfer stage) or rejects by sending M_ERR frame (and
+   disconnects). The term wait in this paragraph means do not send
+   anything while expecting data from remote.
+
+                 Table 2: Session setup, answering side
+   +-----------------------------------------------------------------+
+   | #  | Name     | Predicate(s)        | Action(s)          | Next |
+   |----+----------+---------------------+--------------------+------|
+   | R0 | WaitConn | Incoming connection | Send M_NUL frames  | R1   |
+   |    |          | established         | with system info   |      |
+   |    |          |                     | (at least one      |      |
+   |    |          |                     | M_NUL "SYS ..."    |      |
+   |    |          |                     | frame should be    |      |
+   |    |          |                     | sent before M_ADR) |      |
+   |    |          |                     | Send M_ADR frame   |      |
+   |    |          |                     | with system        |      |
+   |    |          |                     | addresses          |      |
+   |    |          |                     | Set Timer          |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R0   |
+   |----+----------+---------------------+--------------------+------|
+   | R1 | WaitAddr | M_ADR frame         | See if we have a   | R2   |
+   |    |          | received            | password for any   |      |
+   |    |          |                     | of the remote      |      |
+   |    |          |                     | addresses          |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_ERR frame         | Report error       | exit |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_NUL frame         | Log                | R1   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Other known frame   | Report unexpected  | exit |
+   |    |          | received            | frame              |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Unknown frame       | Ignore             | R1   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R1   |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Timer expired       | Report timeout     | exit |
+   |----+----------+---------------------+--------------------+------|
+   | R2 | IsPasswd | Yes, we have a      | Set Timer          | R3   |
+   |    |          | password            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Yes, but we have    | Send M_ERR frame   | exit |
+   |    |          | several different   | Report             |      |
+   |    |          | passwords for       | inconsistent       |      |
+   |    |          | different addresses | password settings  |      |
+   |    |          | of the remote       |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | No, there's no      | Report non-secure  | T0   |
+   |    |          | password            | session            |      |
+   |----+----------+---------------------+--------------------+------|
+   | R3 | WaitPwd  | M_PWD frame         | See if the         | R4   |
+   |    |          | received            | password matches   |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_ERR frame         | Report error       | exit |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | M_NUL frame         | Log                | R4   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Other known frame   | Report unexpected  | exit |
+   |    |          | received            | frame              |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Unknown frame       | Ignore             | R4   |
+   |    |          | received            |                    |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Nothing happens     | Wait               | R3   |
+   |    |          |---------------------+--------------------+------|
+   |    |          | Timer Expired       | Report timeout     | exit |
+   |----+----------+---------------------+--------------------+------|
+   | R4 | PwdAck   | Yes, the password   | Send M_OK frame    | T0   |
+   |    |          | matches             | Report secure      |      |
+   |    |          |                     | session            |      |
+   |    |          |---------------------+--------------------+------|
+   |    |          | No, password does   | Report password    | exit |
+   |    |          | not match           | error              |      |
+   +-----------------------------------------------------------------+
+
+  6.2 File Transfer Stage
+  -----------------------
+
+   File transfer stage is based on two major routines. We call them
+   Receive Routine and Transmit Routine. These routines perform some
+   actions depending on their state variables. State variables are
+   RxState for Receive Routine and TxState for Transmit Routine.
+
+   RxState := { RxWaitF | RxAccF | RxReceD | RxWriteD | RxEOB | RxDone
+   }
+
+   TxState := { TxGNF | TxTryR | TxReadS | TxWLA | TxDone }
+
+                         Table 3: File Transfer
+   +-----------------------------------------------------------------+
+   | #  | Name         | Predicate(s)        | Action(s)      | Next |
+   |----+--------------+---------------------+----------------+------|
+   | T0 | InitTransfer | none                | Set Timer      | T1   |
+   |    |              |                     | Set RxState to |      |
+   |    |              |                     | RxWaitF        |      |
+   |    |              |                     | Set TxState to |      |
+   |    |              |                     | TxGNF          |      |
+   |----+--------------+---------------------+----------------+------|
+   | T1 | Switch       | RxState is RxDone   | Report session | exit |
+   |    |              | and TxState is      | complete       |      |
+   |    |              | TxDone              |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Data Available in   | call Receive   | T2   |
+   |    |              | Input Buffer        | routine        |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Free space exists   | call Transmit  | T3   |
+   |    |              | in output buffer    | routine        |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Nothing happens     | Wait           | T1   |
+   |    |              |---------------------+----------------+------|
+   |    |              | Timer Expired       | Report Timeout | exit |
+   |----+--------------+---------------------+----------------+------|
+   | T2 | Receive      | Receive routine     | Set Timer      | T1   |
+   |    |              | returned OK         |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Receive routine     | Close all      | exit |
+   |    |              | returned Failure    | opened files   |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Receive routine     | Call Receive   | T2   |
+   |    |              | returned Continue   | routine again  |      |
+   |----+--------------+---------------------+----------------+------|
+   | T3 | Transmit     | Transmit routine    | Set Timer      | T1   |
+   |    |              | returned OK         |                |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Transmit routine    | Close all      | exit |
+   |    |              | returned Failure    | opened files   |      |
+   |    |              |---------------------+----------------+------|
+   |    |              | Transmit routine    | Call Transmit  | T3   |
+   |    |              | returned Continue   | routine again  |      |
+   +-----------------------------------------------------------------+
+
+   Tables 4-6 are not actually state machines, but routines called
+   during file transfer stage
+
+   We define here a FIFO queue called "TheQueue", which is used to
+   pass incoming M_GET / M_GOT / M_SKIP frames from Receive Routine to
+   Transmit Routine. Receive routine itself does not react to these
+   frames.
+
+                        Table 4: Receive Routine
+   +-----------------------------------------------------------------+
+   |RxState |Predicate(s) |Condition(s) |Actions(s)|Next    |Return  |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxWaitF |Get a frame  |Haven't got a|none      |RxWaitF |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet    |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got Data     |ignore    |RxWaitF |OK      |
+   |        |             |frame        |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxWaitF |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxWaitF |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_EOB    |Report End|RxEOB   |OK      |
+   |        |             |             |of Batch  |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_FILE   |none      |RxAccF  |continue|
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |             |frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxWaitF |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxAccF  |Decide how to|Accept from  |Report    |RxReceD |OK      |
+   |        |accept       |beginning    |receiving |        |        |
+   |        |Incoming File|             |file      |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Accept from  |Send M_GET|RxReceD |OK      |
+   |        |             |offset (we do|Report    |        |        |
+   |        |             |already have |receiving |        |        |
+   |        |             |a part of    |file,     |        |        |
+   |        |             |file)        |requested |        |        |
+   |        |             |             |offest    |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Accept later |Send      |RxWaitF |OK      |
+   |        |             |(or failed to|M_SKIP    |        |        |
+   |        |             |create file) |Report we |        |        |
+   |        |             |             |will      |        |        |
+   |        |             |             |accept    |        |        |
+   |        |             |             |file      |        |        |
+   |        |             |             |later, not|        |        |
+   |        |             |             |in current|        |        |
+   |        |             |             |session   |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Refuse       |Send M_GOT|RxWaitF |OK      |
+   |        |             |(delete on   |Report we |        |        |
+   |        |             |remote)      |do not    |        |        |
+   |        |             |             |accept    |        |        |
+   |        |             |             |file      |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxReceD |Get a frame  |Didn't got a |none      |RxReceD |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet    |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got Data     |none      |RxWriteD|continue|
+   |        |             |frame        |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxReceD |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxReceD |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_FILE   |Report    |RxAccF  |Continue|
+   |        |             |             |partially |        |        |
+   |        |             |             |received  |        |        |
+   |        |             |             |file      |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |             |frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxReceD |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxWriteD|Write data to|Write Failed |Report    |RxDone  |Failure |
+   |        |file         |             |error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos >   |Report    |RxDone  |Failure |
+   |        |             |Reported     |write     |        |        |
+   |        |             |             |beyond EOF|        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos =   |Close File|RxWaitF |OK      |
+   |        |             |Reported     |Send M_GOT|        |        |
+   |        |             |             |Report    |        |        |
+   |        |             |             |File      |        |        |
+   |        |             |             |Received  |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |File Pos <   |none      |RxReceD |OK      |
+   |        |             |Reported     |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxEOB   |Get a frame  |Didn't get a |none      |RxEOB   |OK      |
+   |        |from Input   |complete     |          |        |        |
+   |        |Buffer       |frame yet or |          |        |        |
+   |        |             |TxState is   |          |        |        |
+   |        |             |not TxDone   |          |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_ERR    |Report    |RxDone  |Failure |
+   |        |             |             |Error     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_GET /  |Add frame |RxEOB   |OK      |
+   |        |             |M_GOT /      |to The    |        |        |
+   |        |             |M_SKIP       |Queue     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got M_NUL    |Log       |RxEOB   |OK      |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got other    |Report    |RxDone  |Failure |
+   |        |             |known frame  |unexpected|        |        |
+   |        |             |or data frame|frame     |        |        |
+   |        |             |-------------+----------+--------+--------|
+   |        |             |Got unknown  |ignore    |RxEOB   |OK      |
+   |        |             |frame        |          |        |        |
+   |--------+-------------+-------------+----------+--------+--------|
+   |RxDone  |none         |none         |none      |RxDone  |OK      |
+   +-----------------------------------------------------------------+
+
+   We define the list called "PendingFiles". After we put the last
+   byte of file into output buffer, we cannot yet consider the file as
+   being successfully transmitted, thus we have to add the file to
+   this list and then look for corresponding incoming M_GET / M_GOT /
+   M_SKIP frames to remove the file from the list and decide whether
+   the file was indeed received by remote or remote will accept this
+   file later, or something else. After we have sent M_EOB frame, we
+   must wait until PendingFiles list gets empty before disconnecting.
+
+   If the connection accidentally breaks, all the files left in
+   PendingFiles are considered unsent and will be re-transmitted in
+   the next session. If the connection breaks when the remote did
+   actually receive the file (but the corresponded confirmation frame
+   (M_GOT) didn't came back to us) and we are resending this file
+   again in the next session, remote may get two copies of the same
+   file (file dupe). Binkp allows to reduce or totally suppress such
+   dupes (at a cost of performance, of course), see Non-Reliable mode
+   and "No Dupes" protocol extension (to be found in a separate
+   document at a later date).
+
+                        Table 5: Transmit Routine
+   +-----------------------------------------------------------------+
+   |TxState|Predicate(s)|Condition(s)  |Actions(s)  |Next   |Return  |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxGNF  |Open next   |File opened OK|Send M_FILE |TxTryR |continue|
+   |       |file from   |              |Report      |       |        |
+   |       |outgoing    |              |sending file|       |        |
+   |       |queue       |--------------+------------+-------+--------|
+   |       |            |Failed to open|Report      |TxDone |Failure |
+   |       |            |file          |failure     |       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |No more files |Send M_EOB  |TxWLA  |continue|
+   |       |            |              |Report end  |       |        |
+   |       |            |              |of batch    |       |        |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxTryR |Check       |TheQueue is   |none        |TxReadS|continue|
+   |       |TheQueue    |empty         |            |       |        |
+   |       |            |--------------+--------------------+--------|
+   |       |            |TheQueue is   |call ProcessTheQueue|continue|
+   |       |            |not empty     |                    |        |
+   |-------+------------+--------------+--------------------+--------|
+   |TxReadS|Read data   |Read failed   |Report Error|TxDone |Failure |
+   |       |block from  |--------------+------------+-------+--------|
+   |       |file        |Read OK,      |Send data   |TxGNF  |OK      |
+   |       |            |Reached EOF   |block frame |       |        |
+   |       |            |              |Close       |       |        |
+   |       |            |              |current file|       |        |
+   |       |            |              |Add current |       |        |
+   |       |            |              |file to     |       |        |
+   |       |            |              |PendingFiles|       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |Read OK, not  |Send data   |TxTryR |OK      |
+   |       |            |reached EOF   |block frame |       |        |
+   |-------+------------+--------------+------------+-------+--------|
+   |TxWLA  |Check       |TheQueue is   |none        |TxDone |OK      |
+   |       |TheQueue    |empty and     |            |       |        |
+   |       |            |RxState >=    |            |       |        |
+   |       |            |RxEOB         |            |       |        |
+   |       |            |--------------+------------+-------+--------|
+   |       |            |TheQueue is   |none        |TxWLA  |OK      |
+   |       |            |empty and     |            |       |        |
+   |       |            |RxState <     |            |       |        |
+   |       |            |RxEOB         |            |       |        |
+   |       |            |--------------+--------------------+--------|
+   |       |            |TheQueue is   |call ProcessTheQueue|continue|
+   |       |            |not empty     |                    |        |
+   |-------+------------+--------------+--------------------+--------|
+   |TxDone |none        |none          |none        |TxDone |OK      |
+   +-----------------------------------------------------------------+
+
+   We define a list called KnownFiles. This list contains files that
+   can be requested by the remote using M_GET command. This list shall
+   at least contain all the files that are part of the PendingFiles
+   list.
+
+                    Table 6: ProcessTheQueue routine
+   +-----------------------------------------------------------------+
+   | Predicate(s)       | Condition(s)       | Actions(s)            |
+   |--------------------+--------------------+-----------------------|
+   | M_GET received     | requested file is  | Report unknown file   |
+   |                    | not in the         |                       |
+   |                    | KnownFiles list    |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_GET received for | Requested pos is   | Close and finalize    |
+   | a known file       | FileSize           | file.                 |
+   |                    |                    | Report that remote    |
+   |                    |                    | refused file being    |
+   |                    |                    | transmitted.          |
+   |                    |                    | Set TxState to        |
+   |                    |                    | TxGetNextFile.        |
+   |                    |--------------------+-----------------------|
+   |                    | Requested pos is   | Set file pointer to   |
+   |                    | less than FileSize | requested pos.        |
+   |                    |                    | Report that remote    |
+   |                    |                    | requested offset.     |
+   |                    |                    | Set TxState to        |
+   |                    |                    | TxReadSend.           |
+   |                    |--------------------+-----------------------|
+   |                    | Requested pos is   | Ignore frame          |
+   |                    | greater than       |                       |
+   |                    | FileSize           |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_GOT file that is | none               | Close and finalize    |
+   | currently          |                    | file                  |
+   | transmitting       |                    | Report Remote refused |
+   |                    |                    | file being            |
+   |                    |                    | transmitted           |
+   |                    |                    | Set TxState to TxGNF  |
+   |--------------------+--------------------+-----------------------|
+   | M_GOT file that is | File is in         | Finalize file         |
+   | not currently      | PendingFiles list  | Report file has been  |
+   | transmitting       |                    | sent                  |
+   |                    |                    | Remove file from the  |
+   |                    |                    | PendingFiles list     |
+   |                    |--------------------+-----------------------|
+   |                    | File is not in     | Ignore frame          |
+   |                    | PendingFiles       |                       |
+   |--------------------+--------------------+-----------------------|
+   | M_SKIP file that   | none               | Close file (do not    |
+   | is currently       |                    | finalize, we will     |
+   | transmitting       |                    | send it later, not in |
+   |                    |                    | current session)      |
+   |                    |                    | Report remote will    |
+   |                    |                    | accept this file      |
+   |                    |                    | later                 |
+   |                    |                    | Set TxState to TxGNF  |
+   |--------------------+--------------------+-----------------------|
+   | M_SKIP file that   | none               | Report remote will    |
+   | is not currently   |                    | accept this file      |
+   | transmitting       |                    | later                 |
+   |                    |                    | Remove file from      |
+   |                    |                    | PendingPiles, if      |
+   |                    |                    | exists there          |
+   +-----------------------------------------------------------------+
+
+  6.3 Session Termination
+  -----------------------
+
+   A session may be terminated in any of the following cases:
+
+          should be deemed aborted due to a fatal error.
+          should be deemed aborted due to non-fatal error typically
+       because of temporary lack of resources to proceed with the
+       session.
+             * all the files have been sent
+          * we have received M_EOB from the remote side (there are no
+            more files for us),
+          * we have received acknowledgements for all the files sent,
+          * we have received all the files re-requested by M_GET,
+       In this case, the session should be deemed successfully
+       completed.
+
+   A session termination itself is not a protocol stage. Mailer may
+   terminate a session at any time simply by issuing disconnect
+   (shutdown) command to the underlying transport layer, provided any
+   of the three conditions above are met. Mailer MUST take all proper
+   steps to provide a graceful shutdown of the transport layer, as it
+   is the transport layer that is responsible for all the data
+   transmitted by one side to be received by another before
+   disconnection, provided that shutdown of the transport layer
+   protocol was successful.
+
+7. Recommended Protocol Extensions
+----------------------------------
+
+   This section documents already implemented and proposed extensions
+   for the binkp/1.0. These extensions are purely optional and are
+   included here for the sake of compatibility with future
+   implementations.
+
+   Sides indicate supported protocol extensions by sending M_NUL
+   frame(s) with "OPT list_of_extensions" string, where
+   list_of_extensions is a space separated list of supported protocol
+   extensions. Whenever multiple M_NUL "OPT ..." frames are received
+   during the session, they SHOULD augment the current list of
+   extensions rather than replace it, unless specifically stated
+   otherwise for a particular option.
+
+   Mailer SHOULD NOT use any extension unless exactly sure that this
+   extension is supported by the remote. Mailer SHOULD use M_NUL "OPT
+   ..." to indicate supported options. Other methods for indicating
+   supported extensions are allowed as long as the provide full
+   backwards compatibility.
+
+  7.1 Non-reliable Mode
+  ---------------------
+
+   Non-reliable mode solves the problem with frequently aborted
+   connections when the sides can not successfully complete file
+   transfer before connection is broken. In this case, if the
+   transmitting side starts retransmission from offset 0, performance
+   degrades as by the time it receives M_GET from the remote, network
+   buffers are already full and by the time they are freed for
+   retransmission from requested offset, the connection might go down
+   again.
+
+   In order to circumvent this problem, a mailer can request the
+   remote to enter non-reliable mode by sending a M_NUL "OPT NR" frame
+   at any time during the session. After the remote acknowledges it by
+   sending an M_NUL "OPT NR" frame indicating that the option is
+   supported, both sides can assume that they are in non-reliable
+   mode.
+
+   When session is in non-reliable mode, the transmitting side may
+   send -1 for the offset value in M_FILE command. If it does so, it
+   should wait for the M_GET frame from the receiving side that
+   explicitly specifies file offset and start transmitting file data
+   from this offset. If the receiving side has indicated that it
+   supports non-reliable mode by sending M_NUL "OPT NR" frame, it must
+   recognize -1 as the file offset in M_FILE command as an explicit
+   request for the file offset and transmit an appropriate M_GET frame
+   as soon as possible.
+
+   It should be understood that this option degrades performance over
+   regular quality connections and it should be used only if
+   absolutely necessary.
+
+  7.2 Multiple Batch Mode
+  -----------------------
+
+   The session is in MB mode if both sides set "MB" flag in any of
+   M_NUL "OPT" packets exchanged before sending of M_OK/M_PWD packets.
+
+   In MB mode both sides restart session from RxDone into InitTransfer
+   state if there were any command packets sent or received by any
+   side between starting at InitTransfer and exchanging of M_EOB by
+   the sides (RxDone state). Otherwise, the session terminates as
+   usual.
+
+   Multiple batches mode is intended to handle WaZOO [FTS-0006] file
+   requests. If there were any WaZOO request files transferred in a
+   batch, sides MAY process them and send resulting files in the next
+   batch. Mailers MAY also generate list of files to send in
+   additional batches by other techniques -- including rescanning of
+   their spools or processing of other magic files transferred before
+   in the same session.
+
+  7.3 Multiple Passwords Mode
+  ---------------------------
+
+   Multiple password mode allows to specify different passwords for
+   the different addresses of the remote.
+
+   Originating side identifies it's multipassword capabilities by
+   sending M_NUL "OPT MPWD" during session setup stage before sending
+   any M_ADR commands and waits for response from the answering side.
+
+   If answering side responds with the M_NUL "OPT MPWD", then it
+   supports multiply passwords too. Answering side also always
+   responds with it's own address list: M_ADR "adr1 adr2 adr3 ...". If
+   M_NUL "OPT MPWD" was not received prior to the first M_ADR command,
+   originating side should assume that the remote does not support
+   multiple password mode and send a single password (if any) for one
+   of the addresses of the remote.
+
+   If the MPWD option was indicated by the answering side, originating
+   side now may send M_PWD "pwd1 pwd2 pwd3 ..." with the number of
+   entries in space separated password list equivalent to the number
+   of addresses presented by the answering side. If there is no
+   password for a particular address, it must send '-' character as a
+   placeholder.
+
+   If the passwords presented are consistent, answering side must
+   acknowledge successful authentication by sending M_OK command.
+
+  7.4 Keyed Hashing Challenge-Response Authentication Mechanism
+  -------------------------------------------------------------
+
+    7.4.1 Overview
+    --------------
+
+   Challenge-Response Authentication Mechanism (CRAM) allows to avoid
+   passing cleartext, reusable passwords across the network. Since it
+   utilizes Keyed-Hashing digests [Keyed], it does not require
+   password to be stored in the clear on the Mailer's media, allowing
+   storage of the intermediate results which are known as "contexts".
+
+   Providing binkp-mailer is capable of [Keyed] digest calculation and
+   conversion of a byte array to a hexadecimal string and back,
+   implementation of CRAM is easily achieved by slightly modifying the
+   state machine.
+
+    7.4.2 Sequence of Steps
+    -----------------------
+
+   CRAM adds an additional synchronization step to binkp protocol. The
+   description of this step follows:
+
+          the Originating side, encoded to a hexadecimal string.
+          hexadecimal string, and a password to produce a digest by
+       applying the keyed Hashing algorithm from [Keyed] where the key
+       is the password and the digested text is the challenge data.
+          digest provided. If the digest is correct, the answering side
+       should consider the Originating side authenticated and responds
+       appropriately.
+
+   Similar technique is used in [IMAP-AUTH].
+
+    7.4.3 Generating and Transmitting Challenge Data
+    ------------------------------------------------
+
+   Size and contents of challenge data are implementation-dependent,
+   but it SHOULD be no smaller than 8 bytes and no bigger than 64
+   bytes. Answering side SHOULD never generate the same challenge
+   data.
+
+   Instead of generating a long challenge data, answering side MAY use
+   a hash function to shorten it. In calculation of a challenge data
+   answering side MAY also use connection/line number, caller's IP
+   address, current time, etc.
+
+   Answering side transmits challenge data in the very first M_NUL
+   message, in the following way:
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   lsthf is a list of aliases of supported hash functions, delimited
+   by slash characters. The list begins with alias of the most
+   preferred and ends with alias of the least preferred hash function.
+
+   Currently defined aliases are: MD5 for [MD5] and SHA1 for [SHA-1].
+
+   cde is the challenge data encoded to hexadecimal string, Lower-case
+   ASCII characters MUST be used for encoding, but Mailer SHOULD also
+   accept upper-case characters. The length of the string MUST be
+   even, and the leading zeros MUST NOT be trimmed.
+
+    7.4.4 Producing and Transmitting a Digest
+    -----------------------------------------
+
+   Originating side responds with:
+
+   M_PWD "CRAM-chosenhf-khde [othropt]"
+
+   where chosenhf is the alias of the chosen hash function and khde is
+   the keyed hashed digest, encoded to a hexadecimal string.
+
+   According to [IMAP-AUTH], keyed hashed digest is produced by
+   calculating
+
+   HASH((secret XOR opad), HASH((secret XOR ipad), challengedata))
+
+   where HASH is chosen hash function, ipad and opad are 36 hex and 5C
+   hex (as defined in [Keyed]) and secret is a password null-padded to
+   a length of 64 bytes. If the password is longer than 64 bytes, the
+   hash-function digest of the password is used as an input (16-byte
+   for [MD5] and 20-byte for [SHA-1]) to the keyed hashed calculation.
+
+    7.4.6 Indicating CRAM Capabilities
+    ----------------------------------
+
+   Answering side MUST send
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   as a very first M_NUL message if it supports CRAM.
+
+   It MAY send other non-M_NUL messages before though. Current
+   specification doesn't define any such non-M_NUL message, they are
+   reserved for protocol extension.
+
+   Originating side MUST be ready to receive non-M_NUL before M_NUL in
+   a CRAM session. Binkp state machine MUST ignore any received
+   message of unknown type in order to be compatible with future
+   extensions.
+
+   If an originating side receives a first message that is a M_ADR or
+   a M_NUL message that is not
+
+   M_NUL "OPT [othropt] CRAM-lsthf-cde [othropt]"
+
+   it MUST decide that the answering side doesn't support CRAM and MAY
+   either disconnect or use old password exchange. If the sides have
+   no any compatible hash function, originator may also either
+   disconnect or use old password exchange. If an originating side
+   decides to disconnect, it SHOULD send M_ERR frame with a proper
+   explanation before disconnecting.
+
+   When parsing M_NUL "OPT ..." string (coming from the answering
+   side), originating side first splits it by using space delimiter to
+   get a list of options, and then if an option begins with
+   "CRAM-lsthf-", takes the remaining substring as a
+   hexadecimal-encoded challenge data.
+
+    7.4.7 Example of Frame Exchange During CRAM Authentication
+    ----------------------------------------------------------
+
+   (Password here is tanstaaftanstaaf)
+
+   Originating :
+     send M_NUL messages
+     and M_ADR
+     wait for first M_NUL message
+
+   Answering   :
+     send M_NUL "OPT ND CRAM-SHA1/MD5-f0315b074d728d483d6887d0182fc328"
+     and other messages
+     wait for M_PWD
+
+   Originating :
+     M_PWD "CRAM-MD5-56be002162a4a15ba7a9064f0c93fd00"
+
+   Answering   :
+     M_OK and continue session
+
+    7.4.8 Notes on Hash Function Algorithms
+    ---------------------------------------
+
+   [MD5] and [SHA-1] are the most widely used cryptographic hash
+   functions. [MD5] has been shown to be vulnerable to collision
+   search attacks [Dobb]. This attack and other currently known
+   weaknesses of [MD5] do not compromise the use of [MD5] within CRAM
+   as specified in this document (see [Dobb]); however, [SHA-1]
+   appears to be a cryptographically stronger function. To this date,
+   [MD5] can be considered for use in CRAM for applications where the
+   superior performance of [MD5] is critical. In any case,
+   implementors and users need to be aware of possible cryptanalytic
+   developments regarding any of these cryptographic hash functions,
+   and the eventual need to replace the underlying hash function.
+
+8. License
+----------
+
+   You can implement binkp protocol in your software as long as you
+   agree to the following conditions:
+
+          other way. You shall include the author(s) of the protocol in
+       your copyright statement for the software.
+          versions. Binkp allows development of the new capabilities
+       without compromising interoperability with previous versions.
+       Therefore, it is important that future developments of the
+       protocol are not pursued in different directions by different
+       people. If you have any suggestions regarding future
+       developments of the protocol, make a reasonable effort to
+       contact the author(s), so that the development efforts can
+       coordinated in a way advantageous for everybody.
+          future binkp specifications, you shall reference to it as a
+       "binkp variation" or "binkp derived".
+
+   Remember that you may use, implement or utilize binkp, it's
+   description or any other associated texts or documentations at your
+   own risk, without any warranty, without even the implied warranty
+   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
+
+   Binkp author: Dima Maloff.
+
+9. Glossary
+-----------
+
+   Many entries in this glossary are provided courtesy of Butterfly
+   Glossary of Internet and Data Communication terms and RFC-1983.
+
+   connection-oriented
+           Data communication method in which communication proceeds
+           through three well-defined phases: connection
+           establishment, data transfer, connection release. TCP is a
+           connection-oriented protocol.
+
+   data link layer
+           The OSI layer that is responsible for data transfer across
+           a single physical connection, or series of bridged
+           connections, between two Network entities.
+
+   flow control
+           A technique for ensuring that a transmitting entity does
+           not overwhelm a receiving entity.
+
+   HDLC
+           (High level Data Link Control). Popular ISO standard
+           bit-oriented, data link layer protocol derived from SDLC.
+           HDLC specifies an encapsulated method of data on
+           synchronous serial data links.
+
+   IP
+           (Internet Protocol). The Internet Protocol, defined in STD
+           5, RFC 791, is the network layer for the TCP/IP Protocol
+           Suite. It is a connectionless, best-effort packet switching
+           protocol.
+
+   network layer
+           Layer 3 of the OSI reference model. Layer 3 is the layer at
+           which routing, addressing and connection management take
+           place.
+
+   OSI (Open Systems Interconnection) Reference Model
+           A seven-layer structure designed to describe computer
+           network architectures and the way that data passes through
+           them. This model was developed by the ISO (International
+           Organization for Standardization) in 1978 to clearly define
+           the interfaces in multivendor networks, and to provide
+           users of those networks with conceptual guidelines in the
+           construction of such networks.
+
+   port
+           A port is a transport layer demultiplexing value. Each
+           application has a unique port identifier associated with
+           it.
+
+   physical layer
+           The OSI layer that provides the means to activate and use
+           physical connections for bit transmission. In plain terms,
+           the Physical Layer provides the procedures for transferring
+           a single bit across a Physical Media.
+
+   Quality of Service
+           (Also QoS). A measure of performance for a transmission
+           system that reflects its transmission quality and
+           availability of service.
+
+   reliable transmission
+           a type of transport service that:
+              * recovers from errors by retransmitting errored frames
+              * delivers frames in correct sequence (also known as
+                stream-oriented)
+              * usually is used in connection-oriented mode
+
+   session layer
+           Layer 5 of the OSI reference model. Coordinates session
+           activity between applications, including application-layer
+           error control, dialog control, and remote procedure calls.
+
+   sliding window flow control
+           Method of flow control in which a receiver gives
+           transmitter permission to transmit data until a window is
+           full. When the window is full, the transmitter must stop
+           transmitting until the receiver advertises a larger window.
+
+   socket
+           Software structure operating as a communications and point
+           within a network device.
+
+   TCP
+           Transmission Control Protocol. An Internet Standard
+           transport layer reliable protocol defined in STD 7, RFC
+           793. It is connection-oriented and stream-oriented.
+
+   TCP/IP protocol suite
+           Transmission Control Protocol over Internet Protocol. This
+           is a common shorthand which refers to the suite of
+           transport and application protocols which runs over IP.
+
+   transport layer
+           Layer 4 of the OSI reference model. The transport layer is
+           responsible for reliable network communication between end
+           nodes. It implements flow and error control and often uses
+           virtual circuits to ensure reliable data delivery.
+
+   unixtime
+           number of seconds elapsed since 00:00:00 UTC, Jan. 1, 1970.
+
+10. References
+--------------
+
+   [FTS-0001]
+           A Basic FidoNet(r) Technical Standard, Revision 16. Randy
+           Bush, Pacific Systems Group, September 30, 1995. FTS-0001.
+
+   [FTS-0006]
+           YOOHOO and YOOHOO/2U2. The netmail handshake used by
+           Opus-CBCS and other intelligent Fidonet mail handling
+           packages. Version 002, Vince Perriello. 30-Nov-1991.
+           FTS-0006.
+
+   [FSC-0039]
+           M.Howard, A type-2 packet extension proposal, FSC-0039
+           Version 4, 29-Sep-1990. FSC-0039.
+
+   [FSC-0045]
+           T.Henderson, Proposed new packet header, Version 1,
+           17-Apr-1990. FSC-0045.
+
+   [FSC-0048]
+           J.Vroonhof, Proposed type-2 packet extension, Version 2,
+           21-Oct-1990. FSC-0048.
+
+   [FSC-0081]
+           M.Staldal, A type-3 packet proposal, Version 1,
+           01-Mar-1995. FSC-0081.
+
+   [EMSI]
+           Joaquim H. Homrighausen, EMSI/IEMSI protocol definition.
+           May 3, 1991. FSC-0056.
+
+   [FTA-1006]
+           Key words to indicate requirement levels, Fidonet Technical
+           Standards Committee administrative. FTA-1006.
+
+   [Halsall95]
+           Data Communications, Computer Networks and Open Systems, F.
+           Halsall, 4th ed., Addison-Wesley, 1995, ISBN 0-201-42293-X.
+
+   [Dobb]
+           H. Dobbertin, "The Status of MD5 After a Recent Attack",
+           RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
+
+   [MD5]
+           Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321,
+           April 1992.
+
+   [SHA-1]
+           NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
+
+   [Keyed]
+           Krawczyk, Bellare, Canetti, "HMAC: Keyed-Hashing for
+           Message Authentication", RFC 2104, February 1997.
+
+   [IMAP-AUTH]
+           Klensin, "IMAP/POP AUTHorize Extension for Simple
+           Challenge/Response", RFC 2195, September, 1997
+
+   [RFC822]
+           Standard for the format of ARPA Internet text messages. D.
+           Crocker. Aug-13-1982. RFC 822, STD0011.
+
+   [UTF8]
+           UTF-8, a transformation format of ISO 10646. F. Yergeau.
+           January 1998, RFC 2279.
+
+   [ISO10646]
+           ISO/IEC 10646-1:1993. International Standard -- Information
+           technology -- Universal Multiple-Octet Coded Character Set
+           (UCS) -- Part 1: Architecture and Basic Multilingual Plane.
+           Five amendments and a technical corrigendum have been
+           published up to now. UTF-8 is described in Annex R,
+           published as Amendment 2.
+
+11. Acknowledgements
+--------------------
+
+   This document is partially based on extracts from RFCs and FTSC
+   publications too numerous to be acknowledged individually.
+
+   The authors would like to thank Joaquim Homrighausen, Kim 'B'
+   Heino, Rune Johansen and many others for fruitful discussions and
+   suggestions regarding protocol design and specifications.
+
+A. Author Contact Data
+-----------------------
+
+   Dima Maloff
+   Fidonet: 2:5020/128
+   E-mail: maloff@corbina.net
+   WWW: http://www.corbina.net/~maloff/
+
+   Maxim Masiutin
+   Fidonet: 2:469/84
+   E-mail: max@ritlabs.com
+   WWW: http://www.ritlabs.com/
+
+   Nick Soveiko
+   Fidonet: 2:5030/23.101
+   E-mail: nsoveiko@doe.carleton.ca
+   WWW: http://www.doe.carleton.ca/~nsoveiko/
+
+B. History
+----------
+
+   Rev.1, 19990611:
+           First release
+
+   Rev.2, 19991008:
+              * Added new topic: "Definitions";
+              * clarified the following topics: "Frame Format",
+                "Protocol Commands and Their Arguments", "Keyed
+                Hashing Challenge-Response Authentication Mechanism";
+              * added "unixtime" item to Glossary topic;
+              * corrected links in References topic.
+
+   Rev.3, 20000731:
+              * Table 6 in section 6.2, File transfer stage has been
+                rewritten: TheListOfSendFiles replaced by PendingFiles
+                which was defined earlier. introduced definition of
+                KnownFiles list. new ProcessTheQueue routine w/respect
+                to handling M_GET command
+              * Section 5.2, File Name Issues was rewritten to clearly
+                define safe and unsafe characters in filenames.
+              * Section 5.3, Non-ASCII Characters was rewritten to
+                clarify Unicode usage.
+              * Expanded descriptions for M_NUL "TIME ...", M_NUL "TRF
+                ...", added description of M_NUL "PHN ..." and M_NUL
+                "OPM ..." frames in section 5.4 Binkp Commands.
+              * IANA port number added to section 3, Protocol
+                Overview.
+              * M_GET description in section 5.4, Binkp Commands was
+                rewritten for clarity.
+              * M_BSY "RETRY ..." option documented.
+              * Minor edits throughout the document to improve
+                readability.
+
+Back Go Back + + diff --git a/html/ftsc/fta-1005.html b/html/ftsc/fta-1005.html new file mode 100755 index 00000000..0cd34d52 --- /dev/null +++ b/html/ftsc/fta-1005.html @@ -0,0 +1,268 @@ + + +FTSC Product ID List. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FTA-1005
+Revision:       3
+Title:          FTSC Product Codes
+Author:         Administrator
+Revision Date:  22 March 1998
+Expiry Date:    22 March 1998
+----------------------------------------------------------------------
+Contents:
+                1. Format of product code list
+                2. Application for a product code
+----------------------------------------------------------------------
+
+
+1. Format of product code list
+------------------------------
+
+  The FTSC publishes a list of all product codes issued. The filename
+  is FTSCPROD.nnn, where nnn is a number which increases with each
+  revision.
+
+  The list is an ASCII text file with one line per product. Each line
+  contains a number of fields, delimited by commas. Some fields may
+  contain more than one value. In this case, the different values are
+  delimited with a forward slash ('/'). Spaces in fields are replaced
+  with underscores ('_'). Fields are not case-sensitive.
+
+  These are the fields which are currently defined:
+
+    code,name,platform,type,contact,netaddr[,assigned[,updated]]
+
+  code      The product code. 4 digits hexadecimal.
+  name      Product name.
+  platform  Platforms(s) supported.
+  type      Type(s) of product.
+  contact   Name of contact person.
+  netaddr   FidoNet address of contact person.
+  assigned  Date the product code was originally assigned.
+  updated   Date of last update of the product code data.
+
+  Platforms
+  ---------
+  See the list for examples. (Will be specified more firmly later).
+
+  Product types
+  -------------
+  Mailer    A mailer is a product that exchanges mail with FTS-0001,
+            FTS-0006, EMSI or other protocols that include a product
+            code field.
+  Packer    A packer is a product that creates .PKT files.
+
+  Dates
+  -----
+  The format is YYYYMMDD. A date field may also be blank.
+
+  If you write software which is dependant on this format, please make
+  it tolerant of additional fields after these for upwards
+  compatibility.
+
+
+2. Application for a product code
+---------------------------------
+
+  FidoNet products without an allocated product code which either
+  create Type-2 packets, or negotiate FTS-0001 sessions must use a
+  product code FEh (254d) in Type-2 compatible packet headers. This
+  code as been reserved for that purpose (use by product without a
+  product code). The product code FFh (255d) has been reserved to
+  indicate that the product code is stored elsewhere in the packet
+  header at an as yet unallocated offset.
+
+  The FTSC is currently working on an update to the Type-2 packet
+  specification, to allow 16-bit codes while keeping full backward
+  compatibility with 8-bit codes (something which the current Type-2
+  proposals in the FSC's are not). Until the specification is ready,
+  16-bit codes are issued with the low byte set to FFh (255d).
+
+  Below is an application form for an FTSC product code, which is used
+  to identify your product when used in FidoNet, and providing a means
+  by which you can be contacted should your product be found
+  responsible for problems encountered during its use. The issuance of
+  this product code in no way implies authorisation or approval of
+  your product for use on the network, only provides a means of ready
+  identification.
+
+  This application should be completed and submitted for only `real'
+  and completed products which will be used by FidoNet systems. If you
+  are currently developing a product which is not yet ready for use on
+  the network out of experimental stage, use product code 0 (zero)
+  which is, by convention, reserved for this purpose.
+
+  Please answer the questions as accurately and completely as
+  possible. We need to know what will actually be used on the net, so
+  describe only the current product, and leave future features and
+  plans for the comments section.
+
+  Send the completed form to the administrator of the FidoNet
+  Technical Standards Committee. Please see FTA-1003 for addresses.
+
+  We hope that you will take the time to revise your answers by
+  submitting updates as your product changes. A summary of the
+  information you provide is compiled into a list of all product codes
+  published and updated periodically by the FTSC called
+  "FTSCPROD.nnn".
+
+
+A. Application Form
+-------------------
+
+--- Cut along here ---------------------------------------------------
+
+FTSC Product Code Application
+=============================
+
+Type of application
+-------------------
+
+1.  Mark whichever is appropriate:
+
+    ____  New product application
+    ____  Update existing product       for existing product code ____
+
+
+2.  If this is an update, please briefly state the nature of the
+    update (change author's node number, change of product name, etc.)
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+Product information
+-------------------
+
+3.  What is the name of the product and the current version name or
+    number?
+
+    __________________________________________________________________
+
+
+4.  What is the name, FidoNet node, and postal address, and voice
+    number of the person(s) or organization responsible for the
+    product?  Where should inquiries be directed and who should be
+    contacted if the product is thought to cause errors on the
+    network?
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+5.  What operating systems does it currently run on?
+
+    __________________________________________________________________
+
+
+6.  Does the product contain a 'mailer'?  E.g. the package transmits
+    mail to other FidoNet systems and can fall back to FTS-0001,
+    though it may handle other protocols.
+
+    __________________________________________________________________
+
+
+7.  If the answer to question (6) is yes, what additional protocols
+    other than FTS-0001 does the product support? Refer to the
+    specific FTSC document which details this protocol, if any.
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+    With what additions or restrictions?
+
+    __________________________________________________________________
+
+
+8.  Is the package capable of servicing file requests, and if so,
+    'Bark' style (FTS-0008) and/or WaZOO .REQ (FTS-0006) or both?
+
+    __________________________________________________________________
+
+
+    With what additions or restrictions?
+
+    __________________________________________________________________
+
+
+9.  Is your software capable of functioning as a Continuous Mail
+    system? i.e. nodes running it might be marked as such in the
+    FidoNet nodelist?
+
+    __________________________________________________________________
+
+
+10. How is the product distributed?
+
+    Public Domain  ____________          Shareware      ______________
+    Commercial     ____________          Other          ______________
+    Object code    ____________          Source code    ______________
+
+    Comments: ________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+
+11. Please give additional comments to describe your product.
+
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+    __________________________________________________________________
+
+--- Cut along here ---------------------------------------------------
+
+
+B. Acknowledgements
+-------------------
+
+  The application form was inspired by one originally published in
+  FSC-0022 and later FSC-0090, originally by Bob Hartman, Jim Long,
+  and Randy Bush and modified by Rick Moore and David Nugent.
+
+
+C. History
+----------
+
+  Rev.1, 19970407: First non-draft release. Author Adrian Walker.
+  Rev.2, 19971229: Author changed to Administrator. Reformatted
+                   document slightly. Changed all dates in the lists
+                   to 4 digit centuries. Added information about
+                   status of 16-bit product codes.
+  Rev.3, 19980322: Moved the product code list out of the document and
+                   into a separate list, FTSCPROD.nnn. Added an
+                   application form. Revised text about 16 bit codes.
+
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0001.html b/html/ftsc/fts-0001.html new file mode 100755 index 00000000..42085282 --- /dev/null +++ b/html/ftsc/fts-0001.html @@ -0,0 +1,1260 @@ + + +A Basic FidoNet(r) Technical Standard. + + + + +
+Document: FTS-0001
+Version:  016
+Date:     30-Sep-95
+
+
+
+
+                     A Basic FidoNet(r) Technical Standard
+|                                Revision 16
+                      Formerly known as FSC001,  FSC-0001
+|                      Randy Bush, Pacific Systems Group
+|                             September 30, 1995
+
+
+
+
+Status of this document:
+
+    This FTS  (FidoNet(r)  Technical  Standard)  specifies  a  standard  for
+    the FidoNet community. FidoNet nodes are expected to adopt and implement
+    this standard. Distribution is subject to the restrictions stated in the
+    copyright paragraph below.
+
+    Fido and FidoNet are registered marks of Tom Jennings and Fido Software.
+
+    Copyright  1986-95,  Randy  Bush.  All  rights  reserved.   A  right  to
+    distribute only  without modification  and only at no charge is granted.
+    Under no  circumstances is this document to be reproduced or distributed
+    as  part of  or packaged with any product or other sales transaction for
+    which any fee is charged.  Any and all other reproduction  or excerpting
+    requires the explicit written consent of the author.
+
+
+ A. Introduction
+
+    FidoNet  has  grown  beyond  most  peoples' fantasies, and  new  FidoNet
+    implementations  are appearing regularly.  Unfortunately, the  scattered
+    nature of the documentation and absence of clear testing procedures have
+    made  implementation  difficult.   FidoNet, in its desire to promote and
+    encourage  FidoNet  implementations,  suggested  a  project  to create a
+    technical  standard for  FidoNet.  The author did not  design or specify
+    the data formats or protocols, only attempted to document them.
+
+    This  document defines the  data structures and communication  protocols
+    which a FidoNet implementation must provide.  The implementor of FidoNet
+    compatible systems is the intended audience of this document.
+
+    The  layered metaphor of the ISO Open Systems Interface reference  model
+    has been used to view FidoNet from a standard perspective.  As with most
+    prospective  ISO/OSI  descriptions, FidoNet  does not always  make  this
+    easy.
+
+    The  content of this document  was gleaned from the references given  at
+    the  end.
+
+    Please direct technical comments and errata to
+|     Randy Bush                       randy@psg.com
+|     Pacific Systems Group
+      9501 S.W. Westhaven Drive
+      Portland, Oregon  US-97225
+|
+
+   1. Basic Requirements for a FidoNet Implementation
+
+      Compatibility is a set of abilities which, when taken as a whole, make
+      it safe to list a net or node in the FidoNet nodelist. In other words,
+      if  another  node should attempt  contact, does it have  a  reasonable
+      chance  of successful communication?  This is a social obligation,  as
+      the  calling  system  pays  money  for the  attempt.   Conversely,  an
+      implementation  should be able to successfully contact other  systems,
+      as life is not a one-way street.
+
+      A FidoNet implementation must be able to call other nodes and transfer
+      messages and files in both directions.  This includes pickup and poll.
+      A FidoNet implementation must be able to accept calls from other nodes
+      and  transfer  messages and  files in both directions.  This  includes
+      pickup.
+
+      FidoNet implementations must be able to receive and process the FidoNet
+      format  nodelist, and transfer nodelists to other nodes.  A  companion
+      document,  FTS-0005, defines the FidoNet format nodelist  and  how  to
+      interpret and process it.
+
+      A  FidoNet implementation must route messages which do not have  files
+      attached through net hosts as shown in a FidoNet format nodelist.
+
+
+   2. Levels of Compliance
+
+      This  documents represents the  most basic FidoNet implementation.   A
+      future  document will define well tested extensions which are optional
+      but  provide sufficient  additional function that implementors  should
+      seriously   consider   them.   SEAdog(tm),  from  System   Enhancement
+      Associates,  is  an  excellent  example  of such an  extended  FidoNet
+      implementation.
+
+
+   3. The ISO/OSI Reference Model (cribbed from "Protocol Verification via
+      Executable Logic Specifications", D. P. Sidhu, in Rudin & West)
+
+      In  the ISO/OSI model, a distributed system consists of entities  that
+      communicate  with  each other  according  to a set of rules  called  a
+      protocol.   The  model is  layered, and there are entities  associated
+      with  each layer of the model which provide services to higher  layers
+      by  exchanging information with their peer entities using the services
+      of  lower layers.  The only actual physical communication between  two
+      systems is at the lowest level.
+
+      Several  techniques  have  been  used  in the  specification  of  such
+      protocols.  A common ingredient in all techniques is the notion of the
+      extended  finite  state automata  or machine.  Extensions include  the
+      addition of state variables for the storing of state information about
+      the  protocol.  The state of an  automation can change as a result  of
+      one of the following events:
+
+      o Request from an upper network layer for service
+
+      o Response to the upper layer
+
+      o Request to the lower network layer to perform a service
+
+      o Response from the lower layer
+
+      o Interaction with the system and environment in which the protocol is
+        implemented (e.g. timeouts, host operating system aborts, ...)
+
+      A  protocol  specification, in  a large part, consists  of  specifying
+      state  changes  in  automata  which  model protocol  entities  and  in
+      describing the data which they exchange.
+
+      For  historical  reasons,  the  term  packet  is used  in  FidoNet  to
+      represent a bundle of messages, as opposed to the more common use as a
+      unit of communication, which is known as a block in FidoNet.
+
+
+   4. Data Description
+
+      A  language  specific  notation  was avoided.  Please help  stamp  out
+      environmental  dependencies.   Only  you  can  prevent  PClone  market
+      dominance.  Don't panic, there are rectangular record layouts too.
+
+      (* non-terminals *)
+      UpperCaseName - to be defined further on
+
+      (* literals *)
+      "ABC"         - ASCII character string, no termination implied
+      nnH           - byte in hexadecimal
+
+      (* terminals *)
+      someName      - 16-bit integer, low order byte first (8080 style)
+      someName[n]   - field of n bytes
+      someName[.n]  - field of n bits
+      someName(n)   - Null terminated string allocated n chars (incl Null)
+      someName{max} - Null terminated string of up to max chars (incl Null)
+
+      (* punctuation *)
+      a b           - one 'a' followed by one 'b'
+      ( a | b )     - either 'a' or 'b', but not both
+      { a }         - zero or more 'a's
+      [ b ]         - zero or one 'b'
+      (* comment *) - ignored
+
+      (* predeclared constant *)
+      Null          = 00H
+
+
+
+ 5. Finite State Machine Notation
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         |  St |
+    |-----+----------+-------------------------+-------------------------+-----|
+    | fnn*|          |                         |                         |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+
+    State #      - Number of this state (e.g. R13).
+                   f  - FSM initial (Window, Sender, Receiver, ...)
+                   nn - state number
+                   *  - state which represents a lower level protocol  which
+                        is represented by yet another automation.
+
+    State Name   - Descriptive name of this state.
+
+    Predicate(s) - Conditions which terminate the state.  If predicates are
+                   non-exclusive, consider them ordered.
+
+    Action(s)    - Action(s) corresponding to predicate(s)
+
+    Next State   - Subsequent state corresponding to predicate(s)
+
+    Ideally,  there  should be  a  supporting section for each  state  which
+    should  give a prose description of the state, its predicates,  actions,
+    etc.  So much for ideals.
+
+
+ B. Application Layer : the System from the User's View
+
+    The application layer is outside the domain of a FidoNet standard, as it
+    is the layer that the user's application sees as opposed to what FidoNet
+    sees.   In  recent  months,  there  has been  sufficient  confusion  and
+    discussion  about  the  format  of  data at this level  to  warrant  the
+    description  of the data structure, the message as it is stored by Fido,
+    SEAdog, and Rover.
+
+    Perfectly valid FidoNet systems may be implemented whose stored messages
+    differ greatly from this format.
+
+
+   1. Application Layer Data Definition : a Stored Message
+
+                               Stored Message
+
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                                               |
+              ~                 fromUserName                  ~
+              |                   36 bytes                    |
+              +-----------------------+-----------------------+
+       36  24 |                                               |
+              ~                  toUserName                   ~
+              |                   36 bytes                    |
+              +-----------------------+-----------------------+
+       72  48 |                                               |
+              ~                    subject                    ~
+              |                   72  bytes                   |
+              +-----------------------+-----------------------+
+      144  90 |                                               |
+              ~                    DateTime                   ~
+              |                    20 bytes                   |
+              +-----------------------+-----------------------+
+      164  A4 | timesRead (low order) | timesRead (high order)|
+              +-----------------------+-----------------------+
+      166  A6 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+      168  A8 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+      170  AA |   cost (low order)    |   cost (high order)   |
+              +-----------------------+-----------------------+
+      172  AC | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+      174  AE | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+      176  B0 | destZone (optional)   | destZone (optional)   |
+              +-----------------------+-----------------------+
+      178  B2 | origZone (optional)   | origZone (optional)   |
+              +-----------------------+-----------------------+
+      180  B4 | destPoint(optional)   | destPoint(optional)   |
+              +-----------------------+-----------------------+
+      182  B6 | origPoint(optional)   | origPoint(optional)   |
+              +-----------------------+-----------------------+
+      184  B8 |  replyTo (low order)  |  replyTo (high order) |
+              +-----------------------+-----------------------+
+      186  BA | Attribute (low order) | Attribute (high order)|
+              +-----------------------+-----------------------+
+      188  BC | nextReply (low order) | nextReply (high order)|
+              +-----------------------+-----------------------+
+      190  BE |                      text                     |
+              ~                    unbounded                  ~
+              |                 null terminated               |
+              `-----------------------------------------------'
+
+      Message    = fromUserName(36)  (* Null terminated *)
+                   toUserName(36)    (* Null terminated *)
+                   subject(72)       (* see FileList below *)
+                   DateTime          (* message body was last edited *)
+                   timesRead         (* number of times msg has been read *)
+                   destNode          (* of message *)
+                   origNode          (* of message *)
+                   cost              (* in lowest unit of originator's
+                                        currency *)
+                   origNet           (* of message *)
+                   destNet           (* of message *)
+                   destZone          (* of message *)
+                   origZone          (* of message *)
+                   destPoint         (* of message *)
+                   origPoint         (* of message *)
+                   replyTo           (* msg to which this replies *)
+                   AttributeWord
+                   nextReply         (* msg which replies to this *)
+                   text(unbounded)   (* Null terminated *)
+
+      DateTime   = (* a character string 20 characters long *)
+                                     (* 01 Jan 86  02:34:56 *)
+                   DayOfMonth " " Month " " Year " "
+                   " " HH ":" MM ":" SS
+                   Null
+
+      DayOfMonth = "01" | "02" | "03" | ... | "31"   (* Fido 0 fills *)
+      Month      = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" |
+                   "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"
+      Year       = "01" | "02" | .. | "85" | "86" | ... | "99" | "00"
+      HH         = "00" | .. | "23"
+      MM         = "00" | .. | "59"
+      SS         = "00" | .. | "59"
+
+      AttributeWord   bit       meaning
+                      ---       --------------------
+                        0  +    Private
+                        1  + s  Crash
+                        2       Recd
+                        3       Sent
+                        4  +    FileAttached
+                        5       InTransit
+                        6       Orphan
+                        7       KillSent
+                        8       Local
+                        9    s  HoldForPickup
+                       10  +    unused
+                       11    s  FileRequest
+                       12  + s  ReturnReceiptRequest
+                       13  + s  IsReturnReceipt
+                       14  + s  AuditRequest
+                       15    s  FileUpdateReq
+
+                             s - need not be recognized, but it's ok
+                             + - not zeroed before packeting
+
+      Bits numbers ascend with arithmetic significance of bit position.
+
+
+      Message Text
+
+      Message text is unbounded and null terminated (note exception below).
+
+      A 'hard' carriage return, 0DH,  marks the end of a paragraph, and must
+      be preserved.
+
+      So   called  'soft'  carriage  returns,  8DH,  may  mark  a   previous
+      processor's  automatic line wrap, and should be ignored.  Beware  that
+      they may be followed by linefeeds, or may not.
+
+      All  linefeeds, 0AH, should be ignored.  Systems which display message
+      text should wrap long lines to suit their application.
+
+      If the first character of a physical line (e.g. the first character of
+      the  message text, or the character immediately after a hard  carriage
+      return (ignoring any linefeeds)) is a ^A (, 01H), then that
+      line  is  not  displayed  as  it  contains  control  information.  The
+      convention for such control lines is:
+        o They begin with ^A
+        o They end at the end of the physical line (i.e. ignore soft s).
+        o They begin with a keyword followed by a colon.
+        o The keywords are uniquely assigned to applications.
+        o They keyword/colon pair is followed by application specific data.
+
+      Current ^A keyword assignments are:
+|     o TOPT  - destination point address
+      o FMPT  - origin point address
+      o INTL   - used for inter-zone address
+
+
+      File Specifications
+
+      If  one  or more  of FileAttached, FileRequest, or  FileUpdateReq  are
+      asserted  in an AttributeWord, the subject{72} field is interpreted as
+      a  list of file specifications  which may include wildcards and  other
+      system-dependent data.  This list is of the form
+
+      FileList = [ FileSpec { Sep FileSpec } ] Null
+
+      FileSpec = (* implementation dependent file specification.  may
+                    not contain Null or any of the characters in Sep. *)
+
+      Sep      = ( " " | "," )  { " " }
+
+
+      There are deviations from and additions to these specifications
+
+      1  - Fido does not necessarily terminate the message text with a Null,
+           but  uses  an empty line (0DH 0AH 0DH 0AH).  Some  Fido utilities
+           use an EOF (1AH).
+
+      2 - SEAdog zeros the message cost field when building a message.
+
+      4 - SEAdog uses a different format for dates, e.g.
+
+      DateTime   = (* a character string 20 characters long *)
+                   (* SEAdog format Mon  1 Jan 86 02:34 *)
+                   DayOfWk " " DayOfMo " " Month " " Year " " HH ":" MM Null
+
+      DayOfWk    = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
+      DayOfMo    = " 1" | " 2" | " 3" | ... | "31"  (* blank fill *)
+
+
+
+   2. Application Layer Protocol : Schedules and Events
+
+      At  the application level, FidoNet imposes few protocol  requirements.
+      An   implementation   must   automatically   originate   and   receive
+      node-to-node  FidoNet  connections.   Some implementations do this  in
+      'windows'  or  time  slots.   Routing  of  messages  will  usually  be
+      different and customizable for each scheduled window.
+
+      The ability to send to and receive from any FidoNet listed node during
+      the Zone Mail Hour (eg. 9:00-10:00 UCT in Z1) is considered mandatory.
+
+      Current  implementations assemble all data for outbound connections at
+      the  start of a window, and  disassemble inbound data at the end of  a
+      window.   Due to performance considerations on small machines, this is
+      considered  a valid optimization.   Observe that it somewhat  inhibits
+      dynamic routing.
+
+
+ C. Presentation Layer : the User from the System's View
+
+   1. Presentation Layer Data Definition : the Packed Message
+
+      To  conserve space and eliminate fields which would be meaningless  if
+      sent  (e.g. timesRead), messages are packed for transmission.  As this
+      is  a data structure which is actually transferred, its definition  is
+      critical  to FidoNet.  A packed  message has a number of fixed  length
+      fields followed by four null terminated strings.
+
+      While  most of the string fields in a stored message are fixed length,
+      to  conserve space strings are variable length when in a packet.   All
+      variable  length strings are all Null terminated, including especially
+      the message text.
+
+
+                                Packed Message
+
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |    0     |     2      |    0      |    0      |
+              +-----------------------+-----------------------+
+        2   2 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+        4   4 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+        6   6 | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+        8   8 | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+       10   A | Attribute (low order) | Attribute (high order)|
+              +-----------------------+-----------------------+
+       12   C |   cost (low order)    |   cost (high order)   |
+              +-----------------------+-----------------------+
+       14   E |                                               |
+              ~                    DateTime                   ~
+              |                    20 bytes                   |
+              +-----------------------+-----------------------+
+       34  22 |                  toUserName                   |
+              ~                  max 36 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                 fromUserName                  |
+              ~                  max 36 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                    subject                    |
+              ~                  max 72 bytes                 ~
+              |                null terminated                |
+              +-----------------------+-----------------------+
+              |                      text                     |
+              ~                    unbounded                  ~
+              |                 null terminated               |
+              `-----------------------------------------------'
+
+      Due  to routing, the origin and  destination net and node of a  packet
+      are  often quite different from  those of the messages within it,  nor
+      need  the origin and destination nets and nodes of the messages within
+      a packet be homogenous.
+
+      PakdMessage  = 02H 00H           (* message type, old type-1 obsolete *)
+                     origNode          (* of message *)
+                     destNode          (* of message *)
+                     origNet           (* of message *)
+                     destNet           (* of message *)
+                     AttributeWord
+                     cost              (* in lowest unit of originator's
+                                          currency *)
+                     DateTime          (* message body was last edited *)
+                     toUserName{36}    (* Null terminated *)
+                     fromUserName{36}  (* Null terminated *)
+                     subject{72}       (* Null terminated *)
+                     text{unbounded}   (* Null terminated *)
+
+
+
+
+
+
+
+ 2. Presentation Layer Protocol : a Mail Window
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W0  | WindTop  | 1 end of window reached | reset modem to not answr| exit|
+   |     |          | 2 time remains in window| ensure modem can answer | W1  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W1  | WindIdle | 1 incoming call         |                         | W2  |
+   |     |          | 2 receive-only mode     |                         | W0  |
+   |     |          | 3 send-only mode        |                         | W3  |
+   |     |          | 4 60-180 secs & no call |                         | W3  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W2* | WindRecv |                         | (receive call R0)       | W3  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W3  | WindCall | 1 select outgoing call  | increment try count     | W4  |
+   |     |          | 2 no outgoing calls     |                         | W0  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W4* | WindSend |                         | (make call S0)          | W5  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | W5  | WindMark | 1 call successful       | remove node fr call list| W0  |
+   |     |          | 2 no connect            | remove if try cnt > lim | W0  |
+   |     |          | 3 call failed           | incr conn cnt, remove   | W0  |
+   |     |          |                         |   if con cnt > lim      |     |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    The  length of the inter-call delay time at W1.4 is not critical.  It is
+    important that this not be a constant, so two systems calling each other
+    do  not incur infinite busy signals.  Sophisticated implementations  may
+    vary  the  inter-call delay  depending  on number of calls to  be  made,
+    window width, user specification, etc.
+
+
+ D. Session Layer Protocol : Connecting to Another FidoNet Machine
+
+    A session is a connection between two FidoNet machines.  It is currently
+    assumed  to be over the  DDD telephone network via modems.  The  calling
+    machine starts out as the sender and the called machine as the receiver.
+    The  pickup  feature is described  by the sender and  receiver  changing
+    roles  midway through the session, after the sender has transferred  the
+    message  packet and any attached files.  Due to the lack of security  in
+    the  pickup protocol (danger of pickup by a fake node), a change in  the
+    protocol may be expected in the near future.
+
+    Once  a connection has been established, each system should ensure  that
+    the  physical connection remains  throughout the session.  For  physical
+    layers  implemented  through modems,  this means monitoring the  carrier
+    detect signal, and terminating the session if it is lost.
+
+    Error  detection at the physical layer should be monitored for both sent
+    and  received  characters.  Parity,  framing, and other physical  errors
+    should be detected.
+
+    Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S0  | SendInit |                         | dial modem              | S1  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S1  | WaitCxD  | 1 carrier detected      | delay 1-5 seconds       | S2  |
+   |     |          | 2 busy, etc.            | report no connection    | exit|
+   |     |          | 3 voice                 | report no carrier       | exit|
+   |     |          | 4 carrier not detected  | report no connection    | exit|
+   |     |          |   within 60 seconds     |                         |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S2  | WhackCRs | 1 over 30 seconds       | report no response  | exit|
+   |     |          | 2 ?? s received     | delay 1 sec             | S3  |
+   |     |          | 3 s not received    | send    | S2  |
+   |     |          |                         |   delay ??? secs        |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S3  | WaitClear| 1 no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+   |     |          | 2 over 60 seconds       | hang up, report garbage | exit|
+   |     |          |   and line not clear    |                         |     |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S4* | TSyncChk | 1 'C' or NAK (peeked at)| (XMODEM send packet XS1)| S5  |
+   |     |          | 2 over 2 seconds        | eat noise, resend TSYNCH| S4  |
+   |     |          | 3 over 30 seconds       | hang up report not Fido | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S5  | CheckMail| 1 XMODEM successful     | (Fido registers success)| S6  |
+   |     |          | 2 XMODEM fail or timeout| hang up, report mail bad| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S6* | SendFiles|                         | (BATCH send files BS0)  | S7  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S7  | CheckFile| 1 BATCH send successful |                         | S8  |
+   |     |          | 2 BATCH send failed     | hang up, rept files fail| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | S8  | TryPickup| 1 wish to pickup        | note send ok            | R2* |
+   |     |          | 2 no desire to pickup   | delay 5 secs            | exit|
+   |     |          |                         |   hang up, rept send ok |     |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    Although  the  above  shows  the  sender  emitting only one  TSYNCH,  it is
+    recommended  that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+
+    In state S4, the phrase "peeked at" means that the character is not removed
+    from the buffer.  Therefore when XS1 is started the proper character for
+    beginning the Xmodem transfer will be detected.
+
+   Receiver
+
+    The  receiving FSM is given  an external timer, the expiration of  which
+    will cause termination with a result of 'no calls' (R0.2).
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R0  | WaitCxD  | 1 carrier detected      |                         | R1  |
+   |     |          | 2 external timer expires| report no calls         | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R1  | WaitBaud | 1 baud rate detected    | send signon with s  | R2  |
+   |     |          | 2 no detect in ?? secs  | hang up, report no baud | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R2  | WaitTsync| 1 TSYNCH received       | ignore input not TSYNCH | R3  |
+   |     |          | 2 60 seconds timeout    | hang up, report not Fido| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R3* | RecMail  |                         | (XMODEM rec packet XR0) | R4  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R4  | XRecEnd  | 1 XMODEM successful     | delay 1 second          | R5  |
+   |     |          |                         |   flush input           |     |
+   |     |          | 2 XMODEM failed         | hang up, rept mail fail | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R5* | RecFiles |                         | (BATCH rec files BR0)   | R6  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R6  | ChkFiles | 1 BATCH recv successful | delay 2 secs            | R7  |
+   |     |          | 2 BATCH recv failed     | hang up, report bad file| exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | R7  | AllowPkup| 1 have pickup for sender| receiver becomes sender | S3* |
+   |     |          | 2 nothing to pickup     | hang up, rept recv ok   | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+ E. Transport Layer : ?????
+
+   1. Data Definitions
+
+   2. Transport Layer Protocol : Routing
+
+      FidoNet   does  not  necessarily  send  a  message  directly  to   its
+      destination.   To reduce the number of network connections, mail to  a
+      subset  of  the  nodelist  may  be  routed  to one  node  for  further
+      distribution  within  that  subset.   In addition, custom  routing  is
+      possible.  Routing of a message is determined in one of three ways.
+
+      o If there are files attached, then a message must be sent directly to
+        its destination.
+
+      o Messages without attached files should be routed through the inbound
+        host  of the destination  node's  subnet  as specified  by a FidoNet
+        format nodelist.
+
+      o To prevent overloading of inbound hosts, a system should provide for
+        host routing to be disabled for a target node, or nodes.
+
+
+ F. Network Layer : the Network's View of the System, Routing and Packets
+
+
+   1. Network Layer Data Definition : the Packet Header
+
+      The  packet contains messages in packed format to be transferred  over
+      the  net during a connection.  As this data structure is  transferred,
+      its definition is critical to FidoNet.
+
+      A  packet may contain zero or more packed messages.  A packet  without
+      messages is often generated as a poll packet.
+
+      Every  packet begins with a  packet header.  The fields of the  packet
+      header are of fixed length.
+
+
+                                Packet Header
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 | origNode (low order)  | origNode (high order) |
+              +-----------------------+-----------------------+
+        2   2 | destNode (low order)  | destNode (high order) |
+              +-----------------------+-----------------------+
+        4   4 |   year (low order)    |   year (high order)   |
+              +-----------------------+-----------------------+
+        6   6 |  month (low order)    |  month (high order)   |
+              +-----------------------+-----------------------+
+        8   8 |   day (low order)     |   day (high order)    |
+              +-----------------------+-----------------------+
+       10   A |   hour (low order)    |   hour (high order)   |
+              +-----------------------+-----------------------+
+       12   C |  minute (low order)   |  minute (high order)  |
+              +-----------------------+-----------------------+
+       14   E |  second (low order)   |  second (high order)  |
+              +-----------------------+-----------------------+
+       16  10 |   baud (low order)    |   baud (high order)   |
+              +-----------------------+-----------------------+
+       18  12 |    0     |     2      |    0      |    0      |
+              +-----------------------+-----------------------+
+       20  14 | origNet (low order)   | origNet (high order)  |
+              +-----------------------+-----------------------+
+       22  16 | destNet (low order)   | destNet (high order)  |
+              +-----------------------+-----------------------+
+       24  18 |       prodCode        |       serialNo        |
+              +-----------------------+-----------------------+
+       26  1A |                                               |
+              |             password   (some impls)           |
+              |                  eight bytes                  |
+              |                  null padded                  |
+              |                                               |
+              +-----------------------+-----------------------+
+       34  22 | origZone (low) (opt)  | origZone (high) (opt) |
+              +-----------------------+-----------------------+
+       36  24 | destZone (low) (opt)  | destZone (high) (opt) |
+              +-----------------------+-----------------------+
+       38  26 |                     fill                      |
+              ~                   20 bytes                    ~
+              |                                               |
+              +-----------------------+-----------------------+
+       58  3A |                 zero or more                  |
+              ~                    packed                     ~
+              |                   messages                    |
+              +-----------------------+-----------------------+
+              |    0     |     0      |    0     |     0      |
+              `-----------------------+-----------------------'
+
+
+      Packet       = PacketHeader  { PakdMessage }  00H 00H
+
+      PacketHeader = origNode   (* of packet, not of messages in packet *)
+                     destNode   (* of packet, not of messages in packet *)
+                     year       (* of packet creation, e.g. 1986 *)
+                     month      (* of packet creation, 0-11 for Jan-Dec *)
+                     day        (* of packet creation, 1-31 *)
+                     hour       (* of packet creation, 0-23 *)
+                     minute     (* of packet creation, 0-59 *)
+                     second     (* of packet creation, 0-59 *)
+                     baud       (* max baud rate of orig and dest, 0=SEA *)
+                     PacketType (* old type-1 packets now obsolete *)
+                     origNet    (* of packet, not of messages in packet *)
+                     destNet    (* of packet, not of messages in packet *)
+                     prodCode   (* 0 for Fido, write to FTSC for others *)
+                     serialNo   (* binary serial number (otherwise null)*)
+                     password   (* session password  (otherwise null)   *)
+                     origZone   (* zone of pkt sender (otherwise null)  *)
+                     destZone   (* zone of pkt receiver (otherwise null)*)
+                     fill[20]
+
+      PacketType   = 02H 00H  (* 01H 00H was used by Fido versions before 10
+                                 which did not support local nets.  The packed
+                                 message header was also different for those
+                                 versions *)
+
+      prodCode     = (  00H      (* Fido *)
+                     |  ...
+                     |  ??H      (* Please apply for new codes *)
+                     )
+
+
+      The  remainder of the packet consists of packed messages.  Each packed
+      message  begins  with  a  message type word 0200H.   A  pseudo-message
+      beginning with the word 0000H signifies the end of the packet.
+
+
+   2. Network Layer Data Description : a File with Attributes
+
+      The  BATCH  protocol uses  the MODEM7 filename and TeLink/XMODEM  file
+      transfer protocols to transfer the file with attributes.
+
+      When  a  file is transferred via  FidoNet, an attempt is made to  also
+      pass  the operating system's attributes  for the file such as  length,
+      modification  date, etc.  FidoNet does this via a special prefix block
+      to  the XMODEM file transfer using a protocol known as TeLink.  As the
+      TeLink  protocol relies on a modification to the XMODEM file  transfer
+      protocol, it is documented at the data link layer level.
+
+      The  MODEM7 file name is redundant if there is also a TeLink block, in
+      which case the name may be taken from either or both.
+
+                              FileName as Sent
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                   fileName                    |
+              ~                   8  bytes                    ~
+              |           left adjusted blank filled          |
+              +-----------------------+-----------------------+
+        8   8 |                    fileExt                    |
+              ~                    3  bytes                   ~
+              |           left adjusted blank filled          |
+              `-----------------------------------------------'
+
+
+ 3. Network Layer Protocol : BATCH File Finite State Machines
+
+
+    BATCH File Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS0*| MoreFiles| 1 more files to send    | (MODEM7 FName send MS0) | BS1 |
+   |     |          | 2 no more files to send |                         | BS3 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS1 | CheckFNm | 1 MODEM7 Filename ok    | (TeLink send file XS0)  | BS2 |
+   |     |          | 2 MODEM7 Filename bad   | report name send bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS2 | CheckFile| 1 TeLink send ok        |                         | BS0 |
+   |     |          | 2 TeLink send bad       | report file send bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BS3 | EndSend  | 1 rec NAK for next file | send EOT, report send ok| exit|
+   |     |          | 2 10 seconds no NAK     | send EOT, report no NAK | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    When  no files remain, the sender responds to the receiver's NAK with an
+    EOT.  The EOT is not ACK/NAKed by the receiver.
+
+    Filenames  must be upper case ASCII.  The data link layer uses "u" as  a
+    control character.
+
+
+    BATCH File Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR0*| RecvName |                         | (MODEM7 FName recv MR0) | BR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR1 | CheckFNm | 1 MODEM7 no more files  | report files recd ok    | exit|
+   |     |          | 2 MODEM7 Filename ok    | (TeLink recv file XR0)  | BR2 |
+   |     |          | 2 MODEM7 Filename bad   | report name recv bad    | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | BR2 | CheckFile| 1 TeLink recv ok        |                         | BR0 |
+   |     |          | 2 TeLink recv bad       | report file recv bad    | exit|
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+ G. Data Link Layer : Error-Free Data Transfer
+
+   1. Data Link Layer Data Definition : XMODEM/TeLink Blocks
+
+      XMODEM  transfers  are  in  blocks  of 128  uninterpreted  data  bytes
+      preceded  by  a three  byte header  and followed by either a one  byte
+      checksum  or a two byte crc remainder.  XMODEM makes no provision  for
+      data  streams  which  are  not  an  integral number  of  blocks  long.
+      Therefore,  the sender pads streams whose length is not a multiple  of
+      128 bytes with the end-of-file character (^Z for MS-DOS), and use some
+      other  means  to convey  the  true data length to the  receiver  (e.g.
+      TeLink file info block).
+
+      Data blocks contain sequence numbers so the receiver can ensure it has
+      the  correct block.  Block  numbers are sequential unsigned eight  bit
+      integers  beginning with 01H and wrapping to 00H, except that a TeLink
+      block is given sequence number 00H.
+
+      For  files which are attached to the mail packet, not the mail  packet
+      itself,  if the sending system is aware of the file attributes as they
+      are  known to the operating system, then the first block of the XMODEM
+      transfer  may be a special TeLink block to transfer that  information.
+      This  block  differs  in that  the  first byte is a SYN  character  as
+      opposed  to an SOH, and it is always sent checksum as opposed to CRC.
+      Should the receiver be unwilling to handle such information, after two
+      NAKs (or "C"s), the sender skips this special block and goes on to the
+      data itself.
+
+
+
+                        XMODEM Data Block (CRC mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |             CRC high order byte               |
+              +-----------------------------------------------+
+      132  84 |             CRC  low order byte               |
+              `-----------------------------------------------'
+
+
+
+                      XMODEM Data Block (Checksum mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+                       TeLink File Descriptor Block
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN  -  File Info Header -  16H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+ data offset
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |     File Length, least significant byte       |  0    0
+              +-----------------------------------------------+
+        4   4 | File Length, second to least significant byte |  1    1
+              +-----------------------------------------------+
+        5   5 |  File Length, second to most significant byte |  2    2
+              +-----------------------------------------------+
+        6   6 |      File Length, most significant byte       |  3    3
+              +-----------------------------------------------+
+        7   7 |            Creation Time of File              |  4    4
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+        9   9 |            Creation Date of File              |  6    6
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  16 chars                     ~
+              |        left justified  blank filled           |
+              +-----------------------------------------------+
+       27  1B |                    00H                        | 24   18
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  16 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       44  2C |            01H (for CRC) or 00H               | 41   29
+              +-----------------------------------------------+
+       45  2D |                    fill                       | 42   2A
+              ~                  86 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      132  84 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+
+      XMODEMData   = XMODEMBlock      (* block of data with header and
+                                         trailer *)
+                     | TeLinkBlock    (* TeLink File Descriptor Block *)
+                     | ACK            (* acknowledge data received ok *)
+                     | NAK            (* negative ACK & poll 1st block *)
+                     | EOT            (* end of xfer, after last block *)
+                     | "C"            (* 43H *)
+
+      XMODEMBlock  = SOH              (* Start of Header, XMODEM Block *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's compl of BlockNumber *)
+                     data[128]        (* uninterpreted user data block *)
+                     (CRC | Checksum) (* error detect/correction code *)
+
+      TeLinkBlock  = SYN              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+                     CreationTime[2]  (* time file last modified or zero *)
+                     CreationDate[2]  (* date file last modified or zero *)
+                     fileName(16)     (* name of file, not vol or dir *)
+                     00H              (* header version number *)
+                     sendingProg(16)  (* name of program on send side *)
+                     crcMode[1]       (* 01H for CRC 00H for Checksum *)
+                     fill[87]         (* zeroed *)
+                     Checksum         (* error detect/correction code *)
+
+      ACK          = 06H              (* acknowledge data received ok *)
+      NAK          = 15H              (* negative ACK & poll 1st block *)
+      SOH          = 01H              (* start of header, begins block *)
+      SYN          = 16H              (* start of TeLink file info blk *)
+      EOT          = 04H              (* end of xfer, after last block *)
+
+      CRC          = crc[2]           (* CCITT Cyclic Redundancy Check *)
+
+      Checksum     = checksum[1]      (* low 8 bits of sum of data bytes
+                                         using unsigned 8 bit arithmetic *)
+
+      CreationDate = year[.7]         (* 7 bits, years since 1980, 0-127  *)
+                     month[.4]        (* 4 bits, month of year, 1-12 *)
+                     day[.5]          (* 5 bits, day of month, 1-31 *)
+
+      CreationTime = hour[.5]         (* 5 bits, hour of day, 0-23 *)
+                     minute[.6]       (* 6 bits, minute of hour, 0-60 *)
+                     biSeconds[.2]    (* 6 bits, seconds/2, 0-29 *)
+
+
+      Note  that the crcMode is always set to 01H in current implementations
+      as  all TeLink/XMODEM implementations use the CRC method.   Therefore,
+      it is always set to 01H by the sender, and is ignored by the receiver.
+
+
+ 2. Data Link Layer Protocol : XMODEM/TeLink Finite State Machines
+
+    The  protocol is receiver driven, the receiver polling the sender  for
+    each  block.   If the receiver polls  for the first block using a  "C"
+    (43H)  as  the poll character,  it would prefer to have the  CRC-CCITT
+    polynomial  remainder error detection code at the end of each block as
+    opposed  to a one byte unsigned checksum.  The sender will respond  to
+    the  "C"  poll iff it can  comply.  If the sender chooses checksum  as
+    opposed  to  CRC, it waits for  the receiver to poll with  NAK  (15H).
+    Should  the  checksum method be  preferable to the receiver, it  polls
+    with NAK rather than "C".
+
+    The sender returns an EOT instead of a data block when no data remain.
+
+    Neither  the  sender nor the  receiver should send the block or  ACK/NAK
+    response  while there is data being received.  They should wait for  the
+    line to settle, and possibly time out.
+
+    It  is  suggested that one's  input buffer be cleared immediately  after
+    sending  block or ACK/NAK response, before waiting for the response from
+    the  other  end.  This  clears  any line garbage which  occurred  during
+    transmit.
+
+
+    XMODEM/TeLink Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS0 | WaitTeLnk| 1 over 40-60 seconds    | report sender timeout   | exit|
+   |     |          | 2 over 2 tries          | note TeLink block failed| XS1 |
+   |     |          | 3 NAK or "C" received   | send TeLink, incr tries | XS0 |
+   |     |          | 4 ACK received          | TeLink ok, set crc/cksm | XS2 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS1 | WaitStart| 1 over 40-60 seconds    | report sender timeout   | exit|
+   |     |          | 2 over 20 tries         | report send failed      | exit|
+   |     |          | 3 NAK received          | set checksum mode       | XS2 |
+   |     |          | 4 "C" recd, I can crc   | set crc mode            | XS2 |
+   |     |          | 5 "C" recd, I can't crc |                         | XS1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS2 | SendBlock| 1 more data available   | send next data block    | XS3 |
+   |     |          |                         |   as checksum or crc    |     |
+   |     |          | 2 last block has gone   | send EOT                | XS4 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS3 | WaitACK  | 1 10 retries or 1 minute| report send failed      | exit|
+   |     |          | 2 ACK received          |                         | XS2 |
+   |     |          | 3 NAK (or C if 1st blk) | resend last block       | XS3 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XS4 | WaitEnd  | 1 10 retries or 1 minute| report send failed      | exit|
+   |     |          | 2 ACK received          | report send successful  | exit|
+   |     |          | 3 NAK received          | resend EOT              | XS4 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    XMODEM/TeLink Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         | St  |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR0 | RecStart | 1 prefer crc mode       | Send "C"                | XR1 |
+   |     |          | 2 want checksum mode    | send NAK                | XR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR1 | WaitFirst| 1 10 retries or 1 minute| report receive failure  | exit|
+   |     |          | 2 > 3 retries or 30 secs| set want checksum mode  | XR0 |
+   |     |          | 3 EOT received          | delay < sec, purge input| exit|
+   |     |          |                         | send ACK, report no file|     |
+   |     |          | 4 TeLink block recd     | send ACK, set crc/cksm  | XR2 |
+   |     |          | 5 data block recd       | send ACK, set crc/cksm  | XR2 |
+   |     |          | 6 bad block or 2-10 secs| incr retry count        | XR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | XR2 | WaitBlock| 1 10 retries or 1 minute| report receive failure  | exit|
+   |     |          | 2 EOT received          | send ACK, report recd ok| exit|
+   |     |          |                         | send ACK, report recd ok|     |
+   |     |          | 3 data block received   | send ACK                | XR2 |
+   |     |          | 4 bad block or 2-10 secs| send NAK, incr retry cnt| XR2 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    A  number of checks should be made to ensure a valid data block has been
+    received.
+
+    o  The  physical  layer  should  have encountered no errors,  e.g.  parity,
+       framing, etc.
+
+    o  The length of the block should not be less than expected.
+
+    o  If  the blocks sequence  number does not match the  complement,  then
+       respond with a NAK and attempt to read the block again.
+
+    o  If the block's sequence number is one previous (remember wrap around)
+       to that of the expected block, respond with an ACK and read again.
+
+    o  If the sequence number fits neither of the above criteria, and is yet
+       not the expected sequence number, abort the receive.
+
+    o  The checksum or CRC should be correct.
+
+
+
+ 3. Data Link Layer Protocol : MODEM7 Filename Finite State Machines
+
+
+    MODEM7 Filename Sender
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         |  St |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS0 | WaitNak  | 1 20 retries or 1 minute| filename send failed    | exit|
+   |     |          | 2 NAK received          | send ACK & 1st ch of fn | MS1 |
+   |     | (note 1) | 3 C received            | return fn skipped       | exit|
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS1 | WaitChAck| 1 ACK rcd, fname done   | send SUB = 1AH          | MS2 |
+   |     |          | 2 ACK rcd, fname ~done  | send next ch of fname   | MS1 |
+   |     |          | 3 other char or 1 sec   | send "u", incr retry cnt| MS0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MS2 | WaitCksm | 1 cksum recd and ok     | send ACK, report fn ok  | exit|
+   |     |          | 2 cksum recd but bad    | send "u", incr retry cnt| MS0 |
+   |     |          | 3 no cksum in 1 sec     | send "u", incr retry cnt| MS0 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+
+    MODEM7 Filename Receiver
+
+   .-----+----------+-------------------------+-------------------------+-----.
+   |State| State    | Predicate(s)            | Action(s)               | Next|
+   |  #  | Name     |                         |                         |  St |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR0 | SendNak  | 1 20 tries or 1 minute  | report filename failure | exit|
+   |     |          | 2                       | send NAK, incr try cnt  | MR1 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR1 | WaitAck  | 1 rcd ACK               |                         | MR2 |
+   |     |          | 2 rcd EOT               | report no files remain  | exit|
+   |     |          | 3 5 secs & no ACK/EOT   |                         | MR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR2 | WaitChar | 1 recd EOT (can happen?)| report no files remain  | exit|
+   |     |          | 2 recd SUB              | send checksum byte      | MR3 |
+   |     |          | 3 recd "u"              |                         | MR0 |
+   |     |          | 4 recd char of name     | send ACK                | MR2 |
+   |     |          | 5 no char in 1 second   |                         | MR0 |
+   |-----+----------+-------------------------+-------------------------+-----|
+   | MR3 | WaitOkCk | 1 recd ACK within 1 sec | report recd filename ok | exit|
+   |     |          | 2 recd "u" or other char|                         | MR0 |
+   `-----+----------+-------------------------+-------------------------+-----'
+
+    SUB  is the ASCII character ^Z or 1AH.  The checksum is the unsigned low
+    order eight bits of the sum of the characters in the transferred filename
+    including the SUB.
+
+    Although  one second timeouts are used successfully by Fido and  SEAdog,
+    some fear that this is too small a timeout for some satellite and packet
+    network links.
+
+    Note 1 - MS0.3 is a common addition to accommodate a common noncompliance.
+             Support of MS0.3 is optional for a compliant mailer.  This hack
+             also requires modification of a number of state tables, see
+             FSC-0011.
+
+
+ H. Physical Layer : the Actual Connection of Two FidoNet Systems
+
+    Will  one of the more hardware-oriented comm types give me some idea  of
+    what's needed here?  Can we leave it open enough to allow implementation
+    over a non-dial net?  Thanks.
+
+
+ I. Revisions since FTS-0001
+
+    89 Oct 25 (rev 13)
+      o packet header: optional serialNo, password, and orig/dest zone
+      o stored message to/from zone/point info added as option per
+        Fido-12 and Dutchie
+      o XR1 and XR2 changes per FSC-0011
+      o reference to FSC-0011 for the MODEM7-avoidance hack, MS0.3
+      o dropped enumeration of product codes
+      o S4 modification from FSC-0011
+      o Nodelist and EID reference appropriate documents
+      o various cosmetics
+    90 July 1-5 (rev 14)
+      o spelling errors caught by Ray Gardner
+      o references to the now dead IFNA elided
+      o offset at end of Packed Message was 10 as opposed to 20 bytes
+      o Packed Message and Packet Header corrections by Roland Gautschi
+      o Offsets in TeLink header caught by Rick Moore
+    90 August 30 (rev 15)
+      o corrected offsets in packet header
+    95 September 30 (rev 16)
+      o TOPT corrected
+      o contact info changed
+
+
+ J. Acknowledgements
+
+    Ben  Baker,  Thom  Henderson,  Tom  Jennings,  Ken Kaplan, and  Gee Wong
+    suggested, informed,  reviewed, and  encouraged.   Tom  and Thom gave me
+    all the basics, and even allowed me to look at actual code.  Bob Hartman 
+    was  foolish  enough  to implement  the  specification, and was generous
+    with useful feedback.  Ray  Gardner caught  my  spelling errors ,
+    and Roland Gautschi and Rick Moore found offset and length errors.
+
+    My employer, Pacific Systems Group was kind enough to donate my time to
+    research and to write this document.
+
+    Fido and FidoNet are registered trademarks of Tom Jennings.
+
+    SEAdog is a trademark of System Enhancement Associates.
+
+
+ K. Bibliography
+
+    Documentation  for the protocols  and data formats are scattered.   Some
+    are  unattributed, some even untitled.
+
+    Anonymous, changes to MODEM to implement CRC option  XMDM-CRC.TXT
+
+    Baker, Ken and Moore, Rick, Nodelist Definition, currently FTS-0005
+
+    Christensen, Ward, "MODEM Protocol Overview" of 1 January 82  XMODEM.TXT
+
+    Hartman, Bob, "Some thoughts that I had on FSC001", FSC-0011
+
+    Henderson, Thom, "SEAdog Electronic Mail System Version 3" of April 86
+
+    International  Standards Organization,  "Data Processing - Open  Systems
+    Interconnection - Basic Reference Model"  ISO/DIS 7498  April 82
+
+    Jennings,   Tom,  "FidoNet  Electronic  Mail  Protocol"  8  February  85
+    FIDOMAIL.DOC
+
+    Jennings,   Tom,  "Fido's  Internal  Structures"  of  13  September  85
+    STRUCT.TXT aka STRUCT.APX
+
+    Jennings, Tom, "Extending XMODEM/MODEM File Transfer Protocol to support
+    DOS" 20 September 83   FILEXFER.DOC
+
+    Jordan, Larry, "XMODEM File Transfer Protocol"  XMDM-LJ.TXT
+
+    Rudin,   H   and   West,  C,  "Protocol  Specification,   Testing,   and
+    Verification,  III" Proceedings of  the IFIP WG 6.1 Third  International
+    Workshop   on   Protocol  Specification,  Testing,   and   Verification,
+    Rueschlikon Switzerland 31 May - 2 June 1983.
+
+    Tanenbaum, Andrew, "Computer Networks" Prentice Hall 1981
+
+    Messages generated by Fido 11w, SEAdog 3.8, and QMail 1.01
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0004.html b/html/ftsc/fts-0004.html new file mode 100755 index 00000000..33d6f901 --- /dev/null +++ b/html/ftsc/fts-0004.html @@ -0,0 +1,414 @@ + + +Echomail Specification. + + + + +
+FTS-0004        EchoMail Specification
+
+This document is directly derived from the documentation of
+
+-------------------------------------------------------------------------------
+
+                           The Conference Mail System
+                                        
+                                       By
+                                  Bob Hartman
+                       Sysop of FidoNet(tm) node 132/101
+                                        
+                  (C) Copyright 1986,87, Spark Software, Inc.
+                                        
+                              427-3 Amherst Street
+                              CS  2032, Suite  232
+                              Nashua,  N.H.  03061
+                                        
+                              ALL RIGHTS RESERVED.
+
+-------------------------------------------------------------------------------
+
+version 3.31 of 12 December, 1987.
+
+With Bob Hartman's kind consent, copying for the purpose of technological
+research and advancement is allowed.
+
+                                        
+-------------------------------------------------------------------------------
+-------------------------------------------------------------------------------
+                                        
+
+     WHAT IS THE CONFERENCE MAIL SYSTEM?
+
+          Conference Mail  is a  technique to  permit several  nodes  on  a
+          network to  share a  message base,  similar  in  concept  to  the
+          conferences available on many of the computer services, but it is
+          most closely related to the Usenet system consisting of more than
+          8,000 systems  world wide. All systems sharing a given conference
+          see any  messages entered  into the  conference  by  any  of  the
+          participating systems.  This can  be implemented in such a way as
+          to be  totally transparent  to the users of a particular node. In
+          fact, they  may not  even be  aware of  the network being used to
+          move their  messages about from node to node! Unfortunately, this
+          has its  disadvantages also  - most  users who  are not  educated
+          about Conference  Mail do  not realize  the messages  transmitted
+          cost MANY  sysops (system  operators) money,  not just  the local
+          sysop. This  is an important consideration in Conference Mail and
+          should not be taken lightly.  In a conference with 100 systems as
+          participants the cost per message can get quite high.
+
+          The Conference  Mail System is designed to operate in conjunction
+          with a  FidoNet compatible  mail server.  The currently supported
+          mail servers  are Fido(tm),  SEAdog(tm), Opus, and Dutchie. Since
+          the mail  server is  a prerequisite  to using the Conference Mail
+          System, it  will be  assumed you  already have  your mail  server
+          operating correctly  on your   system, and you are connected into
+          FidoNet or a compatible network.
+
+
+     HISTORY OF THE CONFERENCE MAIL SYSTEM
+
+          In late  1985, Jeff  Rush, a  Fido  sysop  in  Dallas,  wanted  a
+          convenient means  of sharing  ideas with the other Dallas sysops.
+          He created  a system  of programs  he called  Echomail,  and  the
+          Dallas sysops' Conference was born.
+
+          Within a  short time  sysops in other areas began hearing of this
+          marvelous new  gadget and  Echomail took  on a  life of  its own.
+          Today, a  scant year and a half later, the FidoNet public network
+          boasts a myriad of conferences varying in size from the dozen-or-
+          so participants  in the  FidoNet  Technical  Standards  Committee
+          Conference  to   the  Sysops'  Conference  with  several  hundred
+          participants. It  is not  uncommon for a node to carry 30 or more
+          conferences and share those conferences with 10 or more nodes.
+
+
+     HOW IT WORKS
+
+          The Conference  Mail System  is functionally  compatible with the
+          original Echomail utilities.  In general, the process is:
+
+          1. A  message is  entered into  a designated  area on  a  FidoNet
+          compatible system.
+
+          2. This message is "Exported" along with some control information
+          to each system "linked" to the conference through the originating
+          system.
+
+          3. Each  of the  receiving systems  "Import" the message into the
+          proper Conference Mail area.
+
+          4. The receiving systems then "Export" these messages, along with
+          additional control  information,  to  each  of  their  conference
+          links.
+
+          5. Return to step 3.
+
+          As you  can see,  the method  is quite  simple -  in general.  Of
+          course, following  the steps  literally would mean messages would
+          never stop being Exported and transmitted to other systems.  This
+          obviously would  not be  desired or  the  network  would  quickly
+          become overburdened.  The information  contained in  the 'control
+          information' section  is used  to prevent  transmitting the  same
+          message more than once to a single system.
+
+
+     CONFERENCE MAIL MESSAGE CONTROL INFORMATION
+
+          There are  five pieces  of control  information associated with a
+          Conference  Mail  message.  Some  are  optional,  some  are  not.
+          Normally this information is never entered by the person creating
+          the  message.   The  following   control  fields   determine  how
+          Conference Mail is handled:
+
+          1. Area line
+
+               This is  the first  line of  a conference  mail message. Its
+               actual appearance is:
+
+                                     AREA:CONFERENCE
+
+               Where CONFERENCE is the name of the conference. This line is
+               added when  a conference  is  being  "Exported"  to  another
+               system. It  is based upon information found in the AREAS.BBS
+               (configuration) File  for the  designated message area. This
+               field is  REQUIRED by  the receiving  system to  "Import"  a
+               message into the correct Conference Mail area.
+
+          2. Tear Line
+
+               This line is near the end of a message and consists of three
+               dashes (---)  followed by  an  optional  program  specifier.
+               This is  used to show the first program used to add Echomail
+               compatible control information to the message. The tear line
+               generated by Conference Mail looks like:
+
+                                    --- 
+
+               This  field   is  optional   for  most  Echomail  compatible
+               processors, and  is added  by the  Conference Mail System to
+               ensure complete  compatibility. Some systems will place this
+               line in  the message  when it  is first  created, but  it is
+               normally added when the message is first "exported."
+
+          3. Origin line
+
+               This line  appears near  the bottom of a message and gives a
+               small amount  of  information  about  the  system  where  it
+               originated. It looks like:
+
+                      * Origin: The Conference Mail BBS (1:132/101)
+
+               The "  * Origin:  " part  of the  line is  a constant field.
+               This is followed by the name of the system as taken from the
+               AREAS.BBS file  or a  file named  ORIGIN located  in the DOS
+               directory of  the  designated  message  area.  The  complete
+               network address  (1:132/101 in  this case)  is added  by the
+               program inserting  the line.  This field is generated at the
+               same time  as the  tear line,  and therefore  may either  be
+               generated at  the time  of  creation  or  during  the  first
+               "export"  processing.   Although  the  Origin  line  is  not
+               required by  all Echomail  processors, it  is added  by  the
+               Conference Mail System to ensure complete compatibility.
+
+
+          4. Seen-by Lines
+
+               There can  be many  seen-by lines  at the  end of Conference
+               Mail messages,  and they  are the real "meat" of the control
+               information. They  are used  to  determine  the  systems  to
+               receive the exported messages. The format of the line is:
+
+                           SEEN-BY: 132/101 113 136/601 1014/1
+
+               The net/node  numbers correspond  to the net/node numbers of
+               the systems having already received the message. In this way
+               a message  is never  sent to a system twice. In a conference
+               with many  participants the  number of  seen-by lines can be
+               very large.   This line is added if it is not already a part
+               of the  message, or added to if it already exists, each time
+               a message  is exported  to other systems. This is a REQUIRED
+               field, and  Conference Mail  will not  function correctly if
+               this field  is not put in place by other Echomail compatible
+               programs.
+
+          5. PATH Lines
+
+               These are  the last  lines in  a Conference Mail message and
+               are a  new addition,  and therefore  is not supported by all
+               Echomail processors. It appears as follows:
+
+                                  ^aPATH: 132/101 1014/1
+
+               Where the  ^a stands  for Control-A  (ASCII character 1) and
+               the net/nodes  listed correspond  to  those  systems  having
+               processed the  message before it reached the current system.
+               This is  not the  same as  the seen-by  lines, because those
+               lines list  all systems  the message has been sent to, while
+               the path line contains all systems having actually processed
+               the message.  This is not a required field, and few echomail
+               processors currently  support it,  however it  can  be  used
+               safely with  any other  system, since  the line(s)  will  be
+               ignored. For  a discussion  on how  the  path  line  can  be
+               helpful, see the "Advanced Features" section of this manual.
+
+
+     METHODS OF SENDING CONFERENCE MAIL
+
+          To this  point the  issue of how Conference Mail is actually sent
+          has been glossed over entirely. The phrase has been, "the message
+          is exported  to another  system."   What exactly  does this mean?
+          Well, for starters lets show what is called the "basic" setup:
+
+          In this setup exported mail is placed into the FidoNet mail area.
+          Each message   exported  from a  Conference  Mail  area  has  one
+          message generated  for each  receiving system.  This mail is then
+          sent the  same as any other network mail. When Echomail was first
+          created this was the only way mail could be sent.
+
+          The "basic"  method has some disadvantages. First, since Echomail
+          has grown so large it is not uncommon to get 200 new messages per
+          day imported  into various message bases. It is also not uncommon
+          for a  system to  be exporting  messages to 4 or 5 other systems.
+          Simple arithmetic  shows 800-1000  messages per day would be sent
+          in normal  netmail! This  puts a tremendous strain on any netmail
+          system, not  to mention transmission time and the resultant phone
+          charges. When this limitation of Echomail was first noticed a lot
+          of people started scratching their heads wondering what to do. If
+          a  solution  could  not  be  found  it  appeared  Echomail  would
+          certainly overrun the capabilities of FidoNet.
+
+          Thom Henderson  (from System Enhancement Associates) came up with
+          the original  ARCmail program.  Having previously written the ARC
+          file archiving  and compression  program,  he  knew  the  savings
+          achievable by  having all  of the netmail messages placed in .ARC
+          format for  transmission. As  a byproduct, the messages no longer
+          appeared in  the netmail  area,  but  were  included  in  a  file
+          attached to  a message  (see your  FidoNet mailer manual for file
+          attaches).  In   this  way  the  tremendous  number  of  messages
+          generated, and the phone bill problems were both solved.
+
+          Unfortunately, ARCmail  required the  messages to first be placed
+          into the  netmail area  before it  could be  run. In  effect,  it
+          caused the  messages to  be scanned once when they were exported,
+          once during  the ARCmail  phase, once when ARCmail was run at the
+          other end  to get  the messages out of .ARC format, and once when
+          those messages  were later  imported into  a message  base on the
+          receiving system.  The Conference Mail System solves this problem
+          by eliminating  the ARCmail  program. Conference  Mail builds the
+          ARCmail files during Export, and unpacks them during Import. This
+          way  messages   are  exported  directly  to  ARCmail  style  file
+          attaches, and imported directly from ARCmail style file attaches.
+          The scanning  phases between importing and exporting messages are
+          totally removed and processing time is proportionally reduced.
+
+          This is  now the  most common  method for sending Conference Mail
+          between systems.  The overhead  involved in  doing it  during the
+          importing and exporting phases is much less than what is involved
+          if ARCmailing  is not  utilized. This was a primary consideration
+          in the  design and  implementation of the Conference Mail System,
+          and as  a result  the entire system is optimized for this type of
+          use.  Please  refer  to  the  Import  and  Export  functions  for
+          specifics on how to use the ARCmailing feature.
+
+
+     CONFERENCE TOPOLOGY
+
+          The  way   in  which  systems  link  together  for  a  particular
+          conference is  called the "conference topology."  It is important
+          to know  this structure  for two  reasons: 1)  It is important to
+          have a  topology which  is  efficient  in  the  transfer  of  the
+          Conference Mail  messages, and  2) It  is  important  to  have  a
+          topology which  will not  cause systems  to see the same messages
+          more than once.
+
+          Efficiency can  be measured  in a  number  of  ways;  least  time
+          involved for all systems to receive a message, least cost for all
+          systems to receive a message, and fewest phone calls required for
+          all systems  to receive  a message  are all  valid indicators  of
+          efficiency. Users  of Echomail compatible systems have determined
+          (through trial  and error)  the best  measure of  efficiency is a
+          combination  of  all  three  of  the  measurements  given  above.
+          Balancing the equation is not trivial, but some guidelines can be
+          given:
+
+               1. Never have two systems attempting to send Conference mail
+               to each other at the same time. This results in "collisions"
+               that will  cause both  systems to  fail. To  avoid this, one
+               system should  be responsible  for polling  while the  other
+               system is holding mail. This arrangement can alternate based
+               upon various  criteria, but  both systems  should  never  be
+               attempting to call each other at the same time.
+
+               2. Have  nodes form  "stars" for  distribution of Conference
+               Mail. This arrangement has several nodes all receiving their
+               Conference Mail from the same system. In general the systems
+               on the  "outside"  of  the  star  poll  the  system  on  the
+               "inside". The  system on  the "inside"  in turn  polls other
+               systems to  receive the Conference Mail that is being passed
+               on to the "outside" systems.
+
+               3. Utilize  fully connected  polygons with  a few  vertices.
+               Nodes can  be connected in a triangle (A sends to B and C, B
+               sends to  A and  C, C sends to A and B) or a fully connected
+               square (all  corners of  the square send to all of the other
+               corners). This  method is useful for getting Conference Mail
+               messages to each node as quickly as possible.
+
+
+          All of  these efficiency  guidelines have to be tempered with the
+          guidelines dealing  with keeping  duplicate messages  from  being
+          exported. Duplicates  will occur  in any  topology that  forms  a
+          closed polygon  that is not fully connected. Take for example the
+          following configuration:
+
+                                      A ----- B
+                                      |       |
+                                      |       |
+                                      C ----- D
+
+          This square  is a  closed polygon that is not fully connected. It
+          is capable of generating duplicates as follows:
+
+               1. A message is entered on node A.
+
+               2. Node  A exports  the message to node B and node C placing
+               the seen-by for A, B, and C in the message as it does so.
+
+               3. Node  B sees that node D is not listed in the seen-by and
+               exports the message to node D.
+
+               4. Node  C sees that node D is not listed in the seen-by and
+               exports the message to node D.
+
+          At this  point node  D has  received the  same message  twice - a
+          duplicate was  generated. Normally  a "dup-ring"  will not  be as
+          simple as  a square.  Generally it  will be caused by a system on
+          one end  of a  long chain  accidentally connecting to a system on
+          the other end of the chain. This causes the two ends of the chain
+          to become connected, forming a polygon.
+
+          In FidoNet  this problem  is reduced somewhat by having "Regional
+          Echomail Coordinators"  (RECS) that try to keep track of Echomail
+          connections within  their regions  of the  world. A  further rule
+          which is  followed is  that only  the RECS  are allowed  to  make
+          inter-regional connections for the larger conferences. In return,
+          the RECS  have established  a very  efficient topology which gets
+          messages from  coast to  coast, and onto over 200 systems in less
+          than 24  hours. If  no one were willing to follow the rules, then
+          this system  would collapse,  but due to the excellent efficiency
+          it has remained intact for over a year.
+
+
+     Why a PATH line?
+
+          As was  previously mentioned,  the PATH  line is a new concept in
+          Echomail. It  stores the  net/node numbers  of each system having
+          actually processed  a message.  This  information  is  useful  in
+          correcting the  biggest problem  encountered by  nodes running an
+          Echomail compatible  system - the problem of finding the cause of
+          duplicate messages.  How does  the  PATH  line  help  solve  this
+          problem? Take the following path line as an example:
+
+               ^aPATH: 107/6 107/312 132/101
+
+          This  shows  the  message  was  processed  by  system  107/6  and
+          transferred to  system 107/312.  It further  shows system 107/312
+          transferred the  message to  132/101, and  132/101  processed  it
+          again. Now take the following path line as the example:
+
+               ^aPATH: 107/6 107/312 107/528 107/312 132/101
+
+          This shows  the message  having been processed by node 107/312 on
+          more than one occasion. Based upon the earlier description of the
+          'information control'  fields in  Echomail messages, this clearly
+          is an  error in  processing (see  the section  entitled  "How  it
+          Works"). This  further shows   node  107/528 as  the  node  which
+          apparently processed  the message  incorrectly. In  this case the
+          path line  can be  used to quickly locate the source of duplicate
+          messages.
+
+          In  a   conference  with  many  participants  it  becomes  almost
+          impossible to  determine the  exact topology used. In these cases
+          the use of the path line can help a coordinator of the conference
+          track any  possible breakdowns in the overall topology, while not
+          substantially increasing  the amount  of information transmitted.
+          Having this  small amount of information added to the end of each
+          message pays  for itself very quickly when it can be used to help
+          detect a  topology  problem  causing  duplicate  messages  to  be
+          transmitted to each system.
+
+-30-
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0005.html b/html/ftsc/fts-0005.html new file mode 100755 index 00000000..ba57602a --- /dev/null +++ b/html/ftsc/fts-0005.html @@ -0,0 +1,617 @@ + + +The Distribution Nodelist. + + + + +
+ | Document: FTS-0005
+ | Version:  003
+ | Date:     February 7, 1996
+ | Maintainer: David Nugent, 3:632/348@fidonet
+
+
+                       The Distribution Nodelist
+
+                        Originally by Ben Baker
+       Amended by Rick Moore, 1:115/333@FidoNet, February 5, 1989
+     Amended by David Nugent, 3:632/348@FidoNet, February 27, 1996
+
+
+|   Copyright 1986-1996 by the FidoNet Technical Standards Committee.
+    All rights reserved. Duplication and/or distribution permitted
+    for non-commercial purposes only.
+
+    This document supersedes and replaces the document known under
+|   the names of FSC002, FSC-0002, and FTS-0002. Significant changes,
+|   which excludes mere formatting changes, to the previous version
+|   of this document have been "redlined" (marked with a vertical
+|   bar in the leftmost column).
+
+    This document defines the format and content of the nodelist for
+    the Public FidoNet Network (PFN) as published on Friday of each
+|   week. This format is historically known as the "St. Louis nodelist
+|   format".
+
+    The PFN is an international network of independently owned
+    electronic mail systems, most with interlocking electronic
+    bulletin board systems. The distribution nodelist, or simply
+    "nodelist", is the glue which holds the network together. It is
+    the PFN's "phone book" and it defines the top-level network
+|   structure and is the means by which FidoNet retains its integrity
+|   as a point-to-point mail network.
+
+
+| THE NODELIST
+
+    The nodelist is published as an ASCII text file named
+    NODELIST.nnn, where nnn is a three digit number representing the
+|   day-of-year of the Friday publication date, with zeros filling
+|   positions to the left if necessary. This file is packed into a
+|   archive file named NODELIST.?nn, where 'nn' are the last two
+|   digits of day-of-year, and the character at the position of the
+|   '?' indicating the type of compression used. Conventions as to
+|   which compression method is used for the distributed nodelist is
+|   a matter of local policy and is usually determined by each zone's
+|   Zone Coordinator.
+
+    As stated above, NODELIST.nnn is an ASCII text file. It contains
+    two kinds of lines; comment lines and data lines. Each line is
+    terminated with an ASCII carriage return and line feed character
+    sequence, and contains no trailing white-space (spaces, tabs,
+|   etc.). The file is terminated with a DOS end-of-file character
+|   (character value 26 decimal, or "control-Z").
+
+    Comment lines contain a semicolon (;) in the first character
+    position followed by zero or more alphabetic characters called
+    "interest flags". A program which processes the nodelist may use
+    comment interest flags to determine the disposition of a comment
+    line. The remainder of a comment line (with one exception,
+|   treated below) is free-form ASCII text. There are five types of
+|   comments flags:
+
+|       ;S This is of particular interest to Sysops
+|       ;U This is of particular interest to BBS users
+|       ;F This should appear in any formatted "Fido List"
+|       ;A This is of general interest (shorthand for ;SUF)
+|       ;E This is an error message inserted by the nodelist generator
+|       ; This comment may be ignored by a nodelist processor
+
+    The first line of a nodelist is a special comment line containing
+    identification data for the particular edition of the nodelist.
+    The following is an example of the first line of a nodelist:
+
+    ;A FidoNet Nodelist for Friday, July 3, 1987 -- Day number 184 : 15943
+
+    This line contains the general interest flag, the day, date, and
+|   three-digit (zero-filled) day-of-year number of publication, and
+    ends with a 5 digit decimal number with leading zeros, if
+    necessary. This number is the decimal representation of a check
+    value derived as follows:
+
+        Beginning with the first character of the second line, a
+        16 bit cyclic redundancy check (CRC) is calculated for the
+        entire file, including carriage return and line feed
+        characters, but not including the terminating EOF
+        character. The check polynomial used is the same one used
+        for many file transfer protocols:
+
+                    2**16 + 2**12 + 2**5 + 2**0
+
+    The CRC may be used to verify that the file has not been edited.
+    The importance of this will become evident in the discussion of
+    NODEDIFF, below. CRC calculation techniques are well documented
+|   in various technical references, and will not be treated further
+    here.
+
+    The content of the remaining comments in the nodelist are
+    intended to be informative. Beyond the use of interest flags for
+    distribution, a processing program need not have any interest in
+    them.
+
+    A nodelist data line contains eight variable length "fields"
+    separated by commas (,). No space characters are allowed in a
+    data line, and underscore characters are used in lieu of spaces.
+    The term "alphanumeric character" is defined as the portion of
+    the ASCII character set from 20 hex through 7E hex, inclusive.
+    The following discussion defines the contents of each field in a
+    data line.
+
+
+  Field 1: Keyword
+
+    The keyword field may be empty, or may contain one of the
+    following:
+
+    Zone
+
+        Begins the definition of a geographic zone and define its
+        coordinator. All the data lines following a line with the
+        "Zone" keyword down to, but not including, the next
+        occurrence of a "Zone" keyword, are regions, networks, and
+|       nodes within the defined zone.  Node entries defined
+|       immediately after the "Zone" keyword and before the next
+|       region or host entry are known as zone adminstrative nodes.
+|       These are allocated by the Zone Coordinator for use by nodes
+|       in the entire zone; for example, mail gateways between
+|       FidoNet zones.
+
+    Region
+
+        Begins the definition of a geographic region and defines
+        its coordinator. All the data lines following a line with
+        the "Region" keyword down to,  but not including,  the
+        next occurrence of a "Zone",  "Region",  or "Host"
+        keyword, are independent nodes within the defined region.
+
+    Host
+
+        Begins the definition of a local network and defines its
+|       network coordinator. All the data lines following a line
+        with the Host keyword down to, but not including, the
+        next occurrence of a "Zone", "Region",  or "Host" keyword,
+        are local nodes, members of the defined local network.
+
+    Hub
+
+        Begins the definition of a routing sub-unit within a
+        multi-level local network. The hub is the routing focal
+        point for nodes listed below it until the next occurrence
+        of a "Zone", "Region", "Host", or "Hub" keyword. The hub
+        entry MUST be a redundant entry, with a unique number, for
+        one of the nodes listed below it, within its hub segment.
+        This is necessary because some nodelist processors
+        eliminate these entries in all but the local network.
+
+    Pvt
+
+        Defines a private node with unlisted number. Private nodes
+        are only allowed as members of local networks.
+
+    Hold
+
+        Defines a node which is temporarily down. Mail may be sent
+        to it and is held by its host or coordinator.
+
+    Down
+
+        Defines a node which is not operational. Mail may NOT be
+        sent to it. This keyword may not be used for longer than
+        two weeks on any single node, at which point the "down"
+        node is to be removed from the nodelist.
+
+    
+
+|       The field contains no text (not the sequence ""),
+|       and defines a normal node entry.
+
+|   Only one of these may be used in any individual data line.
+
+
+  Field 2: Zone/Region/Net/Node number
+
+    This field contains only numeric digits and is a number in the
+    range of 0 to 32767. If the line had the "Zone", "Region", or
+    "Host" keyword, the number is the zone, net, or region number,
+    and the node has an implied node number of 0. Otherwise, the
+    number is the node number. The zone number, region or net number,
+    and the node number, taken together, constitute a node's FidoNet
+    address.
+
+    Zone numbers must be unique. Region or net numbers must be unique
+    within their zone, hub numbers unique be within their net, node
+|   numbers unique within their net (and region, for regional
+|   independent nodes, zone for zone administrative entries). Duplicate
+    node numbers under different hubs within the same net are not
+    allowed.
+
+
+  Field 3: Node name
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces, and
+    a comma delimits the end of the field. This is the name by which
+    the node is known, usually as determined by the node or the
+    coordinator responsible for compiling the segment.
+
+
+  Field 4: Location
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces. This
+    field contains the location of the node. It is usually expressed
+    as the primary local location (town, suburb, city, etc.) plus the
+    identifier of the regional geopolitical administrative district
+    (state, province, department, county, etc.). Wherever possible,
+    standard postal abbreviations for the major regional district
+    should be used (IL, BC, NSW, etc.).
+
+
+  Field 5: Sysop name
+
+    This field may contain any alphanumeric characters other than
+    commas and spaces. Underscores are used to represent spaces. This
+    is the name of the system operator.
+
+
+  Field 6: Phone number
+
+    This field contains at least three and usually four numeric
+    sub-fields separated by dashes (-). The fields are country code,
+    city or area code, exchange code, and number. The various parts
+    of the phone number are frequently used to derive cost and
+    routing information, as well as what number is to be dialed. A
+    typical example of the data in a phone number field is
+    1-800-555-1212, corresponding to country 1 (USA), area 800
+    (inbound WATS), exchange 555, and number 1212.
+
+    Alternatively, this field may contain the notation
+    "-Unpublished-" in the case of a private node. In this case, the
+|   keyword "Pvt" must appear at the start of the line.
+
+
+  Field 7: Baud rate
+
+    This field contains one of the values: 300, 1200, 2400, 9600,
+|   19200, or 38400.
+
+|   This baud rate is indicative only of the maximum baud rate that
+|   may be expected when connecting to a node and is generally of use
+|   only where a calling node needs to adjust the baud rate used to
+|   dial to the caller's modem speed in order to achieve a
+|   connection, a requirement that with modem technology available in
+|   1996 is rarely if ever needed. This information is largely
+|   superseded by modem protocol flags (see next section) where any
+|   two nodes using a common protocol may have other expectations
+|   with regards to actual transfer rates. Use of the baud rate field
+|   alone is therefore depreciated.
+
+
+  Field 8 - Flags
+
+    This optional field contains data about the specific operation of
+    the node, such as file requests, modem protocol supported, etc.
+    Any text following the seventh comma on a data line is taken
+    collectively to be the flags field. The required format is zero
+    or more sub-fields, separated by commas. Each sub-field consists
+    of a flag, possibly followed by a value.
+
+    The following flags define special operating conditions:
+
+       Flag    Meaning
+
+       CM      Node accepts mail 24 hours a day
+       MO      Node does not accept human callers
+|      LO      Node accepts calls only from valid listed node
+|              numbers in the current FidoNet nodelist
+
+
+    The following flags define modem protocols supported:
+
+       Flag    Meaning
+
+|      V21     ITU-T V21      300 bps full duplex
+|      V22     ITU-T V22     1200 bps full duplex
+|      V29     ITU-T V29     9600 bps half duplex
+|      V32     ITU-T V32     9600 bps full duplex
+|      V32b    ITU-T V32bis 14400 bps full duplex
+|      V33     ITU-T V33
+|      V34     ITU-T V34    28800 bps full duplex
+
+       H96     Hayes V9600
+       HST     USR Courier HST up to 9600
+|      H14     USR Courier HST up to 14400
+|      H16     USR Courier HST up to 16800
+       MAX     Microcom AX/96xx series
+       PEP     Packet Ensemble Protocol
+|      CSP     Compucom Speedmodem
+|      ZYX     Zyxel series
+|      VFC     V.Fast Class
+|      V32T    V.32 Terbo
+
+       NOTE:   Many V22 modems also support Bell 212A.
+
+    If no modem flag is given, Bell 212A is assumed for 1200 bps
+    systems, ITU-T V22bis is assumed for 2400 bps systems.
+
+
+    The following flags define type of error correction available. A
+    separate error correction flag should not be used when the error
+    correction type can be determined by the modem flag. For
+|   instance, a modem flag of HST implies MNP, V32b implies V32 and
+|   V42b implies V42. Therefore MNP+HST, H14+MNP, H16+MNP, V32+V32b
+|   and V42+V42b flag pairs are redundant and should not be used.
+
+        Flag    Meaning
+
+        MNP     Microcom Networking Protocol error correction
+|       V42     ITU-T LAP-M error correction w/fallback to MNP 1-4
+|       V42b    ITU-T LAP-M error correction w/fallback to MNP 1-5
+
+
+    The following flags define the type(s) of compression of mail
+    packets supported.
+
+        Flag    Meaning
+
+        MN      No compression supported
+
+|       NOTE:   While FidoNet nodes usually exchange mail
+|               using a variety of different file compression
+|               formats negotiated between individual systems, the
+|               presence of this flag indicates the INABILITY TO
+|               RECEIVE MAIL compressed using the SEA ARC version 5
+|               compression format and/or named according to the
+|               ARCmail 0.6 mail bundle naming method. This is, by
+|               convention, the most common mail compression format
+|               in use within FidoNet. The presence of this flag
+|               would normally indicate that all mail should be sent
+|               uncompressed unless there is some overriding
+|               arrangement with the receiving system.
+
+    The following flags indicate the types of file and file update
+    requests supported.
+
+        Flag    Meaning
+
+        XA      Bark and WaZOO file/update requests
+        XB      Bark file/update requests, WaZOO file requests
+|       XC      Bark file requests, WaZOO file file/update
+        XP      Bark file/update requests
+        XR      Bark and WaZOO file requests
+        XW      WaZOO file requests
+|       XX      WaZOO file/update requests
+
+
+    The following flag defines gateways to other domains (mail
+    networks).
+
+        Flag    Meaning
+
+        Gx..x   Gateway to domain 'x..x', where 'x..x` is a string
+                of alphanumeric characters.
+
+        NOTE:   Valid values for 'x..x' are assigned by the FidoNet
+|               International Coordinator or the person appointed as
+|               Internetworking Coordinator by the FidoNet
+|               International Coordinator. Current valid values of
+                'x..x' may usually be found in the notes at the end
+|               of the current FidoNet nodelist. The most common
+|               gateway flag is "GUUCP", to denote a gateway to the
+|               Internet mail system that gates on behalf of the
+|               fidonet.org internet domain.
+
+
+    The following flags define the dedicated mail periods supported.
+    They have the form "#nn" or "!nn" where nn is the UTC hour the mail
+    period begins, '#' indicates Bell 212A compatibility, and '!'
+    indicates incompatibility with Bell 212A.
+
+        Flag    Meaning
+
+|       #01     Zone 5 mail hour (01:00 - 02:00 UTC)
+        #02     Zone 2 mail hour (02:30 - 03:30 UTC)
+|       #03     Zone 4 mail hour (08:00 - 09:00 UTC)
+        #09     Zone 1 mail hour (09:00 - 10:00 UTC)
+        #18     Zone 3 mail hour (18:00 - 19:00 UTC)
+|       #20     Zone 6 mail hour (20:00 - 21:00 UTC)
+
+        NOTE:   When applicable, the mail period flags may be strung
+                together with no intervening commas, e.g.. "#02#09"
+|               or "!02!09". Only mail hours other than that
+                standard within a node's zone should be given. Since
+                observance of mail hour within one's zone is
+                mandatory, it should not be indicated.
+
+
+    The following flag defines user-specific values. If present,
+    this flag MUST be the last flag present in a nodelist entry.
+
+        Flag    Meaning
+
+        Ux..x   A user-specified string, which may contain any
+                alphanumeric character except blanks. This string
+                may contain one to thirty-two characters of
+                information that may be used to add user-defined
+                data to a specific nodelist entry.
+
+|       NOTE:   Ux..x flags are the mechanism by which new flags may
+|               be experimentally introduced into the nodelist for a
+|               trial period to assess their worth. They are
+|               therefore of a temporary nature, and after their
+|               introduction they are eventually either promoted
+|               to a non-U flag or dropped from use altogether.
+
+    The FTSC recognizes that the FidoNet International Coordinator is
+    the ultimate authority over what appears in the FidoNet nodelist.
+    Also, FTSC is by definition a deliberative body, and adding or
+    changing a flag may take a considerable amount of time.
+    Therefore, the FidoNet International Coordinator may temporarily
+    make changes or additions to the flags as defined in this
+    document. The FidoNet International Coordinator will then consult
+    with FTSC over the changes needed to this document to reflect
+    these temporary changes.
+
+
+    The following are examples of nodelist data lines:
+
+    Host,102,SOCALNET,Los_Angeles_CA,Richard_Martz,1-213-874-9484,2400,XP
+    ,101,Rainbow_Data,Culver_City_CA,Don_Brauns,1-213-204-2996,2400,
+
+
+| THE NODEDIFF
+
+|   With more than thirty-five thousand nodes as of this date (1996),
+|   the nodelist, even in archive form, is a document of substantial
+|   size. Since distribution of the nodelist occurs via electronic
+    file transfer, this file is NOT routinely distributed. Instead,
+|   when a new nodelist is prepared weekly, it is compared with the
+    previous week's nodelist, and a file containing only the
+    differences is created and distributed.
+
+|   The distribution difference file, called NODEDIFF.nnn, where nnn
+    is the day-of-year of publication, is actually an editing script
+    which will transform the previous week's nodelist into the
+    current nodelist. A definition of its format follows:
+
+    The first line of NODEDIFF.nnn is an exact copy of the first line
+|   of LAST WEEK'S nodelist (i.e. the first line of the nodelist to
+|   which the current difference file applies). This is used as a
+    first-level confidence check to insure that the correct file is
+    being edited. The second and subsequent lines are editing
+    commands and data.
+
+    There are three editing commands and all have the same format:
+
+  
+
+     is a 1 letter command, one of A, C, or D.
+
+     is a decimal number greater than zero, and defines the
+    number of lines to be operated on by the command. Each command
+    appears on a line by itself. The commands have the following
+    meanings:
+
+        Ann     Add the following nn lines to the output file.
+        Cnn     Copy nn unchanged lines from the input to the output
+                file.
+        Dnn     Delete (or skip) nn lines from the input file.
+
+    The following illustrate how the first few lines of a
+|   hypothetical NODEDIFF.213 might look:
+
+        ;A Friday, July 25, 1986 -- Day number 206 : 27712
+        D2
+        A2
+        ;A Friday, August 1, 1986 -- Day number 213 : 05060
+        ;A
+        C5
+
+    This fragment illustrates all three editing commands. The first
+    line is the first line from the previous nodelist, NODELIST.206.
+    The next line says "delete the first two lines" from
+    NODELIST.206. These are the identification line and the line
+    following it. The next command says "add the next two lines" to
+    NODELIST.213 at the "current" location. The two data lines are
+    followed by a command which says "copy five unchanged lines" from
+    NODELIST.206 to NODELIST.213. Notice that the first line added
+|   will ALWAYS contain the new nodelist CRC, so that the software
+|   applying the changes to the old nodelist may check the result of
+|   its editing.
+
+    Since only the differences will be distributed, it is important
+    to insure the accuracy of the newly created nodelist. This is the
+    function of the CRC mentioned above. It is sufficient for a
+    program designed to perform the above edits to pick the CRC value
+    from the first line added to the output file, then compute the
+    CRC of the rest of the output file. If the two CRCs do not agree,
+    one of the input files has been corrupted. If they do agree, the
+    probability is very high (but not 100%) that the output file is
+    accurate.
+
+    For actual distribution, NODEDIFF.nnn is packed into an archive
+|   file named NODEDIFF.?nn, where 'nn' are the last two digits of
+|   day-of-year, and '?' indicates the compression format used.
+
+
+| NODELIST COMPILATION
+
+|   This section is included for tutorial reasons and is not intended
+|   as a definition of any specific method by which FidoNet MUST
+|   compile its weekly nodelist. It merely represents an attempt to
+|   document the method by which it currently does so. It is intended
+|   to be explanatory, and seeks to answer commonly asked questions,
+|   such as how the nodelist is compiled and where the information
+|   comes from, why the nodelists used in different FidoNet zones are
+|   not the same document, and why the difference file generated for
+|   use in one FidoNet zone cannot be applied to the nodelist
+|   generated for use in a different zone, even though the week
+|   numbers match.
+
+|   Nodelists are compiled via a distributed method, which follows
+|   the same structure as the FidoNet coordinator hierarchy. At the
+|   lowest level, network coordinators maintain a list of the nodes
+|   in their network and are responsible for the addition, removal
+|   and correction of individual node's listings in their "segment"
+|   (as portions of the full nodelist are called). In some larger
+|   networks, it is common for this job to be shared with hub
+|   coordinators appointed by the net coordinator, though the
+|   responsibility for those hub segments still remains with the
+|   network coordinator.
+
+|   At a nominated day during the week, before the regional level
+|   segment is submitted to the zone coordinator, individual net
+|   coordinators submit their segments to the regional coordinator
+|   who subsequently compiles these segments and transmits the merged
+|   copy to the zone coordinator. These are combined by the zone
+|   coordinator with the separate segments of other zones and
+|   compiled into that zone's version of the world nodelist. This
+|   world nodelist is then compared with the previous week's version,
+|   a difference file is generated and subsequently distributed
+|   throughout the zone.
+
+|   In some cases, in the interest of saving in transmission times
+|   and therefore costs, the compilation process itself may be better
+|   served by the submission of DIFFERENCE FILES rather than full
+|   net- or region-level segments. Each coordinator therefore retains
+|   a copy of the previously submitted segments and applies
+|   difference files to those to derive the new one. This process is
+|   exactly identical to the NODEDIFF/NODELIST scenario described
+|   earlier in this document, with the same first line and CRC
+|   validation method used to guard the integrity of the nodelist
+|   segments.
+
+|   For a number of reasons, it is important that publication of the
+|   nodelist be as timely as possible. These reasons include: the
+|   nodelist is a definitive list of valid FidoNet addresses that may
+|   receive mail, and must therefore be as correct and up-to-date as
+|   possible to save nodes the unnecessary expense of mail routed to
+|   possibly non-existing addresses; the nodelist contains the list
+|   of telephone numbers that may be called by any user of the
+|   FidoNet nodelist and should therefore be accurate so as not to
+|   unduly annoy owners of those phone numbers should a listed node
+|   go down and an unsuspecting telephone subscriber inherit the same
+|   telephone number.
+
+|   Given this constraint, the expense of international calls and the
+|   fact that FidoNet is a worldwide network that exists in many time
+|   zones, it may be unreasonable to expect the compilation of the
+|   nodelist to be delayed until each zone coordinator can transmit
+|   their most up-to-date zone segment to a central authority for
+|   compilation and subsequent redistribution in any week. For the
+|   sake of expedience, each zone instead maintains its own separate
+|   world nodelist which contains a compilation of the current zone's
+|   latest segments and including the most current copy to hand of
+|   all other FidoNet zone's segments. The zone level nodelist
+|   generated each week by each zone coordinator is then transmitted
+|   to all other zone coordinators for inclusion into their separate
+|   world nodelist as timing permits.
+
+|   In theory, then, the only difference between nodelists
+|   distributed in each zone in any week are accounted for by timing
+|   differences in the exchange of each zone's separate segment. In
+|   practice, other constraints may interfere with timeliness, such
+|   as the difficulty and expense of international telephonic
+|   communications. Also, another point of variance is introduced by
+|   the fact that each zone usually includes its own zone segment
+|   first into its world nodelist to assist - amongst other things -
+|   software that uses the nodelist for index generation. Some
+|   software in common use in FidoNet indexes the nodelist according
+|   to its sequential order (e.g. version 5 and 6 compiled nodelist
+|   formats), and including the current zone first before others will
+|   have a beneficial effect on software performance.
+
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0006.html b/html/ftsc/fts-0006.html new file mode 100755 index 00000000..6cddb22c --- /dev/null +++ b/html/ftsc/fts-0006.html @@ -0,0 +1,870 @@ + + +YOOHOO and YOOHOO/2U2. + + + + +
+Document: FTS-0006
+Version:  002
+Date:     30-Nov-1991
+
+
+
+
+                            YOOHOO and YOOHOO/2U2
+
+                    The netmail handshake used by Opus-CBCS
+             and other intelligent Fidonet mail handling packages
+
+
+                              Vince Perriello
+                             FidoNet 1:2343/491
+
+
+
+
+Status of this document:
+
+     This FTS (FidoNet(r) Technical Standard) specifies an optional
+     standard for the FidoNet community.  Implementation of the
+     protocols defined in this document is not mandatory,  but all
+     implementations of these protocols are expected to adhere to this
+     standard.  Distribution of this document is subject to the 
+     restrictions listed below.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software
+
+
+
+
+LEGAL STUFF
+-----------
+
+The original  protocol and documentation are by Wynn Wagner III.  Updates
+have  been  made  to  this  document  by  Vince Perriello,  who  also  is
+responsible for most of the sample routine included with this document.
+
+They are  released to the  public for  any use  whatsoever as long as you 
+don't  modify any  transmitted  structure  or try to  make money  hawking
+either the sample code or this document as if you owned them.
+
+If you choose to use the  method  or  the  sample  routines,  you  do  so
+entirely at your own risk.  It  is  possible that the routines will cause
+physical damage to your equipment, an invasion of  fire ants, the plague,
+or an extended visit from in-laws.  If any  of  that  stuff  (or anything
+else) happens, you accept the consequences totally.
+
+
+CREDITS
+-------
+
+Fido  and  Fidonet  are  registered  trademarks of Tom Jennings and  Fido
+Software.
+
+ARCmail was originated by System Enhancement Associates.
+
+The ZModem protocol was designed by Chuck Forsberg. The SEAlink / SEAlink
+Overdrive protocols are copyrighted by System Enhancment Associates.  The
+TeLink protocol was designed and first implemented by Tom Jennings.
+
+The state charts in this document were done by Vince Perriello.
+
+Rick Huebner designed  and  implemented  the  basic  WaZOO  file  request
+method.  Update  request functionality was added by Vince Perriello.  Bob
+Hartman is responsible for the addition of Domain support.
+
+FTS-0001, describing the base FidoNet protocol, was created by Randy Bush.
+
+FTS-0007, describing enhancement to FTS-0001 using SEAlink and/or SEAlink
+Overdrive, was created by Phil Becker.
+
+YooHoo and YooHoo/2u2                                              Page 2
+Overview
+
+
+
+UPFRONT
+-------
+
+YOOHOO and YOOHOO/2U2 are  the  initial  handshakes  for the WaZOO e-mail
+protocol.  They are designed to let two systems establish a common ground
+for a netmail session while making  sure  that non-WaZOO software doesn't
+get upset by material it can't understand.
+
+The YOOHOO procedure begins as a single  byte  (0xf1).   If the system on
+the other end doesn't reply to that byte,  no  further  YOOHOO  or  WaZOO
+transmissions are attempted.  To a non-WaZOO netmail system,  the  YOOHOO
+byte will simply seem like a byte of debris.
+
+The  calling  system  initiates  the  YOOHOO  by  sending  the  attention
+character.   If the receiving system seems interested, the calling system
+sends a  128  byte packet containing such information as system and sysop
+names as well as a "capability mask." A 16-bit CRC protects the integrity
+of the 128-byte packet.
+
+In response, the receiving  system  prepares  a  128  byte packet to send
+back.  This is the YOOHOO/2U2 procedure.
+
+
+FEATURES
+--------
+
+The features of YOOHOO and YOOHOO/2U2 include
+
+      * non-interference with systems that don't understand the
+        handshake
+
+      * almost foolproof method for identifying a remote system
+        and establishing a common ground for transmission
+
+      * built-in room to expand the capabilities of WaZOO without
+        having to resort to a kludge
+
+
+USAGE
+-----
+
+A calling system simply uses  a  routine  that  transmits both YooHoo and
+TSYNC  handshake initiating characters to the  called  system.    If  the
+called system responds with an XMODEM 'NAK',  an FTS-0001 session will be
+initiated.  If an 'ENQ' is received, the  `YooHoo_Sender()'  routine will
+be invoked to handle the session negotiation.
+
+A  receiving  system  can call a routine like `YooHoo_Receiver()'  if  it
+detects the YOOHOO character, or just drop into the FTS-0001  logic if it
+sees a TSYNC.
+
+This simple method allows a mailer to take care of both the TSYNC and the
+YOOHOO handshakes.
+
+YooHoo and YooHoo/2u2                                              Page 3
+WaZOO Protocols
+
+
+
+PROTOCOLS
+---------
+
+Currently there are four WaZOO methods in use:
+
+1. ZedZap 
+   ------
+
+        a Zmodem variant. The originator does a batch send then goes into a
+        receive batch mode.  The called system does receive then send. In 
+        the event of a file request (see description below) made by the 
+        called system, one more turnaround is made to service the request.
+
+      * Unlike the "True" Zmodem protocol described by Chuck Forsberg, 
+        ZedZap routines must be able to handle a batch mode that has no 
+        actual files. In other words, it is possible for there to be a 
+        init sequence followed immediately by a ZFIN.
+
+      * The maximum packet size is 8192. This is usually varied based on 
+        the baud rate. For example, at 2400 it might be 2048 bytes, then 
+        for 9600 baud and above the maximum of 8192 could apply. Note that
+        THIS IS A SIGNIFICANT VARIATION FROM STRICT ZMODEM IMPLEMENTATION.
+        (There's another WaZOO capability bit for those systems which 
+        can not handle this block size)
+
+      * Netmail packets are transmitted as files with names in the form
+        "12345678.PKT". Because of this, multiple packets may be sent in 
+        a single session.
+
+      * If the calling system transmits a .REQ file for file requests, the
+        receiving system can respond to it.  See "WaZOO File Requests" 
+        (below) for information on the .REQ file.
+
+2. ZedZip
+   ------
+
+        This capability is identical to ZedZap, but does not use buffers
+        greater than 1K in size (like "True" Zmodem). It is also 
+        permissible to send a "null" packet in a ZedZip session. This
+        allows a system which must use a strict Zmodem implementation to
+        participate in a WaZOO session using Zmodem.
+
+
+3. DietIFNA
+   --------
+
+        The session operates like FTS-0001/FTS-0007. The notable exceptions 
+        are as follows:
+
+      * The same packet naming convention as ZedZap applies, allowing more
+        than one packet to be transmitted in a single session.
+
+YooHoo and YooHoo/2u2                                              Page 4
+WaZOO Protocols
+
+
+
+      * Telink file transfers don't even attempt to exchange file names
+        using modem7. The receiving system extracts the file name from the 
+        Telink or SEAlink header block.
+
+      * If SEAlink is used, run-ahead (the number of blocks to slide) is 
+        based on the baud rate:  BlocksToSlide = BaudRate / 400, up to a 
+        max of 24 blocks.
+
+      * When there is nothing to send, a system should remain quiet.  In 
+        other words, the end of a session can be determined by a timeout.
+
+      * Under no circumstances should "BARK" file request logic be active
+        during a DietIFNA session. File requests, if any, should be 
+        transmitted using a .REQ file.
+
+
+        Many implementations of DietIfna have been accomplished by the mere
+        exchange of packets, followed by straight FTS-0001/0007 code. This
+        is incorrect but probably not easily remedied at this point. We have
+        made an effort to document this change in "reality" in this revision
+        of the document.
+
+4. Janus
+   -----
+
+        Janus is a full-duplex simultaneous bidirectional file transfer
+        protocol. In other words, it can send and receive files at the same
+        time.  It's very loosely derived from ZModem and HDLC/X.25 protocol
+        technology, in that it uses variable length data-typed packets, and
+        that transmission of file data does not require ACKs.
+
+        The protocol is documented elsewhere; it is beyond the scope of this
+        document to do so.
+
+YooHoo and YooHoo/2u2                                              Page 5
+Choosing WaZOO Methods
+
+
+
+How to decide which WaZOO method to use
+---------------------------------------
+
+
+Since the called system has all the information  necessary to decide what
+WaZOO method to employ,  the best way to implement the process is for the
+calling  system  to send,  in its  capability  mask,  all the  bits which
+correspond to methods it can use (or wants to use)  in communicating with
+the called system.  The called  system then looks at these bits and sends
+back only the bit which corresponds to the method it wants to use.
+
+If the  called system  sends  back a mask  which contains  more  than one
+capability of the  calling system,  it can create a  problem situation if
+one system  arrives at its choice of methods  differently from the other.
+Thus, when the called system doesn't make the choice, both systems should
+choose as follows:
+
+1. Janus
+
+2. ZedZap
+
+3. ZedZip
+
+4. DietIFNA
+
+The capability highest on the list which both systems indicate ability to
+execute should be the one employed.
+
+YooHoo and YooHoo/2u2                                              Page 6
+WaZOO Filename conventions
+
+
+
+WaZOO FILENAMES
+---------------
+
+
+1. MESSAGE PACKETS ... xxxxxxxx.PKT
+
+        Normal (unarchived) messages are sent in a file name that has a tag 
+        of .PKT.  The "x" characters should be hex digits.
+
+
+2. ARCmail ... xxxxxxxx.{MO|TU|WE|TH|FR|SA|SU}#
+
+        Message packets are often shipped in an archive that has been
+        compressed with some LZ utility.
+
+        The file name consists of a name with hex digits. The tag is one of
+        seven two-character prefixes ("MO", "TU", "WE", "TH", "FR", "SA" or
+        "SU") and a number (0-9).
+
+        This particular naming convention was established by ARCmail version
+        0.60, which is a defacto standard in FidoNet.
+
+
+3. FILE REQUESTS ... xxxxxxxx.REQ
+
+        This is explained below.
+
+        In a nutshell, the file name consists of the receiving system's 
+        Fidonet address expressed as two 4-digit hex numbers.  The file tag 
+        is .REQ.
+
+        In a Janus session, the .REQ file isn't actually sent. Janus has
+        a transaction system which sends the .REQ file one line at a time
+        and then accepts the file(s) which the request generates.
+
+YooHoo and YooHoo/2u2                                              Page 7
+Flow of a ZedZap or ZedZip Session
+
+
+
+FLOW OF A ZEDZAP OR ZEDZIP SESSION
+----------------------------------
+
+
+
+The calling system:
+
+
+      * Send YooHoo
+
+      * Receive YooHoo/2u2
+
+      * In a single batch, send bundles, files, file request (.REQ) files 
+        (in that order)
+
+      * In a single batch, receive bundles, files, file requests, and 
+        requested files (in that order)
+
+      * If a file request (.REQ) file came in, send all requested files 
+        in a single batch.
+
+
+Receiving system:
+
+      * Receive YooHoo
+
+      * Send YooHoo/2u2
+
+      * In a single batch, receive bundles, files, file requests
+
+      * In a single batch, send bundles, files, our file requests, and 
+        respond to file requests that arrived from the remote system.
+
+      * If we sent a .REQ file in the preceding step, receive all files 
+        in a single batch.
+
+
+YooHoo and YooHoo/2u2                                              Page 8
+WaZOO File Requests
+
+
+
+WAZOO FILE REQUESTS
+-------------------
+
+Rick Huebner, who adapted the ZModem routines for Opus, and the architect of
+the Janus file transfer protocol, designed the ".REQ file"-based file request
+system.
+
+
+REQ FILE:
+
+A WaZOO file request is based on a request file.  The name of a request file
+is similar to the .OUT and .FLO files used by Opus-CBCS and similar mail
+products (such as BinkleyTerm).
+
+         TEMPLATE: netnode.REQ
+
+         EXAMPLE:  00010002.REQ   ... a request being sent to 1/2
+
+The .REQ file is simply a text file that contains the files we want from the
+remote system. Those file names can include wildcards, but should not contain
+a path. Optionally, there can be a password if the sending system requires one.
+
+The "netnode" part of the file name is built from the remote systems net and
+node numbers.  Both numbers become 4-character hex numbers in the file name.
+
+Let's say we're requesting THIS.ARC and all node lists from 12/2.  The file
+name would be 000C0002.REQ.  The contents would look like this:
+
+                  this.arc
+                  nodelist.*
+
+If the sysop of 12/2 requires a password of THAT to get the file THIS.ARC, the
+REQ file contents would have to change:
+
+                  this.arc !that
+                  nodelist.*
+
+Transaction-level passwords (of 6 or fewer characters) follow the file name:
+
+                  !
+
+YooHoo and YooHoo/2u2                                              Page 9
+WaZOO File Requests
+
+
+
+
+If the request is of the "update" genre, the type of update and the time,
+expressed as a UNIX-style long decimal ASCII number, follows the name, or in
+the event that there is a transaction-level password, the password. For
+example, an update request for file NEWOPUS.*, where you already have a file
+dated 1-January 1989, 00:00 and you live on the East Coast (GMT+06) would be:
+
+                  NEWOPUS.* +599634000
+
+The sign is required, it indicates the type of update request. A '+' means
+that all files matching the filespec "NEWOPUS.*" newer than the shown time
+will be sent, a '-' means that all matching files with dates up to and
+including the indicated time will be sent.
+
+
+The complete format of an action line in an REQ file is, then:
+
+          [!][<+/->
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0007.html b/html/ftsc/fts-0007.html new file mode 100755 index 00000000..4135db75 --- /dev/null +++ b/html/ftsc/fts-0007.html @@ -0,0 +1,1869 @@ + + +An Enhanced FidoNet(r) Technical Standard. + + + + +
+Document: FTS-0007
+Version:  003
+Date:     15-Oct-1990
+Updates:  FTS-0001
+
+
+
+
+                  An Enhanced FidoNet(r) Technical Standard
+                Extending FTS-0001 to include SEAlink protocol
+                    (Including Overdrive and File Restart)
+
+                             October 15, 1990
+
+
+
+
+Status of this document:
+
+    This document specifies an optional standard for the FidoNet community.
+    Implementation of the protocols defined in this document is not mandatory,
+    but all implementations of these protocols are expected to adhere to this
+    standard.  Distribution of this document is subject to the limitations of
+    the copyright notice displayed below.
+
+
+    Copyright 1989-90 by Philip L. Becker.  Portions of this document are
+    copyright 1986-90 by Randy Bush and are incorporated with his consent.
+    All rights reserved.  A right to distribute only without modification and
+    only at no charge is granted.  Under no circumstances is this document to
+    be reproduced or distributed as part of or packaged with any product or
+    other sales transaction for which any fee is charged.  Any and all other
+    reproduction or excerpting requires the explicit written consent of the
+    copyright holders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Introduction
+
+    While the basic FTS-0001 protocol has become reasonably standardized, it
+    is technically inferior when used with modem speeds of 2400bps or higher,
+    and results in considerably slower file transfers than more sophisticated
+    protocols under many line and modem configurations.
+
+    Very sophisticated protocols exist to allow absolute maximum efficiency,
+    but these protocols are much more difficult to implement than the basic
+    XMODEM used by FTS-0001.  A need exists for a standardized, easy to
+    implement extension to the FTS-0001 protocol which can gain much better
+    performance.  SEAlink is such an extension.  It is nearly as easy to
+    implement as the FTS-0001 protocol with which it is fully backward
+    compatible.  Despite its ease of implementation, it provides several
+    significant performance advantages. Among these advantages are:
+
+         o  Transparently communicates with strict FTS-0001 implementations.
+
+         o  Transparently communicates with FTS-0001 variants which omit
+            either the MODEM7 file name or the TeLink header block.
+
+         o  Transparently becomes a sliding window XMODEM protocol when
+            communicating with a like implementation.  This sliding window
+            protocol gives significantly improved throughput when there is
+            an end-to-end delay.
+
+         o  Offers a negotiated streaming mode for high speed asymmetrical
+            modems to further enhance throughput for such links.
+
+         o  Offers a negotiated file restart capability which allows an
+            interrupted transfer to restart where it left off, reducing
+            time spent to retransmit the file.
+
+    This document defines the  data structures and communication protocols
+    which a FidoNet SEAlink implementation must provide.  The implementor of
+    FidoNet compatible systems is the intended audience of this document.
+
+    This document has the same overall format and state table descriptions
+    as FTS-0001.  SEAlink is implemented by modifying the following tables:
+
+       Session Layer:   Sender - S1
+       Network Layer:   Batch File Sender - BS0
+       Network Layer:   Batch File Receiver - BR0
+       Data Link Layer: XMODEM/TeLink Sender - XS0
+       Data Link Layer: XMODEM/TeLink Receiver - XR0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                             1
+                              Table of Contents
+
+
+                                                                          Page
+    The purpose of the SEAlink protocol ...................................  3
+
+    How SEAlink negotiates its enhancements ...............................  4
+
+    Basic requirements for a FidoNet Implementation .......................  5
+
+    Levels of Compliance ..................................................  5
+
+    The ISO/OSI Reference Model ...........................................  5
+
+    Data Description Language .............................................  6
+
+    Finite State Machine Notation .........................................  7
+
+    Glossary of variables and terms .......................................  7
+
+    Application layer .....................................................  8
+
+    Presentation layer ....................................................  8
+
+    Session layer protocol ................................................  8
+         Session State Table: Sender (S0) .................................  9
+         Session State Table: Receiver (R0) ............................... 10
+
+    Transport layer ....................................................... 10
+
+    Network layer ......................................................... 11
+         Data Definition: MODEM7 file name ................................ 11
+         Network State Table: Batch File Sender (BS0) ..................... 12
+         Network State Table: Batch File Receiver (BR0) ................... 13
+
+    Data Link Layer ....................................................... 14
+         Data Definition: XMODEM data block (CRC) ......................... 14
+         Data Definition: XMODEM data block (Checksum) .................... 15
+         Data Definition: TeLink header block ............................. 15
+         Data Definition: SEAlink header block ............................ 16
+         Data Definition: SEAlink RESYNC packet ........................... 16
+         DDL Definition: XMODEMBlock, TeLink header ....................... 17
+         DDL Definition: SEAlink header, ACK, NAK, RESYNC block ........... 18
+         Checksum and CRC calculation algorithms .......................... 19
+         Data Link Layer protocol ......................................... 20
+         Data Link State Table: XMODEM/TeLink/SEAlink Sender (XS0) ........ 21
+         Data Link State Table: Transmitter ACK/NAK check (AC0) ........... 22
+         Data Link State Table: XMODEM/TeLink/SEAlink Receiver (XR0) ...... 24
+         Data Link State Table: Send NAK (SN0) ............................ 26
+         Data Link State Table: Send ACK (SA0) ............................ 26
+         Data Link State Table: MODEM7 Filename Sender (MS0) .............. 27
+         Data Link State Table: MODEM7 Filename Receiver (MR0) ............ 27
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            2
+    The purpose of the SEAlink protocol
+
+    The purpose of the SEAlink protocol is to provide a much higher level
+    of capability than the XMODEM protocol provides, while retaining the
+    ease of implementation which has made the XMODEM protocol ubiquitous.
+
+    In order for an extended protocol to function in FidoNet, it has to be
+    fully upward compatible with FTS-0001 mailers, and also those slight
+    variants of FTS-0001 which can communicate well with FTS-0001 mailers.
+    To meet this requirement, any extension to the FTS-0001 protocol has
+    to be capable of transparently negotiating away its extended capabilities
+    and communicate with strict FTS-0001 mailers (and their approved variants)
+    properly and reliably.
+
+    This means that an extended protocol must miminally do the following:
+
+        o  Detect that the other mailer can or cannot support its extensions
+           automatically, and within the framework of a legitimate FTS-0001
+           protocol encounter.
+
+        o  Support mail sessions with or without MODEM7 file names and with
+           or without TeLink headers in either combination.
+
+    To be useful such an extended protocol should also be able to reliably
+    detect when the other mailer can support its extensions so they can
+    be used to maximum benefits.
+
+    The major problems which exist with a standard FidoNet FTS-0001 session
+    result from the use of the XMODEM protocol.  This is a half duplex protocol
+    which forces a line turnaround on every transmitted block.  As a result,
+    any end-to-end delay in the transmission link is directly added to each
+    transmitted data block twice (once for each line turnaround).
+
+    To dramatize how easily XMODEM is impacted by even small line delays, let's
+    examine a 2400bps call on a line with 500ms (1/2 second) delay on each line
+    turnaround.  This is not an uncommon delay time on long distance calls.  A
+    single data block in the XMODEM CRC format contains 133 characters.  This
+    means it will be transmitted in 554ms.  The ACK/NAK response is a single
+    character and will take 4ms.  Thus with no delay (an ideal link) an XMODEM
+    transfer would send 128 data characters in 558ms for an effective data
+    throughput of about 230cps.  With a 500ms line turnaround delay, these same
+    128 data bytes will take 1558ms resulting in a throughput of 82cps.  If
+    faster modem speeds are used, the percentage impact is even greater.
+
+    The solution to this problem is to enhance the XMODEM protocol by adding
+    a "sliding window" capability which allows more than one block to be sent
+    before an acknowledgment is received.  This converts the protocol to a
+    full duplex protocol, and if the "window size" (the number of blocks which
+    may be sent before the sender must wait for an acknowledgment) is larger
+    that the line turnaround delay, then the ideal throughput can be restored
+    even to lines with long turnaround delays.  SEAlink is such a protocol.
+
+    The standard SEAlink window size is 6 blocks, but the state tables given
+    below implement a receiver which will operate correctly with any window
+    size up to 127 blocks.  Thus an implementation which uses a larger window
+    size will be totally compatible with the standard 6 block window versions.
+
+    A second problem with the XMODEM protocol arises when asymmetrical high
+    speed modems are used.  These modems achieve much higher throughput when
+    data is sent in only one direction.  Since they provide error free links,
+    a protocol which does not send any positive acknowledgments, but only
+    reports any bad blocks received will achieve a significantly higher
+
+
+
+                                                                             3
+    throughput than a protocol which is either full duplex or which turns
+    around between each block such as XMODEM or normal SEAlink.  It is for
+    this purpose that SEAlink Overdrive is provided.  It is a streaming version
+    of SEAlink designed to provide much higher throughput on asymmetrical
+    high speed links which provide end-to-end data flow control.
+
+    Finally, there is the annoying problem which occurs when a large data file
+    transfer has nearly completed and a loss of connection occurs.  Normally
+    the entire file must be retransmitted on a new call, resulting in lost
+    time and money.  The SEAlink RESYNC enhancement allows an interrupted
+    file transfer to be resumed at the point it was interrupted thus minimizing
+    the impact of such an interruption.
+
+    How SEAlink Negotiates its enhancements
+
+    SEAlink makes some assumptions about how FTS-0001 mailer implementations
+    react to various stimuli in order to negotiate its enhancements.  For the
+    sender, the test consists of two parts:
+
+    1.  Send a SEAlink header and see if the other end acknowledges it.  In
+        general it will, because most XMODEM implementations will think that
+        the SEAlink header is a "previous block" and ACK and discard it.  If
+        the receiver refuses to accept a SEAlink header block in three tries,
+        then it clearly cannot do SEAlink protocol and the negotiation is over.
+
+    2.  Since the receiver's acknowledgment of the SEAlink header is not a
+        sufficient criteria to determine if the receiver in fact supports
+        SEAlink, the sender dynamically examines the acknowledgments the
+        receiver provides to determine if their format indicates support of
+        SEAlink or not and adjusts its sending techniques accordingly.  This
+        is also the technique used to detect whether the receiver is in fact
+        supporting any extensions (such as SEAlink Overdrive) which have been
+        requested in the header.
+
+    For the receiver, the negotiation occurs during the receipt of the first
+    valid block.
+
+    1.   If the first block received is a valid SEAlink header, then the
+         transmitter supports SEAlink and the receiver can switch to it.  This
+         same header also indicates if the transmitter wants or can support the
+         SEAlink options such as Overdrive and File RESYNC.
+
+     2.  If the first block received is a valid TeLink header, then the
+         transmitter supports a variant of FTS-0001 and SEAlink support may
+         be assumed to be absent.
+
+     3.  If the first block received is an XMODEM data block then SEAlink
+         support may also be assumed to be absent.
+
+    If the receiver gets a SEAlink header, it can then arbitrarily decide
+    which of any requested options it wishes to use.  It may not use an option
+    for which support is not indicated in the sender's SEAlink header block.
+
+    The remainder of this document provides the details for a full SEAlink
+    implementation with Overdrive and RESYNC support.  A glossary of terms and
+    indicators is provided along with a full state table description of the
+    protocol implementation.
+
+
+
+
+
+
+
+
+                                                                             4
+    This document follows the format of FTS-0001 to allow ease of
+    comparison of the two protocols.  This document could not have been
+    generated without the tremendous efforts of those whose work resulted in
+    FTS-0001.  FidoNet owes a great debt to those efforts.  The following
+    introduction is reprinted from FTS-0001.
+
+    The layered metaphor of the ISO Open Systems Interface reference model
+    has been used to view FidoNet from a standard perspective.  As with most
+    prospective ISO/OSI descriptions, FidoNet does not always make this easy.
+
+
+   1. Basic Requirements for a FidoNet Implementation
+
+      Compatibility is a set of abilities which, when taken as a whole, make
+      it safe to list a net or node in the IFNA nodelist.  In other words,
+      if another node should attempt contact, does it have a reasonable
+      chance of successful communication?  This is a social obligation, as
+      the calling system pays money for the attempt.  Conversely, an
+      implementation should be able to successfully contact other systems,
+      as life is not a one-way street.
+
+      A FidoNet implementation must be able to call other nodes and transfer
+      messages and files in both directions.  This includes pickup and poll.
+
+      A FidoNet implementation must be able to accept calls from other nodes
+      and transfer messages and files in both directions.  This includes
+      pickup.
+
+      A FidoNet implementation must be able to receive and process the IFNA
+      format nodelist, and transfer nodelists to other nodes.  A companion
+      document, FTS-0005, defines the IFNA format nodelist and how to
+      interpret and process it.
+
+      A FidoNet implementation must route messages which do not have files
+      attached through net hosts as shown in an IFNA format nodelist.
+
+
+   2. Levels of Compliance
+
+      This documents represents an extended FidoNet implementation.  It
+      defines a well tested extension which is optional but provides
+      sufficient additional function that implementors should seriously
+      consider it.  SEAdog(tm), from System Enhancement Associates,
+      is the inspiration for this extended FidoNet implementation.
+      System Enhancement Associates is the creator of the SEAlink protocol.
+
+
+   3. The ISO/OSI Reference Model (cribbed from "Protocol Verification via
+      Executable Logic Specifications", D. P. Sidhu, in Rudin & West)
+
+      In the ISO/OSI model, a distributed system consists of entities that
+      communicate with each other according to a set of rules called a
+      protocol.   The model is layered, and there are entities associated
+      with each layer of the model which provide services to higher layers
+      by exchanging information with their peer entities using the services
+      of lower layers.  The only actual physical communication between two
+      systems is at the lowest level.
+
+
+
+
+
+
+
+
+                                                                             5
+      Several techniques have been used in the specification of such
+      protocols.  A common ingredient in all techniques is the notion of the
+      extended finite state automata or machine.  Extensions include the
+      addition of state variables for the storing of state information about
+      the protocol.  The state of an automaton can change as a result of
+      one of the following events:
+
+      o Request from an upper network layer for service
+
+      o Response to the upper layer
+
+      o Request to the lower network layer to perform a service
+
+      o Response from the lower layer
+
+      o Interaction with the system and environment in which the protocol is
+        implemented (e.g. timeouts, host operating system aborts, ...)
+
+      A protocol specification, in a large part, consists of specifying
+      state changes in automata which model protocol entities and in
+      describing the data which they exchange.
+
+      For historical reasons, the term packet is used in FidoNet to
+      represent a bundle of messages, as opposed to the more common use as a
+      unit of communication, which is known as a block in FidoNet.
+
+
+   4. Data Description
+
+      A language specific notation was avoided.  Please help stamp out
+      environmental dependencies.   Don't panic, there are rectangular record
+      layouts too.  The following defines the data description language used.
+
+      (* non-terminals *)
+      UpperCaseName - to be defined further on
+
+      (* literals *)
+      "ABC"         - ASCII character string, no termination implied
+      nnH           - byte in hexadecimal
+
+      (* terminals *)
+      someName      - 16-bit integer, low order byte first (8080 style)
+      someName[n]   - field of n bytes
+      someName[.n]  - field of n bits
+      someName(n)   - Null terminated string allocated n chars (incl Null)
+      someName{max} - Null terminated string of up to max chars (incl Null)
+      someName - String of up to max chars, NOT null terminated
+
+      (* punctuation *)
+      a b           - one 'a' followed by one 'b'
+      ( a | b )     - either 'a' or 'b', but not both
+      { a }         - zero or more 'a's
+      [ b ]         - zero or one 'b'
+      (* comment *) - ignored
+
+      (* predeclared constant *)
+      Null          = 00H
+
+
+
+
+
+
+
+
+                                                                             6
+ 5. Finite State Machine Notation
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | fnn*|          |                         |                         |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+
+    State #      - Number of this state (e.g. R13).
+                   f  - FSM initial (Window, Sender, Receiver, ...)
+                   nn - state number
+                   *  - state which represents a lower level protocol  which
+                        is represented by yet another automation.
+
+    State Name   - Descriptive name of this state.
+
+    Predicate(s) - Conditions which terminate the state.  If predicates are
+                   non-exclusive, consider them ordered.
+
+    Action(s)    - Action(s) corresponding to predicate(s)
+
+    Next State   - Subsequent state corresponding to predicate(s)
+
+    Ideally, there should be a supporting section for each state which
+    should give a prose description of the state, its predicates, actions,
+    etc.  So much for ideals.  The following is a list of all of the terms
+    and variables used in the following state machine descriptions:
+
+
+                     Glossary of variables and terms
+
+    SEAlink - Flag indicating SEAlink or XMODEM mode
+
+    SLO - Flag indicating overdrive if in SEAlink mode
+
+    RESYNC - Flag indicating whether transmitting end can honor RESYNC
+             file positioning requests or only NAKs
+
+    MACFLOW - Flag indicating whether the sender supports the Macintosh flow
+              control option.  This is an optional feature used by TABBY
+              because the Macintosh serial port does not support RTS/CTS.
+
+    CRC - Flag indicating whether block check is done using CRC or Checksum
+
+    T1 and T2 - Timeout Timers which run asynchronously with the code
+
+    WINDOW - Number of unacknowledged blocks which may be transmitted
+
+    SendBLK - Next 128 byte block number in file to send.  May not occur in
+              sequential order, so file positioning may be necessary when
+              it is time to send this block
+
+    ACKBLK - Highest block number in file which has been acknowledged by
+             the receiver as received without error
+
+    Last Blk - Block number of last 128 byte block (or partial block) in the
+               file being sent.
+
+    NumNAK - Number of NAKs received since last ACK
+
+    ACKs Rcvd - Number of ACKs received since the start of this file send
+
+
+
+                                                                             7
+                     Glossary of variables and terms (cont.)
+
+    ACKST - State of ACK/NAK machine during auto-detect of SEAlink or XMODEM
+            style ACK/NAK block receipt
+
+    RESYNC BLK# - Block number in file requested by a received RESYNC packet
+
+    ARBLK8 - Block # (0-255) received in a SEAlink style ACK/NAK packet
+
+    ARBLK - Block # in file (calculated from ARBLK8) which is the actual
+            block being referenced in the SEAlink ACK/NAK packet
+
+    blocknum - Block # (0-255) sent in a SEAlink style ACK/NAK packet
+
+    WriteBLK - Block # in file to write next correctly received data block.
+               Note: Block 1 is the first byte of the file.
+
+    CHR - Temp holding variable for received character during send operation
+
+
+ B. Application Layer : the System from the User's View
+
+    This is unchanged from FTS-0001.
+
+
+ C. Presentation Layer : the User from the System's View
+
+    This is unchanged from FTS-0001.
+
+
+ D. Session Layer Protocol : Connecting to Another FidoNet Machine
+
+    A session is a connection between two FidoNet machines.  It is currently
+    assumed to be over the DDD telephone network via modems.  The calling
+    machine starts out as the sender and the called machine as the receiver.
+    The pickup feature is described by the sender and receiver changing
+    roles midway through the session, after the sender has transferred the
+    message packet and any attached files.  Due to the lack of security in
+    the pickup protocol (danger of pickup by a fake node), extensions to the
+    basic Session protocol have been developed.  This document describes only
+    the minimum Session Layer protocol (as in FTS-0001).
+
+    Once a connection has been established, each system should ensure that
+    the physical connection remains throughout the session.  For physical
+    layers implemented through modems, this means monitoring the carrier
+    detect signal, and terminating the session if it is lost.
+
+    Error detection at the physical layer should be monitored for both sent
+    and received characters.  Parity, framing, and other physical errors
+    should be detected.
+
+    The only change to the Session Layer state tables from FTS-0001 is in the
+    Sender state "S1", Predicate "1" (S1.1) entry.
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                             8
+    Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | S0  | SendInit |                         | dial modem              | S1  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S1  | WaitCxD  |1| carrier detected      | delay 1-5 seconds       | S2  |
+    |     |  (*1)    | |                       | Set SLO if > 2400bps,   |     |
+    |     |          | |                       | Reset SLO if <= 2400bps |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| busy, etc.            | report no connection    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| voice                 | report no carrier       | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| carrier not detected  | report no connection    | exit|
+    |     |          | | within 60 seconds     |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S2  | WhackCRs |1| over 30 seconds       | report no response <cr> | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ?? <cr>s received     | delay 1 sec             | S3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| <cr>s not received    | send <cr> <sp> <cr> <sp>| S2  |
+    |     |          | |                       |   delay ??? secs        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S3  | WaitClear|1| no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| over 60 seconds       | hang up, report garbage | exit|
+    |     |          | | and line not clear    |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S4* | SendMail |                         | (XMODEM send packet XS0)| S5  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S5  | CheckMail|1| XMODEM successful     | (Fido registers success)| S6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM fail or timeout| hang up, report mail bad| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S6* | SendFiles|                         | (BATCH send files BS0)  | S7  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S7  | CheckFile|1| BATCH send successful |                         | S8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH send failed     | hang up, rept files fail| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S8  | TryPickup|1| wish to pickup        | note send ok            | R2* |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no desire to pickup   | delay 5 secs            | exit|
+    |     |          | |                       |   hang up, rept send ok |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Although the above shows the sender emitting only one TSYNCH, it is
+    recommended that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+
+    *1 - The action for (S1.1) is the only change from the corresponding
+         FTS-0001 state table.
+
+
+
+
+
+
+
+
+
+
+
+                                                                             9
+    Receiver
+
+    The receiving FSM is given an external timer, the expiration of which
+    will cause termination with a result of 'no calls' (R0.2).
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R0  | WaitCxD  |1| carrier detected      |                         | R1  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| external timer expires| report no calls         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R1  | WaitBaud |1| baud rate detected    | send signon with <cr>s  | R2  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no detect in ?? secs  | hang up, report no baud | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R2  | WaitTsync|1| TSYNCH received       | ignore input not TSYNCH | R3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| 60 seconds timeout    | hang up, report not Fido| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R3* | RecMail  |                         | (XMODEM rec packet XR0) | R4  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R4  | XRecEnd  |1| XMODEM successful     | delay 1 second          | R5  |
+    |     |          | |                       |   flush input           |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM failed         | hang up, rept mail fail | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R5* | RecFiles |                         | (BATCH rec files BR0)   | R6  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R6  | ChkFiles |1| BATCH recv successful | delay 2 secs            | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH recv failed     | hang up, report bad file| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R7  | AllowPkup|1| have pickup for sender| receiver becomes sender | S3* |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| nothing to pickup     | hang up, rept recv ok   | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    There is no change in the Session Layer Receiver state table from FTS-0001.
+
+
+ E. Transport Layer : ?????
+
+    This is unchanged from FTS-0001.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            10
+ F. Network Layer : the Network's View of the System, Routing and Packets
+
+   1. Network Layer Data Definition : the Packet Header
+
+      This is unchanged from FTS-0001.
+
+
+   2. Network Layer Data Description : a File with Attributes
+
+      The BATCH protocol uses the MODEM7 filename and/or SEAlink/TeLink/XMODEM
+      file transfer protocols to transfer the file with attributes.
+
+      When a file is transferred via FidoNet, an attempt is made to also
+      pass the operating system's attributes for the file such as length,
+      modification date, etc.  FidoNet does this via a special prefix block
+      to the XMODEM file transfer using a protocol known as TeLink.  As the
+      TeLink protocol relies on a modification to the XMODEM file transfer
+      protocol, it is documented at the data link layer level.  Optionally,
+      if both sender and receiver implement the SEAlink extension, file
+      information is passed using the SEAlink header block which also
+      contains feature negotiation information.
+
+      The MODEM7 file name is redundant if there is also a TeLink or SEAlink
+      block, in which case the name may be taken from either or both.  In this
+      extended implementation, the MODEM7 file name is never required.  It
+      is sent, however, if it appears that the other node is using a strict
+      FTS-0001 implementation.  This implementation will adapt to an FTS-0001
+      variant which only sends the TeLink header without the MODEM7 filename
+      also so that it is compatible with all know variants of FTS-0001 which
+      are currently in the FidoNet network.
+
+
+                          FileName as Sent by MODEM7
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |                   fileName                    |
+              ~                   8  bytes                    ~
+              |           left adjusted blank filled          |
+              +-----------------------------------------------+
+        8   8 |                    fileExt                    |
+              ~                    3  bytes                   ~
+              |           left adjusted blank filled          |
+              `-----------------------------------------------'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            11
+ 3. Network Layer Protocol : BATCH File Finite State Machines
+
+    BATCH File Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS0 | MoreFiles|1| more files to send    |                         | BS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no more files to send |                         | BS4 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS1 | WaitType |1| rec NAK               | (MODEM7 FName send MS0) | BS2 |
+    |     |    (*1)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| rec 'C'               | (SEAlink send file XS0) | BS3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| rec other char        | eat character           | BS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| > 20 sec in BS1       | report name send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS2 | CheckFNm |1| MODEM7 Filename ok    | (TeLink send file XS0T) | BS3 |
+    |     |    (*2)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| MODEM7 Filename bad   | report name send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS3 | CheckFile|1| File send ok          |                         | BS0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| File send bad         | report file send bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BS4 | EndSend  |1| rec NAK or 'C'        | send EOT, report send ok| exit|
+    |     |    (*3)  +-+-----------------------+-------------------------+-----+
+    |     |          |2| 10 secs no NAK or 'C' | send EOT, report no NAK | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - Note: Filenames must be upper case ASCII.  The data link layer uses
+         lower case "u" as a control character during MODEM7 name transmission.
+
+    *2 - Note: SEAdog (through version 4.51b) does not possess a state "XS0T".
+         It therefore calls XS0 from state BS2, resulting in a MODEM7 file name
+         being sent with no TeLink header on batch file transmissions when it
+         is not in SEAlink mode.
+
+    *3 - When no files remain, the sender responds to the receiver's NAK with
+         an EOT.  The EOT is not ACK/NAKed by the receiver.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            12
+   BATCH File Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | BR0 | TestSL   |                         | Send 'C',               | BR1 |
+    |     |          |                         |   Set T1 to 10 sec      |     |
+    |     |          |                         |   Set T2 to 120 sec     |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR1 | CheckSL  |1| > 2 sec with no data  | Send 'C'                | BR1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Timer T2 expired      | (MODEM7 FName recv MR0) | BR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Character Waiting     | "Peek" char to CHR (*1) | BR4 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Timer T1 expired      | (MODEM7 FName recv MR0) | BR2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR2 | CheckFNm |1| no more files         | report files recd ok    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Filename ok           | (Rcv file Telink XR0)   | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Filename bad          | report name recv bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR3 | CheckFile|1| File received ok      |                         | BR0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| File received bad     | report file recv bad    | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | BR4 | FindType |1| CHR = NUL             | eat character,          | BR1 |
+    |     |          | |                       |   Reset T1 to 20 secs   |     |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| CHR = SOH             | (Rcv File SEAlink XR0B) | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| CHR = SYN             | (Rcv File Telink XR0B)  | BR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| CHR = EOT or          | eat character,          | exit|
+    |     |          | | CHR = SUB             |   report files recd ok  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| CHR = Other char      | eat character           | BR1 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - "Peek" a character means to place it in CHR but leave it in the input
+         buffer so the next read operation will re-read it.
+
+    *2 - "Eat" a character means to remove it from the input buffer.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            13
+ G. Data Link Layer : Error-Free Data Transfer
+
+   1. Data Link Layer Data Definition : XMODEM/TeLink/SEAlink Blocks
+
+      XMODEM transfers are in blocks of 128 uninterpreted data bytes
+      preceded by a three byte header and followed by either a one byte
+      checksum or a two byte crc remainder.  XMODEM makes no provision  for
+      data streams which are not an integral number of blocks long.
+      Therefore, the sender pads streams whose length is not a multiple of
+      128 bytes with the end-of-file character (^Z for MS-DOS), and uses some
+      other means to convey the true data length to the receiver (e.g.
+      SEAlink or TeLink file info header block).
+
+      Data blocks contain sequence numbers so the receiver can ensure it has
+      the correct block.  Data block numbers are sequential unsigned eight bit
+      integers beginning with 01H and wrapping to 00H.  A TeLink or SEAlink
+      header block is given sequence number 00H.
+
+      For files which are attached to the mail packet (but not the mail packet
+      itself), if the sending system is aware of the file attributes as they
+      are known to the operating system, then the first block of the XMODEM
+      transfer may be a special TeLink block to transfer that information.
+      This block differs in that the first byte is a SYN character as
+      opposed to an SOH, and it is always sent checksum as opposed to CRC.
+      Should the receiver be unwilling to handle such information, after four
+      NAKs (or "C"s), the sender skips this special block and goes on to the
+      data itself.
+
+      In this extended protocol the TeLink header block may be replaced by
+      the SEAlink header block which conveys protocol negotiation information
+      in addition to the file attributes if both nodes implement SEAlink.
+
+
+
+                        XMODEM Data Block (CRC mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |             CRC high order byte               |
+              +-----------------------------------------------+
+      132  84 |             CRC  low order byte               |
+              `-----------------------------------------------'
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            14
+                      XMODEM Data Block (Checksum mode)
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |        SOH  -  Start Of Header -  01H         |
+              +-----------------------------------------------+
+        1   1 |                 BlockNumber                   |
+              +-----------------------------------------------+
+        2   2 |               BlockComplement                 |
+              +-----------------------------------------------+
+        3   3 |                128 bytes  of                  |
+              ~                uninterpreted                  ~
+              |                    data                       |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+                       TeLink File Descriptor Block
+       Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN  -  File Info Header -  16H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |     File Length, least significant byte       |  0    0
+              +-----------------------------------------------+
+        4   4 | File Length, second to least significant byte |  1    1
+              +-----------------------------------------------+
+        5   5 |  File Length, second to most significant byte |  2    2
+              +-----------------------------------------------+
+        6   6 |      File Length, most significant byte       |  3    3
+              +-----------------------------------------------+
+        7   7 |            Creation Time of File              |  4    4
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+        9   9 |            Creation Date of File              |  6    6
+              |                "DOS Format"                   |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  16 chars                     ~
+              |        left justified  blank filled           |
+              +-----------------------------------------------+
+       27  1B |                    00H                        | 24   18
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  16 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       44  2B |            01H (for CRC) or 00H               | 41   29
+              +-----------------------------------------------+
+       45  2C |                    fill                       | 42   2A
+              ~                  86 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      131  83 |                Checksum byte                  |
+              `-----------------------------------------------'
+
+
+
+
+
+                                                                            15
+      Offset           SEAink File Descriptor Block
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SOH  -  Start of Header -   01H         |
+              +-----------------------------------------------+
+        1   1 |                     00H                       |
+              +-----------------------------------------------+
+        2   2 |                     FFH                       |  dec  hex
+              +-----------------------------------------------+
+        3   3 |         File Length, (4 bytes, LSB first)     |  0    0
+              +-----------------------------------------------+
+        7   7 |            Creation Date/Time of File         |  4    4
+              |   (4 bytes, LSB first, seconds since 1979)    |
+              +-----------------------------------------------+
+       11   B |                 File  Name                    |  8    8
+              ~                  17 chars                     ~
+              |        left justified   Null filled           |
+              +-----------------------------------------------+
+       28  1C |            Sending Program Name               | 25   19
+              ~                  15 chars                     ~
+              |         left justified  Null filled           |
+              +-----------------------------------------------+
+       43  2B |            > 0 if SLO Requested               | 40   28
+              +-----------------------------------------------+
+       44  2C |           > 0 if RESYNC Supported             | 41   29
+              +-----------------------------------------------+
+       45  2D |           > 0 if MACFLOW Supported            | 42   2A
+              +-----------------------------------------------+
+       46  2E |                    fill                       | 43   2B
+              ~                  85 bytes                     ~
+              |                  all zero                     |
+              +-----------------------------------------------+
+      131  83 |            CRC high order byte                |
+              +-----------------------------------------------+
+      132  84 |            CRC  low order byte                |
+              `-----------------------------------------------'
+  
+
+      Offset                SEAlink RESYNC packet
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       SYN - Start of RESYNC packet - 16H      |
+              +-----------------------------------------------+
+        1   1 |     ASCII Decimal 128 byte block number in    |
+              ~     file to restart sending.  (No leading     ~
+        n     |     or trailing blanks, MSD first).           |
+              +-----------------------------------------------+
+        n+1   |       ETX -  End of RESYNC packet  - 03H      |
+              +-----------------------------------------------+
+        n+2   |     (*1)     CRC  low order byte              |
+              +-----------------------------------------------+
+        n+3   |     (*1)     CRC high order byte              |
+              `-----------------------------------------------'
+
+              *1 - CRC does not include the SYN or ETX and is
+                   in the reverse byte order from the CRC in a
+                   normal XMODEM data packet.  The following is
+                   a sample RESYNC packet for file block 27 (1BH).
+
+                     SYN   '2'   '7'   ETX  CRCLO CRCHI 
+                   .-----+-----+-----+-----+-----+-----.
+                   | 16H | 32H | 37H | 03H | 43H | 25H |
+                   `-----+-----+-----+-----+-----+-----'
+
+
+                                                                            16
+    Data Description language definitions of block types:
+
+      XMODEMData   =   XMODEMBlock    (* block of data with hdr and trailer *)
+                     | SEALinkBlock   (* SEALink File Descriptor Block *)
+                     | TeLinkBlock    (* TeLink File Descriptor Block *)
+                     | ReSyncBlock    (* SEAlink RESYNC request packet *)
+                     | ACK            (* acknowledge data received ok *)
+                     | NAK            (* negative ACK & poll 1st block *)
+                     | SEAlinkACK     (* acknowledge data received ok *)
+                     | SEAlinkNAK     (* negative ACK & poll 1st block *)
+                     | EOT            (* end of xfer, after last block *)
+                     | "C"            (* 43H *)
+
+
+      XMODEMBlock  = SOH              (* Start of Header, XMODEM Block *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+                     data[128]        (* uninterpreted user data block *)
+                     (CRC | Checksum) (* error detect/correction code *)
+
+
+      TeLinkBlock  = SYN              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+                (*2) CreationTime[2]  (* time file last modified or zero *)
+                (*2) CreationDate[2]  (* date file last modified or zero *)
+                     fileName(16)     (* name of file, not vol or dir *)
+                     00H              (* header version number *)
+                     sendingProg(16)  (* name of program on send side *)
+                (*1) crcMode[1]       (* 01H for CRC 00H for Checksum *)
+                     fill[87]         (* zeroed *)
+                     Checksum         (* error detect/correction code *)
+
+    *1 -  Note that the crcMode is always set to 01H in current implementations
+          as all TeLink/XMODEM implementations use the CRC method.  Therefore,
+          it is always set to 01H by the sender, and is ignored by the receiver.
+
+    *2 -  CreationDate and CreationTime are MS-DOS format as follows:
+
+      CreationDate = year[.7]         (* 7 bits, years since 1980, 0-127  *)
+                     month[.4]        (* 4 bits, month of year, 1-12 *)
+                     day[.5]          (* 5 bits, day of month, 1-31 *)
+
+      CreationTime = hour[.5]         (* 5 bits, hour of day, 0-23 *)
+                     minute[.6]       (* 6 bits, minute of hour, 0-60 *)
+                     biSeconds[.2]    (* 6 bits, seconds/2, 0-29 *)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            17
+    Data Description Language definition of the block types added by this
+    extended protocol specification:
+
+     SEALinkBlock  = SOH              (* File Info Header *)
+                     00H              (* block no, must be first block *)
+                     FFH              (* one's complement of block no *)
+                     fileLength[4]    (* length of data in bytes *)
+              (*1)   Creation[4]      (* Seconds since 1979 file last chgd *)
+                     fileName(17)     (* name of file, not vol or dir *)
+                     sendingProg(15)  (* name of program on send side *)
+                     SLO[1]           (* 01H for Overdrive supported *)
+                     RESYNC[1]        (* 01H for file Restart supported *)
+                     MACFLOW[1]       (* 01H for Macintosh flow supported *)
+                     fill[85]         (* zeroed *)
+                     CRC              (* error detect/correction code *)
+
+    *1 - Creation is a long integer number of seconds since January 1, 1979.
+
+     SEAlinkACK    = ACK              (* indicator data block received ok *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+
+     SEAlinkNAK    = NAK              (* indicator block not received ok *)
+                     blockNumber[1]   (* sequence, i'=mod( i+1, 256 ) *)
+                     blockCompl[1]    (* one's complement of blockNumber *)
+
+     ReSyncBlock   = SYN              (* File Restart Position *)
+                (*1) RestartBlock<20> (* ASCII decimal file block # *)
+                     ETX              (* End of block number text *)
+                     CRC(rev order)   (* error detection code *)
+
+     *1 - RestartBlock is a text ASCII version of the decimal block number
+          in the file desired.  Note:  The first block of the file is block 1.
+
+
+    Definitions of Single byte Character values used in protocol:
+
+      ACK          = 06H              (* acknowledge data received ok *)
+      NAK          = 15H              (* negative ACK & poll 1st block *)
+      SOH          = 01H              (* start of header, begins block *)
+      SYN          = 16H              (* start of TeLink file info blk *)
+      EOT          = 04H              (* end of xfer, after last block *)
+      ETX          = 03H              (* end of RESYNC request data field*)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            18
+    Block Verification calculated values used by this protocol:
+
+      CRC          = crc[2]           (* CCITT Cyclic Redundancy Check *)
+
+      Checksum     = checksum[1]      (* low 8 bits of sum of data bytes
+                                         using unsigned 8 bit arithmetic *)
+
+    Calculating Checksum
+    --------------------
+
+    For blocks which use a checksum to do error detection, the checksum is
+    calculated by initializing an accumulator to zero and doing successive
+    addition of each character in the data field.  Carry is discarded on
+    each addition.  The resulting 8 bit value is the checksum.
+
+    Calculating CRC
+    ---------------
+
+    For blocks which use CRC to do error detection, the CRC is calculated
+    using the CCITT V.41 generator polynomial.  An accumulator is initialized
+    to zero, and then each character of the data field is processed by the
+    CRC generator polynomial.  This process can be quite complex to explain,
+    but is not so complex in practice.  The following CRC routine is
+    given here as an aid to understanding the CRC generation process.
+
+    8086 assembler routine to implement CCITT V.41 CRC algorithm
+    ;---------------------------------------------------------------+
+    ;       CRCUPD - Update CRC value from character in AL          |
+    ;                                                               |
+    ;  CRC is calculated using the CCITT V.41 generator polynomial. |
+    ;    That polynomial is: X^16 + X^12 + X^5 + 1 (X^0)            |
+    ;                                                               |
+    ;  As an aid to understanding, remember that XOR is bitwise     |
+    ;    addition without carry.                                    |
+    ;---------------------------------------------------------------+
+    CRCVAL  DW      0                   ;16 bit CRC accumulator
+    ;
+    CRCUPD: PUSH    AX                  ;All registers preserved
+            PUSH    CX
+            PUSH    DX
+            MOV     DX,[CRCVAL]
+            XOR     DH,AL               ;init X^16 term
+            XOR     DL,DL
+            MOV     CX,8
+    CRCUP1: SHL     DX,1
+            JNC     CRCUP2
+            XOR     DX,1021h            ;X^12 + X^5 + 1
+    CRCUP2: LOOP    CRCUP1
+            XOR     DH,BYTE PTR[CRCVAL] ;finish X^16 term
+            MOV     [CRCVAL],DX         ;update CRC accumulator
+            POP     DX
+            POP     CX
+            POP     AX
+            RET
+
+
+
+
+
+
+
+
+
+
+
+                                                                            19
+ 2. Data Link Layer Protocol : XMODEM/TeLink/SEAlink Finite State Machines
+
+    The protocol is receiver driven, the receiver polling the sender for
+    each block.  If the receiver polls for the first block using a "C"
+    (43H) as  the poll character, it would prefer to have the CRC-CCITT V.41
+    polynomial remainder error detection code at the end of each block as
+    opposed to a one byte unsigned checksum.  The sender will respond to
+    the "C" poll if it can  comply. If the sender chooses checksum as
+    opposed to CRC, it waits for the receiver to poll with  NAK (15H).
+    Should the checksum method be preferable to the receiver, it polls
+    with NAK rather than "C".
+
+    The sender returns an EOT instead of a data block when no data remain.
+
+    With this extended implementation, the sender and the receiver may send
+    blocks or ACK/NAK responses while there is data being received, once the
+    SEAlink protocol has been negotiated.  This full duplex operation allows
+    the throughput gains of a sliding window protocol.  When SEAlink is not
+    set the window size of 1 prohibits data being sent at the same time and
+    restores the attributes of a standard XMODEM protocol.
+
+    ------------------
+    In this extended protocol, the FTS-0001 single state table
+    "XMODEM Sender" is replaced by two state tables.
+
+    The top level table is equivalent to the FTS-0001 XMODEM Sender table.
+    It in turn calls the new state table named "Transmitter ACK/NAK Check"
+    which implements the full duplex adaptive SEAlink/XMODEM dynamic switching
+    along with the Overdrive and file Restart sending features of the extended
+    protocol.
+
+    -----------------
+    In this extended protocol, the FTS-0001 single state table
+    "XMODEM Receiver" is replaced by three state tables.
+
+    The top level table is equivalent to the FTS-0001 XMODEM Receiver table.
+    It in turn calls the two new state tables named "Send NAK" and "Send ACK"
+    which implement the full duplex adaptive SEAlink/TeLink/XMODEM dynamic
+    switching along with the Overdrive and file Restart receiving features of
+    the extended protocol.
+
+
+    Caution!!!!
+    -----------
+    Many current implementations keep file block numbers as 16 bit numbers.
+    This limits the max file size to either 4 megabytes (if number is signed)
+    or 8 megabytes (if number is unsigned).  To handle files up to the maximum
+    size DOS allows (4 gigabytes) at least 25 bits plus sign are required for
+    these numbers.  Good practice is to make file block numbers 32 bit values.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            20
+    XMODEM/TeLink/SEAlink - Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS0 | XmtStart |  Normal Entry Point     | reset SEAlink flag,     | XS1 |
+    |     |          |  for file send          |   SendBLK=1, ACKST=0,   |     |
+    |     |          |                         |   ACKBLK= -1, WINDOW=1, |     |
+    |     |          |                         |   ACKs Rcvd=0,          |     |
+    |     |          |                         |   NumNAK=0,             |     |
+    |     |          |                         |   T1=30 seconds,        |     |
+    |     |          |                    (*1) |   Build SEAlink hdr blk |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS0T| XmTeStrt |  Alternate entry from   | reset SEAlink flag,     | XS1 |
+    |     |          |  Batch Send if TeLink   |   SendBLK=1, ACKST=0,   |     |
+    |     |          |  mode send required     |   ACKBLK= -1, WINDOW=1, |     |
+    |     |          |                         |   ACKs Rcvd=0,          |     |
+    |     |          |                         |   NumNAK=0,             |     |
+    |     |          |                         |   T1=30 seconds,        |     |
+    |     |          |                         |   Build TeLink hdr blk  |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XS1 | CheckACK |                         | (Check ACK/NAK AC0)     | XS2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XS2 | SendBlk  |1| NumNAK > 4 &          | If header = SEAlink     | XS0T|
+    |     |   (*2)   | |   SendBLK = 0         +-------------------------+-----+
+    |     |          | |                       | If header = TeLink,     | XS2 |
+    |     |          | |                       |   NumNAK = 0,           |     |
+    |     |          | |                       |   Incr ACKBLK,          |     |
+    |     |          | |                       |   Incr SendBLK          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NumNAK > 10           | report too many errors  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Timer T1 expired      | report fatal timeout    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| SendBLK > Last Blk+1  |                         | XS3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| SendBLK >ACKBLK+Window|                         | XS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| SendBLK = Last Blk+1  | Send EOT, Incr SendBLK, | XS1 |
+    |     |          | |                       |   Set T1 to 30 seconds  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| SLO set & SEAlink set | Send SendBLK, (*3)      | XS1 |
+    |     |          | |                       |   ACKBLK = SendBLK,     |     |
+    |     |          | |                       |   Incr SendBLK,         |     |
+    |     |          | |                       |   Set T1 to 60 seconds  |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |8| SLO reset or          | Send SendBLK, (*3)      | XS1 |
+    |     |          | |     SEAlink reset     |   Incr SendBLK,         |     |
+    |     |          | |                       |   Set T1 to 30 seconds  |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XS3 | WaitEnd  |1| ACKBLK < Last Blk+1   |                         | XS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKBLK = Last Blk+1   | report send success     | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - Build SEAlink Header block with RESYNC set.  Set SLO if line speed >
+         2400 bps, reset SLO otherwise.
+
+    *2 - State (XS2.1) allows the receiver to refuse one or both header blocks.
+
+    *3 - If SendBLK = 0, then send the SEAlink (or TeLink) header block.
+         If SendBLK > 0, send the corresponding 128 byte file data block where
+                         block #1 begins with the first byte of the file.
+
+                                                                            21
+    XMODEM/TeLink/SEAlink - Transmitter ACK/NAK Check
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC0 | ChkRcvd  |1| No character waiting  |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Character waiting     | Read character to CHR   | AC1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC1 | SLCheck  |1| ACKST > 2             |                         | AC2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKST <=2             |                         | AC6 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC2 | SLVerify |1| ARBLK8 = 1's comp(CHR)| ARBLK = SendBLK -       | AC3 |
+    |     |          | |                       | ((SendBLK-ARBLK8)&0FFh) |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ARBLK8 # 1's comp(CHR)| Reset SEAlink flag,     | AC6 |
+    |     |          | |                       |   WINDOW=1,             |     |
+    |     |          | |                       |   ACKST=0               |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC3 | SLACKNAK |1| ARBLK not valid (*1)  |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKST = 3             | Set SEALink flag,       | AC5 |
+    |     |     (*2) | |                       |   WINDOW = 6,           |     |
+    |     |          | |                       |   ACKBLK = ARBLK,       |     |
+    |     |          | |                       |   Incr ACKs Rcvd,       |     |
+    |     |          | |                       |   ACKST=0               |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKST = 4             | SendBLK = ARBLK,        | AC4 |
+    |     |          | |                       |   ACKST=0               |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC4 | XMCheck  |1| NumNAK < 4            | Set SEAlink Flag,       | exit|
+    |     |          | |                       |   WINDOW = 6            |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NumNAK >= 4           | Reset SEAlink flag,     | exit|
+    |     |          | |                       |   WINDOW = 1            |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC5 | SLOCheck |1| SLO Reset             |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACKs Rcvd < 10        |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKs Rcvd >= 10       | Reset SLO               | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC6 | SL1Check |1| ACKST = 1 or 2        | ARBLK8 = CHR,           | AC6 |
+    |     |          | |                       |   ACKST = ACKST+2       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         |                         | AC7 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| ACKST = 0             |                         | AC7 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| ACKST > 2             |                         | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+                            (Continued on next page)
+
+    *1 - ARBLK is valid only if all of the following are true:
+
+         a. ARBLK >= 0
+         b. ARBLK <= SendBLK
+         c. ARBLK >  SendBLK-128
+
+    *2 - Software error if ACKST is not 3 or 4 in state AC3
+
+
+                                                                            22
+    XMODEM/TeLink/SEAlink - Transmitter ACK/NAK Check
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC7 | ACKNAK   |1| CHR = ACK             | ACKST = 1               | AC8 |
+    |     |          | |                       |   NumNAK = 0            |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| CHR = NAK or 'C'      | Set CRC/Chksm if 1st,   | AC9 |
+    |     |     (*1) | |                       |   ACKST = 2,            |     |
+    |     |          | |                       |   Incr NumNAK,          |     |
+    |     |          | |                       |   Delay 0.6 seconds     |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*1) |3| CHR = SYN             | Receive RESYNC packet,  | AC10|
+    |     |          | |                       |   ACKST = 0             |     |
+    |     |     (*2) +-+-----------------------+-------------------------+-----+
+    |     |          |4| CHR = other           |                         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC8 | XMACK    |1| SEAlink set           |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         | Incr ACKBLK             | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC9 | XMNAK    |1| SEAlink set           |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink reset         | SendBLK = ACKBLK+1      | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | AC10| RESYNC   |1| RESYNC pkt invalid    | Send NAK                | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| RESYNC pkt valid      | Set SEAlink flag,       | exit|
+    |     |          | |                       |   WINDOW = 6,           |     |
+    |     |          | |                       |   SendBLK = RESYNC Blk#,|     |
+    |     |          | |                       |   ACKBLK = SendBLK-1,   |     |
+    |     |          | |                       |   Send ACK              |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - If the output is buffered in local computer memory, any characters
+         which remain in the local buffer should be purged before leaving
+         states (AC7.2) or (AC7.3) to aid in resynchronizing the link.
+
+    *2 - If the implementation is honoring MACFLOW protocol, set the flag in
+         the SEAlink header block and add the following state to (AC7):
+
+    .-----+--------+---+-----------------------+-------------------------+-----.
+    | AC7 |        |3.5| CHR = ^S (13H) &      | Delay 10 seconds or     | exit|
+    |     |        |   |   SEAlink set &       |   until ^Q (11H) rcvd   |     |
+    |     |        |   |   ACKST = 0           |                         |     |
+    `-----+--------+---+-----------------------+-------------------------+-----'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                                            23
+    XMODEM/TeLink/SEAlink - Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR0 | RecInit  |                         | reset SEAlink flag,     | XR1 |
+    |     |          |                         |   reset SLO flag,       |     |
+    |     |          |                         |   reset RESYNC flag,    |     |
+    |     |          |                         |   set CRC flag,         |     |
+    |     |          |                         |   set blocknum=0,       |     |
+    |     |          |                         |   set WriteBLK=1,       |     |
+    |     |          |                         |   reset retry cnt       |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR0B| BrecInit |  Alternate Entry from   | reset SEAlink flag,     | XR2 |
+    |     |          |  Batch Receive (BR4.2)  |   reset SLO flag,       |     |
+    |     |          |  or (BR4.3)             |   reset RESYNC flag,    |     |
+    |     |          |                         |   set CRC flag,         |     |
+    |     |          |                         |   set blocknum=0,       |     |
+    |     |          |                         |   set WriteBLK=1,       |     |
+    |     |          |                         |   reset retry cnt       |     |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | XR1 | RecStart |                         | (Send NAK SN0)          | XR2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR2 | WaitFirst|1| 10 retries or 1 minute| report receive failure  | exit|
+    |     |          | |   w/o valid input     |                         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| > 3 retries or 30 secs| reset CRC flag          | XR1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| EOT received          | (Send ACK SA0),         | exit|
+    |     |          | |                       |   report no file        |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*1) |4| TeLink block recd     | (Send ACK SA0),         | XR3 |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*2) |5| SEAlink block recd    | set SEAlink,            | XR4 |
+    |     |          | |                       |   set RESYNC as         |     |
+    |     |          | |                       |   indicated by header   |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |     (*3) |6| XMODEM data block 1   | Write block to file,    | XR3 |
+    |     |          | |   received            |   Incr WriteBLK,        |     |
+    |     |          | |                       |   Incr blocknum,        |     |
+    |     |          | |                       |   (Send ACK SA0),       |     |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| bad block or 2-10 secs| incr retry count        | XR1 |
+    |     |          | |   without input       |                         |     |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+                              (Continued on next page)
+
+    *1 - A TeLink header packet has the standard XMODEM data block format except
+         that it begins with an SYN instead of an SOH character and has a block
+         number of 0.  Note: SEAdog (through version 4.51b) does not possess
+         (XR2.4) and therefore will consider a TeLink header a bad block and
+         process it according to (XR2.7) when communicating with mailers which
+         do not do SEAlink protocol.
+
+    *2 - A SEAlink header packet has the standard XMODEM data block format
+    *3   except that is has a block number of 0. The first block is an XMODEM
+         data block if its block number is not 0.
+
+
+
+
+                                                                            24
+    XMODEM/TeLink/SEAlink - Receiver (cont.)
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR3 | WaitBlock|1| 10 retries or 1 minute| report receive failure  | exit|
+    |     |          | |   w/o expected block  |                         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| EOT received          | reset SLO flag,         | exit|
+    |     |          | |                       |   (Send ACK SA0)        |     |
+    |     |          | |                       |   report recd ok        | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| expected data         | Decrement blocknum,     | XR3 |
+    |     |          | |   block-1 received    |   (Send ACK SA0)        |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| expected data         | Write block to file,    | XR3 |
+    |     |          | |   block received      |   Incr WriteBLK,        |     |
+    |     |          | |                       |   (Send ACK SA0),       |     |
+    |     |          | |                       |   reset retry cnt       |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| SEAlink set &         | Discard block - resync  | XR3 |
+    |     |          | |   expected block+1 to |   in progress,          |     |
+    |     |          | |   expected block+127  | Send Conditional NAK(*5)|     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| bad block or 2-10 secs| (Send NAK SN0),         | XR3 |
+    |     |          | |   without input       |   incr retry cnt        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR4 | Restart  |1| Want entire file      | (Send ACK SA0),         | XR5 |
+    |     |          | |   or RESYNC not set   | reset retry cnt         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Want to resume an     |  WriteBLK = file restart| XR5 |
+    |     |          | |   interrupted xfer    |    block number,        |     |
+    |     |          | |   and RESYNC is set   |  blocknum=WriteBLK&0FFh,|     |
+    |     |          | |                       |    (Send NAK SN0)       |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | XR5 | SetOvrdr |                         | Set SLO as indicated    | XR3 |
+    |     |          |                         |   by SEAlink header     |     |
+    `-----+----------+-------------------------+-------------------------+-----'
+    Note: The routine that receives a header/data block should do the following:
+
+    1. Report a bad block if the checksum or CRC is not correct or if the
+       physical layer encounters errors (e.g. parity, framing, etc.) regardless
+       of checksum or CRC.  Report a bad block if the length of the block is
+       less than expected (Use a 5 second timeout to detect short blocks).
+    2. If the block's sequence number does not match the complement, then
+       report a bad block if not in SEAlink. If in SEAlink mode don't report
+       this as a bad block, just restart the block search looking for SOH.
+       Check for SOH, BLK, ~BLK characters in a "sliding" fashion and keep
+       cycling until a valid start of block (or timeout) is detected before
+       assembling the remainder of the block.  This procedure makes a resync
+       occur much more rapidly, and with far fewer errors reported.
+    3. If the sequence number and block are good but not the expected number,
+       report state (XR3.3) if previous block.  If not in SEAlink, abort on any
+       other out of sequence block.  If in SEAlink, report back state (XR3.5)
+       or (XR3.6) as indicated by the out of sequence received block number.
+    4. If an EOT is received on a data block prior to the filesize specified
+       in the SEAlink or TeLink header block, a NAK should be issued to ensure
+       that spurious data did not cause a premature EOF.  A NAK should also
+       be issued for the first EOT received in an Xmodem transfer when the
+       final file size is not known.  A second EOT without intervening data
+       would ensure that the file really has been sent, and should be ACK'd.
+    5. If you last sent an ACK, then send a NAK here.  If you last sent a NAK
+       then only NAK evry 32 blocks after the first NAK.  This allows buffer
+       drain in overdrive.  Use (Send NAK SN0) to send the NAK.
+                                                                            25
+    XMODEM/TeLink/SEAlink - Send NAK
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN0 | ClearLine|1| RESYNC flag set       | Send RESYNC packet      | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      |                         | SN1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| > 30 sec contin data  | report failure          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| character waiting     | eat character           | SN0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| clear line            |                         | SN1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN1 | SendNAK  |1| CRC flag set          | Send "C"                | SN2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| CRC flag reset        | send NAK                | SN2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN2 | SEAlink  |1| SEAlink flag reset    |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      | send blocknum, ~blocknum| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SN3 | AckResync|1| Rcv ACK               |                         | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv NAK               | Resend RESYNC packet    | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv Other Char        | eat character           | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| No char for 10 secs   | Resend RESYNC packet    | SN3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 30 seconds in SN3     |                         | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Note: RESYNC packet should send WriteBLK as its desired block number.
+
+
+    XMODEM/TeLink/SEAlink - Send ACK
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA0 | ClearLine|1| SLO flag set          |                         | SA3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      |                         | SA1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| > 30 sec contin data  | report failure          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| character waiting     | eat character           | SA0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| No char waiting       |                         | SA1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA1 | SendACK  |                         | Send ACK                | SA2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA2 | SEAlink  |1| SEAlink flag reset    |                         | SA3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| SEAlink flag set      | send blocknum, ~blocknum| SA3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SA3 | IncBlk   |                         | Incr blocknum           | exit|
+    `-----+----------+-------------------------+-------------------------+-----'
+
+
+
+
+                                                                            26
+ 3. Data Link Layer Protocol : MODEM7 Filename Finite State Machines
+    (There is no change to the MODEM7 state tables from FTS-0001).
+
+    MODEM7 Filename Sender
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS0 | WaitNak  |1| 20 retries or 1 minute| filename send failed    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| NAK received          | send ACK & 1st ch of fn | MS1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS1 | WaitChAck|1| ACK rcd, fname done   | send SUB = 1AH          | MS2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ACK rcd, fname ~done  | send next ch of fname   | MS1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| other char or 1 sec   | send "u", incr retry cnt| MS0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MS2 | WaitCksm |1| cksum recd and ok     | send ACK, report fn ok  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| cksum recd but bad    | send "u", incr retry cnt| MS0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| no cksum in 1 sec     | send "u", incr retry cnt| MS0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+    MODEM7 Filename Receiver
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR0 | SendNak  |1| 20 tries or 1 minute  | report filename failure | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2|                       | send NAK, incr try cnt  | MR1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR1 | WaitAck  |1| rcd ACK               |                         | MR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| rcd EOT               | report no files remain  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 5 secs & no ACK/EOT   |                         | MR0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR2 | WaitChar |1| recd EOT (can happen?)| report no files remain  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| recd SUB              | send checksum byte      | MR3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| recd "u"              |                         | MR0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| recd char of name     | send ACK                | MR2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| no char in 1 second   |                         | MR0 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | MR3 | WaitOkCk |1| recd ACK within 1 sec | report recd filename ok | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| recd "u" or other char|                         | MR0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    SUB  is the ASCII character ^Z or 1AH.  The checksum is the unsigned low
+    order eight bits of the sum of the characters in the transferred filename
+    including the SUB.
+
+    Although 1 second timeouts are used successfully by Fido and SEAdog, some
+    fear that this is too small a value for some satellite and packet networks.
+
+                                                                            27
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0008.html b/html/ftsc/fts-0008.html new file mode 100755 index 00000000..f0fdccf8 --- /dev/null +++ b/html/ftsc/fts-0008.html @@ -0,0 +1,485 @@ + + +Bark file-request protocol extension. + + + + +
+Document: FTS-0008
+Version:  003
+Date:     15-Oct-1990
+Updates:  FTS-0001
+
+
+
+                  An Enhanced FidoNet(r) Technical Standard
+                 Extending FTS-0001 to include Bark requests
+
+                            October 15, 1990
+
+
+
+
+Status of this document:
+
+    This document specifies an optional standard for the FidoNet community.
+    Implementation of the protocols defined in this document is not mandatory,
+    but all implementations of these protocols are expected to adhere to this
+    standard.  Distribution of this document is subject to the limitations of
+    the copyright notice displayed below.
+
+
+    Copyright 1989-90 by Philip L. Becker.  Portions of this document are
+    copyright 1986-90 by Randy Bush and are incorporated with his consent.
+    All rights reserved.  A right to distribute only without modification and
+    only at no charge is granted.  Under no circumstances is this document to
+    be reproduced or distributed as part of or packaged with any product or
+    other sales transaction for which any fee is charged.  Any and all other
+    reproduction or excerpting requires the explicit written consent of the
+    copyright holders.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A. Introduction
+
+ 1. This Document
+
+    This document describes the standard for "Bark" type FidoNet file
+    request operation.  Bark file requests are an extension to the basic
+    FTS-0001 mail session, and this document presents these requests as a
+    modification to that document.
+
+ 2. What are File Requests?
+
+    File Requests are a way of requesting that a specific file be sent during
+    a FidoNet mail session.  This has many advantages over simply logging on to
+    a BBS and downloading a file:
+
+       o  You need not be a validated user
+
+       o  You don't have to spend time searching for the file on the BBS
+
+       o  You can schedule the file request to take place at any time without
+          your being near your computer.
+
+    There are two commonly used types of file requests on FidoNet today, WaZOO
+    and Bark requests.  WaZOO requests are used by Opus and BinkleyTerm, and
+    are not documented here.  See the document FTS-0006 by V. Perriello for a
+    description of these.   Bark requests were the first file request extension
+    to the FTS-0001 protocol, and are supported (at least partially) by many
+    mailers, including SEAdog, Dutchie, BinkleyTerm, and to a certain extent
+    Opus.  This document describes how to implement Bark-type file requests.
+
+
+ B. Terms Used in this Document
+
+ 1. The diagrams and notations used in this document are the same as those used
+    in the FTS-0001 document.  Please see FTS-0001 for a description of these.
+    This document should be considered as an extension to the FTS-0001 session
+    layer protocol, and you will require FTS-0001 in addition to this document
+    to fully understand what is presented here.
+  
+    In addition to the data description language described in FTS-0001 section
+    A.4, one extra terminal used in this notation:
+  
+    (* terminals *)
+    someName - String of up to max chars, NOT null terminated
+ C. Performing File Requests
+
+ 1. Introduction
+
+    A Bark request consists of transmitting a special Bark Request packet which
+    contains a filename, a date (used for update requests), and optionally a
+    password.  The system receiving the request then decides if it can send the
+    requested file or not, and if it can does so using the same protocol used
+    to send attached files.  Bark request handling is always controlled by the
+    answering system, and consists of two phases.  In phase one, the receiving
+    system asks the calling system to honor requests it may have to ask for
+    files from the caller.  In phase two, the receiving system allows the
+    calling system to request files from it.
+
+    Update file requests are the same as normal file requests, with one
+    exception.  If the date in the Bark Request packet (described below) is
+    greater than or equal to the date of the actual file requested, the file
+    will not be sent.  The requestor should set the date to the date of the
+    the actual file on its own end if an update request is desired.
+
+
+ D. The Bark Request Packet
+
+ 1. Data Link Layer Data Definition.
+ 
+    The Bark Request packet is a variable-sized packet containing a header, a
+    filename, a date (which is used only for update requests - in a normal file
+    request it's 0) and an optional password. When receiving a Bark Request
+    packet, the ETX may be used to determine the end of the data portion. Note
+    that the CRC is sent in the reverse byte order of a normal CRC XMODEM data
+    block (see FTS-0001 section G.1).
+
+    Note: some systems will send a password in the data block even if none is
+    needed.  Incoming passwords should be ignored unless the other system is
+    trying to request a passworded file.
+
+  
+
+                          Bark File Request Packet
+      Offset
+      dec hex
+              .-----------------------------------------------.
+        0   0 |       ACK - Start of Bark Request - 06H       |
+              +-----------------------------------------------+
+        1   1 |     Filename - Packed DOS file format         |
+              +-----------------------------------------------+
+        n   n |              SPACE - 20H                      |
+              +-----------------------------------------------+
+        n   n |              Date (0 if not Update Request)   |
+              +-----------------------------------------------+
+        n   n |      SPACE - 20H  (only if pswd follows)      |
+              +-----------------------------------------------+
+        n   n |         Password (optional)                   |
+              +-----------------------------------------------+
+        n   n |       ETX -  End of RESYNC packet  - 03H      |
+              +-----------------------------------------------+
+        n   n |     (*1)     CRC  low order byte              |
+              +-----------------------------------------------+
+        n   n |     (*1)     CRC high order byte              |
+              `-----------------------------------------------'
+
+              *1 - CRC does not include the ACK or ETX and is
+                   in the reverse byte order from the CRC in a
+                   normal XMODEM data packet.
+ 2. Data Description Notation of Bark Request Packet
+
+    DataBlock (no password) = ACK
+                              Filename<12>
+                              Space
+                              Date<11>
+                              ETX
+                              CRC
+  
+    DataBlock (with password) = ACK
+                                Filename<12>
+                                Space
+                                Date<11>
+                                Space
+                                Password<6|8>
+                                ETX
+                                CRC
+  
+    ACK   = 06H       (* Header for file request block *)
+    Space = 20H       (* Space character *)
+    ETX   = 03H       (* End of block *)
+  
+    Filename          (* Name of file requested *)
+    Date              (* ASCII string; the number of seconds
+                         since midnight, January 1, 1970 *)
+    Password          (* The password needed to request this
+                         file, if any.  Maximum length is 6 for
+                         BinkleyTerm and Opus, 8 for SEAdog
+                         and Dutchie. *)
+  
+    CRC = crc[2]      (* CCITT Cyclic Redundancy Check.  The
+                         same algorithm as used for XModem
+                         CRCs.  The CRC is calculated on
+                         all data in the block between but
+                         not including the ACK and the ETX *)
+ E. Session Layer Protocol:
+
+    This section describes the modified FTS-0001 session layer protocol.  This
+    is the only area of FTS-0001 which is modified to implement Bark style file
+    requests.  File Requests are performed at the end of the normal FidoNet
+    mail session, after any mail pickup is performed.
+
+    The diagrams below desribe the session level protocol with Bark file
+    requests implemented.  The state tables have been broken into subroutines
+    but the FTS-0001 portion is not functionally changed.  FTS-0001 sender
+    states S4 through S7 are now table "Send Mail SM0".  FTS-0001 receiver
+    states R3 through R6 are now table "Receive Mail RM0".  They are not
+    functionally changed in any way from FTS-0001, they are just broken out
+    to allow them to be used as subroutines.  Finally Sender states S0 through
+    S3 are unchanged, as are Receiver states R0 through R2.
+
+    The remaining FTS-0001 states are enhanced to implement the Bark file
+    request protocol. In addition, the subroutine state tables "Send Bark SB0"
+    and "Receive Bark RB0" have been added to handle the actual file requests.
+ 
+    The following diagrams fully replace the Session Layer protocol state
+    tables in FTS-0001.  No other changes to FTS-0001 are required to implement
+    the Bark File request feature.
+    Sender  (Top level)
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | S0  | SendInit |                         | dial modem              | S1  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S1  | WaitCxD  |1| carrier detected      | delay 1-5 seconds       | S2  |
+    |     |  (*1)    | |                       | Set SLO if > 2400bps,   |     |
+    |     |          | |                       | Reset SLO if <= 2400bps |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| busy, etc.            | report no connection    | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| voice                 | report no carrier       | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| carrier not detected  | report no connection    | exit|
+    |     |          | | within 60 seconds     |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S2  | WhackCRs |1| over 30 seconds       | report no response  | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| ?? s received     | delay 1 sec             | S3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| s not received    | send    | S2  |
+    |     |          | |                       |   delay ??? secs        |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S3  | WaitClear|1| no input for 0.5 secs | send TSYNCH = AEH       | S4  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| over 60 seconds       | hang up, report garbage | exit|
+    |     |          | | and line not clear    |                         |     |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S4  | SendMail |                         | (Send Mail SM0)         | S5  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | S5  | TryPickup|1| Rcv TSYNC             | (Receive Mail RM0)      | S5  |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv SYN               | (Receive Bark Req RB0)  | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv ENQ               | (Do Bark Requests SB0)  | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Rcv 'C' or NAK        | Send EOT                | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| Rcv Other Char        | Send SUB                | S5  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| No Data for 45 secs   | Hang Up                 | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+    *1 - This state is shown for the extended SEAlink protocol.  Omit the
+         set/reset SLO actions if adding Bark to a strict FTS-0001 protocol
+         implementation, or if not implementing overdrive in SEAdog.
+   
+    *2 - To refuse to pickup mail (S5.1) may send a CAN and stay in (S5).
+
+    Note: Although the above shows the sender emitting only one TSYNCH, it is
+    recommended that a timeout of 5-20 seconds should initiate another TSYNCH.
+    The receiver should tolerate multiple TSYNCHs.
+    Receiver (Top Level)
+
+    The  receiving FSM is given  an external timer, the expiration of  which
+    will cause termination with a result of 'no calls' (R0.2).
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R0  | WaitCxD  |1| carrier detected      |                         | R1  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| external timer expires| report no calls         | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R1  | WaitBaud |1| baud rate detected    | send signon with s  | R2  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| no detect in ?? secs  | hang up, report no baud | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R2  | WaitTsync|1| TSYNCH received       | ignore input not TSYNCH | R3  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| 60 seconds timeout    | hang up, report not Fido| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R3  | RecMail  |                         | (Receive Mail RM0)      | R4  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R4  | AllowPkup|1| Have pickup for sender| Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No pickup for sender  |                         | R6  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R5  | WtPickup |1| Rcv NAK or 'C'        | (Send Mail SM0)         | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv SUB               | Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv CAN               | Report Mail Refused     | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| T1 expired            | Send Tsync,             | R5  |
+    |     |          | |                       |   Set T1=1 sec          |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 45 secs in R5         | Hang Up, report error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R6  | AskBark  |1| Wish to make requests | Send SYN                | R7  |
+    |     |   (*1)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| No requests to make   |                         | R8  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R7  | DoRequest|1| Rcv CAN               | Report Requests Refused | R8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv ENQ               | (Send Bark SB0)         | R8  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv SUB               | Send SYN                | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| Rcv NAK or 'C'        | Send EOT                | R6  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| Rcv Other             | eat character           | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |6| 5 sec, no input       | Send SYN                | R7  |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |7| 45 secs in R7         |                         | R8  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | R8  | WtPickup |1| Allow File Request    | (Receive Bark RB0),     | exit|
+    |     |          | |                       |   Hang Up               |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Disallow Requests     | Hang Up                 | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    *1 - Some implementations always do (R6.1) even if they have no requests.
+    Sender - Send Mail
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | SM0 | SendMail |                         | (XMODEM send packet XS0)| SM1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM1 | CheckMail|1| XMODEM successful     | (Fido registers success)| SM2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM fail or timeout| hang up, report mail bad| exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM2 | SendFiles|                         | (BATCH send files BS0)  | SM3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SM3 | CheckFile|1| BATCH send successful | report success          | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH send failed     | hang up, rept files fail| exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+
+    Sender - Send Bark
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB0 | SendBark |1| File to request       | Build Bark Request Pkt, | SB1 |
+    |     |          | |                       |   Set tries = 0         |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No more files to req  | Send ETB                | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB1 | AskFile  |                         | Send Bark Packet        | SB2 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB2 | RcvFile  |1| Rcv ACK               | (Batch Receive BR0)     | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Tries > 5             | Send ETB, report failed | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Rcv Other             | Purge input, Incr tries | SB1 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| 10 sec w/o ACK        | Incr tries              | SB1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | SB3 | NxtFile  |1| Rcv ENQ               |                         | SB0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Rcv Other             | Purge Input             | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 5 sec, no input       | Send SUB                | SB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| 45 sec in SB3         | Hang up, report error   | exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    Sender & Receiver - Receive Mail
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-------------------------+-------------------------+-----+
+    | RM0 | RecMail  |                         | (XMODEM rec packet XR0) | RM1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM1 | XRecEnd  |1| XMODEM successful     | delay 1 second          | RM2 |
+    |     |          | |                       |   flush input           |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| XMODEM failed         | hang up, rept mail fail | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM2 | RecFiles |                         | (BATCH rec files BR0)   | RM3 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RM3 | ChkFiles |1| BATCH recv successful | delay 2 secs, rprt good | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| BATCH recv failed     | hang up, report bad file| exit|
+    `-----+----------+-+-----------------------+-------------------------+-----'
+
+
+    Sender & Receiver - Receive Bark
+
+    .-----+----------+-------------------------+-------------------------+-----.
+    |State| State    | Predicate(s)            | Action(s)               | Next|
+    |  #  | Name     |                         |                         | St  |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB0 | HonorReq |1| Ok to honor request   | Purge Input, Send ENQ,  | RB1 |
+    |     |          | |                       |   Set T1 = 2 seconds    |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Don't wish to honor   | Send CAN                | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB1 | WaitBark |1| Got ACK               | Rcv Bark Packet (*1)    | RB2 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Got ETB               | Report done             | exit|
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| Got ENQ               | Send ETB                | RB0 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |4| T1 expired            | Purge Input, Send ENQ,  | RB1 |
+    |     |          | |                       |   Set T1 = 2 seconds    |     |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |5| 20 seconds in RB1     | Hang Up, Report error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB2 | AckBark  |1| Bark Pkt Rcvd Good    | Send ACK                | RB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| Bark Pkt Rcv Error    | Send NAK                | RB1 |
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB3 | WaitStrt |1| Got 'C' or NAK        |                         | RB4 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |2| No data for 3 seconds | Send ACK                | RB3 |
+    |     |          +-+-----------------------+-------------------------+-----+
+    |     |          |3| 15 seconds in RB3     | Hang Up, Report Error   | exit|
+    +-----+----------+-+-----------------------+-------------------------+-----+
+    | RB4 | SendFile |1| Can snd requested file| (Batch Send File BS0)   | RB0 |
+    |     |   (*2)   +-+-----------------------+-------------------------+-----+
+    |     |          |2| Can't send file       | Send EOT                | RB0 |
+    `-----+----------+-+-----------------------+-------------------------+-----'
+    *1 - If SUB (16H) received before ETX go to RB0 to resync bark receive
+
+    *2 - While deciding if file exists, and if the password allows it to be
+         sent etc., a NUL may be sent to buy 20 seconds more on the timeout
+         on the other end if it is using the SEAlink extended FTS-0001
+         specification protocol.  Sending a NUL is harmless for a strict
+         FTS-0001 session, but will not buy more time.
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-0009.html b/html/ftsc/fts-0009.html new file mode 100755 index 00000000..5bba0b50 --- /dev/null +++ b/html/ftsc/fts-0009.html @@ -0,0 +1,104 @@ + + +Message identification and reply linkage. + + + + +
+Document: FTS-0009
+Version:  001
+Date:     17-Dec-91
+
+
+
+
+                               MSGID / REPLY
+                  A standard for unique message identifiers
+                          and reply chain linkage
+
+                            17 December, 1991
+
+                                 jim nutt
+                             1:114/30@fidonet
+
+
+
+
+Status of this document:
+
+     This FTS (FidoNet(r) Technical Standard) specifies an optional
+     standard for the FidoNet community.  Implementation of the
+     protocols defined in this document is not mandatory,  but all
+     implementations of these protocols are expected to adhere to this
+     standard.  Distribution of this document is unlimited.
+
+     Fido and FidoNet are registered marks of Tom Jennings and Fido
+     Software.
+
+
+MSGID
+
+     A MSGID line consists of the string "^AMSGID:" (where ^A is a
+     control-A (hex 01) and the double-quotes are not part of the
+     string),  followed by a space,  the address of the originating
+     system,  and a serial number unique to that message on the
+     originating system,  i.e.:
+
+          ^AMSGID: origaddr serialno
+
+     The originating address should be specified in a form that
+     constitutes a valid return address for the originating network.   
+     If the originating address is enclosed in double-quotes,  the
+     entire string between the beginning and ending double-quotes is 
+     considered to be the orginating address.  A double-quote character
+     within a quoted address is represented by by two consecutive
+     double-quote characters.  The serial number may be any eight
+     character hexadecimal number,  as long as it is unique - no two
+     messages from a given system may have the same serial number
+     within a three years.  The manner in which this serial number is
+     generated is left to the implementor.
+
+
+REPLY
+
+     A REPLY line consists of the string "^AREPLY:" (where ^A is a
+     control-A (hex 01) and the double-quotes are not part of the
+     string),  followed by a space, and the origaddr and serialno
+     fields of the MSGID line of the message to which this message is a
+     reply,  i.e.:
+
+        ^AREPLY: origaddr serialno
+
+     The origaddr and serialno fields must be identical to the
+     corresponding fields in the MSGID of the message to which this
+     message is a reply.  A REPLY line is never generated in a 
+     message that is a reply to a message that does not contain a
+     MSGID line.
+
+
+GENERAL
+
+     MSGID and REPLY lines should be placed before the text body of the
+     message in which they appear.
+
+     Finally,  a MSGID is generated only at the time of message
+     creation.  An existing MSGID and/or REPLY should never be stripped
+     from a message passing through an intermediate system.  No system
+     should ever add an MSGID and/or REPLY to,  or modify an existing
+     MSGID / REPLY contained in,  a message not originating on that
+     system.
+ 
+
+ +Back Go Back + + + + diff --git a/html/ftsc/fts-4001.html b/html/ftsc/fts-4001.html new file mode 100755 index 00000000..0bc73190 --- /dev/null +++ b/html/ftsc/fts-4001.html @@ -0,0 +1,192 @@ + + +Addessing Control Paragraphs. + + + + +
+**********************************************************************
+FTSC                             FIDONET TECHNICAL STANDARDS COMMITTEE
+**********************************************************************
+
+Publication:    FTS-4001
+Revision:       1
+Title:          ADDRESSING CONTROL PARAGRAPHS
+Author(s):      FTSC
+
+Revision Date:  1 October 2000
+Expiry Date:    1 October 2002
+----------------------------------------------------------------------
+Contents:
+                1. Credits
+                2. General
+                3. FMPT
+                4. TOPT
+                5. INTL
+----------------------------------------------------------------------
+
+Status of this document
+-----------------------
+
+  This document is a Fidonet Standard (FTS).
+
+  This document specifies a Fidonet standard for the Fidonet
+  community.
+
+  This document is released to the public domain, and may be used,
+  copied or modified for any purpose whatever.
+
+
+1. Credits
+----------
+
+  This document is based on the work of Randy Bush and many others.
+
+
+2. General
+----------
+
+  The general control paragraph format is specified in separate FTSC
+  documents.
+
+  The addressing control paragraphs specified in this document are
+  normally only used in netmail messages and not in echomail messages.
+
+  While it would be technically correct to use them also in echomail,
+  it is known that certain programs will misbehave if they are present
+  there. It is therefore recommended that they should not be used in
+  echomail at the present time.
+
+  If a program processing messages detects these control paragraphs in
+  an echomail message it is recommended that they are disregarded and
+  deleted from any copies of that message exported to other systems.
+
+  Addressing of and address resolution for echomail messages should
+  instead be done with the help of packet and message header
+  information. See separate FTSC documents.
+
+  To determine the address of the original sender of an echomail
+  message, the information in the Origin line should be used. See
+  separate FTSC documents.
+
+
+3. FMPT
+-------
+
+  The FMPT control paragraph shall be used to give information about
+  the point number of the original sender of a message if that point
+  number is not 0. If the point number of the original sender of a
+  message is 0 that message should not contain any FMPT control
+  paragraph.
+
+  The format of a FMPT control paragraph shall be:
+
+    <SOH>"FMPT <point number>"<CR>
+
+  where <point number> is the ASCII representation of the point number
+  of the sender. The point number shall be an unsigned integer in the
+  range 1-65535.
+
+  E.g. a message from point number 1 of a certain node shall contain
+  the following FMPT control paragraph
+
+    <SOH>"FMPT 1"<CR>
+
+  Note that the format of a FMPT control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+
+4. TOPT
+-------
+
+  The TOPT control paragraph shall be used to give information about
+  the point number of the ultimate addressee of a message if that
+  point number is not 0. If the point number of the ultimate addressee
+  of a message is 0 that message should not contain any TOPT control
+  paragraph.
+
+  The format of a TOPT control paragraph shall be:
+
+    <SOH>"TOPT "<point number><CR>
+
+  where <point number> is the ASCII representation of the point number
+  of the addressee. The point number shall be an unsigned integer in
+  the range 1-65535.
+
+  E.g. a message to point number 1 of a certain node shall contain the
+  following TOPT control paragraph
+
+    <SOH>"TOPT 1"<CR>
+
+  Note that the format of a TOPT control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+
+5. INTL
+-------
+
+  The INTL control paragraph shall be used to give information about
+  the zone numbers of the original sender and the ultimate addressee
+  of a message.
+
+  The format of an INTL control paragraph shall be:
+
+    <SOH>"INTL "<destination address>" "<origin address><CR>
+
+  where <destination address> shall be the representation of the
+  address of ultimate destination and <origin address> is the
+  representation of the address of the original sender of the message
+  in question. These addresses shall be given on the form
+  <zone>:<net>/<node> where <zone> is the ASCII representation of the
+  zone number, <net> is the ASCII representation of the net number and
+  <node> is the ASCII representation of the node number. Any point
+  number information shall be given in FMPT and TOPT control
+  paragraphs.
+
+  E.g. a message from address 1:123/4.5 to 2:345/6.7 shall contain the
+  following INTL control paragraph
+
+    <SOH>"INTL 2:345/6 1:123/4"<CR>
+
+  Note that the format of an INTL control paragraph deviates from the
+  general format specified in separate FTSC documents in that it does
+  not contain any colon after the control tag.
+
+  INTL control paragraphs are also often used even when both the
+  originating and the destination systems are in the same zone. This
+  gives both the originating system and the destination system as well
+  as any intermediate routing systems unambiguous zone information
+  even in a situation where one system may be active in a number of
+  different (possibly non-FidoNet) zones.
+
+  Although it is known that some programs may route messages
+  incorrectly if the INTL control paragraph is present in messages
+  where both the originating and the destination systems are in the
+  same zone, it is recommended that the INTL control paragraph is
+  always inserted into netmail messages in packet files.
+
+
+
+A. History
+----------
+
+   Rev.1, 20001001: Initial Release.
+                    Principal author Goran Eriksson.
+
+**********************************************************************
+
+ +Back Go Back + + + + diff --git a/html/ftsc/ftscprod.html b/html/ftsc/ftscprod.html new file mode 100755 index 00000000..09161b20 --- /dev/null +++ b/html/ftsc/ftscprod.html @@ -0,0 +1,311 @@ + + +FTSC Product ID List. + + + + +

FTSC Product codes 22 jan 2000

+

+0000,Fido,MS-DOS,Packer/mailer,Tom_Jennings,1:125/111
+0001,Rover,MS-DOS,Packer/mailer,Bob_Hartman,1:104/501
+0002,SEAdog,MS-DOS,Packer/mailer,Thom_Henderson,1:107/542.1
+0003,WinDog,MS-DOS,Mailer,Solar_Wind_Computing,1:115/333
+0004,Slick-150,HP-150,Packer/mailer,Jerry_Bain,????
+0005,Opus,MS-DOS,Packer/mailer,Doug_Boone,1:124/4227
+0006,Dutchie,MS-DOS,Packer/mailer,Henk_Wevers,2:500/1
+0007,WPL_Library,Amiga,Mailer,Russell_McOrmand,1:163/109
+0008,Tabby,Macintosh,Packer/mailer,Michael_Connick,1:107/412
+0009,SWMail,OS/2,Mailer,Solar_Wind_Computing,1:115/333
+000A,Wolf-68k,CPM-68k,Packer/mailer,Robert_Heller,1:321/153
+000B,QMM,QNX,Packer/mailer,Rick_Duff,1:167/201
+000C,FrontDoor,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17
+000D,GOmail,MS-DOS,Packer,Scott_Green,????
+000E,FFGate,MS-DOS,Packer,Ruedi_Kneubuehler,2:301/580
+000F,FileMgr,MS-DOS,Packer,Erik_van_Emmerik,2:281/611
+0010,FIDZERCP,MS-DOS,Packer,Thorsten_Seidel,2:242/55
+0011,MailMan,MS-DOS,Packer,Ron_Bemis,1:124/1113
+0012,OOPS,MS-DOS,Packer,Tom_Kashuba,1:322/379
+0013,GS-Point,Atari_ST,Packer/mailer,Harry_Lee,1:124/4230
+0014,BGMail,????,????,Ray_Gwinn,1:265/104
+0015,ComMotion/2,OS/2,Packer/mailer,Michael_Buenter,2:301/602
+0016,OurBBS_Fidomailer,MS-DOS/Unix/Coherent,Packer/mailer,Brian_Keahl,1:133/524
+0017,FidoPcb,MS-DOS,Packer,Matjaz_Koce,2:380/100
+0018,WimpLink,Archimedes,Packer/mailer,Remco_de_Vreugd,2:283/307
+0019,BinkScan,MS-DOS,Packer,Shawn_Stoddard,1:362/101
+001A,D'Bridge,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68
+001B,BinkleyTerm,MS-DOS,Mailer,Vince_Perriello,1:343/491
+001C,Yankee,MS-DOS,Packer,Randy_Edwards,????
+001D,uuGate,MS-DOS,Packer,Geoff_Watts,3:690/710
+001E,Daisy,Apple_][,Packer/mailer,Raymond_&_Ken_Lo,3:700/1
+001F,Polar_Bear,????,Packer/mailer,Kenneth_McLeod,1:101/190
+0020,The-Box,MS-DOS/Atari_ST,Packer/mailer,Jac_Kersing/Arjen_Lentz,2:283/333
+0021,STARgate/2,OS/2,Packer/mailer,Shawn_Stoddard,1:362/101
+0022,TMail,MS-DOS,Packer,Larry_Lewis,3:713/600.1701
+0023,TCOMMail,MS-DOS,Packer/mailer,Mike_Ratledge,1:372/888
+0024,GIGO,MS-DOS,Packer,Jason_Fesler,1:203/7707,,940228
+0025,RBBSMail,MS-DOS,Packer,Jan_Terpstra,2:512/10
+0026,Apple-Netmail,Apple_][,Packer/mailer,Bill_Fenner,1:129/87
+0027,Chameleon,Amiga,Mailer,Juergen_Hermann,2:241/2.12
+0028,Majik_Board,MS-DOS,Packer/mailer,Dale_Barnes,1:3601/14.20
+0029,QM,MS-DOS,Packer,George_Peace,1:270/101
+002A,Point_And_Click,Amiga,Packer,Rob_Tillotson,1:201/40.302
+002B,Aurora_Three_Bundler,MS-DOS,Packer,Oliver_McDonald,????
+002C,FourDog,MS-DOS,Packer,Shay_Walters,1:376/12
+002D,MSG-PACK,MS-DOS,Packer,Tom_Hendricks,1:261/662
+002E,AMAX,MS-DOS,Packer,Alan_Applegate,1:104/36
+002F,Domain_Communication_System,????,????,Hal_Duprie,1:101/106
+0030,LesRobot,????,Packer,Lennart_Svensonn,2:501/2
+0031,Rose,MS-DOS,Packer/mailer,Glen_Jackson,1:100/617
+0032,Paragon,Amiga,Packer/mailer,Jon_Radoff,1:322/545
+0033,BinkleyTerm/oMMM/ST,Atari_ST,Packer/mailer,Bill_Scull,1:363/112,,19951209
+0034,StarNet,Atari_ST,Mailer,Eric_Drewry,1:322/566
+0035,ZzyZx,MS-DOS,Packer,Jason_Steck,1:124/424
+0036,QEcho,MS-DOS,Packer,The_QuickBBS_Group,1:363/1701
+0037,BOOM,MS-DOS,Packer,Andrew_Farmer,1:243/1
+0038,PBBS,Amiga,Packer/mailer,Todd_Kover,1:261/1028
+0039,TrapDoor,Amiga,Mailer,Maximilian_Hantsch,2:310/6
+003A,Welmat,Amiga,Mailer,Russell_McOrmand,1:163/109
+003B,NetGate,Unix-386,Packer,David_Nugent,3:632/348
+003C,Odie,MS-DOS,Mailer,Matt_Farrenkopf,1:105/376
+003D,Quick_Gimme,CPM-80/MS-DOS,Packer/mailer,Laeeth_Isaacs,2:254/18
+003E,dbLink,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68
+003F,TosScan,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17
+0040,Beagle,MS-DOS,Mailer,Alexander_Holy,2:310/90
+0041,Igor,MS-DOS,Mailer,Harry_Lee,1:124/4230
+0042,TIMS,MS-DOS,Packer/mailer,Bit_Bucket_Software,1:104/501
+0043,Phoenix,MS-DOS,Packer/mailer,International_Telecommunications,1:296/5,,19930624
+0044,FrontDoor_APX,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17
+0045,XRS,MS-DOS,Packer,Mike_Ratledge,1:372/888
+0046,Juliet_Mail_System,Amiga,Packer,Gregory_Kritsch,1:163/109.30
+0047,Jabberwocky,Macintosh,Packer,Eric_Larson,1:2605/620
+0048,XST,MS-DOS,Packer,Wayne_Michaels,1:380/100
+0049,MailStorm,Amiga,Packer,Russel_Miranda,1:268/106
+004A,BIX-Mail,????,Mailer,Bob_Hartman,1:104/501
+004B,IMAIL,MS-DOS,Packer,IMAIL_INC.,2:246/47
+004C,FTNGate,MS-DOS,Packer,Jason_Steck,1:104/424
+004D,RealMail,MS-DOS,Packer,Taine_Gilliam,1:372/42
+004E,Lora-CBIS,MS-DOS,Mailer,Marco_Maccaferri,2:332/402
+004F,TDCS,PDP-11,Packer/mailer,Terry_Ebdon,2:254/6
+0050,InterMail,MS-DOS,Packer/mailer,Peter_Stewart,1:369/35
+0051,RFD,MS-DOS,Packer,Doug_Belkofer,1:234/10
+0052,Yuppie!,MS-DOS,Packer,Leo_Moll,2:242/2
+0053,EMMA,MS-DOS,Packer,Johan_Zwiekhorst,2:292/100
+0054,QBoxMail,QDOS,Packer/mailer,Jan_Bredenbeek,2:283/500
+0055,Number_4,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15
+0056,Number_5,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15
+0057,GSBBS,MS-DOS,Packer,Michelangelo_Jones,1:260/244
+0058,Merlin,MS-DOS,Packer/mailer,Mark_Lewis,2:258/25
+0059,TPCS,MS-DOS,Packer,Mikael_Kjellstrom,2:201/211
+005A,Raid,MS-DOS,Packer,George_Peace,1:270/101
+005B,Outpost,MS-DOS,Packer/mailer,Mike_Dailor,????
+005C,Nizze,MS-DOS,Packer,Tomas_Nielsen,2:205/202
+005D,Armadillo,Macintosh,Packer,Erik_Sea,1:221/109
+005E,rfmail,Unix,Packer/mailer,Per_Lindqvist,2:201/332
+005F,Msgtoss,MS-DOS,Packer,Mike_Zakharoff,1:343/36
+0060,InfoTex,MS-DOS,Packer/mailer,Jan_Spooren,2:292/852
+0061,GEcho,MS-DOS,Packer,Gerard_van_der_Land,2:283/555,951209
+0062,CDEhost,MS-DOS,Packer,Dennis_D'Annunzio,1:379/28
+0063,Pktize,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17
+0064,PC-RAIN,MS-DOS,Packer/mailer,Ray_Hyder,1:272/40
+0065,Truffle,MS-DOS/OS2,Mailer,Mike_Rissa,2:504/59
+0066,Foozle,Amiga,Packer,Peer_Hasselmeyer,2:247/4
+0067,White_Pointer,Macintosh,Packer/mailer,Alastair_Rakine,3:680/820
+0068,GateWorks,MS-DOS,Packer,Jamie_Penner,1:153/1025
+0069,Portal_of_Power,MS-DOS,Mailer,Soren_Ager,2:230/12
+006A,MacWoof,Macintosh,Packer/mailer,Craig_Vaughan,1:109/342
+006B,Mosaic,MS-DOS,Packer,Christopher_King,1:103/315
+006C,TPBEcho,MS-DOS,Packer,Gerd_Qualmann,2:242/1
+006D,HandyMail,MS-DOS,Packer/mailer,jim_nutt,1:114/30
+006E,EchoSmith,MS-DOS,Packer,Noel_Crow,1:170/409
+006F,FileHost,MS-DOS,Packer,Mark_Cole,2:252/186
+0070,SFTS,MS-DOS,Packer,Bruce_Anderson,1:3402/6
+0071,Benjamin,MS-DOS,Packer/mailer,Stefan_Graf,2:245/4.5436
+0072,RiBBS,OS9_(COCO),Packer/mailer,Ron_Bihler,1:104/54
+0073,MP,MS-DOS,Packer,Ivan_Leong,6:600/28
+0074,Ping,MS-DOS,Packer,David_Nugent,3:632/348
+0075,Door2Europe,MS-DOS,Packer/mailer,Michaela_Schoebel,2:247/14
+0076,SWIFT,MS-DOS,Packer/mailer,Hanno_van_der_Maas,2:500/2
+0077,WMAIL,MS-DOS,Packer,Silvan_Calarco,2:334/100.2
+0078,RATS,MS-DOS,Packer,Jason_DeCaro,1:260/205
+0079,Harry_the_Dirty_Dog,OS2,Mailer/packer,George_Edwards,3:632/340.7
+007A,Maximus-CBCS,MS-DOS/OS2,Packer,Scott_Dudley,1:249/106
+007B,SwifEcho,MS-DOS,Packer,Dana_Bell,1:3801/8
+007C,GCChost,Amiga,Packer,Davide_Massarenti,2:332/505.3
+007D,RPX-Mail,MS-DOS,Packer,Joerg_Wirtgen,2:241/4034
+007E,Tosser,MS-DOS,Packer,Albert_Ng,6:700/185
+007F,TCL,MS-DOS,Packer,Ulf_Hedlund,2:201/602
+0080,MsgTrack,MS-DOS,Packer,Andrew_Farmer,1:243/1
+0081,FMail,MS-DOS/DOS_DPMI/OS2/WIN32,Packer,Folkert_Wijnstra,2:283/619
+0082,Scantoss,MS-DOS,Packer,Michael_Matter,2:243/44.3443
+0083,Point_Manager,Amiga,Packer,Pino_Aliberti,2:335/602.2,,19931012
+0084,IMBINK,MS-DOS,Packer,Mike_Hartmann,2:246/48
+0085,Simplex,MS-DOS/OS2,Packer,Chris_Laforet,1:152/401
+0086,UMTP,MS-DOS,Packer,Byron_Copeland,1:272/26
+0087,Indaba,MS-DOS,Packer,Pieter_Muller,5:7102/11
+0088,Echomail_Engine,MS-DOS,Packer,Joe_Jared,1:103/200
+0089,DragonMail,OS2,Packer,Patrick_O'Riva,1:143/37
+008A,Prox,MS-DOS,Packer,Gerhard_Hoogterp,2:283/1.2
+008B,Tick,MS-DOS/OS2,Packer,Barry_Geller,1:266/12
+008C,RA-Echo,MS-DOS,Packer,Roger_Kirchhoff,2:245/4
+008D,TrapToss,Amiga,Packer,Maximilian_Hantsch,2:310/6
+008E,Babel,MS-DOS/OS2,Packer,Jorgen_Abrahamsen,2:230/100.9
+008F,UMS,Amiga,Packer,Martin_Horneffer,2:242/7.9
+0090,RWMail,MS-DOS,Packer,Remko_Westrik,2:285/309.5
+0091,WildMail,MS-DOS,Packer,Derek_Koopowitz,1:161/502
+0092,AlMAIL,MS-DOS,Packer,Alan_Leung,1:348/207
+0093,XCS,MS-DOS,Packer,Rudi_Kusters,2:512/34.4
+0094,Fone-Link,MS-DOS,Packer/mailer,Chris_Sloyan,1:269/602
+0095,Dogfight,MS-DOS,Packer,Chris_Tyson,2:256/36
+0096,Ascan,MS-DOS,Packer,Arjen_van_Loon,2:281/1.397
+0097,FastMail,MS-DOS,Packer,Jan_Berends,2:282/5
+0098,DoorMan,MS-DOS,Mailer,Christopher_Dean,1:105/70
+0099,PhaedoZap,Atari_ST,Packer,Jeff_Mitchell,1:229/422
+009A,SCREAM,MS-DOS,Packer/mailer,Jem_Miller,1:147/33
+009B,MoonMail,MS-DOS,Packer/mailer,Hasse_Wigdahl,2:206/101
+009C,Backdoor,Sinclair_QL,Packer,Erik_Slagter,2:283/500.3
+009D,MailLink,Archimedes,Packer/mailer,Jan-Jaap_v._d._Geer,2:500/133.1138
+009E,Mail_Manager,MS-DOS,Packer,Andreas_Brodowski,2:241/4006
+009F,Black_Star,Xenix_386,Packer/mailer,Jac_Kersing,2:283/333
+00A0,Bermuda,Atari_ST/MS-DOS,Packer,Jac_Kersing,2:283/333
+00A1,PT,MS-DOS,Packer/mailer,Jerry_Andrew,1:109/426
+00A2,UltiMail,MS-DOS,Mailer,Brett_Floren,1:363/1000
+00A3,GMD,MS-DOS,Packer,John_Souvestre,1:396/1
+00A4,FreeMail,MS-DOS,Packer,Chad_Nelson,1:109/536
+00A5,Meliora,MS-DOS,Packer,Erik_van_Riper,1:107/230
+00A6,Foodo,CPM-80,Packer/mailer,Ron_Murray,3:690/640.7
+00A7,MSBBS,CPM-80,Packer,Marc_Newman,1:106/601
+00A8,Boston_BBS,MS-DOS,Packer/mailer,Tom_Bradford,1:101/625
+00A9,XenoMail,MS-DOS,Packer/mailer,Noah_Wood,1:284/14
+00AA,XenoLink,Amiga,Packer/mailer,Jonathan_Forbes,1:250/642
+00AB,ObjectMatrix,MS-DOS,Packer,Roberto_Ceccarelli,2:332/305.1
+00AC,Milquetoast,Win3/MS-DOS,Mailer,Vince_Perriello,1:343/491
+00AD,PipBase,MS-DOS,Packer,Roberto_Piola,2:334/306
+00AE,EzyMail,MS-DOS,Packer,Peter_Davies,3:636/204
+00AF,FastEcho,MS-DOS,Packer,Tobias_Burchhardt,2:245/39
+00B0,IOS,Atari_ST/TT,Packer,Rinaldo_Visscher,2:280/3.1
+00B1,Communique,MS-DOS,Packer,Ian_Harris,3:620/251
+00B2,PointMail,MS-DOS,Packer,Michele_Clinco,2:331/302.11
+00B3,Harvey's_Robot,MS-DOS,Packer,Harvey_Parisien,1:249/114
+00B4,2daPoint,MS-DOS,Packer,Ron_Pritchett,1:376/74
+00B5,CommLink,MS-DOS,Mailer,Steve_Shapiro,1:382/35
+00B6,fronttoss,MS-DOS,Packer,Dirk_Astrath,2:241/5603
+00B7,SysopPoint,MS-DOS,Packer,Rudolf_Heeb,2:243/44
+00B8,PTMAIL,MS-DOS,Packer,Arturo_Krogulski,2:341/27.7
+00B9,MHS,MS-DOS/OS2/WINNT,Packer/mailer,Matthias_Hertzog,2:301/402,,19940310
+00BA,DLGMail,Amiga,Packer,Steve_Lewis,1:114/52
+00BB,GatePrep,MS-DOS,Packer,Andrew_Allen,1:382/92
+00BC,Spoint,MS-DOS,Packer,Conrad_Thompson,1:130/29.106
+00BD,TurboMail,MS-DOS,Packer,B._J._Weschke,1:2606/403
+00BE,FXMAIL,MS-DOS,Packer,Kenneth_Roach,1:208/401
+00BF,NextBBS,MS-DOS,Packer/mailer,Tomas_Hood,1:352/777
+00C0,EchoToss,MS-DOS,Packer,Mikel_Beck,1:107/218
+00C1,SilverBox,Amiga,Packer,David_Lebel,1:240/516
+00C2,MBMail,MS-DOS,Packer,Ruud_Uphoff,2:500/116.1928
+00C3,SkyFreq,Amiga,Packer,Luca_Spada,2:331/106
+00C4,ProMailer,Amiga,Mailer,Ivan_Pintori,2:335/311.21
+00C5,Mega_Mail,MS-DOS,Packer/mailer,Mirko_Mucko,2:242/94
+00C6,YaBom,MS-DOS,Packer,Berin_Lautenbach,3:620/248
+00C7,TachEcho,MS-DOS,Packer,Tom_Zacios,1:107/376
+00C8,XAP,MS-DOS,Packer,Jeroen_Smulders,2:512/1.8
+00C9,EZMAIL,MS-DOS,Packer,Torben_Paving,2:234/41
+00CA,Arc-Binkley,Archimedes,Mailer,Geoff_Riley,2:250/208
+00CB,Roser,MS-DOS,Packer,Chan_Kafai,6:700/158
+00CC,UU2,MS-DOS,Packer,Dmitri_Zavalishin,2:5020/32
+00CD,NMS,MS-DOS,Packer/mailer,Michiel_de.Bruijn,2:285/505.2
+00CE,BBCSCAN,Archimedes,Packer/mailer,E._G._Snel,2:512/222.17
+00CF,XBBS,MS-DOS,Packer,Mark_Kimes,1:380/16
+00D0,LoTek_Vzrul,,Packer/mailer,Kevin_Gates,gates@sasknet.sk.ca,19951229,20000122
+00D1,Private_Point_Project,MS-DOS,Packer,Oliver_von_Bueren,2:301/701
+00D2,NoSnail,MS-DOS,Packer,Eddie_Rowe,1:19/124
+00D3,SmlNet,MS-DOS,Packer,Steve_T._Gove,1:106/6
+00D4,STIR,MS-DOS,Packer,Paul_Martin,2:250/107.3
+00D5,RiscBBS,Archimedes,Packer,Carl_Declerck,2:292/500.10
+00D6,Hercules,Amiga,Packer/mailer,Andrew_Gray,1:231/590
+00D7,AMPRGATE,MS-DOS,Packer/mailer,Mike_Bilow,1:323/120.1
+00D8,BinkEMSI,MS-DOS,Mailer,Tobias_Burchhardt,2:245/39
+00D9,EditMsg,MS-DOS,Packer,G._K._Pace,1:374/26
+00DA,Roof,Amiga,Packer,Robert_Williamson,1:167/104
+00DB,QwkPkt,MS-DOS,Packer,Ross_West,1:250/412
+00DC,MARISCAN,MS-DOS,Packer,Mario_Elkati,2:341/14.9
+00DD,NewsFlash,MS-DOS,Packer,Chris_Lueders,2:241/5306
+00DE,Paradise,MS-DOS,Packer/mailer,Kenneth_Wall,1:300/5
+00DF,DogMatic-ACB,N/A,Packer/mailer,Martin_Allard,2:245/48
+00E0,T-Mail,MS-DOS,Packer/mailer,Andy_Elkin,2:5030/15
+00E1,JetMail,Atari_ST/STE/TT,Packer,Daniel_Roesen,2:243/93.8
+00E2,MainDoor,MS-DOS,Packer/mailer,Francisco_Sedano,2:341/20
+00E3,Starnet_Products,MS-DOS/OS2,Mailer/Packer,Starnet_Software_Development,1:102/925,,19951209
+00E4,BMB,Amiga,Packer,Dentato_Remo,2:335/311.33
+00E5,BNP,MS-DOS,Packer,Nathan_Moschkin,1:109/427
+00E6,MailMaster,MS-DOS,Packer/mailer,Gary_Murphy,1:130/85
+00E7,Mail_Manager_+Plus+,MS-DOS,Packer,Chip_Morrow,1:226/1240
+00E8,BloufGate,Atari_ST/Unix,Packer,Vincent_Pomey,2:320/100.2
+00E9,CrossPoint,MS-DOS,Packer/mailer,Peter_Mandrella,2:2454/97.80,19920713,19960601
+00EA,DeltaEcho,MS-DOS,Packer,Mikael_Staldal,2:201/337
+00EB,ALLFIX,MS-DOS,Packer,Harald_Harms,2:512/145
+00EC,NetWay,Archimedes,Mailer,Steve_Haslam,2:250/116.3
+00ED,MARSmail,Atari_ST,Packer,Folkert_val_Heusden,2:285/750.2,,19940122
+00EE,ITRACK,MS-DOS/OS2,Packer,Frank_Prade,2:2480/55,,19990119
+00EF,GateUtil,MS-DOS,Packer,Michael_Skurka,1:397/2.1
+00F0,Bert,MS-DOS,Packer/mailer,Arnim_Wiezer,2:241/2104.9
+00F1,Techno,MS-DOS,Packer,Patrik_Holmsten,2:203/133
+00F2,AutoMail,MS-DOS,Packer,Mats_Wallin,2:201/239
+00F3,April,Amiga,Packer,Nick_de_Jong,2:282/309.3
+00F4,Amanda,MS-DOS,Packer,David_Douthitt,1:121/99.14
+00F5,NmFwd,MS-DOS,Packer,Alberto_Pasquale,2:332/504
+00F6,FileScan,MS-DOS,Packer,Matthias_Duesterhoeft,2:241/4512.2
+00F7,FredMail,MS-DOS,Packer,Michael_Butler,3:712/515
+00F8,TP_Kom,MS-DOS,Packer/mailer,Per_Sten,2:201/124
+00F9,FidoZerb,MS-DOS,Packer,Ulrich_Schlechte,2:241/3410.12
+00FA,!!MessageBase,MS-DOS,Packer/mailer,Holger_Lembke,2:240/500.20
+00FB,EMFido,Amiga,Packer,Gary_Glendown,2:249/3.999
+00FC,GS-Toss,MS-DOS,Packer,Marco_Bungalski,2:241/2021
+00FD,QWKDoor,Atari_ST,Packer,Christian_Limpach,2:270/20.1
+00FE,No_product_id_allocated,Any,Packer,No_Author,3:3/20
+00FF,16-bit_product_id,Any,Packer/Mailer,No_Author,3:3/20
+0100,Reserved,None,None,No_Author,3:3/20,19951209
+0101,The_Brake!,Mailer,John_Gladkih,2:5051/16,19951209
+0102,Zeus_BBS,Amiga,Mailer,Alex_May,2:441/58.0,19951209
+0103,XenoPhobe-Mailer,Msdos/Windows/OS2/Linux,Mailer,Peter_Kling,1:374/969.0,19951209
+0104,None,None,None,None,0:0/0,
+0105,Terminate,Msdos/Os2/Windows,Mailer/Packer,SerWiz_Comm_&_Bo_Bendtsen,2:254/261,19951209
+0106,TeleMail,Msdos,Mailer/Packer,Juergen_Weigelt,2:2453/900,19951209
+0107,CMBBS,Msdos/Os2,Mailer/Packer,Christof_Engel,2:2490/5110,19951209
+0108,Shuttle,Windows,Mailer/Packer,MCH_Development_&_Marvin_Hart,1:106/500,19951209
+0109,Quater,Amiga,Mailer,Felice_Murolo,2:335/206,19951209
+010A,Windo,Windows,Mailer,Alan_Chavis,1:147/55,19951209
+010B,Xenia,Msdos/Os2,Mailer,Arjen_Lentz,2:283/512,19960601
+010C,GMS,AmigaOS,Mailer,Mirko_Viviani,2:331/213,19960601
+010D,HNET,Msdos,???,Pedro_Jaramillo,1:102/160,19960601
+010E,Shotgun_Professional,Msdos,???,Brent_Shellenberg,1:140/146,19960621
+010F,SLIPgate,Msdos,???,Kieran_Morrissey,3:634/376,19960723
+0110,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216
+0111,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216
+01FF,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216
+02FF,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216
+03FF,Ravel,Macintosh,Mailer/Packer,Cyril_Moorzin,2:5030/700,19980310
+04FF,Beemail,Windows,Mailer/Packer,Andrius_Cepaitis,2:470/1,19980310
+05FF,QuickToss,DOS,Packer,Sandra_Godinez,1:387/601.3,19980310
+06FF,SpaceMail,???,Mailer,Andreas_Habicht,2:244/6121,19980710
+07FF,Argus,Windows/NT,Mailer,Max_Masyutin,2:469/84,19990216
+08FF,Hurricane,Windows/NT/Solaris,Packer,Paul_Walker,2:254/175.44,19990216
+09FF,Hub_Mailer,OS2,Mailer,Viatcheslav_Odintsov,2:5020/181,19990216
+0AFF,FDInt,MSDOS,Packer,Colin_Turner,2:443/13,19990216
+0BFF,GPMail,OS2,Mailer,Igor_Vanin,2:5030/448,19990216
+0CFF,FTrack,NT/OS2,Tracker,Fyodor_Ustinov,2:5020/79,19990313
+0DFF,Nice_Tosser,DOS/OS2/Win32,Tosser,Robert_Agababyan,2:5020/234.1,19990518
+0EFF,LuckyGate,DOS/OS2/Linux,Packer,Pavel_Gulchouck,2:463/68,19990709
+0FFF,McMail,DOS,Mailer,Simon_Slater,2:443/777,20000102
+
+ +Back Go Back + + + + diff --git a/html/ftsc/index.htm b/html/ftsc/index.htm new file mode 100644 index 00000000..34343c7c --- /dev/null +++ b/html/ftsc/index.htm @@ -0,0 +1,99 @@ + + + + + + + + +Fidonet Standard Commitee documents. + + + +
+
Last update 08-Jun-2001
+

 

+ +

Fidonet Technical Standards

+ +

Introduction

+

+This is an overview of used documents for the development of the MBSE BBS +package. Note that there are more documents, but only the relevant and valid +documents are present here. Also note that these documents are just imported +into html documents without any changes. +

+Michiel Broek. +

+ +


+

FSC Documents

+ + +

+ +

FSP Documents

+ + + +

+

FTA Documents

+ + + +

+

FTS Documents

+ + +
+ +IndexBack to Index +
+ + + diff --git a/html/gwnews.html b/html/gwnews.html new file mode 100755 index 00000000..708339d3 --- /dev/null +++ b/html/gwnews.html @@ -0,0 +1,381 @@ + + + + + + + + +MBSE BBS - Internet gateway - INN. + + + +
+
Last update 10-Apr-2001
+

 

+ +

MBSE BBS - Internet Gateway - INN.

+

+ +

SETUP INND

+

+Below are the files that you need to setup for INN news. I used inn-2.2.2 on +my system. It is configured to install in /opt/news with the command +./configure --prefix=/opt/news during the installation of +inn. +

+


+
+
+##  $Revision$
+##  inn.conf -- inn configuration data
+##  Format:
+##	:
+##
+##  See the inn.conf(5) man page for a full description of each
+##  of these options
+##
+##  Blank values are allowed for certain parameters
+## ---------------------------------
+# All parameters must exist
+#
+organization:		MBSE BBS Development Site
+server:			localhost
+pathhost:		news.mbse.nl
+moderatormailer:
+domain:			mbse.nl
+fromhost:		news.mbse.nl
+pathalias:
+complaints:		abuse@f2802.n280.z2.fidonet.org
+mta:			/usr/sbin/sendmail -oi %s
+mailcmd:		/opt/news/bin/innmail
+checkincludedtext:	false
+maxforks:		10
+maxartsize:		1000000
+nicekids:		4
+nicenewnews:		0
+verifycancels:		false
+logcancelcomm:		false
+wanttrash:		false
+remembertrash:		true
+linecountfuzz:		0
+peertimeout:		3600
+clienttimeout:		600
+allownewnews:		true
+localmaxartsize:	1000000
+logartsize:		true
+logipaddr:		true
+logsitename:		true
+maxconnections:		50
+artcutoff:		14
+icdsynccount:		10
+hiscachesize:		0
+readertrack:		false
+strippostcc:		false
+status:			0
+timer:			0
+readerswhenstopped:	false
+noreader:		false
+extendeddbz:		false
+nnrpdoverstats:		false
+storeonxref:		true
+nnrpdcheckart:		true
+storemsgid:		true
+usecontrolchan:		false
+mergetogroups:		false
+backoffauth:		false
+backoffdb:		/opt/news/db/backoff
+backoffpostfast:	0L
+backoffpostslow:	1L
+backofftrigger:		10000L
+mimeversion:
+mimecontenttype:
+mimeencoding:
+refusecybercancels:	false
+activedenable:		false
+activedupdate:		30
+activedport:		1119
+nnrpperlauth:		false
+#
+# 
+# These options are unlikely to need changing in most situations
+#
+chaninacttime:		600
+chanretrytime:		300
+pauseretrytime:		300
+nntplinklog:		false
+nntpactsync:		200
+badiocount:		5
+blockbackoff:		120
+#
+# ---------------------------------
+# Changing these options can have an effect on the way articles are
+# stored and may require recreating the spool and/or database files
+#
+wireformat:		false
+xrefslave:		false
+nnrpdposthost:
+nnrpdpostport:		119
+spoolfirst:		false
+writelinks:		true
+storageapi:		false
+articlemmap:		false
+overviewmmap:		true
+bindaddress:		all
+sourceaddress:		any
+port:			119
+#
+## Keywords-in-overview options
+## Enabling this without stopping innd and deleting the existing overview
+## database and adding  will probably confuse a lot of things. You must 
+## have compiled this support in too.
+#
+keywords:		false
+keylimit:		512
+keyartlimit:		100000
+keymaxwords:		250
+#
+# Other options
+innflags:		
+doinnwatch:		true
+innwatchsleeptime:	600
+pgpverify:		false
+controlfailnotice:	false
+logcycles:		3
+innwatchpauseload:	1500
+innwatchhiload:		2000
+innwatchloload:		1000
+innwatchspoolspace:	8000
+innwatchbatchspace:	800
+innwatchlibspace:	25000
+innwatchspoolnodes:	200
+docnfsstat:		false
+#
+# ---------------------------------
+# Paths to various aspects of the news system
+#
+pathnews:		/opt/news
+pathbin:		/opt/news/bin
+pathfilter:		/opt/news/bin/filter
+pathcontrol:		/opt/news/bin/control
+pathdb:			/opt/news/db
+pathetc:		/opt/news/etc
+pathrun:		/opt/news/run
+pathlog:		/opt/news/log
+pathhttp:		/opt/news/log
+pathtmp:		/opt/news/tmp
+pathspool:		/opt/news/spool
+patharticles:		/opt/news/spool/articles
+pathoverview:		/opt/news/spool/overview
+pathoutgoing:		/opt/news/spool/outgoing
+pathincoming:		/opt/news/spool/incoming
+patharchive:		/opt/news/spool/archive
+pathuniover:		/opt/news/spool/uniover
+overviewname:		.overview
+#
+# ---------------------------------
+#
+
+
+
+ +
+##  $Revision$
+##  expire.ctl - expire control file
+##  Format:
+##	/remember/:<keep>
+##	<patterns>:<modflag>:<keep>:<default>:<purge>
+##  First line gives history retention; other lines specify expiration
+##  for newsgroups.  Must have a "*:A:..." line which is the default.
+##	<patterns>	wildmat-style patterns for the newsgroups
+##	<modflag>	Pick one of M U A -- modifies pattern to be only
+##			moderated, unmoderated, or all groups
+##	<keep>		Mininum number of days to keep article
+##	<default>	Default number of days to keep the article
+##	<purge>		Flush article after this many days
+##  <keep>, <default>, and <purge> can be floating-point numbers or the
+##  word "never."  Times are based on when received unless -p is used;
+##  see expire.8
+
+##  If article expires before 14 days, we still remember it for 14 days in
+##  case we get offered it again.  Depending on what you use for the innd
+##  -c flag and how paranoid you are about old news, you might want to
+##  make this 28, 30, etc.
+/remember/:14
+
+##  Keep for 1-10 days, allow Expires headers to work.
+*:A:1:10:never
+
+fido.*:A:1:30:60
+comp.*:A:1:30:60
+local.*:A:1:30:60
+nl.*:A:1:30:60
+
+##  Some particular groups stay forever.
+# Keep FAQ's for a month, so they're always available
+#*.answers:M:1:35:90
+news.announce.*:M:1:35:90
+
+# Some other recommendations.  Uncomment if you want
+# .announce groups tend to be low-traffic, high signal.
+# *.announce:M:1:30:90
+# Weather forecasts
+# *.weather:A:1:2:7
+# test posts
+# *.test:A:1:1:1
+
+##  Some particular groups stay forever.
+# dc.dining*:A:never:never:never
+# uunet*:A:never:never:never
+
+
+
+##  $Revision$
+##  Mailing addresses for moderators.
+##  Format:
+##	<newsgroup>:<pathname>
+##  First match found is used.
+##	<newsgroup>	Shell-style newsgroup pattern or specific newsgroup
+##	<pathname>	Mail address, "%s" becomes newgroup name with dots
+##			changed to dashes.
+
+## Russian hierarchies
+fido7.*:%s@fido7.ru
+medlux.*:%s@news.medlux.ru
+relcom.*:%s@moderators.relcom.ru
+
+## Direct all public hierarchies to the master moderator database.
+*:%s@moderators.isc.org
+
+
+
+##  $Revision$
+##  newsfeeds - determine where Usenet articles get sent
+##  Format:
+##	site[/exclude,exclude...]\
+##		:pattern,pattern...[/distrib,distrib...]\
+##		:flag,flag...\
+##		:param
+##  Summary of flags:
+##	<size		Article must be less then size bytes.
+##	>size		Article must be more then size bytes.
+##	Aitems		Article checks -- d (must have Distribution header)
+##			p (don't check for site in Path header)
+##			c (no control messages) C (only control messages)
+##			e (all groups must exist).
+##	Bhigh/low	Internal buffer size before writing to output.
+##	Fname		Name of the spool file.
+##	Gcount		Crossposts limited to count groups.
+##	H[count]	Article must have less then count hops; default is 1.
+##	Isize		Internal buffer size (if a file feed)
+##	Nm		Only moderated groups that match the patterns.
+##	Nu		Only unmoderated groups that match the patterns.
+##	Ppriority	Nice priority of channel or program feed.
+##	Ooriginator	First field of X-Trace must match originator (wildmat).
+##	Ssize		Start spooling if more than size bytes get queued.
+##	Ttype		Feed types -- f (file) m (funnel; param names the
+##			real entry) p (pipe to program) c (send to stdin
+##			channel of param's sub-process) x (like c, but
+##			handles commands on stdin) x (log entry only).
+##	Witems		What to write -- b (article bytesize) f (full path)
+##			g (first newsgroup) h (Message-ID hash) 
+##			m (Message-ID) n (relative path) p (posted time)
+##			s (site that fed article) t (time received)
+##			* (names of funnel feed-in's or all sites that get
+##			the article) N (Newsgroups header) D (Distribution
+##			header) H (all headers) O (overview data)
+##			P (path header) R (replication information)
+##  Param field depends on T flag.  For Tf, relative paths are from the
+##  out.going directory.  For Tp and Tc, it is a shell command to execute.
+##  If a Tm refers to this entry (which will have its own T param) then "*"
+##  is expanded to all the funnel sites that triggered this one.  Useful
+##  for spawning one mail process, e.g.
+##
+##  This file is complicated -- see newsfeeds.5!
+
+##  This is the local site.
+##  The "pattern" field gives the initial subscription list for
+##  all other sites.  You might want to put "!control,!junk,!.*"
+##  there.  The "distrib" subfield limits incoming articles.
+##
+##  You can also have ME/bad.site: to refuse articles from a particular
+##  site (by matching the Path: entry).  Other pseudo-sites may be put
+##  in here, to REFUSE certain types of 3rd-party cancel messages
+##  (See the "Cancel FAQ" news.admin.net-abuse.misc):
+##	cyberspam	Spam cancels, munged articles, binary postings
+##	spewcancel	just munged articles from runaway gateways
+##	bincancel	just binary postings to non-binaries groups
+##
+##  Note that refusing articles means you won't offer them to sites you feed
+
+## Default of  everything to everybody except for junk, control, anything
+## with "local" as the newsgroup prefix (i.e. matches "localhost.stuff") or
+## groups under foo. Articles posted to any group under alt.binaries.warez
+## will not get propagated, even if they're cross posted to something that
+## is.
+ME\
+	:*,!junk,!control*,!foo.*/fido,local\
+	::
+
+## news.wxs.nl via rpost (suck)
+news.wxs.nl/news.wxs.nl:*,!control,!junk,!fido.*,!iba.*,!local.*/!local,!fido::
+
+##  News overview
+# use this flag if storage api is used
+#overview!:*:Tc,Ao,WhR,S30000:/opt/news/bin/overchan
+# else
+overview!:*:Tc,WO,S30000:/opt/news/bin/overchan
+
+
+
+
+##  $Revision$
+##  distrib.pats -- specify default Distribution header for newsgroups
+##  Format:
+##	<weight>:<pattern>:<value>
+##  All articles are matched against all patterns, value to be used is the
+##  one with the highest weight.
+##	<weight>	The weight assigned to this match, integer
+##	<pattern>	Newsgroup name or single wildmat(3) pattern
+##	<value>		Value of Distribution header.
+##
+##
+## Uncomment to default all local.* groups to a distribution of local.
+#10:local.*:local
+10:local.*:local
+10:fido.*:fido
+
+
+
+##  $Revision$
+##  nnrp.access - access file for on-campus NNTP sites
+##  Format:
+##	<host>:<perm>:<user>:<pass>:<groups>
+##	<host>:</path/file>
+##  Connecting host must be found in this file; the last match found is
+##  used, so put defaults first.
+##	<host>		Wildcard name or IP address
+##	<perm>		R to read; P to post
+##	<user>		Username for authentication before posting
+##	<pass>		Password, for same reason
+##	<groups>	Newsgroup patterns that can be read or not read
+##	</path/file>	A second file to scan in the same format as this
+##  To disable posting put a space in the <user> and <pass> fields, since
+##  there is no way for client to enter one.
+##
+## Default is no access, no way to authentication, and no groups.
+*::::!*
+stdin:Read Post:::*
+localhost:Read Post:::*
+127.0.0.1:Read Post:::*
+*.mbse.nl:Read Post:::*
+
+
+ +BackGo back +HomeGo to main + +
+ + + diff --git a/html/images/b_arrow.gif b/html/images/b_arrow.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a28444c38f10fd1af4dad3019084e56fff209ae GIT binary patch literal 1306 zcmZvbduYvJ7{?#ZE@!uM+u6?9?QCb4LgJ5CY)+(^f8`j6EhCY)V z$Nf0&%Yo%MS8<+PJ$-A;o8-khAA+}zx}yuAGU{DOi4pU>y_ z`vZYMFc=JlLWPBe;c&R9sHnKOI1-6OqtTL*lG4)Bva+)B^74v`idZaGSy@?CRTYoN ztE;PPYHDh0YwPOjh!l|~GDKFcN|Dl}3@Ml_9<4}g(uTAp%@Sx78BNBJv1Ax|WEELW z){wPinOG5PVnYlEs-h^WAPpu<2RT|Pqm)&Or6DY>l{QLSrCIvJX|ys%8LJEn4q~lV z)+lS0WzZp2u~uvp8Zlae7sY@JJ^;ao#;A?bsD)&fQN+eET3fAICPQ0T#%N=;VHp$@ za9X3S)s`_gpb)FsXttU$8(T>PwgG}~W8K}S z9miq(&hevgUwGq&6aShqfhe1%!b$Rc715R*)e(k(cb#=PX{{Ep9YR?`Y<}s6`9_= zrr~1K9ei^+@wjzldFPzZeZ4(fUk{w{b-io3a{g(5+qcK*mYX|A2KT8%GS%azPkYzW zzI|lvS!8W!Od@9C@rlu;(b1p5l69~%XZ4Mgn|^oZj3=$YK=5#6)ysLe<Dg2OXHW9^8&48ZrM{{Tp$wl$d;Dk^c zuqA{DEqF*u0xhG5APRyIwh~Z?h}sPFU?3LKgEShWm<_Rx-##xsSbp!lnfd0M?|a+( ze6{=O;R;n~j~YwUPt!+nQmtYAR9pIHM~IBbk-#KO%4AH=6ig%}LMmiJE)+N_nUX67 zpp3*wjm*f6BB6+rI+>F@g_8tnkOg_50l)x&B4i;V#3C%pVl2)QjCf5sJr1m(g zimA9tBsK`EiJ7=bByz}B7jto!NL*2@Ar|5xk$^xJ?7)avg;iON)mei<3O&&TsDMFT zqot|3YCtvg#=+D~-87N}V1ux^x@#mwKn~d!>Y`N z3Uo{Z`rr#e!2-?D4e-DN0OGj7a;1v*ua43gyI7cv?haYgVK^k_!AJ_ubAs=P{5cGp!&;tTsB;aBu3;~WH1r}(7 zJ}5;lf^o33u&|`4$14kp^uZT9tgii*CZar@KoI|k3Q^%7Di$8=TVA+1RXFnS>etI% z*@e=fJCD=CNKdX_8C%WkeD4hHoVzq#to6S4H*MZ(Z!7D}@usxt`G5+Ww{Dcm-_1Yr z`?==|RMF;VxY{z_Ie7E^zS+AUcfbA1k4vvkj;+7jIk+-0bZYGA)syAh6CI~ozr9kt zmtF37;O<)fo%!nJ+#g%bU-mCnC--+JH?E&uteyY==An*q6P>Tis; zWzE}j{n^m=>+3J){@Xn}oW1nmpRWwO_EZa9pn=gJ23mh!9O|h*d1JQP(RQ>%r~d^< C&_fdd literal 0 HcmV?d00001 diff --git a/html/images/domains.gif b/html/images/domains.gif new file mode 100644 index 0000000000000000000000000000000000000000..687bee5d1bed0a147f67499d03d8df34d86e06aa GIT binary patch literal 9684 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 literal 0 HcmV?d00001 diff --git a/html/images/emareas.gif b/html/images/emareas.gif new file mode 100644 index 0000000000000000000000000000000000000000..bdb0346f79452607cc919af78b7d156d25bf1a4b GIT binary patch literal 12641 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 literal 0 HcmV?d00001 diff --git a/html/images/emgroup.gif b/html/images/emgroup.gif new file mode 100644 index 0000000000000000000000000000000000000000..af7326c7b668c0f9613fc8ad270355f168c0cd9e GIT binary patch literal 7214 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 literal 0 HcmV?d00001 diff --git a/html/images/fdb.gif b/html/images/fdb.gif new file mode 100644 index 0000000000000000000000000000000000000000..e8fbb413a26504150542be4f5bec3141f4c876f0 GIT binary patch literal 8368 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 literal 0 HcmV?d00001 diff --git a/html/images/fileecho.gif b/html/images/fileecho.gif new file mode 100644 index 0000000000000000000000000000000000000000..8013ef7021cb33c9db8ab7780e0d3c2c9bacc22e GIT binary patch literal 9573 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 PeOjnZ+ISVY2mk;(c|6A| literal 0 HcmV?d00001 diff --git a/html/images/filefind.gif b/html/images/filefind.gif new file mode 100644 index 0000000000000000000000000000000000000000..5603b32848cd551feed792411aa83707bfb53273 GIT binary patch literal 8243 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 literal 0 HcmV?d00001 diff --git a/html/images/go_to.gif b/html/images/go_to.gif new file mode 100644 index 0000000000000000000000000000000000000000..c1b38483b463f5dc98955d9f587e6b71916c1de1 GIT binary patch literal 1155 zcmX9-QHYdf6g|5;IXg1suB~Duv`)lIw=%ZPRSH+c$;7~cx@nKQ80E`mQB)*!%f;5+ zq`=-HnqpJ932jf+i_Th#*pudk9u}&VAbgS(nke>m=J!6#|9#)R-?`_W^Ubc^Pj1;d zUc(0bjZRdnRT#{;pSU2O^LGO<2Mck!(OP0`L;6m{EwTsEN90h^8>#2~%~|P|cz}_h#y*VVVUS zrp?t|!!-+XthP`OjnFK(^0K9RYNTcXM6zT@Mi5gm6LYZ;OCc%tWD}wihW9!x-7L(K zg0VL@ZtfOtSx7)OOnX>_WuXYkvD(ujEenCD94}KLN2}`0Z6EXNw`Ev zq|gLvOi`&KWus0V^C$oZBRVJJDCACR3L>ud7=H5zo-@*RvyHBinX7~x%{oAlSoQFJI1;^M?>D5>TUfxc5-dkf%E(NS{IJrGdlU-^}R#(%?qQ; zpX~Ye;r%$IlZ)TIa_z$LUet9&_f$n`y4i8lD>W-srOqYIpd!mk7*TAmn4^JL= z=h)~^)xPG^xj)Xzoj;Z_yl=Wk#;;6WZw#J!cTM@Z_4_X$YT&A@J-uaqsWsCh-4`oo zCl+RUbfi)5(bqm5JN^5kjrtw8w`RI$;h$Ijrz*l*@5SGmY@Cj%Iu~U HB|QE=Qrsk( literal 0 HcmV?d00001 diff --git a/html/images/hatch.gif b/html/images/hatch.gif new file mode 100644 index 0000000000000000000000000000000000000000..64e701462bd5042671d1cfa2c449151f55dfc6d9 GIT binary patch literal 7761 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 literal 0 HcmV?d00001 diff --git a/html/images/larrow.gif b/html/images/larrow.gif new file mode 100644 index 0000000000000000000000000000000000000000..5e19567e36ee4995d67047d9c388ba93409a9c6d GIT binary patch literal 1144 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 G0RTJD7!4Hw literal 0 HcmV?d00001 diff --git a/html/images/mbse.jpg b/html/images/mbse.jpg new file mode 100644 index 0000000000000000000000000000000000000000..370c02e24dea3fffe2a3b01e2324eb03e02ac7e9 GIT binary patch literal 10655 zcmb8VWn5d!7cLy2KwGR7cXzkqP+FYgZUu^4aW7s9#T|+lCpaXyTae?tIAnvL|b;{mhzYmh7jQr)9t!d1*Om00II4fbjeQJk0?<0$!q^prRnZL`6k? z_3GtobX*K{G&FRgw>Vh1WW*HYWW=PTl(g&&l+>&=q@;}eOst$-yu7>=41%Hp+#>8e zyxji?L3s7*6*?L^AqEB^Hx(%r_y6De4?By4~Tkyo<6mq?=uHrDcbc?ypPFE(37!koOF+nL1jt6Jlv zXE`p1rKDEe2Md)6=P!?4uuRiDg7TBKs-Ri7FT(<;sR3bOh}4wNLpFt^iSSX$-Jy_= z#zoeE{$<%0hot!M)f>&P&|n}13kCeOTd%wvH@;jSrtJLvmmQ9s2C?9WpVz$;GB-99 zIZuEuXLfmC-Xo#Du)YtdYkv#A{Dbxf{6I6|A1TW4z=t*FU+qV(>Kgl~7rHGz)3TPi zNU1aLPs#3=+&(0H+bsU_JY|hU_6eZac}}sf+{Yd-KIG_&dPk7v(%yr1P;`oTv}1c; z{dZ!~8jhU*^E{({^>^vRZ8x$u2T6)00U~{$$KJyU`uFM#k?;h-(zC~Bqb5BKiZ^^ zRawJ<$1+0D{SR3BBP$ya3QCr0C1vaZKD;tm2~5Z$8mMOz(ZZU>fG^tMH0wAoyAvr(D5;ms1X9!~R_-%wS#<{6 zN4VH9{VlumnyoL=K}c1yB0im;Kh&#h+OVlATl}`d%(Cc!A!OjRj-2x4B&>gKtJ5zj z$8XYiBYDSEl53}0-+=CLbihJa{oVU#MTwGvnLRaial?PBOT~v-3fhT5xo6^8JC3Sw z_`80UhlU z_^rC*(SG9(TX%I<+iIbvTt5|kr|0NdonHxXPNy(FL3RmcUfl#6SB^B4DGENW`FD$} z;&I;PEKF67sFHy5c2NgqE|VBEG3hAy?0>JLi%Gh75sh83Dg}$mtB#dPlW*9>Dg10K z;FjP3INiklC!?Z=ae!0Qjy8*~nt^nR2*NhewmnncH*_d2mH!pF>TQ5k+m9TNa z)G`xRhhGW0D(_ieUPR(;HKqE`&NVOj4y=i+ixjlTT6E9Xgt<)BeHU(EE&us>-BOiv zu7aNg*~j)E2`k9LX?A&KW~C!~wbCB1(h6)w+6{->X4wBpyqRA)PW6U(U}p>EExd&x z7XAP-?-Chdd}5z7opF>nARhs1#;O|)xVbp`cka3xxCg;FcL#AW-rH%*5~Ei~bxCyF zw=U!r-=uu02FDPAd7(LB5uqRc62i0hG(4)OgL9c>p1};-Ctw=naR<4*zma{M$nlwi#-`U$EyI3Tuq`i>P8f$$J<)&JHSy7dRC>!h z=+<=8CBRYO2@rpB#gZL+xvzhL

u`^8`@qow2q3j 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 literal 0 HcmV?d00001 diff --git a/html/images/mbsetup0.gif b/html/images/mbsetup0.gif new file mode 100644 index 0000000000000000000000000000000000000000..356a72493c647eb0302a94fd4a0ffe16c7448811 GIT binary patch literal 11329 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 literal 0 HcmV?d00001 diff --git a/html/images/modems0.gif b/html/images/modems0.gif new file mode 100644 index 0000000000000000000000000000000000000000..f04e8c4c274b63534fd65f5437e6621b88726243 GIT binary patch literal 9537 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 literal 0 HcmV?d00001 diff --git a/html/images/newfiles.gif b/html/images/newfiles.gif new file mode 100644 index 0000000000000000000000000000000000000000..961e269f52b07042b367f9dda371782a1f0fea77 GIT binary patch literal 8784 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 literal 0 HcmV?d00001 diff --git a/html/images/nodelist1.gif b/html/images/nodelist1.gif new file mode 100644 index 0000000000000000000000000000000000000000..7d2bc179f2889747182a9b7fe95d5299da6c2b89 GIT binary patch literal 11133 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 literal 0 HcmV?d00001 diff --git a/html/images/nodelist3.gif b/html/images/nodelist3.gif new file mode 100644 index 0000000000000000000000000000000000000000..b064d6593cfaaf4e22d644fa3e5a2ea1e92ae258 GIT binary patch literal 9576 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 I0sz_n1$g@75C8xG literal 0 HcmV?d00001 diff --git a/html/images/nodelist4.gif b/html/images/nodelist4.gif new file mode 100644 index 0000000000000000000000000000000000000000..b722e8f4071111d51825d0d2432ebe327816af8e GIT binary patch literal 11176 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 C-*j*Q literal 0 HcmV?d00001 diff --git a/html/images/nodelist5.gif b/html/images/nodelist5.gif new file mode 100644 index 0000000000000000000000000000000000000000..ea5b7195aa38333c15a50e74f2845a6e4219c167 GIT binary patch literal 8446 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 literal 0 HcmV?d00001 diff --git a/html/images/nodes.gif b/html/images/nodes.gif new file mode 100644 index 0000000000000000000000000000000000000000..29d530c157451f6786fc244a5b0894c90e67e1c7 GIT binary patch literal 11535 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 D1#)C@ literal 0 HcmV?d00001 diff --git a/html/images/nodes1.gif b/html/images/nodes1.gif new file mode 100644 index 0000000000000000000000000000000000000000..ef162724abf538edf274b881f21297581fb02187 GIT binary patch literal 8803 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 V(IK1HAqVe(dcA%A?>~d+{{trJwB7&! literal 0 HcmV?d00001 diff --git a/html/images/nodes2.gif b/html/images/nodes2.gif new file mode 100644 index 0000000000000000000000000000000000000000..a29e5410f70c2ecd8a04507371a7e22564306f5b GIT binary patch literal 7790 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 literal 0 HcmV?d00001 diff --git a/html/images/nodes3.gif b/html/images/nodes3.gif new file mode 100644 index 0000000000000000000000000000000000000000..b0dbcc3704e0e28d6a28eae870fd8504a0b4a606 GIT binary patch literal 9766 zcmc(D=R4aE^!A6MW(V4e)kUehn+0;KiqPo5YqtP>DeH6eE zDR2!2&>9+868%eniUa_IGvZVt6FaU&d^G)jk^dJCC z3B-BnM4g!4y9QCBDPxN{qVUJ}NUmwYXdyDaQ^58bxQPZRi?~xv^~gXV(l|0fQvd(~ z03`ruaMS7Q0aPG>EROH=1VEz!v0{@RyeSz82n?pY!Oa1f9s{6jfD&zfC&J{!7Ib|R zLdH!B=>4An8X6(``T!Nxe-v*#;*LAjvoPQm9MJ>FK)_Vq9b*ds1Og~20dp39699ma z(UblU;%oEv7bYjipzCW&G}@s!_!RGQO>z?rraUpxkTVUV1TiUrNz_gNy8nR%0J0PS zm;-=&e>A|S`p4H)*Jv=Bl3O`W&w>+l6HG}t$4z^x7jg|^`jZ!ZYJtB7U8Da~0RYDV zXPm$_oLlfz@5?oaJT&fgkOgq_zkJ|8oEgCRAAgN#KpziKT?1gW+DtSl1s)*1*4L^c zAvyiOaz6rq5C2c8IDo_gSWN={R0F5{!1WCP4F=%%qfbBJ+sQP7PW5kIQ&IlMf%;J# z0B{0;+Ag=g(+mkf0RW`H4KQ#U08W8uY7#tPcKx6BMPvY$8@SX1Nd9;I{!a(~|MPtR z1N}d<08kQv+mx(IRoNXOlngv3eN{g@!|yy*fh$$#bVo70wwvp#&h3qTB`Cm6}+D z8meJ$w$UvLK^2HJU8K-)o+v{C!7F{S4}fe`)6vFAu4>kT*xtLm$$L+(=3RXM)s{vQ zSNPjUh22`o@IUlh5Y2?Me=FF^OzFp8gMh;w+--!U?B8F8`g5d&HDsXoCY!mwFAYy0 zQ^=7#_fjaM9=Cx%<-8|2h;U*Z=z+h>xJ&{Bi^4-z?uxbl;AL+#F{3RwGY#poZ7_pU zV~Re%?#*LtP2pn`2W<&2IvHFy?k1ye5Y`j~LBSyI-pZIVYMQ!~`cU<`^N@0no?WTnJ069kem@@5*s#_gC)5u(ju}{& z3)iNvvj_+2g!7+HS)@9iPTLfgpUyZS_fBVBdil@h+;NVg(pU zPG;72Rj&YHw+`n-*lXOVAne!I2ITCt^0z-xZO&b7QtqrA&pE(IR*V9}vd&U}VOfk# zkXXexK1XnxKdono5OmJ@63q+Z*`lg|%*B@EkPQAtyYm`hy;tyhWwrKO0O4Y#^34@K zcagX+iUt~n15RciuKPWBSrjzrbB7UeED+u@qFWW55taQJb|0hJb&=+7ADTe z!D5M}yN~PjWPHp}?bG#jC26H?g zPrW8UXm^Q|uCZU$Dc;DF6md8s)|wRkFRW1KGdqj5%3k%Mx0BG*hg(cN+CA|p1FtQ4 zqzx45zPcoPg)XsGa=m?Vp%qiYXtl9_hE|eEh#Yj_c*1Ge$EH9JyQcLP5WU8X-+HTaOFQ(2{5s3p^sh*I!88fRJdugBwl@`txzz5fLjGd%4`0#4C#AUV zAZ?W$B*t>tg{_r!x8-0?ItdHWaLLy7c0s+mw9}+bDV&XJH2u9CN{`2{2zZR)tBId? zq-`|9RfhHHb)gp~+p8+vod#NUsTBT2n?|rUJ0JQ$an5B?{pLv+V!T|)(O%-4n0lI4 zHQZl{OZjHnQ_@_XkXG&FSxFtN7b!B^#<%eAi8bCg-z9`TQ!gyH|`J*w$p= z)hpIJMWhPv8oaTabcEdxdX!vhs!xL>x(X#aSQ5*XtV<{5tmqqr9iLo^P3!mW=_IM@ z+Q{BiosQyRsMWMAlMctum6O(I(GEW4NyLn7e)6ap_jhtbQR@UypH=ryEZJgt#_E40 zW(4c-I-#kITT~b-MWK5pmMA0qyk7o$p(l=_%!~b3B30*e)^BgjjaYn1L1+l?%C8k; z3)pK>ZkO4CY*M;DNnEm>M-o+<*V*{Xb2)g#o@=2rMyMfMW37PQ9VDmg2o zTwz9b6;lm@&@DjiM;G?$0m8Q=Q+r8i^-0uZpVGpdkG;MU{u#bMpWymF1cG`ji^muY zy-Lz9TNCgFxoZV5ue3qdU$Kaj*r?YMVYq>H5#;oMOH3`C^MO?!)O*NlsCH{^U_%CF zI2?FOC}qdwWzX|JBjG)!InqcQIYA#FHf1iCtvv9aCi7@gh5PEWJsVX|=CO$HtcCok zwhH#l?v6w5q_;Ay^t3OAu>&vHQ_95e-WZ)!WHkTak-2bz(C^|{uP>{FY?=i*j^{_! ztt3Hhwd|Rv2UFa0-(PLn)J9C>5MLX_=^S~(B*uqM-8ZUQ#bs)l2RF=wbBxOaMWaOH z>&c&pzCq$z)-M(gzt-HF291JB-C*2~7Ku?N4!76{<4vDMno_SELVahKpadagG4x-U zDtwt?_;jVM)#ZCsh8tTiyoopq-FK6m8K#QxSR0V|Yk<~WST(Wm{>9^@@xNhI{1uW^U?j z%=Jz0ZF>+5*Mt-W(d0~OUbFSN!ac5$mKbBk-jls`p<-c@eY4lsesA7>J8wW$xH=je z&l(o`Or*ED7ShOU%VzoDIAag`xSGe`Rf?>&-NJYH%B&`_`1Vhjeyy!-@?)NGjt)Qn zJC~EvaPW0~!PV>thm@HTNOtx4J3GsFZTcq2+OIzRgKe0$$y_eQ)qnfKD^@aV3xjL! zOy>9Rac19+7myfDCw>$EU5Z-eutuWZih54rzV3^9qVN-o7OoX08yAT3Nc@mn0D)ME zrr|r`U34iEeM5*0_nSNOTBY!rPz=0r?)n}X7~2~-i1Zqy2t;ssVYtK>Qk}L$dJ>40+JY}9*^)KJ2;(_y_ z=O>@A51cj@XzNFnM;^kBUVu_ax2K(#e{nkQa$V= z!jlv2D!&I2_fG9r3N6qgpN>7l%=@(La7Kxg!TgiTk`$klls?0~f(4&>N-J7ePq9>L zi;Fgf-cgDOPH~}%u;4!X;eTo=Kq>i?DYEoDSm8)r`@WO6LC|ZjsCEO%DzRvmO-qye z(S1ddxs9R`W6?wB(IZUIQ8DPa0o3tEh_)4UrV%4vHpS6S z$K4W-qoQ)ZEgsKk7=M2YdY8)UK~p^IbUgc(D2U4Mp?Cs^VZt+z$m7WGTuljl(+RBU z33;2ugjeE;LR9fhecG!Ai4skTQpGVZ`lF>mN$oC(EISH>F$4re{<6A=2s7ZPO9`=?8V`3AV5jLl|s2J!LCRjw;>xHOw+3 z<3n9W#|?MzRz{vUtPBrM>lbP6&uFFc0zZeN)8VNgcy&L#`FUn_Bz#;MRwtg+K%5ro z6&LBHg8gZN4}##Ok(o==nO0+&15|JfUidd2G18BinnqAO$XrX$RBFnM7e{9m-WEPEF#M=GiAp8 zWkby6I#lJOM&&BX<&&^-QP@k_U16HxClCU#V@$VvG z`A6)5QKcfjLWu#eX8B-^`>#v6XQo9NfAnz=BsIiYRjy#S+;5*EVU5h8rq#o zrqX&wLN#4f6*;!voTiqErGdu2?n6cucT`Sef5X6L0~a%LRUCQ1f%H&CMi_}1*w;Lz zsqrOLD(%#(^EQO~HkkNkz<5gTDc1{@ihP!=QKxBo;ahj_s9smKDQy-RUs}giTCH%< zl&vcEZKo<+ve_b|@*{6kAxopB>VIA|36_1kzcD^TgqeV(v~Sc{X>LN*b7V9DSQON_ z;p=2W522yg9_j6i96+@U(ICBcisX&!pVKrI5KC(+2+cDYs4`vy~fa zT(yM}Tb+{88k|vIuG;Wxr&YMLP{bI0?2GQVMdPE;Qj&F-gxVb6wpaG8q|t53#wd!6 zc5;Vy7q=oK=F}tRxPZ^iDBt!@Li4pd@h{aK6m41i z6BhIgDl6ooomRZ96;-c+Z8t-8#G*RGeLJjZ&|%mnL;EK5Y%7OUgD|`^(7sV(uIuS# zrwwm|en!K++0Gur%+&3;m8j+kug=Zw?%n2YA^S=T2a!)EJvL>r*6d*VDo@s$@(E zcHLy{vYKtOwr^#L#;TO{V`y3jRR@N#z1`6Rz0oahM*a6&`uHK;Ewo*-d;{T$`KlL~ zORt_usiudJ_8)$I{8EjpkQMf3-SmVnsKgl63 zR^gVYE-Km<3ff;}I|A-F(<+|HBH`{SE*Y_P(cm|0TniIK>#@xAT zOW3JyWo;CY8sXjPkK-d^vUbtW)iC^nqw##A?2faru2W?()IMpHgvJXqe$T^cer{(5i7u?6GU(({UL zGFW=*2UOIgJR$08irsc9PI`KIYU-t}sI$MwYtwGA@|c9kJTP+`TR%3!bZ{FLS6$i& zZyro3$2or<407z{p^cU2nTgz)VZe8pl}*aAjqh-`o(_!R`vzlXrw^n04>o&kC9=6} zyELu_)@cS2#JwW9(m?`uPoUaRzGNeZDONMO8C`~LfZ+1{#}&6TmWy-pnimXr;}{`h zAyT8(nUiQ!3?=OMQQGhY-}rCZp>o3D73+{Ff0uUoBqzRd1Xf|rA_By>Gw z#6=smkukb#ViT+p8e>m8E8E&k?)Zn;GX9uuS!{O_2~W>#&gOqvH02QgdvI}qwjs^9 z(_ubZ0=i&NjrD^ju3U(+FD#O(Y$Rd2-qNtK-|l=z9Hy%t7%MD z`5!*^wKd8<^48(M#;ec#t6vl5@6nA4J1z|I7k}G^cc>LU=${RuTNXB3l10P_F09{n ziXl3ibQ3b$T1~owoQ6JM4P{E>TBH}AEv&}R{E4(jln<;CY*zA1hd;0_9MR!UpiBJC z8-5Ej-xKH8?C08~+uut=&s!5j&B_z5X6_r$atQuC6t#a)8Z|_kexPNa*t%ctu6=md|B%z{PmlU4aP|8m`vlAOKkCI^g~gG( zi~oM!IwVFff8CEYy0t+@)u$}A{f>CZ#dj#%+;(&RNVbQOA zOA3xNV8Nk$_5l%-1sf;4kM{|a!&V02jB+uyDslnQhC}{18Z(|VSUfO!U*S?&R=zLt z%LMoI*6tQFp&^S9971SbB=~T#p#S49@g7?aJuiIy(#Eb5zZh&=96kQ@7d(|T_8zFc}6WywBav>Rc zSn9mrIV7^4^~b*X93TPz0SA-QvCE}tEWP_qep`wI_|qO7ev_Hhz(w=vum8Tlesf+` zEA26yZxc9dMswR^IrSSLVhNn8aZf*DR+;FRND(0N(^Wh}k$R3ilwF>Oo)ZEUb9^Oi zJGRoFMsBQ6q%2cdEj2(5{Th^;37$$6@BYAKHau#oV<+W&OI9kfyH( z3GT|T*C+Bm)19%3o$h_=fohYUVl^y3lnLT_@=)VWR;@8~0YquPsiVz2TTU&%sT85P zTz7G|fGwopTxrm?g5Hequ|`*^|Me|#)X}egqxYDwLFN}rSZ%7sD>{i?ji2r1uZ3Dg zJYbNCz zY3ej&Z_5j5%HLy4>XCmKCZwgzmCsnLuy?%Q|L2(F*5EtgG9C3*q3+$D8l_CEc5NGN zy-DQMsOp_l;kM$p)!gw2~IrD1JnD0_HQ(n1r=SVDMPe{O+pHPWAepZ01c6@Et zXY6TD>;04>oOUw5@C)n2LQ9TCP5IN}r!xHp4Azy5XIEa;CSuvf-+5BVU%TaasGYVF?vqBFZ`FpsgBHKAz5SGR z;=Y$iF36c{?`^`adt=w$!HA?x=*NiB0`Q@s+7G#pF#7aH`AumVMi=*gJ5##p@bS^8q6uP{025Nqa&rDUU2e0QiG^O4u$$vsf- z_Pt%>s89U90rB)0Ne~(g$QXMBmML_wdFjh1)kFl|ZQ`74IOeFs;wo zu@@V!WT@|^EY5&j)=bRhV--U!8cIpOwhz( zyMpQ{5SGsE{4ZZp9WH2Fx!Q-?3#CAz3 z{XjxYyv^%KCC2=Yi9AMAd$VF3aWY?Jq5=uAHkagqWP*9~edPJ}a(twRfj#}xYS>*5 zMzw%>OT`@{w)8uns~w+B*3ui6>AmS1*7?{6V=aFkFjBzkMom$!@N37~k}%;dBjUZm zywm&aK8xSJNCm9*@h!_z{TcT02E9vuC!NxC$%H*vBcp~xc*fLn@WcI^GO;>(ETEzj|Vx$&P@qXNKThWJT?ouDwTUe<&CZMLnY=d;sE^ryA?gIZRi&NDbGoqBY*qtgSPnR$vcpk5m7 zl1flt6!C11FVVSAd}=)Z_xs)EC28jyP*mV?57KWn^RMUMjK!_fGc=aXB`7505BbJv z$K3$OFhP?UI?u-1$Lt3d@8Qdx4d>n8GF_p6VJmFtlis&7_VKZo6P%*>5>3RRb|ri* z_bVRzhRrSA*+=7F&ZD7N9XCYCIF^yYs(@a&Z~ns zYfn4UZ_b$4#EHX0SF@Se|)%{Jd?(M|KUGx z{m_5&$o(w3yXgeUuW@Gc@Df+ay)^9{ckmE>w4wN>JyB{D8)s$z=I;%(Jj?xsj5p}z zwwoO77qb!LW0HrmGC-N|Pv+KjUcMWw&0C%5q?xjtWK0*I!T2MYOM(p9F?dj0dWiSU zQD^%bLz%o4umf`k<0T6!k#&gx-fxuNDs5#Oe?ux4(dFC0B&n4pDe=iba(zh0;n=%3uJ6itWqnFJwvT=Zb&1ijwu`uTLRa3M zBzB4)i;1yHOYI^hgiw;JvPP1f{WM)cN3!d@a)D!=BoH~-%O+{EE(M(?`6OxO-3H-k zv{Id%7E9Omteit<*F&;EvPa!oLfzVO-8wqmx)$Af?%n#K-3CeBhI!pab=}5Y-6rGR zrmNj%$K4;uddwLWKIY~1&4PoNdMtE$EG>Gh+~S&a@fwi#N$U0O>h%+ncjzi16IZAr zYV?u^D!MT$*_-rwjCY5~_37vJhCzVvxo%G#`AE6$FQH1dEq$SUO3?A%m}4cERYl~C zLZC$-G`c$)u8;)pc7rGyIw(izC>!S~>A;o02=&KacBkkK!&kvK4gfXg9Ds{({Tq;a`QV6xc6iLZf9;+1ZVuA-$ za^V;#t71u+QoR&5hfk&GxWBm$YeuHhz@%L3pxPj(il$XcVN^=uP(?@g7PTma)%CZ# zW2@^_GTjH7>Uv9cRN4nr47z^tgm&lF4WP>)!w}WZV@MN+TARf{c^QN_?$_Tz2Envo zaiMC41K7QD#oo~J->cXjj)5vZ)iJ(7qzR;_WiXmmrQE%{?ousncfeW)(ln=5sM9yg zr`92*wxOfkku+2~pxzffxL=2z9#>E}rkWjB*`^&jTE#R%I3Dp<@#D+M=yvQWM(t9An=u z<-SYGv0Q3vqM%KL;S|A?RD7UI%YKT9Vi|1QXRE99Yw6p z)5~!wp`KT4y6R9JO(|Un|2UV4t_h8wg-YbkoIoSmM5V;5@@{UdcEwT^iCVoNqVIZvy8pu!ajb!F?m23cNQJ#5ol#JQX58 h6{_2#rvQ|c68ZT}_4O0^6D{>Ew~B85wlpP!!B`NennOthFr@;(N&qOH zI?)uc1Os3Y08-&kSJbCw22+ASN|X*_z;6H`0{|8vQZxVSmKgw)0N^XX@T@*?0}LpE zfJE=NF~3c3k-;D=C;@RlhWP6i1(`_+D^9I{3fPhXIxGMxbqeq{(kvFqux9 znx7KT|DOSRdZ7>qKu`Z~M5?>|iKqIO2K-_p`T#W;m?^q$YzctD00;!U=MXUg0B!0U zl>bo_f8YMtL>Dpz9aahS+eA;rGzL=>GMS4d|Hxod4$6iv=J=fSwE}VRhzWDQSrSB^mO%ih|G+v7K7)%PEA8Ob_}u1H)ZC0N?}w zojrbt(;Njr3jmY=l@f3b08W8e1_~lzM*f$5DK&uO2d?x1ivQl<|6JhzUl;z5^nZQ< z0Fi)eAWrqF{Eko%tDs4L)wiyQ>wKEo>eU53F?as9Tj;MY>`S<->_qMI{>wlL{~M&q zKus|&#z-M6XaYN3$L|iMo-L z-aS~4ny!4`70soEE>kMk973An(B<9V!(`DMX&XZ*gK*(x;0vnLu+;p-zQmB=;B(?uf(bO&8KZ`DYKWkA@q*amj zv1jhB)Wm2=OD^W}?B^=3GDrTN=NI63cluhctny)}A!LE_a=jtgXN&7S#E((1|4!(M zD*wvYoBI3)0iZ=Mr7xGit%E&?f8G2+0fb0qhpzr5)gCRx-DqOQ1V1wk?Y2dm#W4() zTEt77MizuA(F&|3=6~=`48IRfE%KU;lj4oqr0F+`2C8OwL%i!FR%4BCrxu4A6Z(sv zGpB2;W!b}+K@-u?wo=KgqI6!H40`jRHD>GVNtV|bHh42?;{C}%(p;FT4i=VY%WFNC3g25s*vgW$+h}|ACq6EgVv*((UuD_ zc@Jgw3a-NkR~zAi7kijJv@tl6rgx4b(8VZ*r=DXBx|P%H$qIk&5{p=p#zNWzV(mF4g7F{`(nn%RQ`Kk4gqT!y|scMO+<@ z@#5203zXDrWhVsLv)+?o863U%$g2$*s~(!UvR`A`8R5Ui^){^`6PNXP$8iJe@@KVK z8ywHRyp0e!ow3YtJe{>EDL7PM7*0;?aqqiKh5TA zKT5CwG(q(Um3_!d`>e|F@JnaP(t0AB48v;|_v<%vY04W~7&Vs_9+k}d@a*F=MEo|~2G{oF5(f?n_OT^~|Y;k`IY z()?<9Q>3KFFQ7a|K)R5&gl$kST<ExMPZp{{Co14^UvkypfU$dTa~7HnC> z+Ow_hI_Hw2J5eP4U|OT{+4WR>jP>yg1Dtq4a=IXC?XJ9P*0A@^c%G|xv66+M8vQ{^ zTt^+BJQ;zPC`igjUGd)G(ro##p$CJg+<)jAsS@Ywo-|Hvdo9kO-{YUB*<0E_c*g14 zofML@c~xySLv2)5;h)|1sh6G~&1$auxO}63w;}MrxAiN=CAU+!R7E4R^O-^dLa%;P z`KWPtK(#)zJ5*3*UjUOf^(z}3wycx4JysJxS;j45&HF%_fX?+OOMi<}`w*>|>6Vf+ zfl1MgiymgV@g`kqf0v8VZls8%KG*138E1xO@0|m;s)|&>r=bkm73iw!1{HqGTY}p1 zb`^!GsoO@+WyiFVZRM@_oU>RZ);UR=0tjxY_vxC8MzYjCoq z+^R^%^>S{mbE*iXDrRCUq@!Y#l=Y3-{~yD{FeDmX@KW_bHr@SPl6n$qcq4n3u^^Fpkuud5i`!abK~pzR^7CjV^fD?Y;+0Pe zl^3^Pamc!*o1I2Wh&bLBn4gRF^sEz$+wU{ZVPXHpSrdt4ag(|Qtd*D>5{ek;pNs^nhaQJm1?xK^cj?>Fx4PchK#SrU3on$FF$)^{;L z!6&|T?wD;;674wj%*e;VlcRDPCKb`F87hA`J{VALG38U~?erkuqILe7BzlATkhWym|TDBGF{JWCch;7%fuG23h`cmRu*CgeLI+ebw zVYjB!ZJyC;?@yCUR~ScWN}xRd1vAh^TeV9X2j`5V9dg6_vxYZoRal zFV;39&F#Oi5X$3&`yYm@D~Ynr18jahG`K zrJEkO&gK$v-@J1AOEFtWy<~{bqab5y%iEBE47JbnHbI?g!9x(oVOqzoN1+Uv!QpD5 z4CfBqkDMmXyi~jcl2Zb9Hau>qf3be(sqq#f{K!wQ(Q1dzx#Si^{L#mKtFWV~z-=#g zbe~ltx+nZ zamS|qO|+`M8?xWp3>{cCZh7`8+F&EmFY+2lL*R6WFRKc zXoNEo6R(4lZXn{AiBYURNq4f6*taEb8OCrBlkS3(dBGA~QL%hJ$^2Q#cMOwTza@(j zlONNQ5`~*2pBSb{_@t~!rARfU$jzpVmZm6xQ~!}p4W>#}@kv$BO0~C0)tpV$C8oA^ zrs_$jz4b|bZJ1_|l_u$vW;B~-=96qfO#3LE&IV4m^hvkzN&J+R?l7Bv)|l=D&T#XI zcahHU^vSp>ZGAu;?>(Cln3Vyp4VgU8_-dFrWRMY_l^N|L8L1&5^xQ!_>c&S_)(+)x z!D{zppR5k|8)@_}lbf<0R%aH>#>GWRe2dERbB9_KLh~}A;@2MHmgJ;u4kZJOxhSWCK0gzjm!px#uIa)sn15GL z@**pTelCyJ=-UICZ-UTo`93*S;N14v+&d&46`mK@OA&{4vmA?aq z${Xd$_`<}YMectWz=_{9FN&lFiu7cPZ3K$n`WBnp78_uS4G_g97sW5Pi{Hz@)dk>| zzVPR^a2pK#)lR-rFWhCW*hwbS)u==l0r!NK@J5yR&XuqalmxPu-k>ifg&37GXq1LS zODUsDqvuL5`b*>45x+qQ&KtmIRv;b9lZD}dA$c+{5a|ratT_Z!5Lq0JNVY3U9YhrE zNE9LwY3!)hF+{l$DjSM)#UQKZkPgZy;5~|_6NU9fbqJywkx2LGLNC5DyH!-XW?8RH zS&vM4pHT^B2jR9_HtLHk+Cg<(Aj+bVlNk6k1Im>T`3+M(#$G;b^aL+c0WqrBy^xsG zET54bg(` z2v#+Kj1TLo1YcHr@KxTGt%>BTx$jpKYEi@AT*KK!s{Yk4$qFlnVXAI3Rv}G7@cWU;6=7>4wW^ z@I$<4uGqIj{lnN0c}>Z88zDbHBxglM8Pr@nroe7B#cqD%9m&Yd$q4$ z(;1>hTMJXlAr@nwh?vJjG+|h_F*UGQxNI{T$5UmWgu~Q2D%aY|Vug65_Mty}}Y zib%%tPR%BD!J0m1=gVGSB=+f`)Oaf!I;zMhki-bwy4?avRhwbj4klNT69%jXqB%U*S%$IZ*Hm! zlx;nLwp?ebH<@o?;B4QTPu?+Z=(d+=W5l%2xBrZ(W-;k-Gi<)OC;3dPQ{Jyb7uhL# zCI0ZLQ=g;jDZbXquL8TGCF4@^L<+@o%N)tXGlkP?F2|jOt##?3Q=v z-eEvrHFpPs8+Eg>dfJV&SMAk;ZTeRkOxZoP7aa~-t)KjRhhV)Q7Sb)`I;lB3Otib- z`FA?*^$KTqD7N&N$@RG{^pTGI`n-I)$T8SJ&K{bWx#1aFJDsF^Nq_fU$ zBB-_GOC0Xk;FxzzEnaIjY+>d-appt$Fu`H`W()3y@OY+t(ju-SCt%!!aZW*Gu8=FK zSiXJ!YE+v8!}n+0ZE=ogw)<5MPDG@-R&G*(siiD#o(eG!|AWuXnG1yt#mFsmb0r#> z3{#PWXOTJGLZ*|$IrGp(loiuxSnCKq^TfTq`oh7PS)IB0#qmuY^mgk~^3L?ZQ0qR| zavXAs5U?2jXRtwMSvG3Y(-^rWH+&UPa?(0)=|2GwhRJf@HMW});i|c7Uu~DAvS$>y*X4D`i2=*n3h|E!iojo-r2&L*LQ6Bu8wt^CcXGdv>uj_R&A+f;Bsr|xwZ++)uHKAkCDrTT zQTwxR0ypgjHtsELTw7RRYMxY&9Z?k78qwL}A#Ir97c^SySAJ{t^ zYFoF>-G;Jk?=`ov1$M6vRdq5hrQug!>Fy*P{P@f+4Uh!v3LlU)<6< z{&GK5cXyC|_DRLi(87B3!TJ`C|I9K!my+y#*0E`#|lH}jGYYQ2N`P-1Zhp>Xus@GyzxcF z!qZ&u+|f|k+=R`nTfP)(x@ccc#VTHf3SRY^!~65DR1B~1By1vqeD$I2YV0s&)cjA6 z&YzhCVlz+cymQ7h`OnbOpKT$ME10yAm#~#baz^~wdwFp{CY8J--4Q0QF2Jah$s!2y zZ)Y;>FdwJ}f|Ww3m>H-O^;Z4~XXaA)dgs*-mFQa{X5E>u{=Hf*`9Ny$>oxV{2RgYb zSwGt~DFGH?1E25T@gcNtmb$avZ0hF92au@Q-);?OikSCm8|ZE0zv<*Cgt5Qdd5e4p zyX`^m{y?WfqCAj>Lx0bp#%kzwx9?}6>0;1uTNnrAzy#yL0iP7C6?xO(`G-WqY4G!V zymwN~zNW#^$KE)um}e~>&O>bpT#W76hV1|$N8XQw<}~`X6_I4cYo-Z3`ZQdoh~>^V zI(6uUznU-eck6Ik`r^KNHRR&HK~eD`6rN+!WIEqqzr?ikSY~FM31wcUn|*#XjB5>2 zwD)^@kUgE!`OMi(W`nTT#7D z=hT1P6FVXc+$*J4mtbPb%#|Mngo^fLuQh`HFea(6E;105Zn060sB9ZJB&twp{fZV~ zXZ0`bWLS=IROShqKqzbu`W>n4lI&j<+_L&w-5YTn>e|bGqU^@YU^@So^4*5D`;}xGWO*SPSUpa@~KSPl;qtk$qMr&o%K3bGud@CtGC~l*@s*X$J*iai-Vfg-ezYk z89ldaf6ZRzUMg`4?3%T#FLy*U;k0njw-_($mb>c-c2A#1x9kwSNd6lm6pvazk2~Jx zbZG6C;5--z;O5$xVGGJ}fH``#9#5}tq#Z1o=KlFL@3krIy^^5D{c|FN_SaaKm)fyU zO;UEY>w=`Stnc>t)RNPl`_v!5?rucwTglwkMeorCFA-k*{p>7;3IJofr!3|@|9YXgan1k--z8S<|eg4(|PLZ`B@ z*m$Nu^XX>@{RGDW`&kDiOJZ2>t~ry{c^&yLQR7F#_ek22|A1t!f4NqayJYn6IpbJG z$ZuI*+87)0-R)sFp0DN?dRt1jmYk#BG8M2CgSx<;qcIAo4>O_ z-!(gmaNfIn#4n{n>=^YQL9Md>-T0#a=t+b@%SU$OJO4-qjwVJ>7iy)3m)}dOju)}y zW8u;0qt$;Ey<~rvW7GQ|-G`&Gxm|^cf};t??#tjO(yFKO$&ry?t%O}~_fE!D zd%U{;K~QZ*^WN!EET+Z$kpOA-h5GT+!1A|zPZ6GNT=CbUl&Fh9aZOr1Nw3pVWjDka z1+<(xlhcRz^f{}g2gICeV2Z0BCC7bqJ-H8I6b?CC@L647TF0E<-PQ_L=R+@&@pZsEL_OrXrn66@H+X% zuWz?SY&F>gU#FpO7Cz!aXjut9NheIeX~MR3JT8Wz2NNY+xb2r=zSSEBwxw!unYJHm z-ohm&5ii5+-WJQeL+Vc=Aw72b^_X`Ro|7nZ8he8t8U32{$ueuzT?k!*L|(s>9SsHm+5ZC9-fSTN literal 0 HcmV?d00001 diff --git a/html/images/nodes5.gif b/html/images/nodes5.gif new file mode 100644 index 0000000000000000000000000000000000000000..78ee5af7d0e7ef5f93925ad374b97a2ed41311b0 GIT binary patch literal 8316 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 bm3;i+V6*~(V#miySlS&-G?~em0IB~1aSCF% literal 0 HcmV?d00001 diff --git a/html/images/protocol.gif b/html/images/protocol.gif new file mode 100644 index 0000000000000000000000000000000000000000..63e542aed43e56a520b41591eb7429de857f292f GIT binary patch literal 8586 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%0AZOB{fO?0czjnya8?ey4;yvHlxj^N!E3 zsjyr;TVTuVE(dtr^yyKVEXG#T*W&@B>1MGJ^XfAjnXc>h)l~-G8!{H8?xBu-Kk*DJ z$9uA4MbmXiPi89{G9HRv+nQ_gKIY;8!hGt83B z?qw_Tv$B(3%ZHe&GpmHcwE1yNW%~$e(N8ONYO3C)?>aUEJuP)Zl+M{HpTr272KhNOF06TsqST&-K$1(B<~mP$Y<#>^jvGPJ zw@$B#MnMib@O?V(upXm`nZt@u@69g?o`kWPBSfe7_IIr3%<;@Imdbb_jCm7bA*^Z v{~PLiwxr;DIyOr_?(`)eVtxO8wJt8`nt^N06g!Q}bWDa(z#Y`U1-#280lX&P*+~v(2=XE zKbfVMo-HTev=^IyuKB%n;^b9xIXAX7RJ|Dbcw8DMlH2lCtu=)Q#h-7tUBA|ybyhcY z=hq*;*KxIa@69>aTgJ^e|!aCmcq9s}w;H~n=9Ix8Os z8a^F=zrU;d|F5%Y?~(k1=DKf>-mM*c-0;4R+rQqfkKv&Yrz%H>$_tgFukM_Q-rB+Q K%V*_twE7<>Tt1)x literal 0 HcmV?d00001 diff --git a/html/images/security.gif b/html/images/security.gif new file mode 100644 index 0000000000000000000000000000000000000000..74e4182691c0d4fe792481d4fa723e5644b8bc0d GIT binary patch literal 8033 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 literal 0 HcmV?d00001 diff --git a/html/images/tty.gif b/html/images/tty.gif new file mode 100644 index 0000000000000000000000000000000000000000..042d7a5603f781c7ef22ef3de2ff1d76e15ef749 GIT binary patch literal 10032 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 literal 0 HcmV?d00001 diff --git a/html/images/tty1.gif b/html/images/tty1.gif new file mode 100644 index 0000000000000000000000000000000000000000..168412ef59d0d40e13ce9722b770e7339db1d72f GIT binary patch literal 10047 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 Ap8x;= literal 0 HcmV?d00001 diff --git a/html/images/tty2.gif b/html/images/tty2.gif new file mode 100644 index 0000000000000000000000000000000000000000..df2e9ee46dffea563499ad8477687942ccad6924 GIT binary patch literal 10357 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 J(trTj{{tt)r(OU6 literal 0 HcmV?d00001 diff --git a/html/images/tty3.gif b/html/images/tty3.gif new file mode 100644 index 0000000000000000000000000000000000000000..19c787f5cc100896963a5a2840096e5251d9d56e GIT binary patch literal 9243 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 literal 0 HcmV?d00001 diff --git a/html/images/uarrow.gif b/html/images/uarrow.gif new file mode 100644 index 0000000000000000000000000000000000000000..9b89e80542419a37e7c54c5001a736ad7ab6fd47 GIT binary patch literal 1147 zcmYjQU1-i>6hH5pye@pa*|;FK7c-8M=7N+qZ9cA$&V`S{YmrCG#k?t*wCwo(A0K&Y`#;Zf&iS3+`Td@E!>0ACR_~oh&GenJ zrRh)8M{!cUi}mjA(Bm&cWJHbxCSg)0V{)coA|Vk{Aro?;z){JRTqyu$Bt~jvMs5@d zMV!>hoZKm#BuIlS$O8=k1^^Tx3lSj}VNn)iah71jv!x;?;v$jS!Q}bWDa(z#Y`U11x5PciycOJ7_fF(zF5UHb_|pB;({rtz`8@*< z&g65Wl>>zFmkzUEDK)14(_^Q4FRrgf}Xd9aO&`>K`M+d7|ikGJ2bd;e|db$8e4Ba?=^cH^eh z+jr~trdnBCT%z~OxzRbjrKaAaXBWiId_#3@A)0F59QZNtvA_Ao#H-tzd&>RA{iTW9 z%d2;uw{$$MD}0@QXk?(HJfm@4PrguWzxHVLww_PVi|v1JPHm`bEL}y_(3;wY-#Ob; zY;5pfQcHBtYOFb#)t6@+zIYj%a>Ma_`uB5d)1O^BPFcF>|6_e=(cAL5{>~3)ny;3( Hw$hqkGomyD literal 0 HcmV?d00001 diff --git a/html/images/users.gif b/html/images/users.gif new file mode 100644 index 0000000000000000000000000000000000000000..983e8ec7f09560948362235d62c68477da591878 GIT binary patch literal 13897 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 literal 0 HcmV?d00001 diff --git a/html/index.htm b/html/index.htm new file mode 100755 index 00000000..a7aa940d --- /dev/null +++ b/html/index.htm @@ -0,0 +1,136 @@ + + + + + + + + +Running a BBS under Linux. + + + +

+
+

MBSE BBS System Guide v0.33.17

+
+ +
Last update 07-Jul-2001

+ + +

Introduction

+ + +

 

+ +

Release Notes

+ + +

 

+ +

MBSE BBS Reference Manual

+ +
    +
  1. Running a BBS under Linux
  2. +
  3. Which distribution to use
  4. +
  5. Basic installation MBSE BBS
  6. +
  7. Finishing installation of MBSE BBS
  8. +
  9. Configuring the bbs with mbsetup
  10. +
      +
    1. Edit Global configuration +
    2. Edit Fido networks +
    3. Edit Archiver programs +
    4. Edit Virus scanners +
    5. Edit Modem types +
    6. Edit TTY lines info +
    7. Edit Fidonet nodes +
    8. Edit BBS setup +
        +
      1. Edit Security limits +
      2. Edit Language setup +
      3. Edit BBS menus +
      4. Edit File areas +
      5. Edit Transfer protocols +
      6. Edit BBS List data +
      7. Edit Oneliners +
      8. Edit TimeBank data +
      9. Edit Safe Cracker data +
      +
    9. Edit Mail setup +
        +
      1. Echo mail groups +
      2. Echo mail areas +
      +
    10. Edit File echo's setup +
        +
      1. Edit Fileecho groups +
      2. Edit Fileecho areas +
      3. Edit Hatch manager +
      4. Edit Magic files +
      +
    11. Edit Newfiles groups +
    12. Edit Newfiles reports +
    13. Edit Filefind setup +
    14. Edit Files database +
    15. Edit BBS users +
    16. Edit Services +
    17. Edit Domains +
    18. Edit task manager +
    19. Show software information +
    20. Create site documents +
    +
  11. Starting and Stopping the BBS
  12. +
  13. Setup mgetty for the BBS
  14. +
  15. Programs and utilities
  16. +
      +
    1. import, Import databases
    2. +
    3. mbaff, Announce newfiles and filefind
    4. +
    5. mball, Allfiles and newfiles list creator
    6. +
    7. mbchat, Sysop to user chat utility
    8. +
    9. mbcico, The Fidonet mailer ala ifcico
    10. +
    11. mbdiff, Nodelist difference processor
    12. +
    13. mbfbgen, FileBase generator utility
    14. +
    15. mbfido, Fidonet mail and files procesor
    16. +
    17. mbfile, Files database maintenance program
    18. +
    19. mbindex, Nodelist index compiler
    20. +
    21. mblang, Language datafile compiler
    22. +
    23. mbmail, Mail Transport Agent for email
    24. +
    25. mbmon, The monitor program
    26. +
    27. mbmsg, The messagebase utility program
    28. +
    29. mbout, The mailer outbound program
    30. +
    31. mbpasswd, The passwd wrapper
    32. +
    33. mbsebbs, The bbs program
    34. +
    35. mbseq, Sequence number creator
    36. +
    37. mbsetup, The setup program
    38. +
    39. mbstat, The bbs status change program
    40. +
    41. mbtask, The taskmanager for the bbs system
    42. +
    43. mbtoberep, The toberep.data lister
    44. +
    45. mbuser, The userbase maintenance program
    46. +
    47. mbuseradd, The useradd wrapper
    48. +
    +
  17. Netmail routing behaviour
  18. +
  19. Fido to Internet Gateway
  20. +
  21. Nodediff and Nodelist processing
  22. +
  23. Using UPS semafore's
  24. +
+

 

+ +

Other Notes

+ + + +
+BackBack  +TopTop +
+ + + diff --git a/html/install.html b/html/install.html new file mode 100755 index 00000000..f71dd1d6 --- /dev/null +++ b/html/install.html @@ -0,0 +1,54 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 03-Jul-2001
+

 

+ + +Installing the BBS. + + +

Installing the BBS.

+ + +

Installing the BBS.

+

+Now you have shell scripts in ~/etc, most of them are called by cron, some +are called during system startup and shutdown. You also have some default +configuration files, these are ttyinfo, modems, fidonet networks. In the +default (english) directory you now have default menu datafiles and ansi +screens. These are copies of my test system so you have to edit them to +build your own bbs.
+Editing ansi screens can be done on a Linux system with duhdraw, +this is available from 2:280/2802 as duhdraw.tgz (68 Kbytes). +The binaries are included in this archive, if you compile it yourself +it may give trouble so if the binaries work, use these.
+Another editor is available from +http://www.drastic.net/bmdraw/, +you can find the tar.gz file in +http://www.drastic.net/bmdraw/files/bmd022.tgz, it's about 36 Kbytes. +This is also a thedraw clone for Linux. Note, at my system I needed to run it as root.
+You may also want to edit ~/etc/header.txt and ~/etc/footer.txt, these +files are the top and bottom of the newfiles/allfiles listings. + +

+

the next step.

+

+The next step is the setup of the bbs. +

+ +Back to IndexBack to Index +

+ + + diff --git a/html/intergate.html b/html/intergate.html new file mode 100644 index 00000000..bb1ef0b4 --- /dev/null +++ b/html/intergate.html @@ -0,0 +1,102 @@ + + + + + + + + +MBSE BBS - Internet gateway. + + + +
+
Last update 26-Apr-2001
+

 

+ +

MBSE BBS - Internet Gateway.

+

+ +

WARNING: THIS IS DIFFERENT FROM VERSION 0.33.14 AND UP

+

+ +

Introduction.

+

+Since version 0.33.14 the email gateway is build into MBSE BBS and since +version 0.33.15 the newsgateway is build into MBSE BBS. Since version 0.33.16 the +newsgateway to UUCP nodes is added. To route +email trafic to and from the internet you need a internet MTA. I stopped using +sendmail for this because it gave too much trouble setting it +up together with MBSE BBS. +Today I use Postfix, +a well documented, secure and easy to setup MTA. For the actual gate from +Postfix to the BBS you I use mbmail which you need to add to the +Postfix configuration.

+

+There may be two reasons to create a gateway, one is to gate internet news and +email to the Fidonet bbs users, another reason may be that you want to make +echomail as news available on your system so that users can connect to your +bbs with their favourite browser an get the mail and news using pop3 and +nntp protocols. The setup is the same for both reasons so I will make one +description for the whole setup. +

 

+ +

Setup a newsgate node with inn.

+

+If you only want to gate internet news to your bbs users and not want to +make echomail available as news, and you have a permament internet connection +then you don't need your own news server. Just configure MBSE BBS to use the +newsserver of your ISP in screen 1.14 with mbsetup. All other users need +to run a newsserver on the bbs machine or another networked machine. You +could use inn news for a newsserver. +To connect a small feed with your ISP you could use suck. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. The command mbfido news will check all +configured newsgroups for new newsarticles. If you set it up for the first +time you need to run mbfido news -learn to fill the dupes +database for news with all the already excisting news articles. If you skip +that, you may get a lot of old articles that will be gated. Just run that +command once after you have set this up. Later when you receive fresh articles +the command mbfido news will only gate new arrived articles. +See the configuration of INN news configuration. +

 

+ +

Setup a newsgate with rnews.

+

+This is the setup if you don't want an NNTP newsserver like inn, but a simple +cnews setup for UUCP links only. In mbsetup menu 1.14 you need +to set this up. You need to fill in the path to the rnews program so that +mbfido can post articles to cnews. MORE INFO NEEDED. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. +

 

+ +

Setup a newsgate via UUCP.

+

+With this setup you don't run a local newsserver, only your bbs users and +Fidonet links can then use news. You need to install uucp +on your system. With mbsetup menu 1.14 you need to set this +up. Suppose your ISP's nodename is xs4all the you probably need to set the +UUCP path to /var/spool/uucp/xs4all and the UUCP node to +xs4all. Your own nodename will be your system's hostname without +the domain part. +

+In each echomail area you want to gate you need to fill in the newsgroup +name of that area and echomail received in that area will automatic be +posted to that newsgroup. +

 

+ +

Setup a email gate.

+

+See Postfix (email) configuration +

+ +Back Go Back +

+ + + diff --git a/html/intro.html b/html/intro.html new file mode 100644 index 00000000..56443d68 --- /dev/null +++ b/html/intro.html @@ -0,0 +1,99 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 28-Jan-2001
+

 

+

Introduction to MBSE BBS.

+

+ +

Distribution.

+

+There are only five official distribution sites for the mbse bbs package. They are: +

    +
  1. http://mbse.sourceforge.net Primary site +
  2. http://mbse.freezer-burn.org Mirror site +
  3. http://www.telematique.org/mbse Mirror site +
  4. fidonet node 2:280/2802 (+31-255-515973). +
  5. fidonet node 2:280/2801 (+31-255-533858). +
+If you find mbse bbs on another site it may be out of date. I have no control over these sites. +New versions of mbse bbs are announced in the fidonet area LINUX_BBS. On the official fidonet +nodes you can request the latest version with the magic MBSEBBS. You will then get a zip file, +in this zip file is the original tar.gz file. This is to let systems who only support 8.3 +filenames to pickup the distribution package. You can also subscribe to the mailinglist +mbse-announce@lists.sourceforge.net to receive announcements. This will also work for fidonet +systems if you send your netmail via the official fido/internet gateway. You can also +subscribe online at sourceforge +

 

+ +

History.

+

+At the end of 1997 I was looking for several BBS systems that could run on +Linux and it must be capable to run Fidonet mail. After reviewing almost +all packages that were available at that time I found that there were no +packages that suited my needs. Some had the plain user interfaces that +my bbs users were used to but no Fidonet capabilities, others looked +awfull or were difficult to use by normal bbs users without Unix experience. +I also didn't want to run shareware anymore, one day you pay for some program, +and the next day support is over because the writer of that program decided +to stop development or simply dissapears from the Fidonet stage. With all +Y2K problems ahead the solution should be Open Software so that you have +the sources in case something goes wrong. +One package was very interesting and had the look and feel of RemoteAcces, +that package was RapidBBS. There was only one problem, it had no Fidonet +capabilities. I rewrote the data structures and created a deamon that should +control all bbs acivities. In march 1998 I started writing the mbfido program +that should handle all Fidonet mail and .tic files. In june 1998 the final +message base format became JAM using the LoraBBS sources as a guide to create +the JAM libraries. The original JAMapi was not stable enough to do all the work +that needed to be done. +

+In Juli 1998 the first version of MBSE BBS was installed on the bbs I have, +on the second line. The first line was running McMail, GEcho and RA on a +Novell client while on the Linux box the mars_nwe emulator from Martin Stower +was running. In november 1998 mbcico was created from ifcico from Eugene M. +Crosser. In Januari 1999 it did also compile and run on a Sun Sparcstation 2 +system. +

+In April 1999 the motherboard of the Linux server died, I replaced it with +the MOBO of one of the client machines. From that day on, MBSE BBS became the +only bbs running on my system, because I was short on serial port boards at +that time. McMail and RA became history and MBSE BBS was on its own. From that +day on, updates were almost daily, all users and up and downlinks showed that +there were plenty of bugs to solve. One month later most problems were solved. +

+In juli 1999 Jan van de Werken started beta testing MBSE BBS on his system. +In September 1999 MBSE BBS was public released for the first time. +

 

+ +

Is it Y2K ready?

+

+There have been no problems since 1 januari 2000 with MBSE BBS. I do run +pktdate by Tobias Ernst in the tosser, this solves problems with incoming +mail. Due to the internal date format, this program should run until 2038, +just as long as Unix/Linux and the internet will function without changing +the date format. +

 

+ +

Future plans.

+

+Plans are to complete integrate news, email, www and chat into MBSE BBS. It +should work for browsers about the same as with ANSI character terminals. +

 

+ + +Back Go Back +

+ + + diff --git a/html/invoking.html b/html/invoking.html new file mode 100644 index 00000000..f6c5ac7f --- /dev/null +++ b/html/invoking.html @@ -0,0 +1,70 @@ + + + + + + + + +Starting and stopping the BBS. + + + +
+
Last update 06-Jun-2001
+

 

+ +

Starting and Stopping the BBS.

+

+Now it is time to check the starting and stopping of the BBS. As you have +installed everything, setup the BBS etc, you must check if the shutdown and +reboot work properly. As root type shutdown -r now and +watch the console. You should see messages that the BBS is closing while +the systems shuts down. This should be one of the first things to happen. +Because Slackware up to version 7.0.0 is tricky to automatic install the shutdown scripts, +you won't see this happen on older Slackware versions. If you want, you can edit +/etc/rc.d/rc.6 and /etc/rc.d/rc.K and insert the line /opt/mbse/etc/rc.shutdown +at the proper places.

+ +When your system comes up again, one of the last messages before the login +prompt appears or just before X-windows starts, you should see messages that +the BBS is started.

+ +Login as user mbse and check the logfiles if everything looks +good. If something is wrong, reread the previous documentation and check if +you did everything right.

+ +Next logon to your BBS locally using the account "bbs". You will then create +the first user of your BBS, this will be you, the sysop of course. +After you logout the BBS start as user +mbse the program mbsetup and edit your user record +to set your level to that of the sysop. One more thing, the unix account you +must create when you logon as new BBS user may not be mbse +as this is the normal Admin account the BBS and its utilities use.

+ +Now login with your unix account and see if everything still works. After all +this and if you have setup mgetty you may want to test if +users really can login with a modem. Also check a mailer session, can you +dialout, ie. poll other nodes and can they call you. There is a lot that can +go wrong with unix permissions if you are not precise in wat you are doing.

+ +If everything is working it is time to create poll events, and adjust other +scripts to your local needs to get your BBS full up and running.

+ +To do this you must install a crontab for user mbse As user +mbse go to the directory ~/mbsebbs-0.33.xx. +In that directory type +sh ./CRON.sh and a default crontab will be installed.

+ +To add poll events, edit the crontab with the command crontab -e + At the bottom of that file there is an example of how to do that. +Now that the crontab is installed, all maintenance will now work, automatic +dialout, scanning and tossing mail etc. In other words, the bbs is up and +running. +

+ +Back Go Back +

+ + + diff --git a/html/known_bugs.html b/html/known_bugs.html new file mode 100644 index 00000000..56034619 --- /dev/null +++ b/html/known_bugs.html @@ -0,0 +1,37 @@ + + + + + + + + +Running a BBS under Linux. + + + +
+
Last update 28-Jan-2001
+

 

+

MBSE BBS - Known bugs.

+

+ +There are always more bugs, but these are known.... + +

    +
  • Reading of function keys in mbsebbs doesn't work always good, especially on +slow links and over PPP. + +
  • Memory leaks in mbfido during mailtoss. + +
  • Problems with D'Bridge [1a] mailers. + +
  • Sometimes binkp sessions hang on sending files during bidirectional transfers. + +
  • mbsetup crashes at several places if in system aka's the domain name is 12 characters long. +
+ +Back Go Back + + + diff --git a/html/license/copying.html b/html/license/copying.html new file mode 100644 index 00000000..ebf91634 --- /dev/null +++ b/html/license/copying.html @@ -0,0 +1,360 @@ + + +GNU General Public License. + + + + +
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    
+    Copyright (C) 19yy  
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  , 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+ +Back Go Back + + + + diff --git a/html/license/hydracom.html b/html/license/hydracom.html new file mode 100644 index 00000000..49a8a742 --- /dev/null +++ b/html/license/hydracom.html @@ -0,0 +1,120 @@ + + +Hydracom License. + + + + +
+                              HydraCom Version 1.00
+
+                         A sample implementation of the
+                   HYDRA Bi-Directional File Transfer Protocol
+
+                             HydraCom was written by
+                   Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT
+                  COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED
+
+                       The HYDRA protocol was designed by
+                 Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and
+                             Joaquim H. Homrighausen
+                  COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED
+
+
+  DISCLAIMER
+
+  This program is provided "as is" and comes with no warranties of any
+  kind, either expressed or implied. In no event shall the authors be
+  liable to you or anyone else for any damages, including any lost
+  profits, lost savings or other incidental or consequential damages
+  arising out of the use or inability to use this software.
+
+
+  HYDRACOM / SOURCE LICENSE
+
+  HydraCom, its associated utilities (HydraCfg) and the HydraCom
+  sourcecode may be freely distributed, copied and used, no fee charged.
+  All files, executables and sourcecode remain the copyrighted property
+  of Arjen G. Lentz and LENTZ SOFTWARE-DEVELOPMENT.
+  The distribution archives should remain intact with no files removed
+  or modified. For special purposes, it is allowed to repack the
+  archives using a different compression system.
+
+  HydraCom may be bundled up with for instance terminal or BBS packages,
+  even commercial ones, provided the buyer/user is clearly informed
+  about the fact that Hydra and HydraCom are free, not owned by the
+  distributor/retailer in question, and is not included in any possible
+  charge regarding the rest of the package. This documentation must also
+  be present so the user can inform himself about Hydra and HydraCom.
+  The same rules apply to inclusion in shareware and CD-ROM libraries.
+  In all cases, the author of HydraCom must be given credit in any
+  informational screens and literature that contain such information.
+
+  The Hydra/HydraCom sourcecode may also be freely used and integrated
+  into other software or library, provided this is clearly stated in any
+  informational screens and literature pertaining to this program, and
+  credit is given to the original author. If the sourcecode of that
+  program or library is released or otherwise published, the notices
+  present at the top of every Hydra/HydraCom source file must be
+  retained in their original unmodified form.
+
+  In addition to the above license, everyone using any part of the
+  sourcecode, programs or files is fully bound by the general license of
+  the Hydra protocol as present in the Hydra protocol description
+  document. For easy reference, the paragraph in question is reprinted
+  below.
+
+  Any use of, or operation on (including copying/distributing) any of
+  the above mentioned files implies full and unconditional acceptance of
+  this license and disclaimer.
+
+
+  HYDRA PROTOCOL LICENSE 
+
+  You are granted a license to implement the HYDRA file transfer
+  protocol, HYDRA hereafter, in your own programs and/or use the sample
+  source code and adapt these to your particular situation and needs;
+  subject to the following conditions:
+
+   -  You must refer to it as the HYDRA file transfer protocol, and you
+      must give credit to the authors of HYDRA in any information
+      screens or literature pertaining to your programs that contains
+      other such information (credits, your own copyrights, etc.).
+
+   -  HYDRA will always remain backwards compatible with previous
+      revisions. HYDRA allows for expansion of its features without
+      interfering with previous revisions. It is, however, important
+      that different people do not expand the protocol in different
+      directions. We therefore ask you to contact us if you have any
+      needs/ideas regarding HYDRA, so development can be synchronized
+      and beneficial to all.
+
+   -  If your implementation cannot converse with past or future
+      revisions as supplied by us, then you must refer to it as "HYDRA
+      derived", or as "a variation of HYDRA", or words to that effect.
+
+
+  Hydra protocol design and HydraCom driver:         Hydra protocol design:
+  Arjen G. Lentz                                     Joaquim H. Homrighausen
+  LENTZ SOFTWARE-DEVELOPMENT                         389, route d'Arlon
+  Langegracht 7B                                     L-8011 Strassen
+  3811 BT  Amersfoort                                Luxembourg
+  The Netherlands
+  FidoNet 2:283/512, AINEX-BBS +31-33-633916         FidoNet 2:270/17
+  arjen_lentz@f512.n283.z2.fidonet.org               joho@ae.lu
+
+  Please feel free to contact us at any time to share your comments about our
+  software and/or licensing policies.
+
+ +Back Go Back + + + + diff --git a/html/license/index.htm b/html/license/index.htm new file mode 100644 index 00000000..eec8b7f2 --- /dev/null +++ b/html/license/index.htm @@ -0,0 +1,39 @@ + + + + + + + + +Licenses. + + + +
+
Last update 29-Jan-2001
+

 

+ +

Licenses.

+ +

Introduction

+

+This is an overview of the licenses that are valid for the use of MBSE BBS or +parts of it. +
+Michiel Broek. +

+ +

License Documents.

+ + + +IndexBack to Index +
+ + + diff --git a/html/license/jam.html b/html/license/jam.html new file mode 100644 index 00000000..80e415f9 --- /dev/null +++ b/html/license/jam.html @@ -0,0 +1,78 @@ + + +JAM License. + + + + +
+    ---------------------------------------------------------------------
+                                  JAM(mbp)
+                The Joaquim-Andrew-Mats Message Base Proposal
+    ---------------------------------------------------------------------
+            Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                           Mats Birch, Mats Wallin.
+                             ALL RIGHTS RESERVED.
+    ---------------------------------------------------------------------
+
+
+    =====================================================================
+    LEGAL NOTICE
+    ---------------------------------------------------------------------
+
+    The JAM(mbp) documentation and JAM API and information attached
+    hereto, hereafter referred to as JAM, is protected by applicable
+    copyright laws and international treaty provisions. JAM is provided
+    "as is", without warranty of any kind or fitness for a particular
+    purpose, either expressed or implied, all of are hereby explicitly
+    disclaimed. The authors only guarantees that JAM will occupy disk
+    space.
+
+    The entire risk as to the quality and performance of JAM is with you.
+    Should JAM prove defective or incorrect, you assume the entire cost
+    of all necessary servicing, repair, and/or correction. In no event
+    shall the authors be liable to the you or anyone else for any damages
+    or costs, including, but not limited to, any lost profits, lost
+    savings, lost income, lost information, loss of the right to use JAM,
+    or other incidental or consequential damages arising out of the use
+    or inability to use JAM.
+
+    All information provided in JAM is subject to change without further
+    notice.
+
+    JAM may be published and distributed to other people as long as no
+    part of it is modified by any means, this includes translation to
+    any other language (technical or social), and as long as no charges
+    are applied (including but not limited to trading). This information
+    may not be used to reverse engineer any application developed by the
+    authors.
+
+    All applications that support JAM must include one of the following
+    notices in their documentation and somewhere in the product's credit
+    section:
+
+    "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                               Mats Birch, Mats Wallin.
+                               ALL RIGHTS RESERVED."
+
+    or
+
+    "This product uses the JAM(mbp) API -
+     Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
+                    Mats Wallin. ALL RIGHTS RESERVED."
+
+    All trademarks are trademarks or registered trademarks of their
+    respective holders.
+
+ +Back Go Back + + + + diff --git a/html/manual.css b/html/manual.css new file mode 100644 index 00000000..d9818384 --- /dev/null +++ b/html/manual.css @@ -0,0 +1,24 @@ +/* + * stylesheet for the MBSE BBS manual. + */ + + +BODY { background-color: white; font-family: Arial, Helvetica; font-size: 12pt; } + +/* + * H1 is the page header, H3 the paragraph header, H5 is topright update date. + */ +H1 { color: red; align: center; font-family: Arial, Helvetica; font-size: 16pt; font-weight: bold } +H2 { color: orange; align: center; font-family: Arial, Helvetica; font-size: 16pt; font-weight: bold } +H3 { color: black; margin-left: 40; font-family: Arial, Helvetica; font-size: 14pt; font-weight: bold } +H5 { color: black; align: right; font-family: Arial, Helvetica; font-size: 8pt; } + +A:link { color: blue } +A:visited { color: darkblue } +A:active { color: red } + +PRE { color: brown; font-family: fixed; } +CODE { color: brown; font-family: fixed; } +HR { border-top: solid medium navy } + + diff --git a/html/menus/control.html b/html/menus/control.html new file mode 100644 index 00000000..acc11d09 --- /dev/null +++ b/html/menus/control.html @@ -0,0 +1,127 @@ + + + + + + + + +MBSE BBS Menus - Control Codes in ANSI and ASCII files. + + + +
+
Last update 27-Jun-2001
+

 

+ +

MBSE BBS Control Codes in ANSI and ASCII files

+
+ + +

Single Control characters

+
+ Code      Description
+ ----      ---------------------------------------
+  A        Wait for a key
+  B        Print text above sec. level
+  F        Control-code F
+  K        Control-code K
+  P        Wait one second
+  U        Control-code U
+
+
+
+The control-B syntax is: ^B<seclevel>^B<The text to show>^B
+For example: ^B32000^BThis is the text^B
+

+ +

Control-F followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  !        Display transfer protocol
+  A        Number of uploads
+  B        Number of downloads
+  C        Downloads in Kilobytes
+  D        Uploads in Kilobytes
+  E        Download plus upload Kilobytes
+  F        Download Kilobyte limit
+  G        Last transfer time
+  H        Current file area number
+  I        Current file area description
+  J        Download files limit
+  K        Description of user limit
+
+
+
+

+ +

Control-K followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  A        Print date in format DD-MM-YYYY
+  B        Print time in HH:MM:SS
+  C        Print date in DD-Mmm
+  D        Print date in DD-Mmm-YYYY
+  E        Print locked port baudrate
+  F        Last caller
+  G        Total users in userlist
+  H        Number of system calls
+  I        Current message area number
+  J        Current message area description
+  K        Print random oneliner
+  L        Print number of messages in current area.
+  M        Print users LastRead pointer of current message area.
+  N        Print users current e-mail mailbox name.
+  O        Print number of messages in current e-mail box.
+  P        Print users LastRead pointer of current e-mail box.
+
+
+
+

+ +

Control-U followed by:

+
+ Code      Description
+ ----      ---------------------------------------
+  A        User's full name
+  B        User's location
+  C        User's voice phone
+  D        User's data phone
+  E        User's last login date
+  F        User's first login date
+  G        User's last login time
+  H        User's security level
+  I        User's total calls
+  J        User's time used today
+  K        User's connect time this session
+  L        User's time left today
+  M        User's screen length
+  N        User's first name
+  O        User's last name
+  P        User's graphics mode (On/Off)
+  Q        User's news bulletins (On/Off)
+  R        User's hot-keys (On/Off)
+  S        User's daily time limit
+  T        User's date of birth
+  U        User's messages posted
+  X        User's language
+  Y        User's handle
+  Z        User's do not disturb flag (On/Off)
+  1        User's check for new mail (On/Off)
+  2        User's check for new files (On/Off)
+  3        User's fullscreen editor (On/Off);
+
+
+
+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/index.htm b/html/menus/index.htm new file mode 100644 index 00000000..e9cf81d5 --- /dev/null +++ b/html/menus/index.htm @@ -0,0 +1,149 @@ + + + + + + + + +MBSE BBS Menu System. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Menu System

+

Menus sections: +Global menus  +File areas  +Message areas  +User settings  +Onliners  +BBS lists  +ANSI Control Codes +

+

+


+

+ +

Introduction.

+

+One of the most powerfull features of the BBS is it's menu system. You +have complete control over each individual menu item which can be restricted +according to criteria such as security levels. +

 

+ +

ANSI Screens.

+

+For the menus to work properly you must also draw ANSI screens, this +is what the users will see. For Linux there is "Duh DRAW" written by Ben +Fowler, see sunsite.unc.edu /pub/Lunux/docs. +If you can't find it or have no internet access, you can also use +THEDRAW. This utility can be found on many BBS'es around the world. Unfortunatly +it is a DOS program so you will need dosemu on your Linux box or a seperate +DOS computer. You can define main screens and include screens for each +menu, the include screen may for example show the keys that you have available +in every menu. See the list of control codes. +

 

+ +

Automatic commands.

+

+A menu function is usually executed when a user presses the hot-key +assigned to that particular menu item. But menu functions can also be executed +automatically. Each menu item contains an AutoExec field. By default this +field is set to No, but by toggling it to Yes, the menu item can be made +to execute when it is played back (displayed) by the BBS.

+

+As you read through the menu function types outlined in this chapter, +you may come to realize that this is a very powerfull feature. For example, +when used with the menu function that displays a text file, you can design +very elaborate, graphical text file menus that you wouldn't normally be +able to display in a line-by-line menu.

+

+Automatic menu execution can be used in many other instances as well. +Just to give you some ideas, it might be used to display a text file to +users who have a security level equal to or greater than a certain level. +Yet another use is to execute multiple function menus which are used to +execute several functions when a single command is entered. +

 

+ +

Multiple languages.

+

+For each language you can define a set of menus. Only for the default +language all menus must exist. It makes sense to make the filenames of +your menus for each language the same and not to translate them. If a menu +is missing for a non default language, the menu from the default language +path is used. +

 

+ +

Editing a menu.

+

+The order of the menu lines in the setup is not important except for +the autoexec menus, they must be placed in the right order from start, +ie. begin with the menu specific screen display, then the global include +display and finally show the prompt. +

+ + +

    +
  1. Selection key. This is the key a user must press to activate +this menu. This field is ignored when AutoExec is set to Yes.
  2. + +
  3. Type nr. this is the menu type to execute. For a description +of all available types see below.
  4. + +
  5. Optional data. Some menus need optional data, for example the +function goto another menu needs the name of that menu file here.
  6. + +
  7. Display. What is to be displayed to the user. This field has +no meaning yet. What you want to diplay must be done with ANSI screens. +
  8. + +
  9. Security. This is the minimum security level to execute this +selection. The security is a level number combined with 32 bitmapped flags. +NOTE: level 0 and no flags means +everyone can select this menu. Good for logout options and all other options +everyone must be able to execute.
  10. + +
  11. Min. age. The minumum age the user must be to execute this selection. +You may want to restrict access to certain areas to users older than 18 +years. If you leave this to 0, every one can execute this menu.
  12. + +
  13. Max. lvl. The maximum level a user must have to execute this +menu. If you leave this at 0 then the maximum level has no effect.
  14. + +
  15. Password. You can protect the menu selection with a password. +If this field is empty, no password check is done.
  16. + +
  17. Credit. How much credit a user must have to execute this menu +selection. This field is not in use yet.
  18. + +
  19. Colors. The display color for the display line, not in use yet. +
  20. + +
  21. AutoExec. If this is an automatic executed selection.
  22. + +
  23. Menu open. Will be implemented later, you will be able to set +opening hours for this menu selection.
  24. +
  25. No door.sys Suppress writing of a door.sys file in the users +home directory. This item is only visible with menu type 7.
  26. +
  27. Y2K style Writes the dates in the door.sys file in the new style, +with 4 digit year numbers, else the old 2 digit style is used. This item +is only visible with menu type 7.
  28. +
+

 

+ +

Final warning.

+

+If a submenu is missing, the BBS falls back to the main menu. This menu +must be called "main" (or else set another name in the global +setup) or your BBS won't start and complain. Submenus may be nested 50 +levels deep. +

+ +Back Back +

+ + diff --git a/html/menus/menu0.html b/html/menus/menu0.html new file mode 100644 index 00000000..b7cb38a2 --- /dev/null +++ b/html/menus/menu0.html @@ -0,0 +1,176 @@ + + + + + + + + +MBSE BBS Menus - Global Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Global Menus

+
+ +
    + +
  1. Goto another menu: This will start the execution + of another menu. The current menu level is not stored on the stack.
    + Optional data: The name of the new menu.
    +

    + +

  2. Gosub another menu: This will start the execution + of another menu. The current menu level is stored on the stack. Gosub's may + be nested 50 levels deep.
    + Optional data: The name of the new menu.
    +

    + +

  3. Return from Gosub: This will go back one + gosub level. If you are already at the top level nothing happens.
    + Optional data: None.
    +

    + +

  4. Return to top menu: Return to the top (main) + menu. The name of this menu is set in the global setup. + Default is main.mnu
    + Optional data: None.
    +

    + +

  5. Display .a?? file with controlcodes: This will + display an ANSI file to the user. If the user has Graphics No set + then the ASCII version is shown. Search is done first in the users language + path and if that fails the default language path is used. + Control codes in the + file are substituted with the current values the represent.
    + Optional data: The name of the file to display. Do not + give the filename extension!
    +

    + +

  6. Show menu prompt: Display the menu prompt.
    + Optional data: The prompt to display. This string may + contain some control characters that are replaced with information. The + prompt is displayed in White on Black and is hardcoded at the moment. +
      +
    • ~ This will insert the number of minutes the user + has left. +
    • @ This will insert the name of the current file area. +
    • ^ This will insert the name of the current message area. +
    • # This will insert the current local time. +
    +

    + +

  7. Run external program: This will execute + external programs.
    + Optional data: The full path and filename of the external + program. This can be a shell too. Look for a lot of programs, for example + if you want to give your users internet mail with elm, the user can get a + shell prompt by typing !/bin/sh. If you want this look for + anyway you might consider using a restricted shell.
    +

    + +

  8. Show product information: This will show + copyright information about MBSE BBS.
    + Optional data: None.
    +

    + +

  9. Display todays callers: This will display a + list of todays callers to the BBS.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  10. Display userlist: Display all users in the + users database except those that are hidden.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  11. Time statistics: Display the users time + statistics.
    + Optional data: None.
    +

    + +

  12. Page Sysop: Page sysop for a chat.
    + Optional data: A message to the user
    + The message to the user could be something like "Calling sysop, please + wait ..." or "I will see if Michiel wants to chat with you, please wait!" + As sysop you will know best what to put in that line. +

    + +

  13. Terminate call: Terminale this call and + hangup.
    + Optional data: None. +

    + +

  14. Make a log entry: This will write a line in + the logfile.
    + Optional data: The information you want in the logfile.
    +

    + +

  15. Print text to screen: Write text to the users + screen.
    + Optional data: The text that must appear on the users + screen. The @ character is replaced with a newline.
    +

    + +

  16. Who is online: Displays the who is online + list and what they are doing. Users that are hidden are not displayed.
    + Optional data: "/H" Show handles instead of real names.
    +

    + +

  17. Comment to sysop: Enter the texteditor and + let the user write a message to the sysop. The area is predefined in the + global setup.
    + Optional data: None.
    +

    + +

  18. Send online message: Send an online message + to a user on another line.
    + Optional data: "/H" Use handles instead of real names.
    +

    + +

  19. Display textfile with more: This will display + a textfile to the user. After each full screen the user is prompted with + More Y/n/=.
    + Optional data: The full path and filename to the file.
    +

    + +

  20. Display .a?? file with control codes and wait: + This will display a ANSI or ASCII file to the user with + control codes and wait for Enter when it is finished.
    + Optional data: The filename without extension of the + file to display.
    +

    + +

  21. Expert mode .a?? Not of any use anymore. + This one will be removed.
    + Optional data: The name of the file without extension + to display.
    +

    + +

  22. Nextuser door: This runs the message to next + user door.
    + Optional data: None.
    +

    + +

  23. Timebank door: This runs the time bank door.
    + Optional data: None.
    +

    + +

  24. Safe cracker door: This runs the Safe Cracker + door.
    + Optional data: None.
    +
+ +
+Index + Main Index  +Back + Menus Index +
+ + + diff --git a/html/menus/menu100.html b/html/menus/menu100.html new file mode 100644 index 00000000..95e18066 --- /dev/null +++ b/html/menus/menu100.html @@ -0,0 +1,147 @@ + + + + + + + + +MBSE BBS Menus - File Area Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS File Area Menus

+
+ +
    + +
  1. Select another area: This option will show + a list of available areas and let the user select a new area. If there is + optional data the new area will be selected without user intervention.
    + Optional data: If there is an option the area is direct + selected. Current options are: F+ goto next available area. + F- goto previous available area.
    +

    + +

  2. File List: This option will display a list + of files with their dates, sizes and description. During the display of the + list the user can select (Tag) files for later download.
    + Optional data: None.
    +

    + +

  3. View File: Not yet implemented.
    + Optional data: None.
    +

    + +

  4. Download File(s): This option will start to + transmit files to the user if he has tagged files for download. Tagging files + for download can be done during File List, Keyword Scan, Filename Scan or + Newfile Scan. If a user didn't select a transfer protocol before now he will be + forced to select a file transfer protocol.
    + Optional Data: None.
    +

    + +

  5. Raw Directory: This option will display the + contents of a directory in raw format.
    + Optional data: If the option is /F the + contents of the current directory is shown. If the option is the full path + to a directory, the contents of that directory is shown.
    +

    + +

  6. Keyword Scan: This option will search for + files in the files database for a matching keyword. The search is not case + sensitive. If there are files found the user is able to select (Tag) these + files for later download.
    + Optional data: None.
    +

    + +

  7. Filename Scan: This option will search for + a filename match in the files database. The search is not case sensitive. + If there are files found the user is able to select (Tag) these files for + later download.
    + Optional data: None.
    +

    + +

  8. Newfiles Scan: This option will scan for new + files available for download since the last time the user was online. As + option the user can change that date from which to start the search. Any files + found the user may select (Tag) for later download.
    + Optional data: None.
    +

    + +

  9. Upload: This option will let the user upload + files to the bbs. If the current area has an alternate upload area, the upload + will end up in that area. If the user uses X-modem or another ancient protocol + he will first be asked for a filename. Normal modern protocols don't need this. + The filename is checked before the transfer is done to protect the bbs. Further + the files the user will upload will at first be placed under the users home + directory ~/upl. After the upload(s) the files are checked + for virusses. If all is well, the file is imported in the bbs. If the file + contains a valid FILE_ID.DIZ file inside the archive, that file will be used + for the description of the upload, if not, the uploader will have to describe + the file.
    + Optional data: None.
    +

    + +

  10. Edit Taglist: This option is for the user to + edit the list of files he has tagged for later download.
    + Optional data: None.
    +

    + +

  11. View file in homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  12. Download Direct: Download a file direct.
    + Optional data: The full path and filename to the file to + download.
    +

    + +

  13. Copy file to Homedir: This option will copy + a file from a download directory to the users home directory. It will be + checked if the user has enough room in his directory, the default Quota for + users is 10 MBytes.
    + Optional data: None.
    +

    + +

  14. List Homedir: This option will list the files + in the users home directory.
    + Optional data: None.
    +

    + +

  15. Delete in Homedir: This option will let the + user delete one or more files from his home directory.
    + Optional data: None.
    +

    + +

  16. Unpack file in Homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  17. Pack files in Homedir: Not yet implemented.
    + Optional data: None.
    +

    + +

  18. Download Homedir: This option will let the + user download from his home directory.
    + Optional data: None.
    +

    + +

  19. Upload Homedir: This option will let the user + upload files to his home directory.
    + Optional data: None.
    +
+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu200.html b/html/menus/menu200.html new file mode 100644 index 00000000..ba4ca392 --- /dev/null +++ b/html/menus/menu200.html @@ -0,0 +1,138 @@ + + + + + + + + +MBSE BBS Menus - Message Area Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Message Area Menus

+
+ +
    + +
  1. Select another area: This option will show + a list of all available areas and let the user select a new area. If there + is optional data the area will be selected without user intervention.
    + Optional data: If there is an option the area is direct + selected. Current options are M+ goto the next available + area. M- goto the previous available area.
    +

    + +

  2. Post a Message: This option lets the user + post a new message.
    + Optional data: None.
    +

    + +

  3. Read Messages: This option lets the user + read messages. If he has done that before in that area he will be suggested + to start after the message he has last read. During reading of messages + the user can reply to other messages.
    + Optional data: None.
    +

    + +

  4. Check for Mail: Check for new arrived mail.
    + Optional data: None.
    +

    + +

  5. Quickscan Messages: Make a quick overview + list of all messages in that area.
    + Optional data: None.
    +

    + +

  6. Delete a Message: This option will let the + user delete a specific message. He must the the owner or recipient of that + message or have sysop rights in that area to be able to delete a message.
    + Optional data: None.
    +

    + +

  7. Mail Status: This gives a complete overview + of all available mail at the bbs.
    + Optional data: None.
    +

    + +

  8. OLR: Tag Area: This option lets + the user tag one or more areas to be included in his offline mail packet.
    + Optional data: None.
    +

    + +

  9. OLR: Untag Area: This option lets + the user untag one or more areas not to be included in his offline mail + packet.
    + Optional data: None.
    +

    + +

  10. OLR: View Tags: This option lets + the user view which areas will be included in his offline mail packet.
    + Optional data: None.
    +

    + +

  11. OLR: Restrict Date: Not yet + implemented.
    + Optional data: None.
    +

    + +

  12. OLR: Upload Mail: Let the user upload + mail or a new offline reader setup. The packet format is automatic detected. + Currently BlueWave is supported. QWK support will be added later.
    + Optional data: None.
    +

    + +

  13. OLR: Download BlueWave: Download mail in + BlueWave version 2 format.
    + Optional data: None.
    +

    + +

  14. OLR: Download QWK: Download mail in QWK + format.
    + Optional data: None.
    +

    + +

  15. OLR: Download ASCII: Download mail in flat + ASCII format. Not yet implemented.
    + Optional data: None.
    +

    + +

  16. Read Email Read users private email.
    + Optional data: None.
    +

    + +

  17. Write Email Post an email message.
    + Optional data: None.
    +

    + +

  18. Trash Email Put email in the trashcan. + Not Yet implemented.
    + Optional data: None.
    +

    + +

  19. Choose Mailbox Choose another private + mailbox. Valid boxes are: mailbox (normal in/out), archive and trash.
    + Optional data: If there is an option the area is direct + selected. Current options are M+ goto the next mailbox. + M- goto the previous mailbox.
    +

    + +

  20. Quickscan Email Make a quick overview + list of all messages in the selected e-mail area.
    + Optional data: None.
    +

    +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu300.html b/html/menus/menu300.html new file mode 100644 index 00000000..3fd35ae1 --- /dev/null +++ b/html/menus/menu300.html @@ -0,0 +1,99 @@ + + + + + + + + +MBSE BBS Menus - User Settings Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS User Settings Menus

+
+ +
    + +
  1. Change Transfer Protocol: Let the user + select a new file transfer protocol.
    + Optional data: None.
    +

    + +

  2. Change Password: Let the user change + his FidoNet password.
    + Optional data: None.
    +

    + +

  3. Change Location: Let the user change + his location.
    + Optional data: None.
    +

    + +

  4. Change Graphics: Let the user toggle + graphics mode on or off.
    + Optional data: None.
    +

    + +

  5. Change Voicephone: Let the user change + his voice phonenumber.
    + Optional data: None.
    +

    + +

  6. Change Dataphone: Let the user change + his data phonenumber.
    + Optional data: None.
    +

    + +

  7. Change Expertmode: This command will be + removed.
    + Optional data: None.
    +

    + +

  8. Change Scrennlength: This command will + let the user set a new screenlength, the default is 24.
    + Optional data: None.
    +

    + +

  9. Change Date of Birth: Let the user set a + new date of birth. Check's are done if the date is more or less realistic. + This command should not be made available users if you use the regular + date of birth validation check.
    + Optional data: None.
    +

    + +

  10. Change Language: Let the user select a new + default language.
    + Optional data: None.
    +

    + +

  11. Change Hotkeys: Let the user toggle the + use of Hotkeys on or off..
    + Optional data: None.
    +

    + +

  12. Change Handle: Let the user select a new + handle (nickname).
    + Optional data: None.
    +

    + +

  13. Change Don't Disturb: Let the user toggle + the "do not disturb" flag.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu400.html b/html/menus/menu400.html new file mode 100644 index 00000000..68b341a9 --- /dev/null +++ b/html/menus/menu400.html @@ -0,0 +1,60 @@ + + + + + + + + +MBSE BBS Menus - Oneliner Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS Oneliner Menus

+
+ +
    + +
  1. Oneliner Add: Let the user add a new + oneliner.
    + Optional data: None.
    +

    + +

  2. Oneliner List: Let the user list all the + available oneliners.
    + Optional data: None.
    +

    + +

  3. Oneliner Show: Let the user show a + specific oneliner.
    + Optional data: None.
    +

    + +

  4. Oneliner Delete: Let the user delete a + oneliner. In order to do so he must be the owner of that oneliner or + he must have sysop access level. The oneliner is not really removed, only + marked for deletion.
    + Optional data: None.
    +

    + +

  5. Oneliner Print: Show a random chosen + oneliner on the screen. If you make this command automatic, each time that + this menu is executed a new oneliner will popup.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/menus/menu500.html b/html/menus/menu500.html new file mode 100644 index 00000000..bc2972b9 --- /dev/null +++ b/html/menus/menu500.html @@ -0,0 +1,56 @@ + + + + + + + + +MBSE BBS Menus - BBS List Menus. + + + +
+
Last update 02-Feb-2001
+

 

+ +

MBSE BBS BBS List Menus

+
+ +
    + +
  1. Add a BBS: Let the user add a BBS to the + BBS advertising database.
    + Optional data: None.
    +

    + +

  2. List BBS'es: Show a list of BBS'es in the + BBS database.
    + Optional data: None.
    +

    + +

  3. Show BBS: Show a specific BBS.
    + Optional data: None.
    +

    + +

  4. Delete BBS: Delete a specific BBS. The BBS + must have been entered by the user or the user must have sysop rights to + be able to delete a BBS.
    + Optional data: None.
    +

    + +

  5. Search BBS: Search for a specific BBS.
    + Optional data: None.
    +

    + +

+ +
+Index +Main Index  +Back +Menus Index +
+ + + diff --git a/html/mgetty.html b/html/mgetty.html new file mode 100644 index 00000000..0b7e6c23 --- /dev/null +++ b/html/mgetty.html @@ -0,0 +1,172 @@ + + + + + + + + +Setup mgetty for MBSE BBS. + + + +
+
Last update 29-Jan-2001
+

 

+ +

Setup mgetty for MBSE BBS

+

+To handle incoming calls you can use mgetty written by +Gert Doering, (gert@greenie.muc.de). Others may work. You have to compile +mgetty with the -DFIDO flag to accept Fidonet mailer calls. +If you want incoming PPP calls as well, add the -DAUTO_PPP as well. Below +you can see the mgetty.config and login.config for mgetty that I use. I +have also included a part of my /etc/inittab to show how mgetty + will spawn from init. +

+ +


+
+# inittab       This is only a part of my /etc/inittab!
+#               In this example it runs in runlevel 3 and 4.
+#
+# Serial lines
+s1:34:respawn:/usr/local/sbin/mgetty -i /opt/mbse/etc/issue ttyS0
+#
+# End of /etc/inittab
+
+
+
+# mgetty configuration file: mgetty.config
+#
+# ----- global section -----
+#
+# In this section, you put the global defaults, per-port stuff is below
+#
+# set the global debug level to "4" (default from policy.h)
+debug 4
+#
+# set the local fax station id
+fax-id ++31-255-515973
+#
+# access the modem(s) with 38400 bps
+speed 38400
+#
+#  use these options to make the /dev/tty-device owned by "uucp.uucp" 
+#  and mode "rw-rw-r--" (0664). *LEADING ZERO NEEDED!*
+port-owner uucp
+port-group uucp
+port-mode 0664
+#
+#  use these options to make incoming faxes owned by "root.uucp" 
+#  and mode "rw-r-----" (0640). *LEADING ZERO NEEDED!*
+fax-owner root
+fax-group uucp
+fax-mode 0640
+#
+#
+# ----- port specific section -----
+# 
+# Here you can put things that are valid only for one line, not the others
+#
+# Dynalink 1428EXTRA faxmodem at port 0 (COM1).
+#
+port ttyS0
+speed 57600
+switchbd 19200
+modem-type cls2
+init-chat "" \d\dAT&F&C1&D3X4W2B0M0Q0V1H0&K3S0=0 OK
+#
+# end of mgetty.config
+
+
+
+# login.config
+#
+# This is a sample "login dispatcher" configuration file for mgetty
+#
+# Format:
+#	username userid utmp_entry login_program [arguments]
+#
+# Meaning:
+#       for a "username" entered at mgettys login: prompt, call
+#	"login_program" with [arguments], with the uid set to "userid",
+#	and a USER_PROCESS utmp entry with ut_user = "utmp_entry"
+#
+#
+# Use this one for fido calls (login name /FIDO/ is handled specially)
+#
+#  mgetty has to be compiled with "-DFIDO", otherwise a fido call won't
+#  be detected.
+#
+/FIDO/	mbse	fido	/opt/mbse/bin/mbcico @
+#
+#
+# Automatic PPP startup on receipt of LCP configure request (AutoPPP).
+#  mgetty has to be compiled with "-DAUTO_PPP" for this to work.
+#  Warning: Case is significant, AUTOPPP or autoppp won't work!
+#  Consult the "pppd" man page to find pppd options that work for you.
+#  See also PPP-HOWTO on how to set this up.
+#
+/AutoPPP/ -	a_ppp	/etc/ppp/paplogin
+#
+# This is the "standard" behaviour - *dont* set a userid or utmp
+#  entry here, otherwise /bin/login will fail!
+#  This entry isn't really necessary: if it's missing, the built-in
+#  default will do exactly this.
+#
+*	-	-	/bin/login @
+#
+# You might use this instead, it will directly start the BBS when the call
+# is not a PPP call and not a Fidonet mailer. Use only one of these two!
+# THIS IS NOT YET TESTED!
+#
+*	-	-	/opt/mbse/bin/mbsebbs
+#
+# end of login.config
+
+
+ +

+If you use /bin/login the users can get confused by the Unix login prompt. +Most of them are used to DOS based bbs systems and will try to login with +two names which won't work of course. For this reason I have added the +-i /opt/mbse/etc/issue options to the mgetty +line in /etc/inittab. The file /opt/mbse/etc/issue is a plain textfile +explaining users how to login to start the bbs. It could look like this:
+

+
+      .--.     Welcome at MBSE BBS Development.
+     |o_o |    --------------------------------
+     |:_/ |
+    //   \ \   This may or may not work today...
+   (|     | )
+  /'\_   _/`\
+  \___)=(___/  
+Powered by Linux.
+
+To start the bbs login with "bbs" without quotes.
+Voor het bbs login met "bbs" zonder aanhalingstekens.
+
+There is a default /opt/mbse/etc/issue installed by the installation script. +You need to edit this to insert your bbs name in it or even completely replace +this file for a nicer one. Don't make it too big, don't put control characters +in it as this may prevent some mailers to connect to your system. +

+I discovered that some systems don't have the right permissions on the serial +port for MBSE BBS. To fix this type the following commands: +

+su
+password: enter root password here
+chmod 666 /dev/ttyS0
+chown uucp.uucp /dev/ttyS0
+exit
+
+Note that /dev/ttyS0 is for COM1, /dev/ttyS1 for COM2 etc. +

+ +Back Go Back +

+ + + diff --git a/html/misc/dropfile.html b/html/misc/dropfile.html new file mode 100644 index 00000000..f4e86ebc --- /dev/null +++ b/html/misc/dropfile.html @@ -0,0 +1,117 @@ + + + + + + + + +BBS doors dropfiles. + + + +
+
Last update 02-Feb-2001
+

 

+ +

BBS doors dropfiles.

+

+ +

Dropfiles for Unix BBS systems.

+

+Not all options that are available under DOS or OS/2 can be used with Unix +BBS systems and must be faked. +

 

+ +

DOOR.SYS format.

+

+The door.sys format is a 52 lines ascii textfile, each line is terminated with +a cr/lf pair. In the setup it is possible to force the creation of MM-DD-YYYY +dates instead of the MM-DD-YY style. Newer doors sometimes need that. +

+Line	Description
+-----	-----------------------------------------------------------------
+1	Port, 2 characters in DOS format, p.e. COM1
+2	Effective Baudrate
+3	Databits
+4	Nodenumber, 1..9999
+5	Locked baudrate
+6	Screen display, Y=snoop on, N=snoop off. On Linux allways N.
+7	Printer Y=on N=off
+8	Page Bell Y=on N=off
+9	Caller alarm Y=on N=off
+10	Users first name and lastname
+11	Users location
+12	Voice/Home phone
+13	Work/Dataphone
+14	Password, empty if not available (stored coded).
+15	Security level, 0..32768
+16	Users number of calls
+17	Users last call date MM-DD-YY
+18	Seconds remaining this call
+19	Time left in minutes
+20	ANSI, "GR" is yes, otherwise ?
+21	Screen length
+22	User mode, always N
+23	Always blank
+24	Always blank
+25	Subscription expire date MM-DD-YY
+26	Users record number
+27	Default protocol
+28	Users total number of uploads
+29	Users total number of downloads
+30	Users daily download kilobytes total
+31	Daily download kilobyte limit
+32	Users date of birth MM-DD-YY
+33	Path to users database files   Cannot be used on Linux.
+34	Path to message database files
+35	Sysop first and last name
+36	Users handle
+37	Next event starting time or "none"
+38	Error-free connection Y=Yes or N=No
+39	Always set to N
+40	Always set to Y
+41	Text color as defined in setup 7 = gray.
+42	Always 0
+43	Last new files scan date MM-DD-YY
+44	Time of this call HH:MM
+45	Time of last call HH:MM
+46	Always set to 32768
+47	Number of files downloaded today
+48	Total kilobytes uploaded
+49	Total kilobytes downloaded
+50	Comment stored in users record
+51	Always set to 0
+52	Total number of messages posted
+
+

 

+ +

DORINFOn.DEF dropfile.

+

+The DORINFOn.DEF file is a 12 lines ascii textfile, each line terminated with +a cr/lf pair. All characters in the file are uppercase. The n in the filename +represents the current line number and will be between 1 and 9. Using number +1 seems always fine. +

+Line	Description
+------	------------------------------------------------------------------
+1	System name
+2	Sysop's first name
+3	Sysop's last name
+4	Port name, like COM1, COM2 etc. COM0 = local
+5	Baudrate format: "19200 BAUD-R,N,8,1"
+6	Always 0
+7	Users firstname
+8	Users lastname
+9	Users location
+10	Graphics mode: 0=no, 1=ANSI, 2=Avatar, 3=ANSI+Avatar
+11	Security level, 0..32767
+12	Time left in minutes
+
+

+ +Back Go Back +

+ + + diff --git a/html/misc/filefind.html b/html/misc/filefind.html new file mode 100644 index 00000000..a76c38ff --- /dev/null +++ b/html/misc/filefind.html @@ -0,0 +1,331 @@ + + +Implementation and Usage of FileFind Utilities. + + + + +
+ Document:   fsc-00xx
+ Version:    0.6
+ Date        Aug 30, 1995
+ Title:      Implementation and Usage of FileFind Utilities
+ Authors:    Robert Williamson FidoNet#1:167/104.0  robert@ecs.mtlnet.org
+
+  Intro
+
+    A portion of the document is derived from information in
+      AllFix.DOC by Harald Harms @ 2:281/910
+    with  additional  sections  from
+      FQuery.DOC by Robert Williamson @ 1:167/104
+
+        The  MSdos program ALLFIX by Harald Harms first introduced the idea
+    of searching for files via echomail.  The term applied to this function
+    is  'FileFind'.   A FileFind system allows sysops, points and BBS users
+    to  search  for  files  by  placing  a  message  to 'ALLFIX' in an echo
+    designated  for  the purpose of finding files.  All FTN sites running a
+    FileFind  processor which is configured to scan that echo will reply to
+    that  user if there any files matching his query.  This system provides
+    a  method  for  searching  many  FTN sites throughout the world, with a
+    single message.
+
+        FileFind  programs  work by either scanning through defined message
+    bases or scanning packets for defined AREA tagnames for messages to the
+    default  name  ALLFIX.   All FileFind programs MUST respond to the name
+    ALLFIX,  but  may also respond to the name FILEFIND and the name of the
+    particular  FileFind  program  in  use  or  defined  for the echo.  The
+    FileFind  program  will  process  these messages, examining the Subject
+    field  for  search  queries.  If any valid query is found, the FileFind
+    program  will  search  the  sites files database for files matching the
+    users's query.
+
+        If the FileFind program finds any matches, it will generate a reply
+    containing  a list of the files found, and some basic information ABOUT
+    the  system  posting  the reply.  When the user who initially wrote the
+    request  reads  the reply, he will then be able to decide if any of the
+    reported  files  meet  his  needs,  and  from the ABOUT included in the
+    reply, learn where and how he may get those files.
+
+
+  FileFind Query Message Structure
+
+    To: name_of_FileFind program
+
+    The  message  must be addressed to ALLFIX so that all FileFind programs
+    can  respond.   To  use  features  specific  to  a  particular FileFind
+    program,  or  to  limit  the  responses  to  a particular platform, the
+    message  should  be  addressed  to  that program's name.  Some FileFind
+    programs  will  respond  to more than two names.
+
+    Subject:
+    A  space-separated  list  of  file  specifications,  keywords or quoted
+    strings.
+
+    keyword     - single word preceeded by a '/' with no intervening spaces,
+                  must be at least 3 characters, not including the '/'.
+                  a keyword search is in actually a substring search of the
+                  site's filelist.
+
+    description - string enclosed in double-quotes,
+                  if a single word, must be more than 3 characters.
+
+    filespec    - single word, no spaces, no double-quotes or preceding /,
+                  must be at least 3 characters, not including any wildcard
+                  or pattern matching charcaters, such as '*'.
+                  Messages addressed to ALLFIX must not have any embedded
+                  pattern matching characters.
+
+
+        The  minimum  number  of  characters  for  description, keyword and
+    filespec  queries  is an implementation detail of the FileFind program.
+    These  values  should  be configurable, but should never be settable to
+    values of less than 3.
+
+        Each  implementation  should  allow  the  operator  the  ability to
+    configure a list of disallowed keywords.
+
+  NetMail Queries
+
+        Some  FileFind  programs  may also have the ability to process file
+    search  queries  received  as  netmail and addressed to the name of the
+    particular  FileFInd  program  with this capability.  In this case, all
+    replies are via netmail also.
+
+  NetMail Commands
+        FileFind   Netmail   commands  are  identifed  by  a  leading  '%'.
+    Implementation  of  netmail  commands  is  optional.   If  implemented,
+    compliant  FileFind  utilities  should be able to process the following
+    minimum NetMail command set.
+
+
+    %HELP       - netmail only, returns an extended help text for the
+                  FileFind program, the ABOUT of the the site and a list
+                  of MAGIC freqable names.
+    %ABOUT      - netmail only, returns the ABOUT of the site and a full
+ or %MAGIC        list of MAGIC names.
+
+    %NEWFILES   - netmail only, returns the NEWFILES list of the site
+ or %NEW          via netmail.
+
+    Extended NetMail Commands:
+        Implementation  of  the  following netmail commands is optional and
+    not required for compliance with the FileFind NetMail Command set.
+
+    %REPORT 
+                - sends a configuration report for echo 
+                  this allows an echo moderator to check if a site running
+                  a  FileFind  utility  is  compliant with the rules of the
+                  filefind echo.
+
+    %REQUEST 
+                - if found, will place requested file on hold for remote
+                  site
+
+    %UUREQUEST 
+                - if  found,  and  the filesize after uuencoding is less
+                  than 60K, it will be sent as multiple netmail messages
+
+
+  The Site ABOUT
+
+        Obviously,  a  system that neither accepts file requests nor allows
+    users  to  download  on  their  first  call should not be responding to
+    FileFind  messages.   If  there  are  any limitations for the caller to
+    acquire  any  of  the  files  that  the  site  has  advertised as being
+    available  in  it's FileFind response, these limitations MUST be listed
+    in  the  reply.   This information should be included in the ABOUT file
+    that the FileFind program user creates.
+
+        The  site  ABOUT  should  contain  the  following information.  The
+    FileFind  program  implementor  should  instruct  his  users  on  these
+    requirements.
+
+      - sitename
+      - site operator's name
+      - complete phonenumber
+      - baud rate
+      - hours during which filerequests are accepted, if at all
+      - hours during which users can download
+      - conditions for file requests and user downloads
+      NOTE: the above information should be within the first 14 lines.
+      optional:
+      - a list a MAGIC names
+      - an indication if magic names are also available to terminal users.
+
+  Searching for Files and Creating Replies
+
+        The  method  used by the FileFind program to search for requests is
+    up  to  the  implementor.   However,  if searching a list, the FileFind
+    program should confirm the actual existance of all files that match the
+    query specification.
+
+        The  FileFind  program  should  only  process  description strings,
+    filespecs  or  keywords  that  contain more than 3 valid characters and
+    should  have configuration options to define greater minimum lengths on
+    a per-echo basis.
+
+        For  filespecs,  the  wildcard  character '*' IS considered a valid
+    specification  as  well  as the '?' wildcard, but only the '?' is to be
+    counted  as  a  character  when  determining the length of query.  File
+    extensions  are  not necessary and any characters AFTER a '*' are to be
+    ignored.   The  FileFind  program should be configurable so as to allow
+    replacement  all  of the file extensions with '.*' or '#?' dependant on
+    platform.   This  results  in  queries being independant of the various
+    archivers in use.
+
+    Replies
+
+        Replies  created  by  FileFind  utilities  are  expected  to  be in
+    compliance with the following FTN specifications:
+        FTS-0001    -  packed message format
+        FTS-0009    -  MSGID/REPLY
+        FSC-0046    -  PID and tear line
+
+        In  addition, a FileFind utility may use the FID:  control line for
+    any  information needed that cannot be put in a PID:  without violating
+    that specification.
+
+        ^AFID: ascii text CR
+
+    Must be less than 80 characters including ^A and terminating CR.
+
+    There  are three ways in which the FileFind program can create replies:
+        - write the replies in the echo in which the query appeared.
+        - write the replies in an echo that has been specifically
+          designated for that purpose in the particular FTN or for
+          a gorup of echos in that FTN.
+        - reply via routed netmail.
+
+        Since each FTN site connected to a particular FileFind program area
+    is  capable  of creating an information reply, there is much concern as
+    to  the  amount  of  traffic  that  can  be generated, FileFind program
+    developers  must  be sensitive to these concerns by providing the means
+    to  their users to limit the traffic on a per-echo basis.  For example,
+    various  FileFind  echos  have  rules  limiting  the  size or number of
+    replies,  or  the length of the system information that may be included
+    in a reply.
+
+  Limiting replies
+
+    It is strongly suggested that some default limitations be built-in.
+
+    Limiting Site Header (ABOUT):
+
+        If the site's ABOUT, (the text that has been configured in order to
+    add  the  system's  information  and Magic names list to the reply), is
+    greater  than  14  lines,  the  remainder should NOT be posted.  A line
+    should  be  added  to  the response indicated this, and the user may be
+    invited to either Freq or download the MAGIC name's ABOUT or MAGIC, for
+    a  full  list of magic names.  The FileFind program may optionally send
+    the full system information and magic name list via routed netmail.
+
+    Limiting Match List due to ambiguity of query:
+
+        If  the list of matches (note:  not the size of the message itself)
+    is  greater than 32K, the FileFind program should post a message to the
+    user to indicate that his query may have been too ambiguous and perhaps
+    invite him to freq or download the MAGIC name FILES for a full list.
+
+    Splitting Match List into Multiple Messages:
+
+        If the list of matches is greater than 10K, it should be split into
+    multiple  messages  of  no more than 8K.  Although the backbone permits
+    messages  up  to  16K  in length, 8K is a more readable size.  Only the
+    first  split  message  may  contain  the ABOUT information of the site.
+    Each  message must be given both a unique Subject field (eg:  prepended
+    by  "Part n/n") and a unique MSGID:.  This because some tossers may use
+    either or both for dupe detection.
+
+    Limiting Number of Split Messages:
+
+        If  the  number of messages is greater than the preset limit of the
+    echo,  and  the FileFind Program does not have an option to forward the
+    replies  via  netmail,  the  replies  should  be discarded and the user
+    informed that his request may have been too amibiguous.
+
+
+    NetMail Reply:
+
+        The  FileFind program may have an option to forward all replies via
+    routed netmail, or to do so under certain conditions as outlined above.
+    Obviously, if the FileFind program can process netmail queries, it MUST
+    respond via netmail.
+
+    User NetMail Reply Request:
+
+        Alternativly the user can request a netmail reply for his echomail
+    query by preceeding the query with either "%" or "!".
+      eg;
+        Subject:  % /fsc /fts
+
+        If  the  FileFind  program  does  not support this feature, it must
+    ignore  any  echomail  query message that has a "%" or "!" as the first
+    WORD of the Subject field.
+
+    Second Reply or Extended Response Request:
+
+        The  FileFind  site  indicates  availablility  of  Second  Reply by
+    placing the string 'program_name 4d_address' in the From:  field of the
+    message.
+        eg: FROM: FQUERY 1:167/104.0
+
+        When a user replies to a FileFind reply, the message will be to the
+    FileFind  program  @  {network  address}.  When processing the FileFind
+    conferences, the FileFind program will treat any message to itself that
+    includes the site address as a Second Reply Request.
+
+        If  this feature is available, the FileFind program will include up
+    to  a maximum of 15 files (maximum 12K match list) in it's replies.  If
+    the  user  wants  a  more  detailed  listing,  he simply replies to the
+    FileFind  program's  reply.   Only  the system that posted the original
+    reply  will  respond to that new request.  This second, specific reply,
+    will  contain  up  to  50  files (32K of matchlist) either including or
+    SKIPPING the first 15.  These numbers may be replaced by byte limits in
+    some implementations.
+
+    No Second Reply in Designated Reply Echo:
+
+        The Designated Reply Echo method does not allow replies to be made,
+    because  the FileFind program may not be permitted to scan a Designated
+    Reply  Echo.  The FileFind program should automatically report up to 50
+    files  for any requests.  Therefore, the traffic limitaion features may
+    be  disabled for networks that require the FileFind program to reply in
+    a Designated Reply Echo, and disallow Second Reply in that echo.
+
+    Disable Local Messages:
+
+        The  FileFind  program must be able to to disable the processing of
+    local  messages.  What this means is that the FileFind program will not
+    process  any messages generated on that FTN site, including messages by
+    the  sysop  using  an  offline  reader,  or by a site's BBS or off-line
+    reader users.  This should NOT exclude messages from a site's points.
+
+
+    Limit by Age:
+
+        The  FileFind program must be configurable so that the operator can
+    limit  the  age  of an query message that is acceptable for processing.
+    This  should  be  in  number  of  days.   The  FileFind  program may be
+    configured  to  process all the FileFind requests regardless of how old
+    they are.  Age should never be greater than 365 days.
+
+    LinkMGR Support:
+        Implmentors  may choose to support the LinkMGR proposal for netmail
+    queries  and  commands.   In this proposal, the queries and commands do
+    not  appear  in  the  subject  field but rather, in the the BODY of the
+    message.  The subject field wil contain the LinkMGR password.
+        Use of the LinkMGR method allows the user to send multiple commands
+    to the fIleFind program.
+
+ +Back Go Back + + + + diff --git a/html/misc/fileid.html b/html/misc/fileid.html new file mode 100644 index 00000000..2c413751 --- /dev/null +++ b/html/misc/fileid.html @@ -0,0 +1,386 @@ + + +FILE_ID.DIZ Information. + + + + +
+FILEID.TXT v1.8 by Richard Holler [CIS 73567,1547]
+Last Revision 05/05/94
+
+This text file was prepared at the request of the ASP (Association of 
+Shareware Professionals), but the information contained in it may be of 
+value to any shareware author.
+
+
+FILE_ID.DIZ INFORMATION
+-----------------------
+Basically, the FILE_ID.DIZ file is a straight ASCII text file, distributed 
+inside your distribution archive file along with your program files, which 
+contains a description of your program. This file will be used by most BBS 
+(Bulletin Board System) softwares for the online file description of your 
+file. We recommend that the FILE_ID.DIZ file be used in all of your 
+distribution archives. 
+
+This text file contains a description of the FILE_ID.DIZ file, as well as a 
+description of the recommended distribution archive format.
+
+
+WHY SHOULD YOU USE FILE_ID.DIZ?
+-------------------------------
+The use of this file will insure that the online description of your 
+program will be in your own words (and who better to describe your program 
+than yourself?), and that it will remain the same no matter how many 
+different people upload your file to various BBS systems. 
+
+As more and more BBS software makes use of this file, you can be assured 
+that your own description will replace such online descriptions as "Cool 
+Program" or "OK utility, but needs better ..."
+
+Please note that the ASP Hub Network, the Author Direct FDN (File 
+Distribution Network), and the majority of other electronic distribution 
+services *REQUIRE* that a valid FILE_ID.DIZ file be contained in your 
+submitted distribution archive. If your file doesn't contain a valid 
+FILE_ID.DIZ file, then it simply won't be distributed by these services. 
+Furthermore, most BBS sysops will not accept uploads of files which do not 
+contain a valid FILE_ID.DIZ file, so you automatically lose out on that 
+distribution as well.
+
+
+DESCRIPTION:
+------------
+FILE_ID.DIZ was created by Clark Development for use with their PCBDescribe 
+utility, as a means for BBS callers to upload a file without having to 
+manually type in a file description. It also ensures that the online 
+description is always the same regardless of the number of different BBS 
+systems the file is posted on. It has since been accepted by the BBS 
+industry more-or-less as the "standard" file description source. (The 
+extension of "DIZ" actually stands for "Description In Zip").
+
+NOTE: The FILE_ID.DIZ file *MUST* be named exactly that, and *NOT* 
+something like .DIZ. It will *ONLY* be used if it is named 
+FILE_ID.DIZ!
+
+The FILE_ID.DIZ file is nothing more than a straight ASCII text file which 
+contains the full description of the archived file containing it. It is 
+used by most popular BBS software to describe your program, rather than 
+using the description supplied by the person that uploaded your file. It 
+should be placed *INSIDE* your distribution archive file.
+
+The BBS software will "look" inside the archive file. If a FILE_ID.DIZ file 
+is found, it will replace any existing online file description with the 
+text contained in FILE_ID.DIZ. It is an excellent method for making sure 
+that your program files are described the way that "you" want them 
+described. Even sysops who's software can't automatically make use of the 
+FILE_ID.DIZ file have found it to be an excellent source for their manually 
+added file descriptions.
+
+
+STRUCTURE:
+----------
+The file consists of straight ASCII text, up to 10 lines of text, each line 
+being no more than 45 characters long. It should *NOT* contain any blank 
+lines, any form of centering or formatting, or any Hi-ASCII or ANSI 
+characters. (i.e. it should ONLY contain alpha & numeric characters).
+
+We recommended that it consist of 5 basic parts:
+
+   1. the proper name of your program
+   2. the version number
+   3. the "ASP" identifier (optional, for ASP members)
+   4. the description separator
+   4. the description
+
+All of the above parts should be separated by a single "space".
+
+PROGRAM NAME: To set it apart from the rest, it is recommended that you use 
+ALL CAPS for the program name.
+
+VERSION NUMBER: The version number should be in the form of "v12.34". 
+
+ASP IDENTIFIER: If you are an ASP author, we recommend that an "" 
+identifying mark be added after the version number, to identify your 
+product as an ASP-authored product.
+
+DESCRIPTION SEPARATOR: To separate the actual description text, insert a 
+simple "-" (dash/minus) character after the ASP identifier (or version 
+number, if not using the ASP identifier), and in front of the description 
+text.
+
+DESCRIPTION: You should attempt to FULLY describe your product, including 
+its most important functions and features. Be sure to include anything 
+which will separate your program from it's competition, and make the BBS 
+user want to download your file. Also try to include any hardware or 
+software requirements that your product may have.
+
+You should try to use the first 2 lines of the text to give a basic 
+description of your program. This is helpful for sysops who's BBS software 
+limits them to less than 10 lines, 45 characters. Sysops who are limited to 
+using shorter descriptions can simply use the 1st two lines and truncate 
+the rest. Thus, you can basically still supply your own description for BBS 
+software which does not actually utilize the FILE_ID.DIZ feature.
+
+The remaining lines of text can be used to elaborate on the programs 
+features, enhancements from the prior version, information concerning 
+multi-file sets. Please note that older versions of some BBS software can 
+only use 8 lines of text. It is advisable that you create your FILE_ID.DIZ 
+file so that the file can be truncated to various line lengths without 
+destroying it's usefulness.
+
+
+EXAMPLE
+-------
+MY PROGRAM v1.23  - A program which will
+do anything for anybody. Will run in only 2k
+of memory. Can be run from the command line,
+or installed as a TSR. Completely menu-
+driven. Version 1.23 reduces the previous 4k
+memory requirements, and adds an enhanced
+graphical user interface. Also, MY PROGRAM 
+now contains Windows and DESQview support. 
+Coming soon - an OS/2 version.
+From Do-It-All Software, Inc. $15.00
+
+
+MULTIPLE DISK INFO
+------------------
+Please note that if your distribution archive requires multiple archive 
+files, you should create a separate, specific FILE_ID.DIZ file for each 
+archive. This can be utilized to describe the various contents of each 
+archive, and to identify each disk in the set. For example, the FILE_ID.DIZ 
+file for disk #1 could contain:
+
+   "MY PROGRAM v1.23  Program Executable 
+    Files - Disk 1 of 2"
+    [followed by detailed description text]
+
+while the FILE_ID.DIZ file for disk #2 could contain:
+
+   "MY PROGRAM v1.23  Documentation Files - 
+    Disk 2 of 2"
+    [followed by more detailed description text]
+
+Optionally, you could also create a "complete" FILE_ID.DIZ file for the 
+first disk, which would fully describe the program in detail, and identify 
+it as Disk 1 of x. Then, for each remaining file in the set, simply include 
+the Program Name, version number, ASP identifier, and the disk number (i.e. 
+"MY PROGRAM v1.23  Disk 2 of x").
+
+
+ADDITIONAL INFO
+---------------
+Please don't be tempted to use fancy graphic or ANSI sequences in the 
+FILE_ID.DIZ file, as most BBS software will not allow this, and will render 
+your FILE_ID.DIZ file useless. Also, don't be tempted to simply copy your 
+program description file to FILE_ID.DIZ. Attempting to "format" your 
+FILE_ID.DIZ file (i.e line centering, right & left justification, etc) will 
+also cause unexpected results, especially for BBS software which re-formats 
+descriptions to other than 10line/45char.
+
+Fred Hill  has written a freeware utility which interactively creates 
+a valid FILE_ID.DIZ file. The file is called DIZGEN.ZIP and can be found on 
+CompuServe (GO IBMBBS, Library 2) as well as on many fine BBS systems. I 
+highly recommend that you download a copy of this wonderful utility for 
+creating your FILE_ID.DIZ files.
+
+<*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*><*>
+
+The following is a recommendation for the structure and contents of 
+distribution archives prepared for use on BBS systems.
+
+
+DISTRIBUTION DISK RECOMMENDATIONS
+---------------------------------
+The following are recommendations for preparing your program files for 
+distribution to Bulletin Board Systems (BBSs) via the ASP's distribution 
+services, as well as other methods.
+
+Two varieties of program files are defined here:
+
+1) Program files which utilize an "install" utility and self-extracting 
+program archives (later referred to as "Author-Installed Programs").
+
+2) Programs files which do not use install utilities or self-extracting 
+archives (later referred to as "User-Installed Programs").
+
+
+AUTHOR-INSTALLED PROGRAMS:
+--------------------------
+These programs require a bit more work from the author, but will eliminate 
+many user mistakes, especially in programs which require complicated 
+setups.
+
+Most "installation" utility programs will make use of program files which 
+have been "archived" into Self-Extracting (SFX) archives. We will attempt 
+to define which files should be contained in the Self-Extracting archives, 
+and which files should not.
+
+1. Files which should be contained in the self-extracting program file
+archive:
+
+        a. All program-specific executable files.
+        b. Any required configuration and/or data files required by the
+           program.
+        c. Program documentation files. Optionally, these may be left
+           outside of the self-extracting archive, in order to allow
+           them to be viewed/read by the various archive viewing utlities.
+        d. Any other program-specific files that are required for the
+           operation of the program.
+
+2. The files described above should be compiled into a self-extracting 
+archive file, which will then be extracted by the install utility.
+
+NOTE: the author is required to abide by any distribution requirements 
+specified by the archive utility author, and to obtain any required 
+distribution rights necessary. Please check to see if distribution rights 
+are required for your archive utility choice.
+
+3. Files which should NOT be contained in the self-extracting program file 
+archive:
+
+        a. The install utility itself (obviously).
+        b. The FILE_ID.DIZ file. (described in detail in the section
+           preceding this one)
+        c. Any distribution/information files, such as VENDOR.TXT,
+           SYSOP.TXT, etc.
+        d. Any description or information file, such as DESCRIBE.TXT.
+        e. A user file (such as README.1ST), which should explain how
+           to use the install utility, what the user should expect
+           during the installation, and any preparation that the user
+           should make prior to the installation. This file might also
+           contain a brief description of your program, in case the user
+           is able to read the documentation files in the distribution
+           archive prior to downloading (many BBS systems offer this
+           ability to the user).
+
+4. The actual distribution archive file (described below) should then 
+contain the install utility, the self-extracting program archive, and the 
+files described in #3 above.
+
+
+USER-INSTALLED PROGRAMS:
+------------------------
+This type of distribution archive is much simpler than the Author-Installed 
+variety. It should simply be an archive file, containing all of the files 
+for the program described above.
+
+Since this type of program requires the user to do all of the installation 
+manually, it should contain very specific and detailed information 
+regarding the installation requirements (such as INSTALL.TXT).
+
+
+THE DISTRIBUTION ARCHIVE FILE:
+------------------------------
+The actual distribution archive file should merely be an archive file 
+containing the files described above. For BBS distribution, this archive 
+should be of the standard archive format, and -NOT- a self-extracting 
+archive.  Many sysops will not allow self-extracting archives, and most BBS 
+software will not allow self-extracting archives to be uploaded.
+
+There are many popular archive utilities available, such as PKZIP, LHA, 
+LHARC, ARJ, etc. Most BBS systems are capable of handling archives in 
+virtually any format. However, you should be aware that most BBS systems 
+will convert your archive format to the format of choice by the sysop. By 
+following the methods described above, this conversion process should not 
+affect your program, or any self-extracting files which are contained 
+within your distribution archive file.
+
+You should also retain the default archive file extension defined by the 
+archive utility. For example, PKZIP uses a ".ZIP", LHARC uses "LZH", etc. 
+Changing the file extension may cause the BBS software to delete your file 
+because it doesn't recognize the format.
+
+For the actual filename for your distribution archive, it is recommended 
+that the program filename be limited to 6 characters to represent the 
+program's name (i.e. MYPROG could represent "My Program"). This should be 
+followed by 2 numeric digits which will represent the version number of 
+your release. Even if this is your initial release it should include the 
+version number in the filename (i.e. MYPROG10.ZIP would indicate the 
+program called "My Program" version 1.0).
+
+Please note that CompuServe limits filenames to only 6 characters. By 
+limiting the file "name" to 6 characters, you will easily be able to rename 
+the archive for CompuServe uploading by simply removing the 2-digit version 
+identifier, to make the file compatible with CompuServe libraries.
+
+By including the 2-digit version number in the archive filename, it will be 
+very easy for both the user and the sysop (and yourself) to identify older 
+versions of your program.
+
+
+MULTIPLE DISTRIBUTION ARCHIVES
+------------------------------
+At one time, it was recommended that your final distribution archive not be 
+larger than 350k, so that it would fit on a single 360k floppy disk and 
+still leave room for any distribution files necessary for Disk Vendors. 
+(i.e. Disk Vendors will often include their own GO.BAT file, or other 
+various small files to help their customers install the software). This 
+limitation is slowly falling by the wayside as more and more computer 
+systems have 3.5" floppy disk drives as standard.
+
+If your program is large enough to require more than one distribution 
+archive, it is recommended that your filename be limited to 5 characters 
+rather than 6 as described above. Following the 5-character name should be 
+the same 2-digit version number. Then, append a single "letter" to identify 
+the disk (i.e. MYPGM10A.ZIP, MYPGM10B.ZIP, etc.). For uploading to 
+CompuServe, these filenames may then be shortened to 6 characters by 
+removing the version identifiers (i.e. MYPGMA.ZIP, MYPGMB.ZIP). However, 
+for CompuServe it is recommended that you simply create a single 
+distibution file, and eliminate the multi-part file set.
+
+If your program requires multiple distribution archives, -BE SURE- to 
+create separate FILE_ID.DIZ files for each distribution archive. Also, each 
+FILE_ID.DIZ file should contain disk number information pertaining to each 
+individual archive (i.e. Disk 1 of 3, Disk 2 of 3, etc.).
+
+
+THE DISTRIBUTION DISK
+---------------------
+It is recommended that your distribution disk simply contain a ZIPd version 
+of your product. However, If you choose to supply "unarchived" files on a 
+distribution disk for Disk Vendor use, it is _VERY_ important that you 
+specify in your documentation a suggested archive filename, so that BBS 
+sysops can create archived files with the proper author-specified 
+filenames. This information should be contained in your SYSOP.TXT (or 
+VENDOR.TXT) file. If you don't supply a suggested archive file name, the 
+sysops will be forced to create the name themselves, thus you may end up 
+with thousands of versions of your products on BBS systems all over the 
+world, but all with different filenames.
+
+Please note that the ASP Hub Network, and nearly every other electronic 
+distribution service *REQUIRE* that your files be submitted as an archived 
+file, using the ZIP format. Also note that many BBS sysops will not go to 
+the trouble of ZIPing your unarchived files for you. If you don't supply 
+them with an archived distribution version of your product, it might not 
+get distributed by BBSs.
+
+If you supply your own disk labels, it is recommended that the ASP logo, or 
+at least the initials "ASP" be included on the label, so that anyone can 
+immediately identify your disk as an ASP member's software.
+
+
+SUMMARY
+-------
+Your distribution disk should now be ready to submit to the various BBSs, 
+distribution services, and Disk Vendors.
+
+You may choose to create a separate distribution disk for use by BBSs and 
+Disk Vendors. However, if you follow the above steps in preparing your 
+distribution archive file, a separate "Disk Vendor" disk is probably not 
+necessary. The majority of disk vendors will be able to accept your 
+distribution file/disk if it is prepared in the above described format.
+
+
+ +Back Go Back + + + + diff --git a/html/misc/ftpserver.html b/html/misc/ftpserver.html new file mode 100644 index 00000000..0a817406 --- /dev/null +++ b/html/misc/ftpserver.html @@ -0,0 +1,98 @@ + + + + + + + + +Howto setup an FTP server to work with MBSE BBS. + + + +
+
Last update 06-Jun-2001
+

 

+ +

How to setup an FTP server to work with MBSE BBS.

+

+ +In order to let MBSE BBS and your FTP server to both function together you must +organize a special file structure. Note that even if you don't setup an FTP +server you must still create a structure like this for the fidonet mailer, +if you don't, mail and files will get lost! +Note that this description is written for wu-ftpd, on your distribution there +may be another ftpd installed. Don't use mbftpd yet! +

+

The filestructure I used is as follows:

+
+/var/spool/mbse/ftp/pub/dos_util/dos_4dos	- Public download areas
+               |   |   |        /dos_disk
+               |   |   |        /dos_file
+               |   |   /virnet/mcafee
+               |   |          /win16
+               |   |          /win32
+               |   /bin				- FTP bin directory
+               |   /etc				- FTP etc directory
+               |   /incoming			- FTP public upload.
+               /mail/out			- Your default outbound
+               |    /out.009			- Outbound Zone 9
+               |    /inbound			- Inbound directory
+               /raonly/upload			- Non-public download areas
+               |      /sysop
+               |      /logfiles
+               /tic_queue			- Queue for .tic files.
+
+
+ +In order to give DOS style names for fidonet sessions you must set the +DOS path and Unix path in mbsetup (1.3.11 and 1.3.12) to +"m:" and "/var/spool/mbse". Note that to get +forwarding of .tic files to work the tic_queue must be a +subdirectory of "/var/spool/mbse" too. You could actually use any drive letter for +the DOS path. +

+This means that a fidonet file attach from the dos_4dos public download +directory shall get the subject "M:\FTP\PUB\DOS_UTIL\DOS_4DOS\COMMAND.ZIP". + +

+As you can see, anonymous ftp users can't get to the mail, non-public +downloads etc. Normally, your BBS users have unix accounts and will be able +to do a ftp login and access any directory on your system. Because the bbs +users have mbsebbs as their shell and this shell is not in the file +/etc/shells the ftp daemon will not let the bbs users in. So even +your own bbs users must login as anonymous to get files from the ftp server. +

+Note the following directory permissions MUST BE SET!!!!::: See also +the man pages for the DARPA ftpd server. +

+ +

+Directory               	owner group mode perms
+------------------------------- ----- ----- ---- ----------
+/var/spool/mbse			mbse  bbs   0755 drwxr-xr-x
+/var/spool/mbse/ftp		root  wheel 0555 dr-xr-xr-x
+/var/spool/mbse/ftp/bin		root  wheel 0555 dr-xr-xr-x
+/var/spool/mbse/ftp/bin/ls	root  bin   0111 ---x--x--x
+/var/spool/mbse/ftp/etc		root  root  0555 dr-xr-xr-x
+/var/spool/mbse/ftp/etc/passwd	root  root  0444 -r--r--r--
+/var/spool/mbse/ftp/etc/group	root  root  0444 -r--r--r--
+/var/spool/mbse/ftp/pub		mbse  bbs   0775 drwxrwxr-x
+/var/spool/mbse/ftp/incoming   	ftp   users 0755 drwxr-xr-x
+
+
+Note that all subdirectories under ../pub also must be owned by mbse + and group bbs and have at least mode 775 as long +as it are real bbs subdirectories. The bbs will maintain these directories +automatic and must have the rights to do so. + +

+In the /var/spool/mbse/ftp/etc/group file, add the group bbs so that your directory +listings give the proper groupname instead of a number. +

+ +Back Go Back +

+ + + diff --git a/html/misc/index.htm b/html/misc/index.htm new file mode 100644 index 00000000..56b80af0 --- /dev/null +++ b/html/misc/index.htm @@ -0,0 +1,46 @@ + + + + + + + + +Miscellaneous Documents + + + +
+
Last update 02-Feb-2001
+

 

+ +

Miscellaneous Documents

+ +

Introduction

+

+This is an overview of used unofficial documents for the development of the +MBSE BBS package. +

+Michiel Broek. +

+


+

Documents

+ + +
+ +IndexBack to Index +
+ + + diff --git a/html/misc/ipmailer.html b/html/misc/ipmailer.html new file mode 100644 index 00000000..8faf1c1b --- /dev/null +++ b/html/misc/ipmailer.html @@ -0,0 +1,172 @@ + + +Integration of IP-Nodes in the nodelist. + + + + +
+Publication:    FSP-????
+Revision:       1
+Title:          Integration of IP-Nodes in the nodelist (FTS-0005)
+Author:         Lothar Behet, 2:2446/301
+Revision Date:  25 October 1998
+Expiry Date:
+----------------------------------------------------------------------
+
+Contents:
+1. Required fields according to FTS-0005, basic flags for ip-nodes
+2. Optional extensions
+3. Addendum
+----------------------------------------------------------------------
+
+1.  Description of the nodelist format
+--------------------------------------
+
+Every node entry contains the following 8 fields:
+
+keyword,node_number,node_name,location,sysop_name,
+phone_number,baud_rate,flags
+
+Certain fields have defined values according to FTS-0005.
+
+1.1.	Implementation for IP-connectivity
+	Because of the limited characterset in the phone_field and
+	to avoid any misinterpretion by conventional dialing, the
+	ip-specific address-information is entered in another field
+	and there are additional flags required.
+
+1.1.1.  Field #1 (keyword) is PVT for an ip-only node without
+	conventional phone number related connectivity. In this
+	case, the phone field contains "-Unpublished-" according
+	to FTS-0005.
+
+1.1.2.  Field #2 (node_number) contains the node number within his
+	net and zone.
+
+1.1.3.  Field #3 (node_name) is used for the FQDN (Fully Qualified
+	Domain Name) or the ip-address.
+
+1.1.4.  Field #4 (location) contains the geographical location of
+	the node. While some nets/regions cannot supply their
+	ip-only nodes with a adequate link, these nodes may be
+	collected in a seperate net or region, until their original
+	net/region support additional ip-connectivity. This special
+	net/region is definitely a temporary solution for routing
+	within a region or zone!
+
+1.1.5.  Field #5 (sysop_name) represants the name of the system
+	operator.
+
+1.1.6.  Field #6 (phone_number) contains the phone_number for
+	conventional connectivity. In case of an ip-only node
+	it must contain "-Unpublished-".
+
+1.1.7.  Field #7 (baud_rate) contains the maximum baud rate for
+	conventional connectivity or 300 in case of an ip_only node.
+
+1.1.8.  Field #8 (flags) represents operational definitions for the
+	node.
+	Note that these are user flags.
+	The ip-flags consist of two parts:
+	A basic transport and an optional non-standard port,
+	seperated by a colon.
+	The default port may be omitted, but is listed as optional
+	parameter in this document. In some cases, two flag names
+	are mentioned:
+	The second one is supported by some software nowadays, but
+	these values may conflict with other programs, which not
+	completely decode the length of each individual flag (i.e.
+	TELN conflicts with the T-flag for online-time)
+	Additional flags for ip-nodes are:
+
+1.1.8.1.  IBN[:24554] (Argus: BND[:24554])
+	BinkP protocol
+
+1.1.8.2.  IFC[:60179]
+	Raw protocol as used by ifcico
+
+1.1.8.3.  ITN[:23] (Argus: TEL[:23])
+	Telnet protocol. Some variants of ifcico support Telnet
+	on port 60177, which should be added as additional flag
+	ITN:60177.
+
+1.1.8.4.  IVM[:3141]
+	Vmodem protocol
+
+1.1.8.5.  IP
+	General flag for special protocol specifications, if the
+	flags conforming to 1.1.8.1. to 1.1.8.4. are not relevant.
+
+1.1.9.  Comments on the proposed nodelist flags
+	The additional flagnames in () are supported at this moment
+	by Argus, based on the use in z2r50. But the TEL[NET]-flag
+	stays in conflict with the generally in all zones and
+	regions used T-flag (online time according to FSC-0062).
+
+
+2.  Optional extensions for future use
+--------------------------------------
+
+While the above mentioned flags (1.1.8.1 to 1.1.8.4) define a
+minimum set of operational flags for ip-nodes, several additions
+are already foreseeable at this moment.
+
+2.1.	Additional sessions_handshake parameters
+	There is at least one program, which supports several
+	transport protocols according to chapter 1.1.8. on a
+	single port. If other programs should imitate this habit,
+	then the following extension to the flag suite 1.1.8.
+	(transport[:port[:handshake]])is advised:
+
+2.1.1.  FTS-0001 session handshake:   1
+2.1.2.  Yoohoo session handshake  :   Y
+2.1.3.  EMSI sessions handshake   :   E
+2.1.4.  BinkP sessions handshake  :   B
+
+2.2.	Non-handshaking protocols
+	While the definitions until this chapter describe direct
+	handshaking sessions with optional password authentification,
+	there are several other methods for the tunneling of fidonet
+	data via the internet available.
+	The setup of these connections does not rely on the nodelist
+	(at this moment of writing), but we can think of standard
+	setup procedures to use the nodelist for configuration of
+	this additional transport methods.
+	Therefore the following flags 2.2.1. to 2.2.4. are advised
+	for at least informational purpose.
+
+2.2.1.  IFT
+	FTP (File Transfer Protocol)
+
+2.2.2.  ITX
+	TransX, an Email based variant
+
+2.2.3.  IUC
+	Uuencoded packet (one packet per message)
+
+2.2.4.  IEM
+	Email based (generally, without exact specification at
+	this moment)
+
+
+3.  Addendum
+------------
+
+This proposal is based on a maximum compatibility to generally used
+definitions and standards within the Fidonet community.
+Future developments might make additions necessary, if they can not
+be expressed with the existing set of flags as defined by this FSP.
+
+ +Back Go Back + + + + diff --git a/html/misc/jam.html b/html/misc/jam.html new file mode 100644 index 00000000..c1ca8d50 --- /dev/null +++ b/html/misc/jam.html @@ -0,0 +1,638 @@ + + +JAM Message Base Proposal. + + + + +
+Filename....: JAM-001
+Rev.........: 001
+Dated.......: 93-07-01
+Status .....: Released
+Subject.....: JAM message base proposal
+Author......: Joaquim Homrighausen
+Co-Authors..: Andrew Milner, Mats Birch, Mats Wallin
+
+    ---------------------------------------------------------------------
+                                  JAM(mbp)
+                The Joaquim-Andrew-Mats Message Base Proposal
+    ---------------------------------------------------------------------
+            Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                           Mats Birch, Mats Wallin.
+                             ALL RIGHTS RESERVED.
+    ---------------------------------------------------------------------
+
+
+    =====================================================================
+    Restrictions
+    ---------------------------------------------------------------------
+    JAM may be used by any developer as long as these specifications are
+    followed exactly. JAM may be used free-of-charge by any developer
+    for any purpose, commercially or otherwise.
+
+    This document may be freely copied and distributed, but must NEVER be
+    distributed in a modified form. If you have an enhancement request,
+    please contact the author of this document; do not change it
+    yourself.
+
+    All applications that support JAM must include one of the following
+    notices in their documentation and somewhere in the product's credit
+    section:
+
+    "JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner,
+                               Mats Birch, Mats Wallin.
+                               ALL RIGHTS RESERVED."
+
+    or
+
+    "This product uses the JAM(mbp) API -
+     Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch,
+                    Mats Wallin. ALL RIGHTS RESERVED."
+
+    No organization, company, person, entity, or other being may impose
+    any fees for any reason for providing this document or the
+    accompanying API. This document and the accompanying API may not be
+    sold or otherwise transferred for personal or company gain under any
+    circumstances.
+
+    =====================================================================
+    Definitions and general notes
+    ---------------------------------------------------------------------
+    CURRENTREV                1
+
+    JAM                       The JAM message base format.
+
+    CRC                       Cyclic Redundancy Check. All CRC values
+                              calculated on strings must assume that the
+                              data within the string has been converted
+                              to lowercase (A-Z = a-z).
+
+    CRC-32                    32-bit CRC (as used in the Zmodem file
+                              transfer protocol) value. The polynom for
+                              a CRC-32 is edb88320H and the CRC-32 seed
+                              is -1L (ffffffffH).
+
+    uchar                     Unsigned 8-bit value
+
+    ushort                    Unsigned 16-bit value
+
+    ulong                     Unsigned 32-bit value
+
+    UNIX date                 An ulong representing the number of seconds
+                              since midnight, January 1, 1970. UNIX-style
+                              dates is the only form of time stamps used
+                              in JAM (1).
+
+    Message #                 The physical record number within the index
+                              file is used as a message number. The
+                              lowest message number is one (1) and the
+                              highest message number is 4294967295
+                              (ffffffffH).
+
+    FTN                       FidoNet Technology Network
+
+    FTS                       FidoNet Technical Standard
+
+    (1) All timestamps created locally (i.e. those not imported from
+        other systems) are stored in local time.
+
+    =====================================================================
+    Files
+    ---------------------------------------------------------------------
+    Each conference is made up from four files. How and where these files
+    are stored and named is implementation dependant. The only file with
+    a fixed minimum size is the .JHR (header data) file. It has a 1024-
+    byte block used to hold information about a specific message area as
+    described later.
+
+    filename.JHR - Message header data
+    filename.JDT - Message text data
+    filename.JDX - Message index
+    filename.JLR - Lastread information
+
+    A future revision of JAM may also include a file that holds the
+    following three items:
+
+      - The highest assigned user number
+      - The last generated message ID
+      - A global conference list with the conference name, description,
+        and physical location of the message base.
+
+    =====================================================================
+    .JHR file header
+    ---------------------------------------------------------------------
+    Below is the format of the 1024-byte record at the beginning of all
+    .JHR files. The first actual message header starts at offset 1024 in
+    the .JHR file.
+
+    FixedHeaderInfoStruct:
+        ulong   Signature;       //  followed by 
+        ulong   datecreated;     // Creation date
+        ulong   modcounter;      // Update counter
+        ulong   activemsgs;      // Number of active (not deleted) msgs
+        ulong   passwordcrc;     // CRC-32 of password to access
+        ulong   basemsgnum;      // Lowest message number in index file
+        uchar   RESERVED[1000];  // Reserved space
+    end;
+
+    MODCOUNTER must be incremented and updated on disk each time an
+    application modifies the contents of the message base. When it
+    reaches ffffffffH, it wraps to zero.
+
+    ---------------------------------------------------------------------
+    BaseMsgNum                        Lowest message number in index file
+    ---------------------------------------------------------------------
+    This field determines the lowest message number in the index file.
+    The value for this field is one (1) when a message area is first
+    created. By using this field, a message area can be packed (deleted
+    messages are removed) without renumbering it. If BaseMsgNum contains
+    500, the first index record points to message number 500.
+
+    BaseMsgNum has to be taken into account when an application
+    calculates the next available message number (for creating new
+    messages) as well as the highest and lowest message number in a
+    message area.
+
+    ---------------------------------------------------------------------
+    ????????.JHR                                          Message headers
+    ---------------------------------------------------------------------
+    The .JHR file contains none or more Header records. Each record
+    define one message and contains information about the message and its
+    text (if any). The Header record is of variable length. The layout of
+    the Header record follows.
+
+    MessageHeader:
+        MessageFixedHeader:
+            ulong  Signature;    //  followed by 
+            ushort Revision;     // Revision level of header          (1)
+            ushort ReservedWord; // Reserved for future use
+            ulong  SubfieldLen;  // Length of subfields               (2)
+            ulong  TimesRead;    // Number of times message read
+            ulong  MSGIDcrc;     // CRC-32 of MSGID line              (3)
+            ulong  REPLYcrc;     // CRC-32 of REPLY line              (3)
+            ulong  ReplyTo;      // This msg is a reply to..
+            ulong  Reply1st;     // First reply to this msg
+            ulong  Replynext;    // Next msg in reply chain
+            ulong  DateWritten;  // When msg was written
+            ulong  DateReceived; // When msg was read by recipient
+            ulong  DateProcessed;// When msg was processed by tosser/
+                                 // scanner
+            ulong  MessageNumber;// Message number (1-based)
+            ulong  Attribute;    // Msg attribute, see "Msg Attributes"
+            ulong  Attribute2;   // Reserved for future use
+            ulong  Offset;       // Offset of text in ????????.JDT file
+            ulong  TxtLen;       // Length of message text
+            ulong  PasswordCRC;  // CRC-32 of password to access message
+            ulong  Cost;         // Cost of message
+        end;
+        SubField1                // Extra fields as defined below
+        .
+        .
+        SubFieldXX
+    end;
+
+    (1) This field is intended for future revisions of the specifications
+        to allow the use of a different fixed-length binary message
+        header. The current revision level is one (1).
+
+    (2) The SubfieldLen field is set to zero (0) if the header does not
+        have any subfield data. I.e. the length of the binary header is
+        not included in this field.
+
+    (3) When calculating the CRC-32 of the MSGID and REPLY lines, the
+        text ^aMSGID: and ^aREPLY: should be removed as well as all
+        leading and trailing white space characters.
+
+
+    The SubField structure is made up of an ID, a length specifier, and
+    a block of data. Zero or more subfields may follow the fixed-length
+    binary header. SubFields are not stored in any specific order and
+    are not terminated by any specific character unless otherwise
+    specified.
+
+    SubField:
+        ushort  LoID;            // Field ID, 0-65535
+        ushort  HiID;            // Reserved for future use
+        ulong   datlen;          // Length of buffer that follows
+        uchar   Buffer[datlen];  // DATLEN bytes of data
+    end;
+
+    ---------------------------------------------------------------------
+    Defined LoID codes
+    ---------------------------------------------------------------------
+
+    ID=0, Name=OADDRESS
+
+    A network address. This is used to specify the originating address.
+    More than one OADDRESS field may exist. DATLEN must not exceed 100
+    characters. For a FidoNet-style address, this field must follow the
+    ZONE:NET/NODE.POINT@DOMAIN format where .POINT is excluded if zero
+    and @DOMAIN is excluded if unknown.
+
+
+    ID=1, Name=DADDRESS
+
+    A network address. This is used to specify the destination address.
+    More than one DADDRESS field may exist (e.g. carbon copies). DATLEN
+    must not exceed 100 characters. For a FidoNet-style address, this
+    field must follow the ZONE:NET/NODE.POINT@DOMAIN format where .POINT
+    is excluded if zero and @DOMAIN is excluded if unknown.
+
+
+    ID=2, Name=SENDERNAME
+
+    The sender (author) of the message. DATLEN must not exceed 100
+    characters.
+
+
+    ID=3, Name=RECEIVERNAME
+
+    The recipient of the message. DATLEN must not exceed 100 characters.
+
+
+    ID=4, Name=MSGID
+
+    Used to store the message identification data. All data not relevant
+    to the actual ID string, including leading and trailing white space
+    characters should be removed. DATLEN must not exceed 100 characters.
+
+
+    ID=5, Name=REPLYID
+
+    Used to store the message reply data. All data not relevant to the
+    actual reply string, including leading and trailing white space
+    characters should be removed. DATLEN must not exceed 100 characters.
+
+
+    ID=6, Name=SUBJECT
+
+    The subject of the message. DATLEN must not exceed 100 characters.
+    Note that this field may not be used for FidoNet-style file attaches
+    or file requests.
+
+
+    ID=7, Name=PID
+
+    Used to store the FTN PID kludge line. Only the actual PID data is
+    stored and ^aPID: is stripped along with any leading and trailing
+    white space characters. DATLEN must not exceed 40 characters.
+
+
+    ID=8, Name=TRACE
+
+    This is also referred to as ^aVia information in FTNs. It contains
+    information about a system which the message has travelled through.
+    The format of the field is  where:
+
+       YYYY is the year (1992-9999)
+         MM is the month (01-12)
+         DD is the day (01-31)
+         HH is the hour (00-23)
+         MM is the minute (00-59)
+         SS is the second (00-59)
+
+    The timestamp is stored in ASCII (0-9) characters. The network
+    address is the address of the system. It is expressed in ASCII
+    notation in the native format of the forwarding system.
+
+
+    ID=9, Name=ENCLOSEDFILE
+
+    A file attached to the message. Only one filename may be specified
+    per subfield. No wildcard characters are allowed. If this subfield
+    is present in a message header, the ATTRIBUTE must include the
+    MSG_FILEATTACH bit.
+
+
+    ID=10, Name=ENCLOSEDFILEWALIAS
+
+    Identical to ENCLOSEDFILE with the exception that the filename is
+    followed by a  (00H) and an alias filename to be transmited to
+    the remote system in place of the local name of the file.
+
+
+    ID=11, Name=ENCLOSEDFREQ
+
+    A request for one or more files. Only one filemask may be specified
+    per subfield. If the filemask contains a complete path, it is to be
+    regarded as an update file request. If this subfield is present in a
+    message header, the ATTRIBUTE must include the MSG_FILEREQUEST bit.
+    To indicate that a password is to be transmitted along with the
+    request, a  (00H) character followed by the password is
+    appended. E.g. SECRET*.*MYPASSWORD.
+
+
+    ID=12, Name=ENCLOSEDFILEWCARD
+
+    One or more files attached to the message. Only one filename may be
+    specified per subfield. Wildcard characters are allowed. If this
+    subfield is present in a message header, the ATTRIBUTE must include
+    the MSG_FILEATTACH bit.
+
+
+    ID=13, Name=ENCLOSEDINDIRECTFILE
+
+    One or more files attached to the message. The filename points to an
+    ASCII file with one filename entry per line. If alias filenames are
+    to be used, they are specified after the actual filename and
+    separated by a  (00H) character, e.g. C:\MYFILE.LZHNEWS.
+    Wildcard characters are not allowed.
+
+
+    ID=1000, Name=EMBINDAT
+
+    Reserved for future use.
+
+
+    ID=2000, Name=FTSKLUDGE
+
+    An FTS-compliant "kludge" line not otherwise represented here. All
+    data not relevant to the actual kludge line, including leading and
+    trailing white space and ^A (01H) characters should be removed.
+    DATLEN must not exceed 255 characters. The FTS kludges INTL, TOPT,
+    and FMPT must never be stored as separate SubFields. Their data must
+    be extracted and used for the address SubFields.
+
+
+    ID=2001, Name=SEENBY2D
+
+    Used to store two-dimensional (net/node) SEEN-BY information often
+    used in FTN conference environments. Only the actual SEEN-BY data is
+    stored and ^aSEEN-BY: or SEEN-BY: is stripped along with any leading
+    and trailing white space characters.
+
+
+    ID=2002, Name=PATH2D
+
+    Used to store two-dimensional (net/node) PATH information often used
+    in FTN conference environments. Only the actual PATH data is stored
+    and ^aPATH: is stripped along with any leading and trailing white
+    space characters.
+
+
+    ID=2003, Name=FLAGS
+
+    Used to store the FTN FLAGS kludge information. Note that all FLAG
+    options that have binary representation in the JAM message header
+    must be removed from the FLAGS string prior to storing it. Only
+    the actual flags option string is stored and ^aFLAGS is stripped
+    along with any leading and trailing white space characters.
+
+
+    ID=2004, Name=TZUTCINFO
+
+    Time zone information. This subfield consists of four mandatory
+    bytes and one optional. The first character may be a plus (+) or a
+    minus (-) character to indicate a location east (plus) or west
+    (minus) of UTC 0000. The plus character is implied unless the first
+    character is a minus character. The following four bytes must be
+    digits in the range zero through nine and indicates the offset in
+    hours and minutes. E.g. 0100 indicates an offset of one hour east of
+    UTC.
+
+    ---------------------------------------------------------------------
+    Message attributes
+    ---------------------------------------------------------------------
+    MSG_LOCAL       (0x00000001L)   // Msg created locally
+    MSG_INTRANSIT   (0x00000002L)   // Msg is in-transit
+    MSG_PRIVATE     (0x00000004L)   // Private
+    MSG_READ        (0x00000008L)   // Read by addressee
+    MSG_SENT        (0x00000010L)   // Sent to remote
+    MSG_KILLSENT    (0x00000020L)   // Kill when sent
+    MSG_ARCHIVESENT (0x00000040L)   // Archive when sent
+    MSG_HOLD        (0x00000080L)   // Hold for pick-up
+    MSG_CRASH       (0x00000100L)   // Crash
+    MSG_IMMEDIATE   (0x00000200L)   // Send Msg now, ignore restrictions
+    MSG_DIRECT      (0x00000400L)   // Send directly to destination
+    MSG_GATE        (0x00000800L)   // Send via gateway
+    MSG_FILEREQUEST (0x00001000L)   // File request
+    MSG_FILEATTACH  (0x00002000L)   // File(s) attached to Msg
+    MSG_TRUNCFILE   (0x00004000L)   // Truncate file(s) when sent
+    MSG_KILLFILE    (0x00008000L)   // Delete file(s) when sent
+    MSG_RECEIPTREQ  (0x00010000L)   // Return receipt requested
+    MSG_CONFIRMREQ  (0x00020000L)   // Confirmation receipt requested
+    MSG_ORPHAN      (0x00040000L)   // Unknown destination
+    MSG_ENCRYPT     (0x00080000L)   // Msg text is encrypted          (1)
+    MSG_COMPRESS    (0x00100000L)   // Msg text is compressed         (1)
+    MSG_ESCAPED     (0x00200000L)   // Msg text is seven bit ASCII    (1)
+    MSG_FPU         (0x00400000L)   // Force pickup
+    MSG_TYPELOCAL   (0x00800000L)   // Msg is for local use only
+    MSG_TYPEECHO    (0x01000000L)   // Msg is for conference distribution
+    MSG_TYPENET     (0x02000000L)   // Msg is direct network mail
+    MSG_NODISP      (0x20000000L)   // Msg may not be displayed to user
+    MSG_LOCKED      (0x40000000L)   // Msg is locked, no editing possible
+    MSG_DELETED     (0x80000000L)   // Msg is deleted
+
+    (1) This revision of JAM does not include compression, encryption, or
+        escaping. The bits are reserved for future use.
+
+    =====================================================================
+    ????????.JDT                                             Message text
+    ---------------------------------------------------------------------
+    The .JDT file contains the text of messages. The text is stored as an
+    stream of seven or eight bit ASCII data. Allowed characters in the
+    text are 00H through ffH unless the header ATTRIBUTE field has the
+    MSG_ESCAPED bit enabled, in which case the legal range of data is 20H
+    through 7eH.
+
+    An escaped character is stored as \ where  is the two digit
+    hexadecimal ASCII value of the character. A single \ is stored as \\
+    or \5C. The case of the hexadecimal ASCII value is irrelevant, i.e.
+    5c is treated as 5C.
+
+    =====================================================================
+    ????????.JDX                                            Message index
+    ---------------------------------------------------------------------
+    The .JDX file is used to quickly locate messages for any given user
+    name or to locate a message with a specific number. Each record in
+    the file consists of two ulongs. The first ulong holds the CRC-32 of
+    the recipient's name (lowercase), the second ulong holds the
+    physical offset of the message header in the .JHR (header) file.
+
+    The record number (+BaseMsgNum) within the .JDX file determines a
+    message's number.
+
+    If both ulongs are -1 (ffffffffH), there is no corresponding message
+    header.
+
+    =====================================================================
+    ????????.JLR                                         Lastread storage
+    ---------------------------------------------------------------------
+    The .JLR file is used to maintain a user's position within a message
+    area. The layout of the "lastread" record follows. One record per
+    user is required.
+
+    LastRead:
+        ulong   UserCRC;         // CRC-32 of user name (lowercase)   (1)
+        ulong   UserID;          // Unique UserID
+        ulong   LastReadMsg;     // Last read message number
+        ulong   HighReadMsg;     // Highest read message number
+    end;
+
+    (1) The functions to convert a string to lowercase characters that
+        are provided in the API will only convert characters A-Z (into
+        a-z). It is required that this convention is followed by all
+        applications.
+
+    The UserID field is a unique number for each user. If the "lastread"
+    record is deleted, UserCRC and UserID are both set to -1
+    (ffffffffH). An application may not depend on any specific order in
+    the .JLR file. A user's "lastread" record may appear anywhere in the
+    file and must be searched for when retrieving it and when storing an
+    updated record.
+
+    =====================================================================
+    Updating message headers
+    ---------------------------------------------------------------------
+    If a header record grows after is has been retrieved from the .JHR
+    file, it must be appended to the end of the .JHR file since it would
+    overwrite the following header otherwise. The .JDX file must be
+    properly updated to indicate the new location of the header record.
+    The old header record must be changed to indicate that it has been
+    deleted by setting the MSG_DELETED bit in the Attribute field and the
+    TextLen field to zero (to prevent a maintenance program from removing
+    the message text that is now pointed to by another header).
+
+    =====================================================================
+    Message base sharing and locking
+    ---------------------------------------------------------------------
+    To allow several programs to access the message base at any given
+    time, region locking is used to protect the message base from being
+    corrupted during updates.
+
+    When an application needs to write to any of the message base files,
+    it must first attempt to lock the first byte of the .JHR (header)
+    file. If the lock call fails, the application must either fail or
+    attempt to lock the file again. The message base files may under no
+    circumstances be updated if the application cannot successfully lock
+    the .JHR file.
+
+    Note that data acquired (read) from the message base may not be used
+    when writing data to the message base, unless the application has
+    maintained a lock of the message base from the time the data was
+    acquired or the MODCOUNTER field is the same as when the data was
+    acquired.
+
+    The application must open the files in shareable (DENYNONE) read/
+    write or readonly mode. The only exception to this is an application
+    that requires exclusive access to the message base, such as a message
+    base maintenance utility, it should open the files in non-shareable
+    (DENYALL) read/write mode.
+
+    =====================================================================
+    Reply threads and linking
+    ---------------------------------------------------------------------
+    JAM introduces a new reply link pointer, not commonly used today.
+    This section is an attempt to describe how reply threads, reply
+    linking, and this new reply link pointer is implemented in JAM.
+
+    One of the major differences is that reply threads in JAM are not
+    based on similar or identical subjects of messages since this method
+    does not allow for proper reply threads.
+
+    The method used in JAM is based on the immediate relation between any
+    given message and direct replies to it. This is supported by many
+    message editors by using the MSGID and REPLY FTS kludge fields. These
+    are common, although expressed differently, in messages not based on
+    FidoNet technology, such as RFC-822. The obvious advantages include
+    allowing a program to easily find the original message to a reply,
+    and to find all replies to any given message.
+
+    The reply thread information consists of three fields: ReplyTo,
+    Reply1st, and ReplyNext. The reason for three fields, as opposed to
+    just two, is that with two fields, it is only possible to keep track
+    of the original message of a reply (which is sufficient) and one
+    reply to any given message (which is not sufficient). With three
+    fields, it is possible to maintain a thread of any number of replies
+    to any given message.
+
+    In the description of the different fields below, the following
+    messages and message numbers will be referred to:
+
+      1 -> 2 -> 4 -> 5
+      :    :
+      :    +--> 8
+      :
+      +--> 3 -> 7
+      :
+      +--> 6
+
+    Message number two, three, and six are replies to message number one.
+    Message number four and eight are replies to message number two.
+    Message number seven is a reply to message number three.
+    Message number five is a reply to message number four.
+
+    ---------------------------------------------------------------------
+    ReplyTo
+    ---------------------------------------------------------------------
+    This field holds the number of the message that this message is a
+    reply to. In the example above, the ReplyTo field would contain the
+    following values:
+
+    Message number one would contain zero; message number two, three, and
+    six, would contain one; message number four and eight would contain
+    two; message number seven would contain three, and message number
+    five would contain four.
+
+    ---------------------------------------------------------------------
+    Reply1st
+    ---------------------------------------------------------------------
+    This field holds the number of the first message that is a reply to
+    this message. In the example above, the Reply1st field would contain
+    the following values:
+
+    Message number one would contain two, message number three would
+    contain seven, and message number four would contain five. All other
+    messages would contain zero.
+
+    ---------------------------------------------------------------------
+    ReplyNext
+    ---------------------------------------------------------------------
+    This field is used to create the actual message thread or chain. In
+    the event that there is more than one reply to any given message, it
+    is necessary to maintain a thread of all the replies; this is due to
+    the fact that the original message can only hold information about
+    the first reply (the Reply1st field) to it.
+
+    The first reply (which the original message's Reply1st field holds),
+    has its ReplyNext field pointing to the second reply, the second
+    reply's ReplyNext field poinst to the third reply, and so on.
+
+    In the example above, the ReplyNext field would contain the following
+    values:
+
+    Message number two would contain three, message number three would
+    contain six, and message number four would contain eight. All other
+    messages would contain zero.
+
+    =====================================================================
+    Contacts
+    ---------------------------------------------------------------------
+    Joaquim Homrighausen                            Telefax: +352 316 702
+    389, route d'Arlon                                Modem: +352 316 702
+    L-8011 Strassen                               eMail: 2:270/17@fidonet
+    Luxembourg                                                joho@abs.lu
+
+    Andrew Milner                                   Telefax: +352 251 621
+    9a, Boulevard Joseph II                           Modem: +352 251 621
+    L-1840 Belair                                 eMail: 2:270/18@fidonet
+    Luxembourg                                             andrew@fido.lu
+
+    Mats Wallin                                    Telefax: +46 8 6453285
+    F”rskottsv„gen 11                                Modem: +46 8 6453882
+    S-126 44 H„gersten                           eMail: 2:201/329@fidonet
+    Sweden                                                     mw@fido.lu
+
+ +Back Go Back + + + + diff --git a/html/misc/outbound.html b/html/misc/outbound.html new file mode 100644 index 00000000..4a350c05 --- /dev/null +++ b/html/misc/outbound.html @@ -0,0 +1,114 @@ + + + + + + + + +Binkley style outbound with MBSE BBS. + + + +
+
Last update 02-Feb-2001
+

 

+ +

Binkly style outbound documentation for MBSE BBS.

+

+The MBSE BBS outbound directory structure is BinkleyTerm compatible, with +domains and point subdirectories (full 5d). There are separate "protected" and +"unknown" inbound directories for incoming sessions. Files received during +outbound sessions are always placed in the "protected" inbound directory. Only +the "protected" inbound directory is processed automatic. +

+ +

+Note that this is a very simple document and that it is not even finished. +

+

+.pol	Poll flag, is handled as crash immediate, the length is always 0 bytes.
+
+	Flow files are files with the full pathnames to the files to send
+	on disk. Names are translated by MBSE BBS to full DOS filenames and
+	paths depending on your setup. 
+	If you use it then it is importand that you think about the directory
+	structure to use. See also the documentation about the setup of the
+	ftp server
+	The filenames may be prepended with a special character:
+	#	= Truncate file after sent.
+	- or ^	= Kill file after sent.
+	@	= Leave file after sent, this is the default.
+
+.flo	Normal flow file (contains complete filenames to send).
+.clo	Crash flow file.
+.hlo	Hold flow file.
+.ilo	Immediate flow file, overrides CM flag.
+
+	The following are .pkt files, during the mail session they will be
+	renamed to nnnnnnnn.pkt with an unique name and added to the spool
+	file. Messages can allways be added to the outbound as long as the
+	node isn't locked.
+
+.out	Normal .pkt file.
+.cut	Crash .pkt file.
+.hut	Hold .pkt file.
+.iut	Immediate .pkt file.
+
+	It seems that these are subdirectories used by ifpack during packing
+	of mail. These are used for the news/e-mail gate.
+
+.opk
+.cpk
+.hpk
+.ipk
+
+
+.req	Request file. Contains filenames in ascii with <cr><lf>.
+
+.su0	Arcmail bundles, the last digit may be any digit or letter.
+.mo0
+.tu0
+.we0
+.th0
+.fr0
+.sa0
+
+.sts	Node status file created by mbcico. These are data files containing
+	three values: 
+	1. 'time', this is the last call attempt time (in time_t format).
+	2. 'retries', is the number of retries to try to connect that node. This
+   	    field is zeroed when the call succeeds or when that node calls in.
+	    It is also zeroed when a new poll is created. Currently, mbcico stops
+	    calling a node if the counter is higher then 30.
+	3. 'code', is the return code of the last attempt.
+	0      - Successfull call
+	1      - No dialout port available
+	2      - No CONNECT or TCP connect failed
+ 	3      - Could not reset the modem
+	4      - System is locked
+	5      - Retry time not reached?
+	6      - Fatal error in nodelist lookup
+	7      - Call prohibited by config options
+	8      - Phone number unavailable
+	9      - No free matching port
+	10     - Unused
+	11..29 - Session (handshake) errors.
+	This file is not compatible with the .sts files created by ifcico.
+ +
+.spl	Spool file, created by mbcico.
+
+.bsy	Busy file, for locking nodes. The 'pid' of the process who locked that
+	node is inserted into this file. All programs of the MBSE BBS package
+	(and ifcico package) check if the pid exists if a .bsy file is found.
+	If there is no pid found, the lock is a stale lock and is removed.
+
+
+ +Back +Go Back +
+ + + diff --git a/html/misc/semafore.html b/html/misc/semafore.html new file mode 100644 index 00000000..19dcefc0 --- /dev/null +++ b/html/misc/semafore.html @@ -0,0 +1,51 @@ + + + + + + + + +Semafore files with MBSE BBS. + + + +
+
Last update 22-jul-2001
+

 

+ +

Semafore files with MBSE BBS.

+ +The directory $MBSE_ROOT/sema is the hardcoded semafore directory where all +semafore's must be created, tested and removed. When the system is booting, +the init script will erase all semafore's just before the BBS is started. +This description is valid from MBSE BBS v0.33.17 and newer. + +
+zmh		Purpose: to mark the state of Zone Mail Hour. 
+		Created by "mbtask" at the start of Zone Mail Hour.
+		Removed by "mbtask" at the end of Zone Mail Hour.
+
+upsalarm	Purpose: Signal that the system is running on battery power.
+		Created and removed by UPS software.
+		Checked by mbtask to suspend processing.
+		Checked by mbfido to stop processing.
+
+upsdown		Purpose: Signal that the system will go down on low battery.
+		Created and removed by UPS software.
+		Checked by mbtask to go down.
+		Checked by several scripts and "mbstat wait".
+
+newnews		Purpose: Signal that there are new articles on the news server.
+		Checked by mbtask to start news processing.
+		Removed by mbtask as soon as it is detected.
+
+mbtask.last	Purpose: A timestamp created and touched by "mbtask" every
+		minute so you can check it is running.
+
+ +Back Go Back +
+ + + diff --git a/html/misc/usleep.html b/html/misc/usleep.html new file mode 100644 index 00000000..fc64d73c --- /dev/null +++ b/html/misc/usleep.html @@ -0,0 +1,61 @@ + + +System load and the usleep() call. + + + + +
+		usleep.doc
+
+
+At some time when developping MBSE BBS I decided that background utilities
+did't need full speed to do their jobs. BBS utilities under DOS needed
+to run as fast as possible because you needed to bring the bbs down to run
+these programs and users couldn't login during that time.
+
+Starting with mball, the allfiles creator, I inserted code that does usleep(1)
+after each 5 processed files. The 1 microsecond is not really the time the
+program pauses, it's probably a lot longer. I think this depends on the 
+hardware type, (Intel, Sparc, Alpha etc) how long Linux will really suspends
+executing the utility.
+
+The program speed downgrade at the development machine that mball needed was
+3 times the original exection time, while system loading stayed under 30%.
+At that time the development machine is an 486DX2-66 with a Seagate ST32151N
+SCSI harddisk.
+
+The extra usleep code is only active if you run these utils with the -quiet
+switch and when this is set in mbsetup. See menu 1->5.
+With this switch, the program is mostly run by cron. If you onmit
+this switch, this is probably when you start the program manually, it will
+then always run at full speed, no matter what the setting in mbsetup is.
+
+If you have a fast system or don't care that the performance of your system 
+drops because of background processing, you can turn this future off with
+mbsetup in the global section. (menu 1->5).
+
+Remember, if you have a PII-400 MMX or so with IDE disks, you may still have
+performance problems and need to set that switch to yes. There is only one
+way to find out if you need it.
+
+Well, actually, I tested this on a Dell Latitude PII-266, setting the switch to
+yes gave better performance then no. Why? The CPU has more time for the slow
+IDE disk. With the slow switch on programs runs even faster then with the switch
+off. 
+
+Michiel.
+
+
+ +Back Go Back + + + + diff --git a/html/nodelist.html b/html/nodelist.html new file mode 100644 index 00000000..07dff033 --- /dev/null +++ b/html/nodelist.html @@ -0,0 +1,131 @@ + + + + + + + + +Nodelist and Nidediff processing. + + + +
+
Last update 07-Jun-2001
+

 

+ +

Nodelist and Nodediff processing

+

+ +

Introduction

+

+A received a lot of questions about nodelist and nodediff processing, so +I will describe here the setup of the development system for the Fidonet +nodelist. First of all, it is very important that you +use three separate directories to do the nodelist processing. This is to +make sure that all stages are independent of each other, and if something +goes wrong, you still have a working system. The three directories are:
+

    +
  1. /var/spool/mbse/ftp/pub/fido/nodelist, this is the public +download area, the received diff's are stored here as well as the final +compressed nodelists for download. +
  2. /opt/mbse/tmp/nlwork, this is the working directory +to apply diffs to the previous nodelist. This directory should allways +contain the latest uncompressed nodelist. +
  3. /var/spool/mbse/nodelist, this is the systems nodelist +directory defined in mbsetup, menu 1.3.4 +
+In short the steps to process the nodediff's is as follows: +
    +
  1. Receive the nodediff and store it for download. +
  2. Apply the diff to the latest nodelist. +
  3. Hatch the new compressed nodelist. +
  4. Store the new nodelist for download. +
  5. Unpack the new nodelist in the nodelist compiler directory. +
  6. Set the compile semafore. +
  7. Compile the nodelists. +
+Next I will describe these steps in detail. +

 

+ +

The download area

+

+First define the download area for the bbs. In my case, this is area 20. From +here users can download the nodelists and nodediffs, files to the downlinks +are send from here. Below is the example of my system. +

+ +

 

+ +

The NODEDIFF tic area

+

+From your uplinks you usually receive NODEDIFF files. Create a tic area for +that purpose. I have keep# set to 5, this means the last 5 diff's are stored +in the download directory, older ones are removed. Now you can receive +nodediff files, store them for download, and send them to other nodes. +

+ +

 

+ +

Apply the diff

+

+We do this with the tic magic processor. In this example +I have NODELIST.007 in the /opt/mbse/tmp/nlwork directory. +Note that this filename is uppercase, they are usually stored and distributed +as uppercase names. As I receive the diff files as arc, the filemask on +my system is nodediff.a##. +This means that the file with the name nodediff.a14 in the area NODEDIFF +is a match. The command that is executed expands to +mbdiff /opt/mbse/tmp/nlwork/NODELIST /var/spool/mbse/ftp/pub/fido/nodelist/nodediff.a14 -quiet if the received nodediff is +nodediff.a14.
The mbdiff program applies +nodediff.a14 against NODELIST.007 in the +/opt/mbse/tmp/nlwork directory. If this is successfull, a +new NODELIST.014 is created there, a compressed +nodelist.z14 is created there and NODELIST.007 is +removed.
If this operation fails, only NODELIST.007 will stay +in that directory. +Because the ARC program for Linux isn't good for files, I +left the Arc files command empty in the archiver setup. As a fallback the +mbdiff program uses zip to create the compressed archive.
+If creating the new nodelist fails for some reason, a missed diff or so, +the whole processing stops here. The previous nodelist is still here and +you can manually correct the situation. So, if you missed a diff, see that +you get it and manually give the mbdiff commands as user +mbse until you are up to date. Or, place the latest +uncompressed nodelist in the directory /opt/mbse/tmp/nlwork. +

+ +

 

+ +

Processing the new nodelist

+

+Now that we have created the new compressed nodelist, it has to go somewhere. +The file nodelist.z14 is in the directory +/opt/mbse/tmp/nlwork. The example for the hatch manager +is shown below. The hatch manager runs automatic with the comand +mbfido tic. This setup will hatch the new nodelist in the +tic area NODELIST The two screens below show the tic and +hatch setup for this area. +

+ + +

+Now that we have hatched the new nodelist and stored in in the download area, +and maybe send some copies to downlinks, we have to feed it to the nodelist +compiler for our own system. We use a tic magic command to do +that. In this case we unpack the nodelist in /var/spool/mbse/nodelist +and set the compile semafore so that the mbindex + will compile the new nodelist. Don't be afraid that the unpacked +nodelists will acumulate in the nodelist directory, mbindex +will handle that, only the latest two nodelists are kept there. The +mbindex program is started by the taskmanager +mbtask. +

+ +

 

+ +Back Go Back +
+ + + diff --git a/html/postfix.html b/html/postfix.html new file mode 100644 index 00000000..44ad60cb --- /dev/null +++ b/html/postfix.html @@ -0,0 +1,160 @@ + + + + + + + + +MBSE BBS - Internet Gateway - Postfix setup. + + + +
+
Last update 21-Jun-2001
+

 

+ +

MBSE BBS - Internet Gateway - Postfix setup.

+

+Of course you need to make all these changes as root. +Add the mbmail program as service to the postfix system by +adding two lines to master.cf. +


+
+#
+# Postfix master process configuration file.  Each line describes how
+# a mailer component program should be run. The fields that make up
+# each line are described below. A "-" field value requests that a
+# default value be used for that field.
+#
+# Service: any name that is valid for the specified transport type
+# (the next field).  With INET transports, a service is specified as
+# host:port.  The host part (and colon) may be omitted. Either host
+# or port may be given in symbolic form or in numeric form. Examples
+# for the SMTP server:  localhost:smtp receives mail via the loopback
+# interface only; 10025 receives mail on port 10025.
+#
+# Transport type: "inet" for Internet sockets, "unix" for UNIX-domain
+# sockets, "fifo" for named pipes.
+#
+# Private: whether or not access is restricted to the mail system.
+# Default is private service.  Internet (inet) sockets can't be private.
+#
+# Unprivileged: whether the service runs with root privileges or as
+# the owner of the Postfix system (the owner name is controlled by the
+# mail_owner configuration variable in the main.cf file).
+#
+# Chroot: whether or not the service runs chrooted to the mail queue
+# directory (pathname is controlled by the queue_directory configuration
+# variable in the main.cf file). Presently, all Postfix daemons can run
+# chrooted, except for the pipe and local daemons. The files in the
+# examples/chroot-setup subdirectory describe how to set up a Postfix
+# chroot environment for your type of machine.
+#
+# Wakeup time: automatically wake up the named service after the
+# specified number of seconds.  Specify 0 for no wakeup. Presently,
+# only the local pickup and queue manager daemons need a wakeup timer.
+#
+# Max procs: the maximum number of processes that may execute this
+# service simultaneously. Default is to use a globally configurable
+# limit (the default_process_limit configuration parameter in main.cf).
+#
+# Command + args: the command to be executed. The command name is
+# relative to the Postfix program directory (pathname is controlled by
+# the program_directory configuration variable). Adding one or more
+# -v options turns on verbose logging for that service; adding a -D
+# option enables symbolic debugging (see the debugger_command variable
+# in the main.cf configuration file).
+#
+# In order to use the "uucp" message tranport below, set up entries
+# in the transport table.
+#
+# In order to use the "cyrus" message transport below, configure it
+# in main.cf as the mailbox_transport.
+#
+# SPECIFY ONLY PROGRAMS THAT ARE WRITTEN TO RUN AS POSTFIX DAEMONS.
+# ALL DAEMONS SPECIFIED HERE MUST SPEAK A POSTFIX-INTERNAL PROTOCOL.
+#
+# ==========================================================================
+# service type	private	unpriv	chroot	wakeup	maxproc	command + args
+# 		(yes)	(yes)	(yes)	(never)	(50)
+# ==========================================================================
+smtp	  inet	n	-	n	-	-	smtpd
+pickup	  fifo	n	n	n	60	1	pickup
+cleanup	  unix	-	-	n	-	0	cleanup
+qmgr	  fifo	n	-	n	300	1	qmgr
+rewrite	  unix	-	-	n	-	-	trivial-rewrite
+bounce	  unix	-	-	n	-	0	bounce
+defer	  unix	-	-	n	-	0	bounce
+smtp	  unix	-	-	n	-	-	smtp
+showq     unix	n	-	n	-	-	showq
+error     unix	-	-	n	-	-	error
+local	  unix	-	n	n	-	-	local
+cyrus	  unix	-	n	n	-	-	pipe
+    flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
+uucp	  unix	-	n	n	-	-	pipe
+    flags=F user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
+ifmail    unix  -       n       n       -       1       pipe
+    flags=F user=fido argv=/usr/local/bin/ifmail -r $nexthop ($recipient)
+mbmail    unix  -       n       n       -       1       pipe
+    flags=F user=mbse argv=/opt/mbse/bin/mbmail -r $nexthop ($recipient)
+bsmtp     unix  -       n       n       -       -       pipe
+    flags=F. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient
+
+
+In main.cf change or add the line:
+
+relay_domains = $mydestination, f2802.n280.z2.fidonet.org
+
+The fidonet address will be your fidonet address of course. If you have more +fidonet aka's, add them as well seperated with commas. +

+ +Next you need to add mbmail to the +transport file. +


+
+# /etc/postfix/transport
+#
+# execute "postmap /etc/postfix/transport" after changing this file
+#
+# Local destinations
+#
+seaport.mbse.nl		local:
+www.mbse.nl		local:
+news.mbse.nl		local:
+#
+# Fidonet mailers at this machine. Test on several strings to make sure
+# it will catches everything.
+#
+z1                      mbmail:f2802.n280.z2.fidonet
+.z1                     mbmail:f2802.n280.z2.fidonet
+z2                      mbmail:f2802.n280.z2.fidonet
+.z2                     mbmail:f2802.n280.z2.fidonet
+z3                      mbmail:f2802.n280.z2.fidonet
+.z3                     mbmail:f2802.n280.z2.fidonet
+z4                      mbmail:f2802.n280.z2.fidonet
+.z4                     mbmail:f2802.n280.z2.fidonet
+z5                      mbmail:f2802.n280.z2.fidonet
+.z5                     mbmail:f2802.n280.z2.fidonet
+z6			mbmail:f2802.n280.z2.fidonet
+.z6			mbmail:f2802.n280.z2.fidonet
+fidonet			mbmail:f2802.n280.z2.fidonet
+.fidonet		mbmail:f2802.n280.z2.fidonet
+fidonet.org		mbmail:f2802.n280.z2.fidonet
+.fidonet.org		mbmail:f2802.n280.z2.fidonet
+
+
+Don't forget to run postmap /etc/postfix/transport. Now all +files are changed, run postfix reload to activate the +changes. + +

+ +Back +Go back +Home Go to main +

+ + + diff --git a/html/programs/import.html b/html/programs/import.html new file mode 100755 index 00000000..3046fb19 --- /dev/null +++ b/html/programs/import.html @@ -0,0 +1,41 @@ + + + + + + + + +MBSE BBS Programs - Import Configuration. + + + +
+
Last update 30-Jan-2001
+

 

+ +

import - Import Configuration.

+

+ +

Synopsis.

+

+import [command] +

 

+ +

Description.

+

+import can be used to import the configuration databases from +plain ascii textfiles. This program is not supported. For the format of the +input files look in the source. This program will also not function properly +after 31-Dec-1999. If someone writes real good working conversion programs +to convert BBS, Tosser, Mailer setups to MBSE BBS setup, then make them +public available. On my BBS there is a utility to export RA2.02 databases to +the format that this import program can read. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/index.htm b/html/programs/index.htm new file mode 100644 index 00000000..2c2b3ece --- /dev/null +++ b/html/programs/index.htm @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Programs. + + + +
+
Last update 06-Jun-2001
+

 

+ +

MBSE BBS Programs.

+ + +
    +
  1. import, Import databases +
  2. mbaff, Announce newfiles and filefind +
  3. mball, Allfiles and newfiles list creator +
  4. mbchat, Sysop to user chat utility +
  5. mbcico, The Fidonet mailer ala ifcico +
  6. mbdiff, Nodelist difference processor +
  7. mbfbgen, FileBase Generator utility +
  8. mbfido, Fidonet mail and files procesor +
  9. mbfile, Files database maintenance program +
  10. mbindex, Nodelist index compiler +
  11. mblang, Language datafile compiler +
  12. mbmon, The monitor program +
  13. mbmsg, The messagebase utility program +
  14. mbout, The mailer outbound program +
  15. mbpasswd, The passwd wrapper +
  16. mbsebbs, The bbs program +
  17. mbseq, Sequence number creator +
  18. mbsetup, The setup program +
  19. mbstat, The bbs status change program +
  20. mbtoberep, The toberep.data lister +
  21. mbuser, The userbase maintenance program +
  22. mbuseradd, The adduser wrapper +
+ + +Main Back to Main index +
+ + + diff --git a/html/programs/mbaff.html b/html/programs/mbaff.html new file mode 100644 index 00000000..b5c74263 --- /dev/null +++ b/html/programs/mbaff.html @@ -0,0 +1,99 @@ + + + + + + + + +MBSE BBS Programs - mbaff - Announce new files and Filefind processor. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbaff - Announce new files and FileFind processor.

+

+ +

Synopsis.

+mbaff [command] <options> +

  + +

Description.

+

+mbaff +is the new files report generator and filefind server for mbsebbs. +In order to run mbaff +you must first start mbsed, +this is the deamon which controls all bbs activities. +

+When mbaff +is run with the commandline command announce +the first thing it does is to scan all the file databases for files +from which the announced flag is not yet set, and that area has a valid +newfiles groupname. These files are uploads for example. +If such a file is found the announced flag is set and +the file is added to the +toberep.data +file. This file may already contain +new files who were received as .tic files and processed by the +mbfido program. +After this is done the toberep.data +file is compared against the newfiles +reports to see if there is anything to report. If that's the case the +creation of reports begins in the echomail areas specified. After that the +toberep.data +file is erased and the mailout semafore set.
+The files to announce are divided into groups, the names of the groups are +set in the file download areas. If you plan this well, you can make seperate +announcements for several networks, announce files bij groups of file, ie. HAM +or .jpg pictures, Linux etc. +

+When +mbaff +is run with the commandline command +filefind +it will search each echomail area for unreceived messages addressed to +allfix or filefind. +It will read the message header and mark the message as received. The +search options are set on the subject line. All file areas for which the +filefind flag is set to true will be searched for the requested search +patterns. If there are files found a reply will be generated for the +user who wrote the request. If the reply area is different from the scan +area, the reply is placed in the reply area. If it's not set, the reply +goes into the same area. If the netmail option is set, the reply will +be sent by netmail. To prevent echomail overflow the replies in the same +area are limited to 15 found files, replies in the other echomail area +are limited to 50 files. Netmail replies will contain up to 100 files. +

 

+ +

Environment.

+

+In order to run mbaff you need to set one global environment variable +$MBSE_ROOT. +This variable must point to the root of the bbs directoy structure. The +main configuration file +config.data +must be present in the ~/etc subdirectory. +

 

+ +

Commands.

+

+mbaff announce - Announce new files.
+mbaff filefind - Process filefind requests. +

 

+ +

OPTIONS

+

+mbaff [command] -quiet - Quiet mode, no screen output. +Use this switch if you run mbaff from the crontab. +

+ +Back Back to index  +Index Back to main index +

+ + + diff --git a/html/programs/mball.html b/html/programs/mball.html new file mode 100644 index 00000000..714a0f6e --- /dev/null +++ b/html/programs/mball.html @@ -0,0 +1,77 @@ + + + + + + + + +MBSE BBS Programs - Allfile listing generator. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mball - Allfiles listing generator

+

+ +

Synopsis.

+

+mball [commands] <options> +

 

+ +

Description.

+

+mball is the allfiles and newfiles listing generator that +can be made available on your bbs for your users to get a complete listing +of wat is available for download. When used with the -zip +option it can also produce complessed versions of these two listings. The +resulting files are created in the current directory. After the creation of +these files you can hatch them into your bbs with the programs +mbfido tic when you properly setup a .tic file area for this purpose +and create records for the hatch manager. +

+It can also create 00index files in each download directory +for FTP users. Because this file starts with double zero it is most likely the +file at the top in each directory. At the same time HTTP pages are created in +the download directories of your filebase. These are named index.html, +index1.html and so on, there are as many as needed. The main index is created in the root +of your filebase. If you use the default setup then a user browsing at your bbs +can type http://yoursite.org/files/index.html to see the list +of fileareas. +

 

+ +

Environment.

+

+In order to run mball you need to set the global variable +$MBSE_ROOT. This variable must point to the root of the bbs +directory structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mball index - Create 00index and HTTP files in all download directories.
+mball list - Create allfiles.txt and newfiles.txt files. +

 

+ +

Options.

+

+mball [command] -quiet - Quiet mode, supress screen output.
+mball list -zip - Create zipped listings as well. +

  + +

Setup.

+

+In mbsetup menu 1.15 you need to set the public FTP base, +the days to include in newfiles listings and the maximum security level. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbchat.html b/html/programs/mbchat.html new file mode 100755 index 00000000..87bca2da --- /dev/null +++ b/html/programs/mbchat.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Programs - mbchat - the Sysop to user chat program. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbchat - The Sysop to User chat program.

+

+ +

Synopsys.

+

+mbchat <device> +

 

+ + +

Description.

+

+The program mbchat is used for Sysop to User chat. It +must be started by the sysop if the user has paged the sysop. The sysop +must be logged in as user mbse in order to have write +permissions to the same tty as the user has. For example, if the user is +at ttyS0 (COM1), the command to chat would be mbchat ttyS0. +

 

+ + +

Environment.

+

+In order to run mbchat you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ + +

Bugs.

+

+When you try to chat with a user who is up or downloading a file, the +transfer will fail or may even block. You need to check what the user is +doing before using this program. +

+This program will not be developed anymore and will be replaced by a program +that will chat via mbsed. This is safer and can be used even +from a remote site over the net. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbcico.html b/html/programs/mbcico.html new file mode 100644 index 00000000..e9a980e1 --- /dev/null +++ b/html/programs/mbcico.html @@ -0,0 +1,222 @@ + + + + + + + + +MBSE BBS Programs - mbcico - The Fidonet mailer. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbcico - The Fidonet mailer.

+ +

+This is work in progress.... +

+ +

Synopsis.

+

+-r<role> -a<inetaddr> <node> ...
+-r 0|1        1 - master, o - slave [0]
+-n<phone>     forced phone number
+-l<ttydevice> forced tty device
+-t<tcpmode>   telnet TCP/IP mode, must be one of ifc|itn|ibn, forces TCP/IP
+-a<inetaddr>  supply internet hostname if not in nodelist
+ <node>        should be in domain form, e.g. f11.n22.z3 +(this implies master mode)
+-h            show this help message
+
+ or: mbcico tsync|yoohoo|**EMSI_INQC816|-t ibn|-t ifc|-t itn (this implies slave mode) +

 

+ +

Description.

+

+mbcico stands for MBse "Internet - Fidonet Copy In /Copy Out", +this is a FidoNet(r) compatible transport agent. It is based on +ifcico written by Eugene G. Crosser, <crosser@average.org>, +2:5020/230@FidoNet. I changed the name of the program to make the difference +between ifcico and mbcico. Nowadays it is +quite different then ifcico. +

+Currently it supports FTS-0001, YooHoo/2U2 and EMSI handshake protocols, +Xmodem, Telink, Modem7, Hydra, SEAlink with and without overdrive and +crash recovery, Bark file and update requests, WaZoo protocols: DietIFNA, +plain Zmodem (aka ZedZip, EMSI flag "ZMO") and ZedZap, WaZoo file and +update requests (nodelist flag should be XA). WaZoo file and update requests +do also work with FTS-0001 sessions, this is supported by several well known DOS +mailers also. +Password protected requests and update requests are implemented (but not +yet full tested). +

+There is also a special protocol optimized to use over TCP/IP connections, +contributed by Stanislav Voronyi <stas@uanet.kharkov.ua>, it is +identiefied by EMSI proto code TCP (not registered) and nodelist flag IFC. +The default port is 60179. There is a telnet variant on this, the default +port is 23, and nodelist flag is ITN. The telnet variant is written by +T. Tanaka. +

+There is also a Binkp implementation, this is a +bi-directional TCP/IP protocol. +This protocol is prefferred over the IFC protocol because it is +more efficient. Nodelist flag is IBN, the default port is 24554, and the +nodelist request flag is XX. This Binkp implementation supports multiple +batches, however this is only tested against another mbcico. +I don't know if any other mailer supports this option, but it is documented +in the spec's. +

+Outbound directory structure is BinkleyTerm compatible, with domains and +point subdirectories (full 5d). There are separate "protected" and +"unprotected" inbound directories for the incoming sessions with the nodes +that are in your setup. Files received during outbound sessions are always +stored in the "protected" inbound. +

+"Magic" file request processors are executable files placed in the "magic" +directory. If a request is made for a file with matching name, the +executable from the "magic" directory is run, and its stdout output is mailed +to the requestor. Full requestor's address, in the form of "John Smith of +1:234/56/7" is passed to the executable in the command line. Non-executable +files in the magic directory contain the full names to magic filenames. The +magic NODELIST can thus point to the full path and filename of your latest +nodelist. These magic names are automatic maintained by the mbfido +program when the magic name is set in the .tic file that you receive. +

+To run mbcico in master mode, you need to make dialout +devices read/writeable for mbcico, and do the same for +the directory where your uucp locks are created (usually /var/locks). +

 

+ +

Answer Mode.

+

+To make mbcico work in answer mode, you need +mgetty written by Gert Doering. mbcico must be +started with one of the following parameters: +

+FTS-0001 call:       "/opt/mbse/bin/mbcico tsync"
+FTS-0006 call:       "/opt/mbse/bin/mbcico yoohoo"
+EMSI call:           "/opt/mbse/bin/mbcico **EMSI_....."
+

+In the latter case the received EMSI packet should be passed whitout trailing +CR). To make this work mgetty must be compiled with the +-DFIDO option. Other getty programs might work. +

+To answer TCP/IP calls the following lines should be added to /etc/inetd.conf: +

+binkd   stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t ibn
+tfido   stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t itn
+fido    stream  tcp     nowait  mbse    /opt/mbse/bin/mbcico    mbcico -t ifc
+

+In the file /etc/services the following lines must be present: +

+binkd           24554/tcp               # mbcico IBN mode
+tfido           60177/tcp               # mbcico ITN mode
+fido            60179/tcp               # mbcico IFC mode
+mbse            60180/tcp               # MBSE BBS deamon
+

+In this case I installed the ITN mode at port 60177 instead of 23 like most +sysops do. +

 

+ + +

Master Mode.

+

+To make mbcico scan for pending outbound mail and do +appropriate calls, start it with -r1 flag. It will check +for Zone Mail Hour, outside ZMH only crash mail is delivered. Mail to +non-CM systems is only send when mail has the Immedidate status. +Poll request are always honnored, even to non-CM systems if there is a +poll request in the outbound. Be carefull. +The taskmanager mbtask will start calling mbcico -r1 +if it has seen the scanout semafore. After all calls are completed mbcico +will remove the scanout semafore. +During ZMH all non-compressed mail is send. File requests in the outbound do not +force calling a system. If you make a filerequest, you must also make a +poll for that node to really start the request. You can also force a call +by entering mbcico f2802.n280.z2 on the commandline. +Only one call is made then and there is no dial delay. If mbcico -r1 is +called a random dialdelay is used with each call except for internet calls. +

 

+ +

Environment.

+

+In order to run the mbcico you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. +

 

+ +

Return Codes.

+

+

+0        - No errors
+1..32    - Linux errors, SIGHUP, SIGKILL, etc.
+101      - No dialout ports available.
+102      - Dial failed (no CONNECT or TCP connection failed).
+103      - Could not reset the modem (no OK).
+104      - System is locked.
+105      - not used?
+106      - Nodelist lookup failed.
+107      - Call prohibited by config options.
+108      - Phone number unavailable.
+109      - No matching ports defined.
+110      - Tried to call a CM system outside ZMH.
+111..129 - Session failures (not defined).
+130      - Could not establish session, system is marked undialable.
+
+These codes are also stored in status files for nodes, with the extension +of ".sts". These are small datafiles containing three decimal numbers. +
    +
  1. Time retry code, this is the last call attempt time. This is an unsigned + long representing the number of seconds since the epoch. +
  2. Retries, this is the number of consequtive call attempts made that returned + "call failed" or other errors. This field is zeroed when the call succeeds and + when a new "poll" is created. If the value is 30, the node won't be called + anymore. +
  3. Code, this is the return code of the last attempt. +
+

 

+ +

Configuration.

+

+The behaviour of mbcico can be configured with mbsetup, +section 1.16 If something doesn't do what you want, set the debug on for +that problem. This will produce huge logfiles, but also a lot of information. +Important flags are Device IO, EMSI debug, File forward, Locking, Outboundscan +and Session. +

 

+ +

Bugs.

+

+Incoming calls from McMail mailers, McMail is quite hasty +to establish an EMSI session, and times out in less than a second. So +if your system is heavy loaded, or not too fast, McMail cannot connect +with your system. This is a known problem with McMail 1.0 and older, +later versions are ok. +

 

+ +

Authors.

+

+

+Eugene G. Crosser <crosser@average.org>   Orginal ifcico.
+Stanislav Voronyi <stas@uanet.kharkov.ua> TCP/IP code.
+T. Tanaka                                 Telnet mode.
+Martin Junius                             Rewrite of opentcp().
+Omen Technology Inc                       Zmodem protocol.
+Arjen G. Lentz, Joaquim H. Homrighausen   Hydra transfer protocol.
+Cristof Meerwald                          Implementation of Hydra in ifcico.
+P. Saratxaga                              Tty driver code, yoohoo extensions.
+Dima Maloff                               Binkp protocol.
+Michiel Broek                             Rewrite for MBSE BBS.
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbdiff.html b/html/programs/mbdiff.html new file mode 100644 index 00000000..b83c8134 --- /dev/null +++ b/html/programs/mbdiff.html @@ -0,0 +1,70 @@ + + + + + + + + +MBSE BBS Programs - mbdiff - Nodelist difference file processor. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbdiff - Nodelist difference file processor.

+

+ +

Synopsis.

+

+mbdiff [nodelist] [nodediff] <options> +

 

+ +

Description.

+

+mbdiff applies a (compressed) nodediff file against the +nodelist of the week before to create a new nodelist. The result is a new +plain nodelist and a nodelist compressed with zip. +

 

+ +

Environmet.

+

+In order to run mbdiff you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbdiff [nodelist] [nodediff] The nodelist must be the full +path and filename without the dot and daynumber extension. The nodediff is +the full path and filename to the (compressed) nodediff file fitting on the +latest nodelist. It is adviced to make a seperate working directory where +you keep the nodelists. Don't do this in your normal nodelist directory. +When the operation is successfull, the new nodelist is in the working directory +and the old list is removed. A compressed version of the nodelist is also +placed in the working directory. From here you can hatch the new compressed +nodelist with the mbfido program. +

 

+ +

Options.

+

+-quiet - supress screen output, this switch is needed when +mbdiff runs on the background. +

 

+ +

Bugs.

+

+If you find any bugs, mispelled documentation etc, please contact the author: +Michiel Broek at 2:280/2802@Fidonet or mbroek@users.sourceforge.net +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfbgen.html b/html/programs/mbfbgen.html new file mode 100755 index 00000000..ae37479d --- /dev/null +++ b/html/programs/mbfbgen.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Programs - mbfbgen - FileBase Generato. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbfbgen - FileBase Generator

+

+ +

Synopsis.

+

+mbfbgen +

 

+ +

Description.

+

+mbfbgen is used to import filebase areas from CD-ROM. This +util works like fbgen which is known to RA users. It reads +the file files.bbs to get the filenames and descriptions +to build the filedatabase. +

+To import a filebase you must setup the area with mbsetup. +If you are really importing from a CD that will stay mounted on your system +you must set CDrom to yes. If the files.bbs file is not in the +directory were the files are, but somewere else on the CD, you must fill in +the field Files.bbs in the edit file area screen. +If the files.bbs file is in the same directory together with the files, you may +leave that field blank. +It is handy to use a closed range of file areas. +Once you are ready with the setup start mbfbgen, enter the +start and end area numbers, the uploader name, and the import will start. +This can last quite long as from each file the 32 bits CRC is calculated +that will be stored in the filedatabase. When mbfbgen is +finished, run mbfile index to recreate the filerequest index +file. +

 

+ +

Environmet.

+

+In order to run fbgen you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfido.html b/html/programs/mbfido.html new file mode 100644 index 00000000..50a133a9 --- /dev/null +++ b/html/programs/mbfido.html @@ -0,0 +1,260 @@ + + + + + + + + +MBSE BBS Programs - mbfido - The Fidonet mail and files processor. + + + +
+
Last update 10-Jul-2001
+

 

+ +

mbfido, the fidonet mail and files processor.

+

+ +

Synopsis.

+

+mbfido [command(s)] <options> +

 

+ +

Description.

+

+mbfido +is the program to process fidonet mail and files. In order to run mbfido +you must first start mbtask, +this is the deamon which controls all bbs activities. To prevent that +mbfido will run more than once at the same time a lock +is placed in the protected inbound with the pid of the running +mbfido program. The gateway to and from internet is also +handled by mbfido. +

 

+ +

Specifications.

+

+The recognized mail packets are type 2+ following the FSC-0039 standard with +a fallback to the old stone age packets. +Can handle messages of maximum 429467295 bytes, or less if you have less +memory available, the practical limit is about 1 Meg. Note that most mailprocessors +are only guaranteed to work to maximum 16 KBytes. +Recent experiments in the LINUX echo show that this is still true, +although most tossers seem to process mail up to 32 KBytes. +

 

+ +

Tossing Mail.

+

+First make sure you have the necessary message areas in your setup. At least +you need the badmail and dupemail areas and a netmail area for each network +you participate in. If you don't create badmail and dupemail areas then +bad (unknown area etc) and dupes are lost and you cannot check the reason why. +If you don't create the netmail areas for each network, then netmail to your +system will dissapear. It is not possible to "retoss" the badmail yet after +you have created any missing echomail areas. +

+To prevent .pkt name collision the toss of incoming mail is done in parts. +The first run is to process all uncompressed mailpackets and add mail to the +outbound. Then each compressed ARCmail archive will be uncompressed and +processed and mail will be imported and forwarded as necessary. During all +these passes all filenames are sorted by date and time, the oldest files are +processed first. +

+The recognized mail packets are type 2+ following the FSC-0039 standard with +a fallback to the old stone age packets. The packets are checked for being +addressed to one of your own aka's and for a correct password. The +password check may be switched off in the nodes setup. After all the packet +header checks the messages will be extracted from the packet file. +

+When messages are extracted from the packets, the date format is checked for +Year2000 bugs from other tossers. Several checks are done by ideas of Tobias +Ernst of 2:2476/418. It is also possible to run the pktdate +utility before each packet will be processed. Whatever date format us used in +the original message, mbfido will always rewrite the date +field in the right FTS-0001 format. +

+If the message is a netmail the message is checked for DOMAIN, INTL, FMPT and +TOPT kludges so that full 4d or 5d addressing will be possible. Then a check +is done if this netmail is addressed to one of our aka's. If it's addressed to +"sysop" or "postmaster" the name is replaced with the sysop's name. If the +message is addressed to one of the names defined in the service setup, that +mail will be handled by the service manager, ie. given to areamgr, filemgr or +send further as email to your local system. +
+Then the message is checked if it is addressed to an existing bbs user, and if +so it will be imported into the netmail area of the main zone of the bbs. +If it's not addressed to a bbs user, the message will be readdressed to the +sysop. If the message is not for one of our aka's the message will be put in the +mailqueue for further routing. +

+If the message is a echomail message it will be checked for being a duplicate by +storing the CRC32 value of the AREA: line, message subject, origin line, +message date and msgid kludge and testing if that CRC32 value exists in the +echomail duplicate database. If there is no msgid in the message, the whole +message body will be include to complete the CRC32 dupe check. +Also the existance of the echomail area is checked and the node must be linked to that area. +If the message is not in a passthru area and is not a duplicate it +is finally imported in the message base. +After that is the message will be forwarded to downlinks +by adding the message to the mailqueue. +

 

+ +

Adding mail to the outbound.

+

+Adding mail to the outbound is done in two passes. The first pass is to put all +outgoing mail into the ~/tmp directory, these files are named z.n.n.p.ext +The extension can be qqq for packed mail, nnn for normal unpacked mail, hhh for +hold unpacked mail and ccc for crash unpacked mail. Adding mail to this tmp +directory can allways be done, even if one of the nodes you are adding mail +for is having a mail session with your system. This is a safe operation.
+In the second pass, these temp files are really added to the outbound, but +only if the destination node is not locked, ie. there is no current mailsession +with that node. If there is a mail session going, these temp files will stay in +the temp directory and are added to the outbound in a later run of +mbfido. If adding the mail to the outbound succeeds +the temporary file is removed. +

 

+ +

Alias file.

+

+If the file /opt/mbse/etc/aliases excists, mbfido will try to fetch ftn-style +aliases from there. +If "from" address of a message from FidoNet matches right side +of some entry in alias file, then the Reply-To: header is created +in the RFC message with the name part taken from the left side of the +sysalis entry and domain part taken from myfqdn (below). E.g., if a +fidonet message comes from "John Smith of 1:234/567.89@fidonet" and +there is an entry in the sysalias file: +

+"jsmith:      John.Smith@p89.f567.n234.z1.fidonet.org"
+
+and Domain name value is "mbse.nl", then the resulting message will +contain a line: "Reply-To: jsmith@mbse.nl". +

 

+ +

Commands.

+

+mbfido notify <nodes> +This command will send notify messages to all nodes in your setup which +have the notify option set to on. If you enter nodes as option you may use +wilcards, ie 2:*/* to send messages to all nodes in zone 2. If you specify +exactly one node, messages will be generated even if that node has the +notify function off. From cron you should not specify any nodes, this will +just send to all your links the information about their setup. Each node +will receive a status report for files and mail, and area list for all +file areas and mail areas to each aka a node has, and a flow report for +mail for each aka. +

+mbfido roll +This command will only do something if a new week or month has begun. +If this is true the statistic records in several databases are updated. +You should run this command each midnight from cron to be sure that this when it is +time to do so. This command is always executed before one of the scan, toss or tic commands so +if you don't do this in cron, it will still happen. +

+mbfido scan +Scan for new messages entered at the bbs or by other utilities. If the file +~/tmp/echomail.jam or ~/tmp/netmail.jam exists, +mbfido will only scan the messages in areas which are +pointed at in this file. This is a lot faster then a full mailscan. +If it is not present, all messagebases are scanned +to see if there is a new message. If you specify +-full on the commandline a full messagebase scan is forced. +It is wise to do this sometimes, on my bbs I run this once a day. +

+mbfido tag +The command will create tag- and areas files in the doc directory for each group of +mail and files. +

+mbfido test +This is for testing of the mail routing. In the source "tracker.c" I have +included a list of nodes that will be tested. This is for development only, +but it might be handy for you to test your netmail routing. +

+mbfido tic +Process incoming files accompanied with .tic control files. Several actions can +take place on the incoming file before they are imported in the BBS areas. +Options are rearchiving, replacing banners (with your add), check for DOS +viruses, running scripts for certain filename patterns, send these files to +other nodes etc. All options can be defined for each area. If as a result from +one of the actions there are new files hatched, for example after processing +a nodelist difference file which created a new nodelist, the .tic processing +will start again, until there is really nothing more to do. +

+mbfido toss +Toss incoming fidonet netmail and or echomail. By default mail in the protected +inbound directory will be processed, uncompressed .pkt files and compressed +arcmail bundles are recognized, filename case doesn't matter. +

+mbfido news Scan all defined newsgroups for new newsarticles. +New articles are fetched from the newsserver and stored in your messagebase and +send to your up- and downlinks. This is for use with an NNTP gateway. +

+mbfido uucp +This will read a standard a newsbatch from stdin and gate the articles +to Fidonet and the local message base. This is for use with an UUCP gateway, this +mode should be called by uuxqt. The newsbatch may be compressed or uncompressed or +a single news article. +

+mbnews +This is an alternative to mbfido uucp -quiet. +

 

+ +

Options.

+

+mbfido [command] -nocrc +Disable CRC checking of incoming TIC files. Only use this if you know what +you are doing. +

+mbfido scan -full +Force scanning of all message bases for new entered mail. You need this if +mail in entered with other editors then from mbse. Also, running it once a +day is adviced to catch any missed messages. +

+mbfido news -learn +Scan the newsserver for news articles, and update the news dupes database only. +Use this switch if you start using mbfido to gate news articles for the first time. +Articles will not be gated with this switch, mbfido will just learn which articles +already excist. Normally you only need to use this switch once. +

+mbfido [command] -nodupe +Disable checking for duplicate's. Normally you should not use this switch. +This switch doesn't work with the news command, only for echomail and tic files. +

+mbfido [command] -quiet +Quiet mode, all output to the current tty is supressed. Use this flag if +you toss mail from a script (started by cron) after mail is received. +

+mbfido toss -a Toss mail and allow to autocreate +new message areas. See the message area setup +how to set this up. +mbfido toss -unsecure +Toss mail without checking if the echomail is for your own system en without +checking if the sending node is connected to your system. Nodes who are +excluded from a certain echo, can stil not enter messages in that echo. +

+mbfido [command] -unprotect +Toss from the unprotected inbound directory. The default is to toss from the +protected inbound directory. +

 

+ +

Environment.

+

+In order to run the bbs you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. +

 

+ +

Bugs.

+

+There are still bugs, this program is under development. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbfile.html b/html/programs/mbfile.html new file mode 100644 index 00000000..1afc6dfb --- /dev/null +++ b/html/programs/mbfile.html @@ -0,0 +1,93 @@ + + + + + + + + +MBSE BBS Programs - mbfile - File database maintenance program. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbfile - File database maintenance program.

+

+ +

Synopsys.

+mbfile [commands] <options> +

 

+ +

Description.

+

+mbfile +is the filedatabase maintenance program for mbsebbs. In order to run mbfile you +must have started mbsed, +this is the deamon which controls all bbs activities. +

+The main purpose of mbfile +to do automatic maintenance on the downloadable files on the bbs, such as +removing or moving old files, checking the database and packing the database. +The best way to do the maintenance is to run mbfile +from the crontab. example: +

+30 05 * * * export MBSE_ROOT=/opt/mbse; /opt/mbse/bin/mbfile kill pack check index -quiet
+
+

 

+ +

Environment.

+

+In order to run the bbs you need to set one global environment variable +$MBSE_ROOT +This variable must point to the root of the bbs directoy structure. The +main configuration file config.data +must exist in the subdirectory ~/etc. +

 

+ +

Commands.

+

+mbfile check +Check the database integrity. All files in the filedatabase must exist on +disk and all files on disk must exist in the filedatabase. There are some +exceptions, files.bbs, files.bak, 00index, index*.html, header, readme and +files that start with a dot. +Of all files the date and time is checked, the size and the crc +value of the file. If there is something wrong, the error is corrected or the +file is removed. If the area is a CD-rom area, the check that files on disk +must exist in the filedatabase is skipped. +

+mbfile index +Create fast filerequest index for the mbcico filerequest +processor. +

+mbfile pack +This command will actualy remove the records of files that are marked for +deletion. If the file is still on disk, it will be removed also. So when +you delete files with mbsetup, they are still in your database and on disk +until you run mbfile pack. +

+mbfile kill +Delete or move files in areas that have the download age +set or the filedate age set. A setting of 0 is ignored. +Areas on CD-rom are always skipped. +If the Move to Area option is set the files are moved to the given area. The +upload date and download date are reset to the current date and time. +So if you set in the destination area aging of 14 days, files will stay +there for 14 days after the move. This is good for automatic "last chance" areas. +

 

+ +

Options.

+

+mbfile [command] -quiet +Quiet mode, no screen output. Use this switch if you run mbfile from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbindex.html b/html/programs/mbindex.html new file mode 100644 index 00000000..862e70cd --- /dev/null +++ b/html/programs/mbindex.html @@ -0,0 +1,68 @@ + + + + + + + + +MBSE BBS Programs - mbindex - Nodelist Index Compiler. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbindex - Nodelist Index Compiler.

+

+ +

Synopsis.

+

+mbindex <options> +

 

+ + +

Description.

+

+mbindex is the nodelist index compiler. It will create +an index file containing the sorted fidonet addresses as index file to the +raw nodelists in the defined nodelist directory. Several other programs +use this index file for fast retreival of data from the nodelists. Compiling +new nodelist indexes can always be done, while compiling the result +is stored in temporary index files and only after successfull compilation the +original indexes are renamed and the temporary files get the normal names. +The renamed (old) indexes stay on disk including the previous version of the +old raw nodelist. They stay there in case some program had the nodelist or +index still open. So in the nodelist directory there are current nodelists, +previous +nodelists, current indexes and previous indexes, and during compiling the +temporary indexes. There is no need to manually remove (and not wise to do so) +files from the nodelist directory. +

+The nodelists in the nodelist directory are the normal uncompressed nodelists +in MS-DOS format (with CR/LF). The filename extensions must be two or 3 digits. +So if you have a private pointlist named bestbbs.pts you +will have to rename that to bestbbs.999 to make it work. +

 

+ +

Environment.

+

+In order to run mbindex you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Options.

+

+mbindex -quiet Quiet mode, no screen output. Use the switch +if you run mbindex from a shellscript or from the crontab. +

 

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mblang.html b/html/programs/mblang.html new file mode 100644 index 00000000..e79edd6c --- /dev/null +++ b/html/programs/mblang.html @@ -0,0 +1,38 @@ + + + + + + + + +MBSE BBS Programs - mblang - Language Data Compiler. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mblang - Language Data Compiler

+

+ +

Synopsis.

+

+mblang [language data file] [language source text] +

 

+ +

Description.

+

+mblang compiles the source textfile to language datafile +which is used by the mbsebbs program. You only need to +use this program if you install a new language file. When you build the +complete mbse bbs package, this command is run automatic for you. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmail.html b/html/programs/mbmail.html new file mode 100755 index 00000000..70fe3f2f --- /dev/null +++ b/html/programs/mbmail.html @@ -0,0 +1,47 @@ + + + + + + + + +MBSE BBS Programs - mbmail - Mail User Agent for the email gate. + + + +
+
Last update 10-Apr-2001
+

 

+ +

mbmail - Mail User Agent for the email gate.

+

+ +

Synopsys.

+mbmail -r<addr> -g<grade> -c<charset> -b <recip> +

 

+ +

Description.

+

+mbmail +is the Mail User Agent that should be called by your Internet mailer to deliver +mail to Fidonet systems. This program must always run as user mbse so +your mailer must be capable of doing so. The Postfix mailer I use can do that. +

+ +

Commandline options.

+

+mbfile -r<addr> -g<grade> -c<charset> -b <recip> +The -r<addr> is the address to route the packet to. This should normal be set by +the Internet mailer to one of your aka's. The -g<grade> is the packet flavor. This +can be one of the characters n, c or h which means normal, crash or hold. The -c<charset> will +force a certain characterset. Normally this will be automatic set. The -b switch disables splitting +of long messages. The <recip> are one or more recipients for the message. The message itself is +read from stdin. +

+Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmon.html b/html/programs/mbmon.html new file mode 100644 index 00000000..3c73ab64 --- /dev/null +++ b/html/programs/mbmon.html @@ -0,0 +1,45 @@ + + + + + + + + +MBSE BBS Programs - mbmon - MBSE BBS Monitor. + + + +
+
Last update 07-jun-2001
+

 

+ +

mbmon - MBSE BBS Monitor

+

+ +

Sysnopsis.

+

+mbmon +

 

+ +

Description.

+

+mbmon is the monitor program so that you can see what is +happening on your bbs. It can show all processes and actions of all programs, +show system statitistics, disk useage, and the last callers list. +mbmon must run on the same system where the bbs is. +

 

+ +

Environment.

+

+In order to run mbmon you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbmsg.html b/html/programs/mbmsg.html new file mode 100644 index 00000000..4bc50324 --- /dev/null +++ b/html/programs/mbmsg.html @@ -0,0 +1,93 @@ + + + + + + + + +MBSE BBS Programs - mbmsg - Message Base Utility. + + + +
+
Last update 30-Jan-2001
+

 

+ +

mbmsg - Message Base Utility

+

+ +

Sysnopsis.

+

+mbmsg [commands] <options> +

 

+ +

Description.

+

+mbmsg +is the message base utility program for mbsebbs. In order to run mbmsg you +must have started mbsed, +this is the deamon which controls all bbs activities. +

+The main purpose of mbmsg +is to link messages after tossing mail, and to maintain the size of the message +bases and the age of the messages. The best way to do the maintenance is to +run mbmsg +from the crontab. example: +

+30 05 * * * export MBSE_ROOT=/bbs; /bbs/bin/mbmsg kill pack link -quiet
+
+Another purpose is to automatic post messages in message areas. Echomail and +netmail is possible. +

 

+ +

Environment.

+

+In order to run mbmsg you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbmsg link Link all messages by subject ignoring +Re: in the subject lines. You should run this after tossing or scanning mail. +

+mbmsg kill Kill messages in areas that have the +age set or the maximum messages set. +A setting of 0 is ignored. The messages are not removed from the message base, +they are only marked as deleted. +

+mbmsg pack This command actualy removes the +messages who have the deleted flag set. +The lastread pointers are updated and the messages renumbered. After this +command there is no way you can recover your messages, except from backups. +

+mbmsg post <to> <#> <subj> <file> <flavor> + This command posts a message in numbered area. If a field +consists of more then one word it must be surounded with quotes. +The to field can be "Michiel Broek" for a full name or +"Michiel_Broek@f16.n2801.z2.fidonet" for netmail addressing. Look out: +you need underscore between the firstname and lastname, no spaces. +Flavor can be one or more of the characters "c", "i", "h" or "p" to set the Crash, +Immediate, Hold or Private flags. +If no flavor is needed, use the - (minus sign) as a placeholder. +

 

+ +

Options.

+

+mbmsg [command] -area <#> +Process only one area <#> number. +

+mbmsg [command] -quiet Quiet mode, +no screen output. Use this switch if you run mbmsg +from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbout.html b/html/programs/mbout.html new file mode 100644 index 00000000..ec860b00 --- /dev/null +++ b/html/programs/mbout.html @@ -0,0 +1,105 @@ + + + + + + + + +MBSE BBS Programs - mbout - The Outbound Manager. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbout - The Outbound Manager

+

+ +

Synopsis.

+

+mbout [command] <params> <options> +

 

+ +

Description.

+

+mbout is the outbound manager for MBSE BBS. It can ask +information from the nodelists, create and remove polls, request and send files and +display the outbound status. Most of the tasks such as create and remove +polls should be done from the crontab. +

 

+ +

Environment.

+

+In order to run mbout you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbout att <node> <flavor> <file> will attach +the specified file to the specified node. The node should be in the format +f2802.n280.z2, flavor should be crash, immediate, normal or hold. Only the first +letter of the flavor parameter is needed. +If the node is not in the nodelist, the status is Down or Hold, then this command fails. +To non-CM nodes you mus use the Immediate flavor if you want to send the file direct. +The flavors Hold and Normal are still allowed. The file must be in the directory range +from where file attaches are allowed. +

+mbout poll [node..node] creates poll requests in the outbound +for one or more nodes. The node should be in the format f2802.n280.z2. The semafore +scanout is created so that the mailer will start calling. +The mailer will handle the poll request as if it should deliver immediate mail, +so the node will be called as long as the poll request exists, even to nodes which are not CM. +The error counter for the node to poll will be reset to zero, so a node that was +previous marked undialable will be called again. +If a call to a node is successfull, the poll file will be removed by mbcico. +If a node is not in the nodelist or has the status Down or Hold, no poll will be created for that node. +

+mbout stop [node..node] removes poll requests that are +leftover when polling nodes didn't succeed. There is no check if the node is +in the nodelist or has the status Down or Hold, the poll is always removed. +

+mbout req <node> <file> [file..file] creates +filerequests to a node. One or more filenames may be given including wildcards. +It is not possible to do update or password protected uploads yet. If there +is already a requestlist for that node, the new requests will be added. This +command does not call a node, you need to create a poll request to make the +actual call. This is also practical if you want some files from your uplink, +just make the requests and the actual request is send when your normal +scheduled poll to your uplink is processed. +

+mbout stat shows the status of the mailer outbound. +This status is also written to the logfile. +

+mbout node <node> will show the nodelist information for +a certain node. +

 

+ +

Options.

+

+mbout [commands] -quiet will suppress screen output. This is +usefull if you run mbout from the crontab or from background +scripts. +

 

+ +

Examples.

+

+This is an example of crontab entries that writes the outbound status to the +logfile and creates and stops polling of 2 nodes.
+

+00 00 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout stat -quiet
+00 01 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout poll f98.n100.z92 f0.n100.z92 -quiet
+00 02 * * * export MBSE_ROOT=/opt/mbse; $MBSE_ROOT/bin/mbout stop f98.n100.z92 f0.n100.z92 -quiet
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbpasswd.html b/html/programs/mbpasswd.html new file mode 100644 index 00000000..487838df --- /dev/null +++ b/html/programs/mbpasswd.html @@ -0,0 +1,66 @@ + + + + + + + + +MBSE BBS Programs - mbuseradd - The useradd wrapper. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbpasswd - The password wrapper.

+

+ +

Synopsis.

+

+mbpasswd [-opt] [username] [password] +

 

+ +

Description.

+

+mbpasswd is the wrapper for the passwd program +is present on all Linux systems. To use passwd to change the password of +another user is only allowed by root. The mbpasswd program overcomes this limitation. +The wrapper mbpasswd is run from the bbs by user mbse when an ordinary +user is logged in the bbs. The program is called when a new user logs in the bbs or +when an excisting user changes his password. His password under Unix is then always the same as his +password in the bbs program. This is necessary for the user to be able to get +his email using the pop3 protocol.

+You never need to run mbpasswd by hand, in fact it is protected so that only +members of group bbs are allowed to use it. +

 

+ +

Environment.

+

+mbpasswd must be installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root         6644 Jun 26 21:23 /opt/mbse/bin/mbpasswd*
+
+

 

+ +

Commands.

+

+mbpasswd [-opt] [username] [password] for example:
+

+mbpasswd -f michiel secret
+
+Valid options are -f (forced), this will also change locked passwords, +this has only effect if your system uses shadow passwords. If you use +-n as option, locked passwords cannot be changed. For a new user the +-f option is used by mbsebbs, when a user changes his own password the +-n option is used. +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbsebbs.html b/html/programs/mbsebbs.html new file mode 100644 index 00000000..632d1243 --- /dev/null +++ b/html/programs/mbsebbs.html @@ -0,0 +1,149 @@ + + + + + + + + +MBSE BBS Programs - mbsebbs - The main BBS program. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbsebbs - The main BBS program

+

+ +

Synopsis.

+

+mbsebbs +

 

+ +

Description.

+

+mbsebbs is the main bbs program for the users. +To be able to use the bbs, the bbs mustbe set open with mbstat open +or users may not login. This is normally done at system boot. +Also Zone Mail Hour is honored if the user logs in +on a tty that has the honor ZMH flag set to true. If it +is ZMH and the ZMH flag is true, the user will be kicked out of the bbs. You +should only set this flag on the modem lines where you need to be available +for ZMH if your "Fidonet" network requires that. +

+The first visible action is to show the logo.ans file. Because it is not +known who is trying to login, you only need to place this file in the +default language directory. +

+The next check is to see if the user is allowed to login on the tty he +currently is on. +If this tty is not available or is not in your setup, the user is kicked +out. If he is allowed to login, a message is shown at which port he is on, +unless you have turned this feature off in the setup. +

+If a user logs in the first check is if he/she has a Unix account or not. +Unix users bypass the login prompt. Other users will get the normal prompt +the same way DOS based bbs programs do. At that time it is checked if the +user has IEMSI capabilities, if that is true, IEMSI login will be tried. +If the user is not known, the newuser procedure begins. +

+If the user login is successfull, his favourite language will be loaded. +Then it is checked if the user is the Sysop, if so, the Sysop flag is set. +If the user has a blank password, he is asked to create a new password. +Next it is checked if the user has an Unix account, if not he is forced to +create a Unix account. This situation can exist after switching to MBSE BBS +and you have converted your old userbase to the userbase for MBSE BBS. +If the users Date of Birth is invalid, he is forced to enter the right +Date of Birth. +The next check is to see if the user has passed the expiry date, this is a +usefull feature for systems with donating users. +Finally the access limits are set for the user and time remaining for today and +download limits are set. +

+After successfull login the user can be presented with a bunch of advertising +screens. I will only name the screens without filename extension, as these +screens are searched for in the following order;
+

    +
  1. filename.ans in the users favourite language directory. +
  2. filename.ans in the default language directory. +
  3. filename.asc in the users favourite language directory. +
  4. filename.asc in the default language directory. +
  5. If nothing is found, nothing is displayed. +
+welcome. This screen can contain information about the session +the user has, his download limits, time left etc. +

+welcome1 is shown if the user has show bulletins set to true. +

+birthday is shown if the user logs in at his birthday and if he +has show bullentins set to true. +

+dd-mm is shown if dd is the date of today and +mm is the current month and if the user has show bulletins +set to true. +

+sec20 is shown if the user has the security level in the +filename, level 20 in this example. Als the display bulletins must be set to +true. +

+news is shown if the user has the display bulletins set to +true. +

+onceonly is shown only if the user has never seen this screen, +the test is to compare the users last login date against the date of this file. +

+After all these screens the users Offline Reader areas are checked to see if +you as sysop didn't change the message areas. If you made changes, the users +setup is adjusted and he will be notified. This means he sees a list +with deleted areas and new areas. +

+Next if the user has newmail scan set to true all message bases are checked to +see if the user has new mail. This includes a check to see if he has Unix mail. +If there is Unix mail, those mails are retrieved from the POP3 server and stored +in his private mailbox. +If there is new mail for the user, the user sees a list of areas with the messages +in it and he is offered to read and reply these messages. +

+Then if the user has show newfiles set to true and he is not a new bbs user +he will see a list of new files you have on your bbs. During this display +he can tag files for later download. +

+The final setup is to set the users "do not disturb" flag and then the menu +system is started. The menu system will run forever, until the user chooses +to logoff, the connection is lost or his daily timelimit is reached. For the +possibilities and setup of the menus see +MBSE BBS Menu System +

 

+ +

Environment.

+

+In order to run mbsebbs you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+If the environment variable CONNECT is present, a log entry +will be made with the connect speed. +

+If the environment variable CALLER_ID is present, a log entry +will be made with the caller id. +

+If the environment variable LOGNAME is present and it is not +bbs then it is assumed that it is a Unixmode login of the +user who's Unixname is in the LOGNAME environment variable. +This variable is set by the /bin/login program, so users that telnet to your +bbs or login via mgetty and login with their Unixname will +set this. If the LOGNAME is bbs then the +user is prompted to enter his Fidonet style name. By the way, you can change +that default bbs username with mbsetup. +

 

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbseq.html b/html/programs/mbseq.html new file mode 100644 index 00000000..1ab89e47 --- /dev/null +++ b/html/programs/mbseq.html @@ -0,0 +1,49 @@ + + + + + + + + +MBSE BBS Programs - mbseq - Sequence number creator. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbseq - Sequence number creator

+

+ +

Synopsis.

+

+mbseq +

 

+ +

Description.

+

+mbseq writes a eight character hexadecimal unique sequence +number to the stdout. This number is received from mbsed +which keeps track of the generated sequence numbers. This written number can +be used in shell scripts to create unique filenames for Fidonet .pkt files, +for example: +

+ +cp temp.pkt `mbseq`.pkt + +

 

+ +

Bugs.

+

+Nah, it's only 50 lines code, what could go wrong? +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbsetup.html b/html/programs/mbsetup.html new file mode 100644 index 00000000..42733478 --- /dev/null +++ b/html/programs/mbsetup.html @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Programs - mbsetup - The Setup Program. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbsetup - The Setup Program

+

+ +

Synopsis.

+

+mbsetup +

 

+ +

Description.

+

+mbsetup is the setup program for MBSE BBS. It should be run +only by user mbse. If you run it by accident as root file +permissions will be wrong and your bbs may not function. For a detailed +description of all setup options see MBSE BBS +Setup Guide +

 

+ +

Environment.

+

+In order to run mbsetup you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. If it is not present, ie you run +mbsetup for the first time, a default +config.data will be created. This will also happen with +several other databases. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbstat.html b/html/programs/mbstat.html new file mode 100644 index 00000000..f589c93e --- /dev/null +++ b/html/programs/mbstat.html @@ -0,0 +1,79 @@ + + + + + + + + +MBSE BBS Programs - mbstat - MBSE BBS Status Changer. + + + +
+
Last update 07-Jul-2001
+

 

+ +

mbstat - MBSE BBS Status Changer

+

+ +

Synopsis.

+

+mbstat [commands] <options> +

 

+ +

Description.

+

+mbstat changes the bbs status between open and close, can wait +for all users to logoff and wait for critical utilities to stop their actions. +

 

+ +

Environment.

+

+In order to run mbstat you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

 

+ +

Commands.

+

+mbstat semafore scanout will set the internal +semafore scanout in the mbtask daemon. The following semafore's +are valid: scanout, mailout, mailin, mbindex, reqindex, msglink. +

+mbstat close will close the bbs for users. +Users that are just logging in to the bbs will be thrown out after a short message. +Users already logged in will be thrown out when they pass by a menu prompt. +So users who are doing file transfers can finish their transfers before being disconnected. +

+mbstat open opens the bbs for users. +This should be run from one of the system startup scripts right after you started +mbsed. If you installed everything as it should this +command is already executed at system startup. +

+mbstat wait will +wait for the bbs to become free. This includes a check for utilities that +do critical actions so they can finish their job without corrupting the bbs +databases. The default is to wait 60 minutes. If the semafore +upsdown exists it will wait only 30 seconds. +

+You should run mbstat close wait in your system shutdown script so +that the system shutdown will wait for a clean shutdown of the bbs before +the rest of your system goes down. If you installed everything as it should +be then these commands are already installed in your system shutdown scripts. +

+ +

Options.

+

+mbstat [command] -quiet will supress screen output. +This is good for using mbstat in scripts. +

+ + +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbtask.html b/html/programs/mbtask.html new file mode 100644 index 00000000..bc0cfebc --- /dev/null +++ b/html/programs/mbtask.html @@ -0,0 +1,319 @@ + + + + + + + + +MBSE BBS Programs - mbtask - MBSE BBS Taskmanager. + + + +
+
Last update 07-Jul-2001
+

 

+ +

mbtask - MBSE BBS Taskmanager

+

+ +

Sysopsis.

+

+mbtask +

 

+ +

Description.

+

+mbtask is the taskmanager for the whole MBSE BBS system. +This deamon keeps track of all client actions, +does the logging for the clients, does database locking, authorizes clients, +set/resets users "do not disturb flags", sends and receives chat messages, +keeps track of Zone Mail Hour and the BBS open/close status. Communication +between mbsed and the client programs is done via Unix +Datagram sockets. The protocol used to communicate between mbtask +and the clients is explained later. +This daemon also watches the semafore directory for some special files. +It also starts programs when they are needed. +The very first time mbtask is started it creates a default config.data and task.data, +the main configuration and task configuration files +mbtask should be started at system boot so the bbs system will start working. +The init script that is installed on your system will do that. +This program is introduced with MBSE BBS v0.33.16 +and replaces the run_inout and mailer scripts that were called by cron every minute. +

+After startup and initalization mbtask runs internally once per second forever. +If there is nothing to do then this time will slowly increase upto 5 seconds. This time will be reset +to one second as soon as there is work to be done. The actual work is to check a number of external and +internal semafore's and act on these. +But before any program is started a number of things are checked: +

    +
  1. Check the system's load average. If it is too busy the processing of background + tasks is suspended until your system load drops. + The default setup is set at 1.50 but you can change that with mbsetup. Experience + will learn what the best value will be and I need some feedback on that.
    +
  2. The UPS semafore upsalarm will be checked. This means that the system is running on + battery power and no new jobs are started. +
  3. The UPS semafore upsdown will be checked. This is the fatal one, if + this one excists mbtask will try to stop all current running jobs. + If there are no jobs left running then mbtask will stop itself. + The upsdown semafore means that the system + will shutdown and power off, that's why it's fatal and there is no way back.
    +
  4. The status of the bbs will be checked, is it open or closed. If it is closed, no + jobs will be started. +
  5. The Zone Mail Hour is checked. If ZMH begins the semafore's zmh is created and + a outbound scan is forced. + If ZMH ends the semafore zmh is removed a new outbound scan is forced. +
  6. Each twenty seconds a ping is send to the IP addresses defined with mbsetup to + check if the internet can be reached. If both ping addresses fail, it is assumed that + the internet can't be reached. Note: this is for future use! +
+Each new minute the timestamp of semafore mbtask.last is updated so that you can check that +mbtask is running. Also each minute is checked if the system configuration files are +changed, is so they are reloaded. There is no need to stop and start mbtask if you made +changes to the system configuration. +Then all kind of internal semafore's will be checked. The commands that are executed have default +values, but they can be changed wit mbsetup. The commands can be scripts as well. +The checks and actions are: +

+ + + + + + + + + + + + + + + +
SemaforeSpeedTasktypeDepends onJob to run
mailoutFastmbfidoMax. 1 mbfido taskmbfido scan web -quiet
mailinFastmbfidoMax. 1 mbfido taskmbfido tic toss web -quiet
newnewsFastmbfidoMax. 1 mbfido taskmbfido news web -quiet
mbindexFastmbindexNo other tasksmbindex -quiet and if excist: goldnode
msglinkFastmbfidoNo other tasksmbmsg link -quiet
reqindexFastmbfileNo other tasksmbfile index -quiet
scanoutSlowcallOnly 1 call taskmbcico -r1
+

+The Fast and Slow values mean: Fast is each second, Slow is check each 20 seconds. +As you can see, the system will not do too much at the same time. Jobs like compiling +new nodelists or create file request indexes have a very low priority. Because this +daemon checks the semafore's each second it responds much better that the old scripts +running on the cron daemon. The system will be expanded so that more outgoing calls +will be done at the same time, ie. ISDN and analogue calls, and if they are present +internet calls, will be made at the same time. +

+The mbtask program keeps also track of a unique number generator, this is +just a simple counter that is increased each time it is asked for a new number. +It will take years for the numbers to repeat. Even if the status file is lost +the chance that numbers are repeated on your system are almost zero. The first +time the counter is initialized it is set to the current unix time in seconds +since 1 januari 1970. This counter is used by several programs to create unique +.pkt filenames, msgid numbers etc. +

 

+ +

Environment.

+

+In order to run mbtask you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. +

 

+ + +

Security.

+

+mbtaskmbse before the child process is created and the rest +of the initialisation is done. +The child process can never get root privileges because it is spawned by user mbse. +

 

+ + +

Communications.

+

+Communication between the server and the clients is established by +Unix datagram sockets. There can be only 1 server running. +The server will accept connections from clients on your local machine only. +The limit for the amount of clients that can connect to the server is set to 100. +

+The server creates a Unix datagram socket at startup and waits for connections. +The name of this this socket is /opt/mbse/tmp/mbtask. +When a client connects it creates a Unix datagram socket in /opt/mbse/tmp, the name is +the name of the program, added with the pid of the program. So if mbcico is started +with pid 2312 the socket will be /opt/mbse/tmp/mbcico2312. +

+All commands are 4 capital letters followed by a colon, a number indicating +how much data fields will follow. If that number is higher than zero, the +data fields are seperated with commas. The command is terminated +with a ; character. Examples are:
+

+GCLO:0;                 Zero datafields command.
+DOPE:1,dbname;          One datafield command.
+
+All commands will receive a reply as soon as possible. If a +resource is temporary not available, a reply will follow too, telling +this condition. Replies can also contain optional data. Examples:
+
+100:0;                  Response 100, no data.
+200:1,Syntax error;     One datafield.
+
+The server has a 10 minute timeout for receiving data when a connection +is established. The clients need to "ping" the server at regular intervals +to prevent a disconnect. All official MBSE BBS programs do that. The pid +send with most commands is the pid of the calling program. Since this number +is unique, it is used to keep track of the connected clients. +

+The commands are divided in 26 catagories, most unused at this time. +

+

+Catagories:
+
+Cat.    Description
+----    -------------------------------------------
+Axxx    Accounting, system monitor info etc.
+Cxxx    Chatting
+Gxxx    Global commands.
+Sxxx    Status commands.
+
+
+
+         Group A, Accounting.
+
+Command: AINI:5,pid,tty,uid,prg,city;   Initialize connection, and who am I.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADOI:2,pid,doing;              What am I doing right now.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ACLO:1,pid;                    Close my connection.
+Reply:   107:0;                         Connection closed.
+         200:1,Syntax Error;            Error, connection is still open.
+
+Command: ALOG:5,fil,prg,pid,grade,txt;  Write a line of text in logfile with grade.
+Reply:   100:0;                         Ok.
+         201:1,errno;                   Error, number in errno.
+
+Command: AUSR:3,pid,uid,city;           Set username and city
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADIS:2,pid,flag;               Set Do Not Disturb flag.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ATIM:1,time;                   Set new Client/Server timer in seconds.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ADEF:0;                        Set Client/Server timer to default (10 minutes).
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+Command: ATTY:2,pid,tty;                Set new tty name.
+Reply:   100:0;                         Ok.
+         200:1,Syntax Error;            Error.
+
+
+         Group C, Chatting (just some ideas).
+
+Command: CIPM:1,pid;                    Is Personal Message present.
+Reply:   100:2,fromname,message;        Yes, from .. with message text.
+         100:0;                         No.
+
+Command: CSPM:3,fromuser,touser,txt;    Send personal message to user.
+Reply:   100:1,n;                       n: 0=Ok, 1=Do not disturb, 2=Buffer full, 3=Error.
+         100:0;                         Impossible.
+
+         The next commandis are some ideas, they are not implemented.
+
+        -CBPM:2,fromuser,txt;           Broadcast message to all users.
+        -CJCH:2,pid,channel;            Join Channel
+        -CCCH:2,pid,channel;            Close Channel
+        -CAML:2,channel,text;           Add textline to channel
+        -CIML:1,channel;                Is new textline present
+        -CSSP:1,user,reason;            Send Sysop Page
+        -CESP:1,user;                   Retract Sysop Page
+        -CRSP:1,user;                   Reject user Page
+        -CFCH:2,channel,user;           Force user in chatmode (for Sysop chat).
+        -CKCH:2,channel,user;           Kill user chatmode (for Sysops and moderators).
+
+
+        Group G, Global commands.
+
+Command: GNOP:0;                        No OPerations.
+Reply:   100:0;                         Ok.
+
+Command: GPNG:1,data;                   Ping, echo data.
+Reply:   100:1,data;                    Ping reply.
+
+Command: GVER:0;                        Give server version.
+Reply:   100:1,Version ....;            Version reply.
+
+Command: GSTA:0;                        Get complete mbsed status record. (13 fields)
+Reply:   100:19,start,laststart,daily,startups,clients,tot_clients,tot_peak,syntax_errs,
+                com_errs,today_clients,today_peak,today_syntax,today_comerr,bbsopen,
+                is_zmh,processing,system_load,sequence;
+
+Command: GMON:1,n;                      Get registration info line, 1=First, 0=Next line.
+Reply:   100:7,pid,tty,user,program,city,isdoing,starttime;
+         100:0;                         No more lines.
+
+Command: GDST:0;                        Get filesystem status (see note below).
+         100:n,data1, ..., data10;      Maximum 10 filesystems datalines.
+
+Command: GSYS:0;                        Get bbs statistics.
+         100:7,calls,pots_calls,isdn_calls,network_calls,local_calls,startdate,lastcaller;
+
+Command: GLCC:0;                        Get Lastcallers count
+         100,1,n;                       Return counter value.
+
+Command: GLCR:1,recno;                  Get Lastcaller record
+         100:9,user,location,level,tty,time,minsmcalls,speed,cations;
+         201:1,16;                      Not available.
+
+
+         Group S, Status commands.
+
+Command: SBBS:0;                        Get BBS Status (open, zmh, shutdown).
+Reply:   100:2,0,The system is open for use;
+         100:2,1,The system is closed right now!;
+         100:2,2,The system is closed for Zone Mail Hour!;
+
+Command: SOPE:0;                        Open the BBS.
+Reply:   100:0;                         Ok.
+
+Command: SCLO:1,mesage;                 Close the BBS with reason.
+Reply:   100:0;                         Ok.
+
+Command: SFRE:0;                        Is the BBS Free.
+Reply:   100:1,Running utilities: n  Active users: n;
+         100:0;                         It's free.
+
+Command: SSEQ:0;                        Get next unique sequence number.
+Reply:   100:1,number;                  Next unique sequence number.
+
+Command: SEST:1,semafore;               Get status of internal semafore.
+Reply:   100:1,n;                       1 = set, 0 = not set.
+         200:1,16;                      Semafore not known.
+
+Command: SECR:1,semafore;               Set semafore
+Reply:   100:0;                         Ok.
+         200:1,16;                      Error.
+
+Command: SERM:1,semafore;               Remove semafore
+Reply:   100:0;                         Ok (also if there was no semafore).
+         200:1,16;                      Semafore not known.
+
+Note: in reply of GDST the reply is 100:n,size free mountpoint fstype,..... +where n = 1 for 1 filesystem, and 10 for a total of 10 filesystems. There +will never be a reply for more then 10 filesystems. The reported filesystems +are retrieved from /etc/mtab which is the actual mountstatus. This is used +by the mbmon program to get a "live" view of your filesystems. +

 

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbtoberep.html b/html/programs/mbtoberep.html new file mode 100644 index 00000000..86413043 --- /dev/null +++ b/html/programs/mbtoberep.html @@ -0,0 +1,47 @@ + + + + + + + + +MBSE BBS Programs - mbtoberep - List newfiles to report. + + + +
+
Last update 31-Jan-2001
+

 

+ +

mbtoberep - List newfiles to report

+

+ +

Synopsis.

+

+mbtoberep +

 

+ +

Description.

+

+mbtoberep is a small utility to list the file +~/etc/toberep.data which contains the newfiles found on your system before +mbaff announce is run. This program is intended for system +development but I decided to leave it in the distribution for now. If you +pipe the output thru more or less you are able to inspect the records. +

 

+ +

Environment.

+

+In order to run mbtoberep you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbuser.html b/html/programs/mbuser.html new file mode 100644 index 00000000..b09b1665 --- /dev/null +++ b/html/programs/mbuser.html @@ -0,0 +1,71 @@ + + + + + + + + +MBSE BBS Programs - mbuser - User Database Maintenance. + + + +
+
Last update 02-Feb-2001
+

 

+ +

mbuser - User Database Maintenance

+

+ +

Sysnopsis.

+

+mbuser [commands] <options> +

 

+ +

Description.

+

+mbuser is the user database maintenance program. It can delete +users upto a certain level who have not called for a number of days. It can +also pack the user database. This is not really a pack of the database, the +deleted records are zeroed but the database is never shrinked. Every user +once in this database will keep his record forever. This is to be sure that +all LastRead Pointers will be correct. Records that are zeroed can be +reused for new users. mbuser must run setuid root and +setgid root because it executes /usr/sbin/userdel to delete the Unix account +of the user that is removed from the bbs. +

 

+ +

Environment.

+

+In order to run mbuser you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. mbuser must be +installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root        23560 Jun 19 19:50 /opt/mbse/bin/mbuser*
+
+

 

+ +

Commands.

+

+mbuser kill [n] [l] will mark users to delete who have not +called in n days upto and including level l. +

+mbuser pack will delete (zero) the users marked for deletion. +You should also run this command if you marked users to delete with +mbsetup. +

 

+ +

Options.

+

+mbuser [command] -quiet will suppress screen output, this is +for running mbuser in the background or from the crontab. +

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/programs/mbuseradd.html b/html/programs/mbuseradd.html new file mode 100644 index 00000000..92950b61 --- /dev/null +++ b/html/programs/mbuseradd.html @@ -0,0 +1,72 @@ + + + + + + + + +MBSE BBS Programs - mbuseradd - The useradd wrapper. + + + +
+
Last update 02-Feb-2001
+

 

+ +

mbuseradd - The useradd wrapper.

+

+ +

Sysnopsis.

+

+mbuseradd [gid] [username] [comment] [userdir] +

 

+ +

Description.

+

+mbuseradd is the wrapper for the useradd +program that should be present on most Linux systems. useradd +may only be executed by root and there are some other minor +things that need to be done as root to create a new Unix +account that can be used with MBSE BBS. The solution for these problems is +mbuseradd, this little program runs setuid root and setgid +root. If it fails to do that it aborts. mbuseradd is called +by mbsebbs from the newuser function. You never need to +run mbuseradd by hand. If it is successfull the user will +have an entry in /etc/passwd, the comment is his Fidonet name, and his shell +is $MBSE_ROOT/bin/mbsebbs. +

+If all this is successfull until now, the homedirectory for this user is +created and the right ownership and permissions are set. In his homedirectory +the empty file .hushlogin is placed to prevent check for +new mail when he logs into your system. This is the Unix mailcheck that is +skipped and has nothing todo with the check for new mail in the bbs. All +other directories that are needed for the bbs are created by mbsebbs. +

 

+ +

Environment.

+

+In order to run mbuseradd you must set the global variable +$MBSE_ROOT. This variable must point to the root directory +of the bbs structure. The main configuration file config.data +must be present in the ~/etc directory. mbuseradd must be +installed setuid root and setgid root, ls -la looks like this:
+

+-rws--s--x   1 root     root         6644 Jun 26 21:23 /opt/mbse/bin/mbuseradd*
+
+

 

+ +

Commands.

+

+mbuseradd [gid] [name] [comment] [usersdir] for example:
+

+mbuseradd bbs mbroek "Michiel Broek" /opt/mbse/home
+
+

+ +Index Back to index  +Main Back to Main index +

+ + + diff --git a/html/routing.html b/html/routing.html new file mode 100644 index 00000000..75a1d088 --- /dev/null +++ b/html/routing.html @@ -0,0 +1,211 @@ + + + + + + + + +Netmail routing behaviour. + + + +
+
Last update 07-Jun-2001
+

 

+ +

MBSE BBS Netmail routing behaviour

+ +

Introduction

+

+The mbfido program that is responsible for unpacking, +importing, exporting and routing of netmail has a build in default routing +plan. In general this is quite simple, if we know the destination node or +his uplink, (that node or uplink is in our setup), then we will route via +that node in our setup. If the node or his uplink is not in our setup, then +the nodelist is used and normal fidonet routing is used. This means, if you +are a node, everything goes to your hub, if you are a hub, then mail for +your downlinks will go direct to the downlinks because they are in your setup, +everything else goes to the host. +If you are a host, then your own downlinks will get the mail direct, +the downlinks of the hubs in your net well be routed via the hubs below you. +If it is for a node in your region but outside your net, mail will be routed via +the other hosts in your region. Mail to outside your region will go to the +region coordinators system. +

 

+ +

Tracking and bouncing

+

+At this moment there is no bouncing of undeliverable mail. I will built this +in, but it will only work inside your own net. I will never include code for +bouncing mail outside your net, because nodelists are always not uptodate. +

 

+ +

Special routing

+

+What if you need special routing. The solution is simple, add the routing +nodes to your setup and fill in the "route via" field. If you don't have a +session password with that node, leave the password fields blank. This node +will never know that he is in your setup as long as you have the notify +settings for that node switched off. To figure +out such solutions yourself, I have included the flow diagrams for the tracking +module. +

 

+ +

Main tracking routine:

+
+
+	+=============================+
+	|     Trackmail to dest.      |
+	+--------------+--------------+
+		       |
+	++-------------+-------------++
+	||   rc = GetRoute to dest   || (See next diagram).
+	++-------------+-------------++
+		       |
+	+--------------+--------------+  yes
+	|       rc = R_NOROUTE        +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			| res: R_NOROUTE |
+		       |			+================+
+	+--------------+--------------+  yes
+	|       rc = R_UNLISTED       +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       |			| res: R_UNLISTED|
+		       |			+----------------+
+	+--------------+--------------+  yes
+	|        rc = R_LOCAL         +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			| result: R_LOCAL|
+		       |			+================+
+	+--------------+--------------+  no
+	|   routing node in setup ?   +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|   result:  rc  |
+		       |			+================+
+	+--------------+--------------+  no
+	|   "Route via" filled in ?   +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|  res: R_ROUTE  |
+		       |			+================+
+	+--------------+--------------+
+	|   Change route to address   |
+	|       result = R_ROUTE      |
+	+=============================+
+
+
+

Sub function GetRoute:

+
+
+	+=============================+
+	|          GetRoute           |
+	+--------------+--------------+
+		       |   
+	+--------------+--------------+
+	|      Add domain name	      |
+	+--------------+--------------+
+		       |
+	+--------------+--------------+ yes
+	|  Is dest our own address ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|   rc = R_LOCAL |
+		       |			+================+
+	+--------------+--------------+ yes
+	| Is dest our point address ? +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes (route to boss)
+	|    Are we a point system    +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| dest is my Boss|
+		       |                        |  res: R_DIRECT |
+		       |			+----------------+
+	+--------------+--------------+ yes
+	| Dest. addr. in nodes setup? +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes
+	| Boss of point dest in setup +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			|  rc = R_DIRECT |
+		       |			|   dest = Boss  |
+		       |			+================+
+	+--------------+--------------+ 
+	| Is node listed and do we    | yes
+        | know his uplink in setup ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| dest is uplink |
+		       |			|  rc = R_DIRECT |
+		       |			+================+
+	+--------------+--------------+ yes
+	|   Are we host in network ?  +------------------+
+	+--------------+--------------+		+--------+-------+
+		       | no			| Set host addr. |
+		       |			+--------+-------+
+		       |				 +----------+
+	+--------------+--------------+ yes			    |
+	|    Are we hub in domain ?   +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			|  Set hub addr. |  v
+		       |			+--------+-------+  |
+		       |				 |	    |
+		       +---------------<-----------------+-----<----+
+		       |
+	+--------------+--------------+
+	|    Set our region number    |
+	+--------------+--------------+
+		       |
+		       |
+	+--------------+--------------+ no
+	|       Host address set ?    +-----------------------------+
+	+--------------+--------------+				    |
+		       | yes					    |
+		       |					    |
+	+--------------+--------------+ 
+        |  Dest region <> our region  | yes			    |
+	|  or Dest zone <> our zone   +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			|   Dest to RC   |  |
+		       |			|  rc = R_ROUTE  |  |
+		       |			+================+  |
+	+--------------+--------------+ yes			    |
+	|     Dest net <> our net     +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | no			| to host destnet|  |
+		       |			|  rc = R_ROUTE  |  |
+		       |			+================+  |
+	+--------------+--------------+ yes			    |
+	|       Has node a hub        +------------------+	    |
+	+--------------+--------------+		+--------+-------+  |
+		       | yes			| to node's hub  |  |
+		+------+--------+		|  rc = R_ROUTE  |  |
+		| dest is direct|		+================+  |
+		|  rc = R_ROUTE |				    |
+		+===============+				    |
+								    |
+		       +------------------------<-------------------+
+	+--------------+--------------+ no
+	|       Hub address set ?     +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | yes			|  via our hub   |
+		       |			|  rc = R_ROUTE  |
+		       |			+================+
+	+--------------+--------------+ yes
+	|  Dest node of our hub addr  +-----------------+
+	+--------------+--------------+		+-------+--------+
+		       | no			|  rc = R_DIRECT |
+		       |			+================+
+		+------+-------+
+		| dest is host |
+		| rc = R_ROUTE |
+		+==============+
+
+
+ +Back Go Back +
+ + + diff --git a/html/setup/archiver.html b/html/setup/archiver.html new file mode 100644 index 00000000..9a93ac25 --- /dev/null +++ b/html/setup/archiver.html @@ -0,0 +1,44 @@ + + + + + + + + +MBSE BBS Setup - Archiver programs. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - archiver programs

+

+To process mail, files and test new uploads you need archivers to process those +files. For each (un)archiver you must setup the full path and filename and +commandline switches. Archivers and unarchivers may be different programs such +as zip and unzip.

+There is a little +difference in processing mail and files, mail will always work on the same +directory, while for ticfile processing the archives can contain subdirectories. +So it is obvious that for rearchiving a file you need the recursive +switches to keep the directory structure within an archive as it was.

+There is also a special command to replace a banner in an archive. This is when +you receive files with the banner of your uplink in it and you want to replace +it with the add of your own bbs and you don't want to mess with the files in +the archive.

+The last option is to extract the file FILE_ID.DIZ from the +archive, this can be used for file description when the file is imported in +your bbs. To make life a little more easy, during the first bbs setup the most +common archivers already configured. You only need to make sure that they are +really present on your system. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/bbs.html b/html/setup/bbs.html new file mode 100644 index 00000000..cc6d8c76 --- /dev/null +++ b/html/setup/bbs.html @@ -0,0 +1,42 @@ + + + + + + + + +MBSE BBS Setup - Edit BBS Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Edit BBS Setup.

+

+ +

Edit BBS Setup.

+

+The BBS setup is split in the following sections: +

+ +

    +
  1. Security limits +
  2. Language setup +
  3. BBS menus +
  4. File areas +
  5. Transfer protocols +
  6. BBS List data +
  7. Oneliners +
  8. TimeBank data +
  9. Safe Cracker data +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/bbslist.html b/html/setup/bbslist.html new file mode 100644 index 00000000..36478cc7 --- /dev/null +++ b/html/setup/bbslist.html @@ -0,0 +1,28 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - BBS List Data. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - BBS List Data.

+

+This is not available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/domains.html b/html/setup/domains.html new file mode 100644 index 00000000..b83bb56a --- /dev/null +++ b/html/setup/domains.html @@ -0,0 +1,48 @@ + + + + + + + + +MBSE BBS Setup - Edit Domains. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Edit Domains.

+

+ +

Introduction.

+

+The domains table is used to translate Fidonet domains to internet domains +and back for the Fidonet <-> Internet gateway. When you add entries to +this table make sure that the entry .fidonet and +.ftn is always the last entry. This is the default entry. +New added domains can be moved in place with the Move +command. +

 

+ +

Edit Domains.

+

+

+Fidonet   The Fidonet domain to match.
+Internet  The internet domain to match.
+Active    If this domain is active.
+Deleted   If this domain must be deleted.
+
+

+Next is an example table. +

+ + +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/emareas.html b/html/setup/emareas.html new file mode 100644 index 00000000..0ecaad5b --- /dev/null +++ b/html/setup/emareas.html @@ -0,0 +1,164 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup - Mail Areas. + + + +
+
Last update 08-Jun-2001
+

 

+ +

MBSE BBS Setup - Mail Setup -> Mail Areas.

+

+ +

Introduction.

+

+Mail areas have fixed area numbers, just like file areas. But if you want you +can move areas. +Some offline readers don't like changing the area numbers. All areas can +be of the following types: local, netmail, echomail and news. If you gate +news and echomail in the same area, then select echomail +if this area is a Fidonet area, select news if this area is a Usenet news area. +

+There is a global setup tool, if you are in the main message area setup screen then +you can choose the Global command. This will allow you to do bulk changes on areas +selected by the mail groups. Options are delete connection, add new connection, +replace connection, change connection status, change days old for purge, change +maximum messages for purge, change user security, change aka to use, change origin line, +change netmail reply board and delete message area. +

 

+ +

Message Area Setup.

+

+

+Area Name   The description of the area.
+Area Tag    The echomail area tag.
+Newsgroup   The newsgroup name if you are gating this area.
+Moderator   Leave this blank for now!
+JAM base    The path and name of the JAM message base without extension.
+Origin      The origin line to add to echomail messages.
+Fido Aka    The Fidonet aka for this area.
+QWK name    The name of the area for OffLine Readers.
+Group       The name of the echomail group.
+Distrib.    Leave this blank for now!
+Area Type   Local, Netmail, Echomail or News.
+Msg Kinds   Private/Public, Private, Public, Read Only, FTN moderated, Usenet Moderated
+FTN chars   FTN characterset, not in use yet, defaults to IBMPC 2
+RFC chars   RFC characterset, not in use yet, defaults tp LATIN-1 2
+Days Old    The maximum age of the messages before purging.
+Max. Msgs   The maximum messages in this area.
+Netreply    Netmail reply area if this is echomail.
+Active      If this area is active.
+User Del.   Users may delete their own messages.
+Read Sec.   The security level to read messages.
+Write Sec.  The security level to write messages.
+Sysop Sec.  The security level to do sysop actions.
+Aliases     Allow the use of an Alias.
+Random org  Create random origin lines (Oneliner database).
+Quotes      Add a random quote under new messages (Oneliner database).
+Mandatory   If this area is mandatory for downlinks.
+UnSecure    Don't check link address during toss (Dangerous!).
+OLR Default Switch area default on for OLR users.
+OLR Forced  Area is always on for OLR users.
+Connections This will take you to the screen to edit up and downlinks.
+
+

+ + +

 

+ +

Edit connection

+

+

+Aka         The network address.
+Send to     Export mail to this node.
+Recv from   Import mail form this node.
+Pause       The node is temporary disconnected.
+Excluded    The node is disconnected by the sysop.
+Delete      Delete this connection.
+
+

+A note about the excluded switch. This can be used to disconnect a node +from the area by moderator request. AreaMgr requests from that node +for this area are not processed anymore, he cannot disconnect this area +and reconnect. If you want to prevent a node to connect the area while +he is not connected, you should manually connect the node and then set +the Excluded flag to yes. However, the status of this flag is reported to the +node in the notify messages, so this action is not invisible. +

 

+ + +

Global Commands.

+

+From menu 9.2 you can enter the global commands menu. In this menu you can: +

    +
  1. Delete connection +
  2. Add new connection +
  3. Replace connection +
  4. Change connection status +
  5. Change days old +
  6. Change max. messages +
  7. Change security +
  8. Change aka to use +
  9. Change origin line +
  10. Change netmail reply +
  11. Delete message area +
+After you have selected the action you want and added the items to do, you will see +a screen were you can select message area groups. You can then tag one or more +groups and press enter when you are done. Then you have one chance to perform the +actions or to bail out. All areas matching in that group are affected by your +changes. If you are not happy with the result, don't save the database and no +harm is done. The file mbsetup.log shows all affected areas. +

 

+ + +

Automatic area creation.

+

+If you want to use the automatic area creation you have to define a fictitious +area tagged 'DEFAULT' with the options you want for new areas like this: +

+ 1.  Area Name Area autocreada:
+ 2.  FTN area  DEFAULT
+ 3.  Newsgroup
+ 4.  Moderator
+ 5.  JAM base  /var/spool/mbse/mail/
+ 6.  Origin    Parolas BBX. Por fin.
+ 7.  Fido Aka  0:0/0@                                      22. Sysop Sec.   100
+ 8.  QWK name                      15. Days Old    40      23. Aliases      No
+ 9.  Group     AUTOCREADAS         16. Max. Msgs   1000    24. Quotes       No
+ 10. Distrib.                      17. Netreply    0       25. Mandatory    No
+ 11. Area Type Echomail            18. Active      Yes     26. UnSecure     No
+ 12. Msg Kinds Public              19. User Del.   Yes     27. OLR Default  No
+ 13. FTN chars IBMPC 2             20. Read Sec.   5       28. OLR Forced   No
+ 14. RFC chars LATIN-1 2           21. Write Sec.  5       29. Connections
+
+The FTN area's Tag must be 'DEFAULT' exactly. Connections will be left blank. Fill +the remaining options with your defaults for the new areas. +If Fido AKA has not been filled in, the best fitting AKA according to the origin of +the message will be used from the configuration.
+

+Areas will be created as is laid out in this template, the tag of a new area +will be added to the name and base path, the new tag will be placed in the tag +and qwk name (truncating it if needed). +Only the node from which the new area is received will be added in connections. +

+You will need to change the setup, menu 18, item 2, to change the command +'mbfido tic toss'. Add the -a parameter if you want the automatic +creation of areas to work when importing received mail. +So the commandline would be like /opt/mbse/bin/mbfido tic toss web -a -quiet. +

+ +Back Back to Mail Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/emgroup.html b/html/setup/emgroup.html new file mode 100644 index 00000000..52dc66b7 --- /dev/null +++ b/html/setup/emgroup.html @@ -0,0 +1,50 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup - Message Groups. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Mail Setup - Message Groups.

+

+ +

Introduction.

+

+Message Groups are to logically divide your echomail areas in groups for +different mail networks. It makes sense to select the groups by uplink, and +areas file that is available for each network. By doing that downlinks can +automatic connect areas that are not available at your bbs but are available +from your uplink. NOTE: uplink requesting is not yet implemented! +

 

+ +

Message Group Setup.

+

+

+Name     The name of the group.
+Comment  The description of the group.
+Active   If this group is active.
+Use Aka  The Fidonet aka to use.
+Uplink   The Fidonet aka of your uplink.
+Areas    The name of the areas file (~/etc/file.ext).
+Deleted  If this group must be deleted.
+
+

+ +

+ +Back Back to Mail Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fdb.html b/html/setup/fdb.html new file mode 100644 index 00000000..b705bb24 --- /dev/null +++ b/html/setup/fdb.html @@ -0,0 +1,58 @@ + + + + + + + + +MBSE BBS Setup - Files Database. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Files Database.

+

+ +

Introduction.

+

+This option allows you to manually edit the files in the files database. +The option to edit the file description is not present at this moment, but +will be when I have the time. The basic file entries can't be changed. +

 

+ +

Edit File.

+

+

+FileName  The 8.3 filename of the file.
+Long fn   The long filename of the file, not in use yet.
+FileSize  The size of the file in bytes.
+FileDate  The real date of the file.
+Last DL.  The date of the last download of the file.
+Upl.Date  The upload date.
+Uploader  The name of the uploader.
+Times DL  The number of times downloaded from the BBS.
+Times FTP Not in use yet.
+Times Req The number of times requested by mailer.
+Password  The password to access this file.
+Cost      Not in use yet.
+Free      If this file is free for download.
+Deleted   If this file should be deleted.
+Missing   If this file is missing on disk.
+No Kill   Don't delete this file with mbfile
+Announced If this file is ever announced as new.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fegroup.html b/html/setup/fegroup.html new file mode 100644 index 00000000..3800b70d --- /dev/null +++ b/html/setup/fegroup.html @@ -0,0 +1,64 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - File Groups. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - File Groups.

+

+ +

Introduction.

+

+File echo groups are to logically divide your file echo's for different +file distribution networks. It makes sense to select the groups by uplink and +area file that is available for that file distribution network. By doing that +downlinks can connect areas that are not yet connected at your bbs but are +available from your uplink. NOTE: uplink requests is not yet implemented. +

 

+ +

Cost Sharing.

+

+With the setup of groups you can also specify the Cost Sharing for the +files distribution. The unit cost is the cost for each transmitted file +if the unit size field is zero, or the unit price per transmitted unit size. +The final cost is multiplied with the "Add Prom." factor to add taxes or so. +Also if your uplink sends advanced .tic files, the cost found in that .tic +file will be added to the cost as well. Further you can set the final price +to divide between your downlinks or let them all pay the full price. + +

File Group Setup.

+

+

+Name      File Echo Group name.
+Comment   The description of that group.
+Active    If this group is active.
+Use Aka   The Fidonet aka to use for this group
+Uplink    The Fidonet aka of the uplink.
+Areas     The name of the areas file (in ~/etc).
+Unit Cost The cost per unit.
+Unit Size The size in Kbytes per unit.
+Add Prom. The prommilage to add to the cost.
+Divide    Divide cost over downlinks.
+Deleted   If this group must be deleted.
+
+

+ +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/fidonet.html b/html/setup/fidonet.html new file mode 100644 index 00000000..8de0cd55 --- /dev/null +++ b/html/setup/fidonet.html @@ -0,0 +1,42 @@ + + + + + + + + +MBSE BBS Setup - Fidonet Networks. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - fidonet Networks

+

+Each fidonet network can have maximum 6 zones. The main zone (where you are) +must be the first zone, the others will follow. You can add 6 additional +nodelists to merge with the main nodelist. These additional nodelists are +normally more recent that the main nodelist, so entries in the additional +nodelists will replace entries from the main nodelist when you compile the +nodelists. In the shown example you can see that I have a regional nodelist +and a pointlist added for my region. For each additional list you must +specify the RC address because that information is normally present in these +nodelists. Watch out! Nodelist names are case sensitive. If you receive a +nodelist and automatic put them in place with the mbfido +program, and the resulting file is uppercase, you must use uppercase names +here also. You don't need to give the extension of the nodelist name, the +mbindex will figure that out. +

+ + +


+Back Back to index +
+Home Back to main index +
+ + + diff --git a/html/setup/fileecho.html b/html/setup/fileecho.html new file mode 100644 index 00000000..d74a678e --- /dev/null +++ b/html/setup/fileecho.html @@ -0,0 +1,94 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - TIC Areas. + + + +
+
Last update 08-Jun-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - TIC Areas.

+

+ +

Introduction.

+

+In this setup you can define the File Echo's or TIC areas. Files received or +send from this areas are bound together with a *.tic file with information +about the file and where to store that file. Each file echo must belong to a +group, in this grouprecord is the information about costsharing and some +other details. When a file is received at your system you can do several +things with that file before it is stored in your download areas such as; +scanning the file for virusses, extracting the FILE_ID.DIZ file to use as +description, allow update of magic alias, convert to another compression +format, replace the file archive comment with an add of your own bbs and limit +the number of files (nodelists). +

 

+ +

TIC Area Setup.

+

+

+Comment    A description for this area.
+Area tag   The tag for this area.
+BBS area   The BBS download area number, 0 means passthru.
+Message    Not in use yet.
+Group      The group where this area belongs to.
+Keep #     The number of files to keep, the name must match.
+Fido aka   The Fidonet aka to use for this area.
+Convert    The archiver to convert to, leave blank for none.
+Banner     The bannerfile (in ~/etc) to replace in the archive.
+Replace    Honor the "Replace" command in the .tic file.
+Dupecheck  Check for duplicates in this area.
+Secure     Check if the sending system is connected.
+No touch   Don't touch the filedate, keep it original.
+Virus sc.  Try to scan for virusses.
+Announce   Files may be announced in this area.
+Upd magic  Allow update magic request name.
+File_id    Try to use the FILE_ID.DIZ file for description.
+Conv.all   Convert archive even if it is already right.
+Send org.  Send original received file instead of the file from the BBS.
+Mandatory  Downlinks can't disconnect from this area.
+Notified   Not in use yet.
+Upl discon Not in use yet.
+Deleted    If this area must be deleted.
+Active     If this area is active.
+Systems    To the screen with connected systems.
+
+

+ +

+ + +

Global Commands.

+

+From menu 10.2 you can enter the global commands menu. In this menu you can: +

    +
  1. Delete connection +
  2. Add new connection +
  3. Replace connection +
  4. Change connection status +
  5. Change aka to use +
  6. Delete TIC area +
+After you have selected the action you want and added the items to do, you will see +a screen were you can select TIC file area groups. You can then tag one or more +groups and press enter when you are done. Then you have one chance to perform the +actions or to bail out. All areas matching in that group are affected by your +changes. If you are not happy with the result, don't save the database and no +harm is done. The file mbsetup.log shows all affected areas. +

 

+ + +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/filefind.html b/html/setup/filefind.html new file mode 100644 index 00000000..fc67e2a6 --- /dev/null +++ b/html/setup/filefind.html @@ -0,0 +1,58 @@ + + + + + + + + +MBSE BBS Setup - Filefind Areas. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Filefind Areas.

+

+ +

Introduction.

+

+The filefind idea on Fidonet came from the program Allfix written by Harald +Harms. The idea is +that a user writes a mail in a filefind area addressed to "Allfix" with in the +subject line the items to search for. On all BBS'es with a filefind utility +those programs try to find the requested files and then produce a reply of +which files they have found. That reply can be in the same area, in a special +reply echo or can be sent by netmail. Usually the user gets a lot of replies +from which he can see if someone has the file(s) available he was searching +for. +

 

+ +

Filefind Setup.

+

+

+Comment     The comment for this area.
+Origin      The origin line to use for the reply.
+Aka to use  The Fidonet aka to use in this area.
+Scan area   The JAM area in which to scan for requests.
+Reply area  The JAM area to put the replies in, leave blank if in the same area.
+Language    Not in use yet, but DO select one!
+Template    Not in use yet.
+Active      If this area is active.
+Deleted     If this area must be deleted.
+Net. reply  If the reply will be sent by netmail.
+Hi ACSII    If high ASCII is allowed in the replies.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/files.html b/html/setup/files.html new file mode 100644 index 00000000..e30518b9 --- /dev/null +++ b/html/setup/files.html @@ -0,0 +1,79 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - File Areas. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - File Areas.

+

+ +

File Areas introduction.

+

+This is the setup for the file areas in which users can up and download files. +This database has fixed area numbers, the database can't be packed. This is +done because areas can point to other areas and users are "used" to use +areas by number. Also the .tic areas reference the file areas by record +numbers. Extending the database is allways possible. One important note, +before you can set this up, you need to define the +newfiles groups. +

 

+ +

File Areas Setup.

+

+

+Area Name  The area name.
+Path       The full path to the file area.
+Down Sec.  The download security level.
+Upl. Sec.  The upload security level.
+List Sec.  The security level to list the files in this area.
+Files.bbs  The full path and filename if this area is on CDROM.
+           You may leave this blank if it is in the Path together
+           with the files.
+Available  If this area is available.
+Check New  Check this area for new files if a user logs in.
+Dupecheck  Check this area for duplicates if a user uploads a file.
+Free area  If all files in this area are free.
+Direct DL  Allow direct download from this area.
+Pwd upl.   Allow users to password protect their uploads.
+Filefind   Search in this area for filefind requests.
+Add alpha  Add .tic files alphabetic sorted or at the bottom of the list.
+CDrom      Is this a CDROM area. The affects the behaviour of some
+           other utilities because the Path is read-only.
+File req.  Allow File Request from this area.
+BBS group  Not in use yet.
+New group  New files announce group. See Newfiles groups for more info.
+Min. age   Minimum user age to access this area.
+Password   The password for this area. If blank, no password is needed.
+DL days    How long must a file not been downloaded to (re)move it.
+FD days    How old must a file be to be (re)moved.
+Move area  The area to move the file to, if zero it is deleted.
+Cost       The cost in units to download from this area.
+Archiver   The archiver to use to repack the files with.
+Upload     Alternate upload area. If a user uploads a file in this
+           area, it will be placed in the alternate area. If the
+           value is zero, the file will be placed in the current
+           file area. On CD-rom areas you must not leave this zero
+           unless you set the upload security level so high that
+           nobody can upload in this area.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/global.html b/html/setup/global.html new file mode 100644 index 00000000..165635da --- /dev/null +++ b/html/setup/global.html @@ -0,0 +1,464 @@ + + + + + + + + +MBSE BBS Setup - Global Setup. + + + +
+
Last update 22-Jun-2001
+

 

+ +

MBSE BBS Setup - Global Setup

+

+ +In this setup you can edit all global settings for MBSE BBS. All sections will +be discussed below. +

+ +

1.1. Edit Registration Info.

+

+

+System name       The name of your BBS
+Domain name       Your internet domain name (or a fake name if you have 
+                  no direct connection).
+Sysop uid         The Unix name of your Sysop account
+Sysop Fido        The Fidonet name of your Sysop account
+Location          The Location of your BBS
+QWK/Bluewave      The packet name for Offline mail downloads.
+Omed id.          Not in use
+Comment           A comment line for your BBS
+Origin line       The default origin line for echomail
+Startup uid       The default username "bbs"
+
+

+ +

1.2. Edit Global Filenames.

+

+

+System logfile    The name of the main logfile
+Error logfile     The name of the errors logfile
+Default menu      The name of the default main menu
+Default language  The name of the default language
+Chat logfile      The name of the logfile for chatting
+Welcome logo      The name of the BBS logo ANSI file
+
+

+ +

1.3. Edit Global Paths

+

+

+BBS Menus         The path to the default menus
+Txtfiles          The path to the default ANSI and ASCII textfiles
+Home dirs         The path to the users home directories
+Nodelists         The path to the nodelist directory
+Inbound           The unprotected fidonet inbound
+Prot inb.         The (password) protected fidonet inbound
+Outbound          The outbound for the main aka
+Bad TIC's         Where bad TIC files are saved
+TIC queue         Where TIC files for downlinks are kept
+Magic's           Where the magic filerequests are kept
+DOS path          The DOS drive and path
+Unix path         The Translated DOS path in real
+LeaveCase         Leave outbound .flo filenames as is, No forces to uppercase
+
+The DOS path and Unix path are translated for in and outbound mail sessions, +so the outside world will be happy. The DOS path is a fake, you can put +anything you like in there, but "C:\OUT" is a good choice. Note that +the TIC queue must be somewere in the Unix path, otherwise it is +impossible to create a DOS path from the path to the TIC files in that +directory. To set this up correctly is also important if you use other mailers +as well, for example binkd, or even a DOS binkly-style mailer running from +a network. All those mailer must "see" the same file attaches in the .flo +files. If you leave the DOS path empty, no translation will be performed +and the Unix paths will be stored in the .flo files. +

+ +

1.4. Edit BBS Configuration

+

+

+Private system    Set to true when only pre-registered users are allowed
+Exclude Sysop     True is Sysop will be invisible
+Show connect      Show connection info at logon
+Ask protocols     Ask protocol before each up/download
+Sysop level       The Sysop security level
+Password Length   The minimum password length, should be 6.
+Password Char.    The password hiding character
+Idle timeout      The idle timeout in minutes
+Login Enters      Maximum times for only enter 
+Login Attempts    Maximum login attempts
+Homedir Quota     Maximum size in MBytes for each user
+Location length   The minimum length of the location (3 in Holland!)
+Show new msgarea  Show new available message areas at logon (for OLR users)
+OLR Max. msgs.    Maximum messages to download, 0 is no limit.
+OLR Newfile days  The maximum age for newfiles in the OLR packet
+OLR Max Filereq   Maximum filerequests allowed for OLR users
+BBS Log Level     What will be logged or not the BBS program
+Utils Log Level   What will be logged or not for utilities
+Utils slowly      Should utilities release timeslices
+CrashMail level   Minimum level to allow sending netmail crash
+FileAttach level  Minimum level to allow attach files to netmail
+Min diskspace MB  At which low diskspace level utilities should stop working.
+
+The minimum diskspace setting is to prevent that files get corrupted if your filesystem +is full. All drives are checked except CD-roms and floppies and the /boot directory if that +one is on a separate filesystem. Ext2, msdos and vfat partitions +are checked. The lowest free diskspace found counts. Default is 10 MB. +Note, Reiserfs is not supported at this moment because I don't have access to a +system with reisefs volumes. This means that if you use Reiserfs that you are not +protected against a full filesystem. +

+ +

1.5. New users defaults.

+

+

+Access level      The access level and flags after registration
+Cap. Username     Capitalize the username
+Ask ANSI          Ask for ANSI screen (default is yes)
+Ask Sex           Ask for Male/Female
+Ask Voicephone    Ask for voice phonenumber
+Ask Dataphone     Ask for data phonenumber
+Telephone scan    Scan for duplicate numbers
+Ask Handle        Ask for handle (nickname)
+Ask Birth date    Ask for birthdate (needed for checks)
+Ask Location      Ask for users location
+Ask Hot-Keys      Ask for hot-keyed menus (default is yes)
+One word names    Allow one word names
+Ask address       Not implemented
+Give email        Give new users email access (default is yes)
+
+

+ +

1.6. Text Colors.

+

+Several prompts use different colors. They can be changed with the following +menu. +

+ + +

+ +

1.7. Next User Door.

+

+This is a "message to nextuser" door I found in RapidBBS. It allows a user +to write a message to the next BBS user. +

+Text file         The textfile to display
+Quote             The prompt to show
+
+

+ +

1.8. Safe cracker door.

+

+This is a door I found in RapidBBS, it is a simple number guessing game. +

+Digit 1           The first digit to guess
+Digit 2           The second digit to guess
+Digit 3           The third digit to guess
+Max trys          The maximum number of trys per day
+Max numb          The highest number to guess
+Num gen           Automatic number generation
+Prize             The prize to win
+Welcome           The welcome file to display
+Opened            The file to display to the winner
+
+

+ +

1.9. Time Bank Door.

+

+This is the timebank door I found in RapidBBS. It allows a user to deposit +time or download kilobytes on his bank account so when he needs it for +big downloads he can use his savings for extra large downloads. Anyway, +I haven't figured this one out completly for myself, so the meaning of all +these settings are not well explained right now. +

+Time balance      Maximum time balance
+Max time withdraw Maximum time to withdraw
+Max time deposit  Maximum time to deposit
+Kb. balance       Maximum Kilobytes balance
+Max Kb. withdraw  Maximum Kilobytes to withdraw
+Max Kb. deposit   Maximum Kilobytes to deposit
+Users time ratio  Time ratio
+Users Kb. ratio   Kilobytes ratio
+
+

+ +

1.10. Sysop paging

+

+For sysop chat we use a program that will connect to the users tty. This is +not a nice solution because it will not work over a network, but at least +it works. +

+Ext. chat         External chat program, not in use!
+Chat device       The device where the sysop is called (beeped)
+Call script       For future use
+Page length       The length of a page in seconds
+Page times        Maximum number of times a user may page the sysop
+Sysop area        Message from user to Sysop area number
+Ask reason        Ask reason for chat, this will be logged
+Use Extern        Use external chat 
+Log Chat          Log the chat conversation
+Prompt Chk.       Check at menu prompts for Sysop breaking in
+Freeze Time       Freeze users time during chat
+Sunday..Saturday  The times the Sysop is normal available
+

+ +

1.11. Flag Descriptions.

+

+In this menu you can give the 32 users flags a meaningfull description. +

+ +

1.12. Fileecho Processing.

+

+A note, when you change the number of Systems or Groups, the databases affected +will be updated automatic. +

+Keep days         How long TIC files should be kept on hold
+Hatch pwd         The internal hatch password. Make this weird.
+Drv space         The minimal free space on your disk in kilobytes
+Systems           The maximum number of connected nodes
+Groups            The maximum number of fileecho groups
+Max. dupes        The maximum number of entries in dupe database
+Keep date         Keep original filedate
+Keep netm         Keep sent netmails
+Res future        Reset dates in the future
+Loc resp          Respond to local created filefind messages
+Repl ext          Replace filename extension with .* before filesearch
+Plus all          Allow filemgr +all command
+Notify            Allow filemgr notify=on/off command
+Passwd            Allow filemgr passwd command
+Message           Allow filemgr message=on/off command
+Tic on/off        Allow filemgr tic=on/off command
+Pause             Allow filemgr pause/resume commands
+

+ +

1.13. Edit Fidonet mail and echomail processing.

+

+Note that the first 2 mailboards must also exist in the normal mail areas if +you want to see what is in them. Here they are defined for quick access of the +tosser. For the Max. systems and groups see 1.12. If you use MBSE BBS together +with a DOS based BBS (using DOSEMU or mars netware emulator), you can set the +behaviour of the outbound to 4d. addressing instead of 5d. This option may +dissapear in the future.
+Another option is present, this is the pktdate option. This +is the full path and filename to an external program that can inspect and +correct the mail .pkt files. Originally I put this in to run pktname of Tobias +Ernst of 2:2476/418 to fix y2k problems in the incoming mail. At this time +most y2k fixes are build in, but in case you need it it's there. To make it +clear; the y2ktools written by Tobias are static compiled for Linux and they +should run on all Linux i386 versions. Until now, I still use pktdate because +it is necessary.
+ +

+Badboard          The path and filename of the bad messages
+Dupeboard         The path and filename of the duplicate messages
+Pktdate           Full path and filename of a .pkt preprocessor
+Max pkts.         Maximum Kb. of mail packets before a new one is created.
+Max arcs.         Maximum size in Kilobytes of an arcmail file
+Keep days         How many day should we keep ARCmail on hold
+Echo dupes        Maximum number of entries in the echomail dupe database
+Reject old        Reject echomail messages older then n days
+Max msgs          Default maximum number of messages in each area
+Days old          Default number of days old to keep messages
+Max systems       Maximum number of nodes to connect to echomail
+Max groups        Maximum number of echomail groups
+4d address        Use 4d. addressing (not needed you only use MBSE BBS)
+Split at          Gently split messages after n KBytes (12..60)
+Force at          Force split of messages after n KBytes (16..63)
+

+A note about the splitting of messages. Some tossers can't handle +messages greater than 16 KBytes, these tossers are rare these days. Most +tossers can handle messages of 32 KBytes. To set these values on the safe +side set "Split at" to 27 and "Force at" to 31. This means that a long +newfile report will be split after 27 KBytes when a new group of files +should start in the report. If it can't find that point because a large +number of files is in the group that is just being processed, the message +split will be forced right after the file that passes the 31 KBytes limit. +I use values of 1 KBytes below maximum for overhead such as SEEN-BY and +PATH lines. Values larger then 32 KBytes is not a good idea, recent tests +in May 1999 have shown that your messages will not reach all systems +if they are larger then 32 KBytes. Splitting is used for newsfiles reports +and gated news articles to Fidonet. +

+ +

1.14. Edit Internet mail and news processing.

+

+Email and news is setup here. There are three possible configurations which you +can set with 1.14.11: +

    +
  • No ISP. If you don't have any connection to the internet + use this setting. Email will come from the default Fidonet UUCP gate and will be send out + via the UUCP gate. Users have email addresses like + user@f2802.m280.z2.fidonet.org Note, the username is their + Unix name when sending email. +
  • Dial ISP. If you dial the internet regulary or are connected + with a cable modem without a valid DNS (Nameserver) entry you should use + this mode. Email will be sent via your local SMTP port, then through your + own sendmail (or whatever you use) to your ISP. + As soon as you are connected to the internet + the mail will be sent to your ISP's mailer. In your sendmail you should + define the mailer of your ISP as Smarthost. Incoming email will still come + from the UUCP gate. Users have email addresses like + user@f2802.m280.z2.fidonet.org Note, the username is their + Unix name. +
  • Perm ISP. If you are permanent connected to the internet + either with a static or dynamic IP address use this option. Use this option + also if you have an UUCP domain and hav a dialup UUCP connection. You need to + register a DNS name and MX record for your system, if you don't you won't be able to + receive email from the internet and must use the previous Dial mode. + If you have a dynamic IP address you can still get a DNS name from for + example dynip.com + Incoming email will come directly from the internet, but if someone sends + email via the UUCP gate it is also accepted. Users have email addresses like + user@yourbbs.domain.org. Note, the username is their + Unix name. +
+Another word of wisdom from my side, configuration of the internet, ppp, sendmail etc. is not discussed +here, see the HOWTO's and other documentation that exists at +www.linuxdoc.org, it's all there. + +
+POP3 node         The POP3 node to use, should be localhost
+SMTP node         The SMTP node to use, should be localhost
+NNTP node         The NNTP node to use, should be localhost
+NNTP m.r.         If the NNTP server needs the Mode Reader command
+NNTP user         The username for the NNTP server if needed
+NNTP pass         The password for the NNTP server if needed
+News dupes        The number of entries for the news dupes database.
+Email aka         The Fidonet aka to use for the fidonet.org UUCP gate
+UUCP aka          The default Fidonet UUCP gate, 2:292/875@fidonet
+Emailmode         The email mode, discussed above
+News mode         Newsfeed mode, INN, rnews or UUCP.
+Split at          Gently split newfiles reports after n KBytes (12..60)
+Force at          Force split of newfiles reports after n KBytes (16..63)
+Control ok        Allow news control messages to be gated
+No regate         Don't regate already gated messages
+
+In rnews mode the NNTP entries are replaced by:
+
+Path rnews        The full path and filename to the rnews binary.
+
+In UUCP mode the NNTP entries are replaced by:
+
+UUCP path         The full path to the uucppublic directory.
+UUCP node         The UUCP nodename of your ISP.
+

+ + +

+

1.15. Allfiles and Newfiles lists.

+

+These are the settings that affect the generation of newfiles and allfiles reports. +

+Ftp base          The root of the public download area (.../ftp)
+New days          The number of days old files are "newfiles"
+Security          The highest security level to include files in the reports
+Groups            The number of newfile groups the newfiles database can hold
+

+ +

1.16. Fidonet Aka's.

+

+Here you can enter 40 fidonet addresses. These are 5d addresses. +

+ +

1.17. Mailer Setup.

+

+Note that you can't disable FTS-0001 sessions as that is a mandatory session +protocol in Fidonet. There are 40 phonenumber translations present, this is for +countries with lots of telephone operators with all kind of prefixes for +carrier select functions. +

+Mailer logl.      The logging level for mailer sessions
+Default phone     The default phonenumber for EMSI sessions
+TCP/IP flags      The TCP/IP capability flags for TCP/IP sessions
+Default speed     The default speed for EMSI sessions
+Timeout reset     The timout for normal modem commands
+Timeout connect   The timeout for waiting for connect
+Dial delay        The maximum delay between calls, minimum is 10 seconds.
+No Filerquests    Disable filerequests
+No callout        Disable callout
+No hold mail      Send "hold" mail if we make the call
+No pickup all     Exchange mail for one aka only
+No EMSI session   Disable EMSI
+No YooHoo/2U2     Disable FTS-0006 sessions
+No Zmodem         Disable zmodem protocol
+No Zedzap         Disable zedzap protocol
+No Hydra          Disable Hydra protocol
+No TCP/IP         Disable TCP/IP protocol, set to Yes if you don't have internet.
+Phonetrans 1..40  Maximum 40 phone number translations
+Max. files        Maximum files to request, 0 is unlimited 
+Max. MBytes       Maximum MBytes to request, 0 is unlimited
+
+ +

1.18. FTPD Settings.

+

+A new program is mbftpd. This is a replacement for the normal +ftp server for Linux with special futures for MBSE BBS. This is not working +yet so don't use it. Setting it up is adviced. +

+Base path         The ftp base directory (ie. /SYS/usr/ftp).
+Upload pth        Incoming files (ie. /SYS/usr/ftp/incoming).
+Banner msg        The banner file to display before login.
+Path filter       The legal character in upload filenames.
+Path msg          Message to display if illegal characters in upload.
+Email addr        Your email address.
+Shutdown          Shutdown message if FTP server is closed.
+Readme login      Readme to display after login.
+Readme cwd*       Readme to display after chdir.
+Msg login         Welcome message after login.
+Msg cwd*          Message to display in directory.
+Userslimit        Maximum FTP users allowed.
+Loginfails        Maximum login failures.
+Compress          If compress command is allowed.
+Tar               If tar command is allowed.
+Mkdir ok          If users may create directories.
+Log commands      Log user commands.
+Anonymous         If anonymous login is allowed.
+User mbse         If user mbse is allowed. Dangerous!
+
+ +

1.19. Edit HTML pages setup.

+

+Here you setup the HTML pages that can be created with the +mbfile web command. These are HTML pages of your download +areas and indexes of all areas. If there are pictures in these areas +thumbnails are created if you have the convert +command available. The document root is the same as defined in your +web server. The link to ftp must be created from that directory to +your ftp base directory. To do that become root, cd to the document root +and type ln -s /var/spool/mbse/ftp files In this case the link +is called files. Note that all download areas are accesible, +there is no user authentication yet available. +

+Docs root         The path to the httpd documents root.
+Link to ftp       The link to the ftp directory.
+URL name          The URL of your webserver.
+Charset           The default character set, ISO-8859-1.
+Table color       The tables background color.
+Header color      The tables header background color.
+Author name       The author name you want in the HTTP headers.
+Convert command   The graphics convert command. (ImageMagick needed).
+Files/page        The number of files to display per web page.
+Icon Home         The name of the Home icon file.
+Text Home         The text to display for Home.
+Icon Back         The name of the Back icon file.
+Text Back         The text to display for Back.
+Icon Prev.        The name of the Previous page icon file.
+Text Prev.        The text to display for Previous page.
+Icon Next         The name of the Next page icon file.
+Text Next         The text to display for Next page.
+
+

+ +Back Back to index +
+Home Back to main index +

+ + + diff --git a/html/setup/hatch.html b/html/setup/hatch.html new file mode 100644 index 00000000..13a17023 --- /dev/null +++ b/html/setup/hatch.html @@ -0,0 +1,61 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - Hatch Manager. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - Hatch Manager.

+

+ +

Introduction.

+

+Hatch files is nothing more than entering a new file into a file echo. That +file is searched for on your system in a specific directory with a certain +filemask. This can be for example a new created nodelist or an allfiles listing. +Everytime mbfido tic is run it will scan for files defined +in this setup. If such a file is found, a special .tic file is written and +stored in the mailers inbound directory. When the mbfido +starts processing .tic files, that new hatched file will be processed as if +it was received form another system. To let this work, you obviously need +an existing TIC area. +

 

+ +

Hatch Manager Setup.

+

+

+Mask    The path and filename mask to search for. 
+        "?" matches any character, "#" matches digits and "@" matches
+        alpha characters. Don't use "*", this doesn't work!
+Area    The area to hatch this file in.
+Replace The filename to replace, ie. "nodelist.z*"
+Magic   The filerequest magic name, ie. "nodelist"
+Desc    The description of the file, %12 in the description
+        means copy the 12th character of the name in place.
+Dupe    Check for duplicates.
+Active  If this area is active.
+Deleted If this area must be deleted.
+Days    The days in the week to scan for this file.
+Month   The dates in the month to scan for this file.
+
+

+ + +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/index.htm b/html/setup/index.htm new file mode 100644 index 00000000..0ae82b24 --- /dev/null +++ b/html/setup/index.htm @@ -0,0 +1,80 @@ + + + + + + + + +MBSE BBS setup. + + + +
+
Last update 27-May-2001
+

 

+ +

MBSE BBS Setup Guide

+

+ +

Invoking mbsetup

+

+As user mbse type mbsetup to start the setup +program. This version is not yet finished. There are a few items you can't +setup yet. +When you start mbsetup you will see the following screen: +

+ +

 

+ +

mbsetup main options

+

+

    +
  1. Edit Global configuration +
  2. Edit Fido networks +
  3. Edit Archiver programs +
  4. Edit Virus scanners +
  5. Edit Modem types +
  6. Edit TTY lines info +
  7. Edit Fidonet nodes +
  8. Edit BBS setup +
      +
    1. Edit Security limits +
    2. Edit Language setup +
    3. Edit BBS menus +
    4. Edit File areas +
    5. Edit Transfer protocols +
    6. Edit BBS List data +
    7. Edit Oneliners +
    8. Edit TimeBank data +
    9. Edit Safe Cracker data +
    +
  9. Edit Mail setup +
      +
    1. Echo mail groups +
    2. Echo mail areas +
    +
  10. Edit File echo's setup +
      +
    1. Edit Fileecho groups +
    2. Edit Fileecho areas +
    3. Edit Hatch manager +
    4. Edit Magic files +
    +
  11. Edit Newfiles groups +
  12. Edit Newfiles reports +
  13. Edit Filefind setup +
  14. Edit Files database +
  15. Edit BBS users +
  16. Edit Services +
  17. Edit Domains +
  18. Edit Task Manager +
  19. Show software information +
  20. Create site documents +
+ +BackBack to index +
+ + + diff --git a/html/setup/language.html b/html/setup/language.html new file mode 100644 index 00000000..1b006ef6 --- /dev/null +++ b/html/setup/language.html @@ -0,0 +1,57 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Language Setup. + + + +
+
Last update 25-Jul-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Language Setup.

+

+ +

Language introduction.

+

+You need to define at least one language, this is the default language. +The paths to the BBS menus and Txtfiles for the default language +must be exactly the same as defined in the global setup, menus 1.3.1 and 1.3.2
+I did this so you can make your +own local languages next to the default languages. If something is not +present in your local language, the BBS will fall back to the default +language. This is true for the menus and textfiles for the BBS. It is +therefore wise to name all menus and textfiles the same for all languages used. +When you setup the languages for the first time, entries for English, Dutch, +Spanish and Italian are created. +

 

+ +

Language setup.

+

+

+Select      The letter to select this language.
+Name        The name of this language.
+Menupath    The path to the menu files.
+Textpath    The path to the ANSI and ASCII textfiles.
+Macropath   Not in use yet.
+Available   If this language is available.
+Datafile    The name of the language datafile in ~/etc
+Security    The minimum security level to select this language.
+Deleted     If this language must be deleted.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/magic.html b/html/setup/magic.html new file mode 100644 index 00000000..f9987581 --- /dev/null +++ b/html/setup/magic.html @@ -0,0 +1,74 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup - Magic Files Setup. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup - Magics Files Setup.

+

+ +

Introduction.

+

+Magics are special actions that you can perform if files received in a .tic +area. The actions are: copy file to a directory, unpack file in a directory, +set number of files to keep, move file to another .tic area, update magic +request alias, adopt file into another area, store in another path, +delete file (don't process it further) and execute a command. The edit screen +is different for all kinds of actions you select. More than one magic record +may exist for each area. With all these actions you can for example can setup +processing of nodediff's and unpacking nodelists in the nodelist directory. +

 

+ +

Magics Setup.

+

+

+Magic     The action to perform, select with the spacebar.
+Filemask  The filemask to scan for. "?" Matches all characters,
+          "#" matches any digit and "@" any alpha character.
+Active    If this magic is active.
+Deleted   If this magic must be deleted.
+Area      The area in which this magic is found.
+To path   The destination path. (Copy, Other path and Unpack).
+To area   The destination area. (Adopt and Move).
+Command   The command to execute. (Execute).
+Keep #    The number of files to keep. (Keep).
+Compile   Trigger "compile nodelists". (Copy, Unpack and Execute).
+
+

 

+ +

Macro's

+

+In the commandline for the magic execute command you may use macro's to replace +parts of the commandline. The following macro's are defined: +

+%F   Replaced by the full path and filename of the file.
+%P   Replaced by the full path to the file.
+%N   Replaced by the filename without dot and extension.
+%E   Replaced by the extension of the filename.
+%L   The last 2 characters of the filename extension.
+%D   The day number of the year, 3 digits.
+%C   The last 2 digits of the day number of the year.
+%A   The .tic area name.
+
+ +

+ +

+ +Back Back to File Echo's Setup  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/mail.html b/html/setup/mail.html new file mode 100644 index 00000000..f7f9048a --- /dev/null +++ b/html/setup/mail.html @@ -0,0 +1,35 @@ + + + + + + + + +MBSE BBS Setup - Mail Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Mail Setup.

+

+ +

Edit Mail Setup.

+

+The Mail Setup is split in the following sections: +

+ +

    +
  1. Echo mail groups +
  2. Echo mail areas +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/modems.html b/html/setup/modems.html new file mode 100644 index 00000000..5d5e9081 --- /dev/null +++ b/html/setup/modems.html @@ -0,0 +1,88 @@ + + + + + + + + +MBSE BBS Setup - Modem types. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - Modem types

+

+In the setup screen you can define all kinds of modems you use. This includes +ISDN modems. +This is not the setup of individual lines, that is in the next section, so +if you own a bbs with 5 analogue lines with only two brands and types of +modems connected, you need only to define those two types of modems here. Some +defaults are installed during initial bbs setup. +

 

+ +

Setup a modem.

+

+

+Type             The description of this modem.
+Init 1           The first modem init string.
+Init 2           The second init string (if needed).
+Init 3           The third init string (if needed).
+Reset            Not in use
+Hangup           Only needed if drop DTR doesn't work.
+Dial             The dial command.
+Info             Command to get caller-id (not tested).
+Ok               The modem "OK" response.
+Offset           The answer/connect time offset.
+Speed            The maximum modem linespeed, ie 28800.
+Available        If this modem is available.
+Deleted          If this modem must be deleted.
+Stripdash        Strip dashes from the dial command.
+Connect strings  Here you can define 20 connect strings.
+Error strings    Here you can define 10 non-connect strings.
+
+

 

+ +

Special characters

+

+

+\\               Send one backslash.
+\r               Send the CR character.
+\n               Send the LF character.
+\t               Send the TAB character.
+\b               Send the BS character.
+\s               Send a space character.
+\d               Wait one second.
+\p               Wait 0,25 second.
+\D               Send untranslated phone number.
+\T               Send translated phone number.
+
+

 

+ +

The Hangup field

+

+This is only needed if your modem doesn't hangup by dropping the DTR line for +one second. Most modems do that if &D2 or &D3 is in the init string. +

 

+ +

The Offset field.

+

+The Offset field is to calculate the cost for outgoing calls. +Analogue modems need time to establish the connection, 6 seconds is quite +common. So when you see the CONNECT BLABLA message, the phone connection +is there already 6 seconds and you are already paying for 6 seconds. This +offset is thus added to the total calculated connect time for cost +calculations. For ISDN modems this can be 1 or 0. +

 

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/newfiles.html b/html/setup/newfiles.html new file mode 100644 index 00000000..6823b5d6 --- /dev/null +++ b/html/setup/newfiles.html @@ -0,0 +1,54 @@ + + + + + + + + +MBSE BBS Setup - Newfiles Reports. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Newfiles Reports.

+

+ +

Introduction.

+

+For each network you can define one or more newfiles reports to announce the +newfiles that arrived on your BBS. The files to include in the reports are +specified by the newfiles groups you can include or exclude for announcement. +

 

+ +

Reports Setup.

+

+

+Comment     The comment for this report.
+Msg area    The JAM message base to write the report in.
+Origin line The origin line to use.
+From name   The name to use in the "From:" field.
+To name     The name to use in the "To  :" field.
+Subject     The text to use in the "Subj:" field.
+Language    Not in use yet, but DO select! 
+Template    Not in use yet.
+Aka to use  The Fidonet aka to use in this area.
+Active      If this report is active.
+Deleted     If this report must be deleted.
+High ASCII  Allow high ASCII in this area.
+New groups  The screen to define the groups to include.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/newgroups.html b/html/setup/newgroups.html new file mode 100644 index 00000000..894dd9a0 --- /dev/null +++ b/html/setup/newgroups.html @@ -0,0 +1,49 @@ + + + + + + + + +MBSE BBS Setup - Newfiles Groups. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Newfiles Groups.

+

+ +

Introduction

+

+The newfiles group are there to create separate newfiles announcements for +several networks and areas. Even if you don't want to make different +announcements you still need to define at least 2 groups. One is a group +where you don't announce files in and one where you do. These groups are +linked to the BBS file areas and must be defined before you define the BBS +file areas. As you can see in the example picture I seperated the groups +in subjects. +

 

+ +

Newfiles Groups Setup.

+

+

+Name    The tag name of the group.
+Comment The comment for this group.
+Active  If this group is active.
+Deleted If this group must be deleted.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/nodes.html b/html/setup/nodes.html new file mode 100644 index 00000000..cf8084c7 --- /dev/null +++ b/html/setup/nodes.html @@ -0,0 +1,146 @@ + + + + + + + + +MBSE BBS Setup - Fidonet nodes. + + + +
+
Last update 22-Jun-2001
+

 

+ +

MBSE BBS Setup - Fidonet nodes.

+

+ +

Introduction

+

+Unlike many other bbs packages, for each node you need only one record. If you +have a relation with a node for one network with costsharing, and other +networks without costsharing you need two records for that node. For each node +you can setup the aka's, mail, files and session handshake. +

 

+ +

Main setup

+

+

+Sysop name       The name of the system operator.
+Fido aka's       Maximum 20 Fido addresses.
+Dial command     You can put an override here for the normal 
+                 dial command. If you leave this empty the 
+                 command from the modem setup is used.
+Phone number 1   An alternative phone number/ip address to dial.
+Phone number 2   An alternative phone number/ip address to dial.
+                 Use these above commands if the node has
+                 another phone number as mentioned in the
+                 nodelist. If you call this node via TCP/IP
+                 and the IP address can't be resolved by
+                 the nodelist, you may enter an IP address
+                 or hostname here.
+Route via        A route via Fido address. All mail for this
+                 node will be send via this Aka, even mail 
+                 and files for other networks. This can be
+                 usefull if this node has internet access
+                 so you can send everything to this node
+                 over the internet.
+Netmail direct   Set "direct" flag in netmail to this node.
+Netmail crash    Send netmail always "crash" to this node.
+Netmail hold     Put mail on "hold" for this node.
+Send notify      Send automatic generated notify messages.
+Language         The language to use (not yet working).
+Deleted          If this node must be deleted.
+No EMSI          Disable EMSI handshake.
+No YooHoo/2U2    Disable FTSC-0006 handshake.
+No Filerequest   Disable filerquest from this node.
+Don't call       Do not call this node.
+No Hold mail     Only pickup mail if we call, send nothing.
+Pickup primary   Only exchange mail for one Aka.
+No Zmodem        Disable Zmodem protocol.
+No Zedzap        Disable Zedzap protocol.
+No Hydra         Disable Hydra protocol.
+No TCP/IP        Disbale TCP/IP protocol, forces dial only.
+
+

+ +

 

+ +

Mail setup

+

+

+Session pwd      The mailer session password.
+Check PKT pwd    Check password in received .pkt files. If not,
+                 errors or missing passwords are only logged.
+                 If set, errors or missing password are refused
+                 and the .pkt files are renamed to .bad
+UplMgr program   The name of the Areamgr program of this node.
+                 (This doesn't work yet).
+UplMgr passwd    The password for the Areamgr of this node.
+Mail forward     Not in use yet.
+ARCmail comp.    Use ARCmail 0.60 file naming convention for out of zone mail.
+ARCmail a..z     Allow a..z last character for ARCmail filenames.
+
+

+ +

 

+ +

Mail groups

+

+Here you can tag which mail groups are available for this node. Note that all +groups are visible here, even for networks this node has no aka's in. Be +carefull not to allow a node to connect areas from networks he has no aka in. +

+ +

 

+ +

File setup

+

+

+Files password   The password for .tic files.
+Mgr password     The password for the Areamgr and Filemgr.
+UplMgr program   The name of the Filemgr progrom of this node.
+UplMgr passwd    The password of the Filemgr if this node.
+UplMgr Add +     Add a "+" in the command to connect areas.
+Incl. message    Send a netmail message for each file to send.
+Send TIC file    Send .tic file to this node.
+Advanced TIC     Send advanced or standard .tic files.
+File forward     Forward TIC files for this node (not yet).
+Billing          Is Costsharing active for this node.
+Bill direct      Send the bill direct or on command.
+Credit           The credit this node has in units.
+Debet            The debet we have with this node (informational).
+Add              Add (or substract) factor to the bill.
+Warn level       The debet level when to write a warning mesage.
+Stop level       The debet level when to stop sending files.
+
+

+ +

 

+ +

File groups

+

+The same story as for mail groups is true for the file groups. +

+ +

 

+ +

Statistics

+

+In this statistics screen you can see the mail and files flow with this +node. Values are stored for the current week, the previous week, the +current month and previous month and the overall total since you defined +this node. There are actual 12 months of statistics stored in the nodes +record, only 2 are visible. +

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/oneliner.html b/html/setup/oneliner.html new file mode 100644 index 00000000..3973e6ef --- /dev/null +++ b/html/setup/oneliner.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Oneliners. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Oneliners.

+

+ +

Oneliners.

+

+Oneliners are small quotes that can be random selected and displayed to +your users. From the same database oneliners can be selected and inserted +at the bottom of messages. With the oneliners setup you can edit, add, +delete and import oneliners. Import is done from plain ASCII textfiles, +one quote on each line. The lines should be maximum 70 characters long. +

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/protocol.html b/html/setup/protocol.html new file mode 100644 index 00000000..1ffb48e8 --- /dev/null +++ b/html/setup/protocol.html @@ -0,0 +1,55 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Transfer Protocols. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Transfer Protocols.

+

+ +

Introduction.

+

+It might look strange that you have to define transfer protocols for the bbs +while for the mailer you don't need to do that. This is historic, ifcico +already had internal protocols and the precessor of the bbs package had external +protocols. Because my priority was make the bbs working it still is that way. +When time comes I will build some of the protocols internal, adding external +protocols will allways be possible. +

 

+ +

Transfer Protocols Setup.

+

+

+Select Key  The key the user has to press to select this protocol.
+Name        The name of this protocol.
+Upload      The full path and filename and parameters to upload files.
+Download    The full path and filename and parameters to download files.
+Available   If this protocol is available.
+Batching    If this is a batching protocol.
+Bi direct   If this is a bi-directional protocol (Not supported yet).
+Advice      A small advice to the user shown before the transfer starts.
+Efficiency  The efficiency in percent. Has no real meaning.
+Deleted     If this protocol must be deleted.
+Sec. level  The security level a user must have to select this protocol.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/safe.html b/html/setup/safe.html new file mode 100755 index 00000000..95096a82 --- /dev/null +++ b/html/setup/safe.html @@ -0,0 +1,29 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Safe Cracker Data. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Safe Cracker Data

+

+This is meant to edit users personal safe cracker records and to reset +the winner. This is not available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/security.html b/html/setup/security.html new file mode 100644 index 00000000..b172514b --- /dev/null +++ b/html/setup/security.html @@ -0,0 +1,56 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - Security Limits. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - Security Limits.

+

+ +

Security limits, introduction.

+

+Every BBS needs several security limits to make a difference between several +user groups. These are the twits, regular users and (co-)sysops. If you have +a donation system you will probably have more different levels. Every level a +user can have must have a record in this file. To operate MBSE BBS you need at +least 3 levels, twit with level 0, new users with the level as setup in 1.5.1, +and the sysop level as setup in 1.4.5 As said, for special usergroups you can +add more levels as you need. If a user logs in and has a level in the userbase +you didn't define here, he won't be able to login. Even the twit level needs +some access to be able to throw him out in a nice but friendly way, give him +5 minutes, 1 file to download and no more then 1 Kb so he will understand he +is not wanted. Some defaults are installed during first bbs setup. +

 

+ +

Limits setup

+

+

+Access level    The access level value.
+Maximum time    The maximum time each day.
+Download Kb.    Maximum Kilobytes download each day.
+Download Files  Maximum files to download each day.
+Description     The description for this level.
+Available       If this level is available.
+Deleted         If this level must be deleted.
+
+

+ +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/services.html b/html/setup/services.html new file mode 100644 index 00000000..0259cf35 --- /dev/null +++ b/html/setup/services.html @@ -0,0 +1,69 @@ + + + + + + + + +MBSE BBS Setup - Edit Services. + + + +
+
Last update 06-Jun-2001
+

 

+ +

MBSE BBS Setup - Edit Services.

+

+ +

Introduction.

+

+Services are special mail accounts. Netmail addressed to one of these names +will be handled according to the action that is selected. Current implemented +actions are AreaMgr, FileMgr and Email. So if you name a service +Areamgr and set the action to AreaMgr then an incoming +netmail will be directed to the Areamgr function. If you define a service +listserv and set the action to Email then +and incoming netmail will be converted to email and send to listserv +at your host.
+If you should want to run some votemanager on your system you can +do that by creating a service votemgr with the type set to email. +You also need to setup a valid unix user votemgr so that there will be an excisting +mailbox. Then with some external scripts you can process all received messages. +

 

+ +

Edit Services.

+

+

+Name      The name of the Service.
+Type      Toggle the service type with the spacebar.
+Active    If this service is active.
+Deleted   If this service must be deleted.
+
+

+Here are some example services: +

+

+UUCP		Email
+allfix          FileMgr
+areamgr         AreaMgr                                                  
+fmail           AreaMgr                                                  
+gecho           AreaMgr                                                  
+listserv        Email                                                    
+majordomo       Email                                                    
+mbsebbs         Email                                                    
+mbsebbs-owner   Email                                                    
+mbtic           FileMgr                                                  
+owner-mbsebbs   Email
+raid            FileMgr
+
+Note: the UUCP services is needed if you are gating email! +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/sitedoc.html b/html/setup/sitedoc.html new file mode 100644 index 00000000..95435f3f --- /dev/null +++ b/html/setup/sitedoc.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - Create Sitedocs. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Create Sitedocs.

+

+ +

Create Sitedocs

+

+This option creates 3 documents in the doc directory under the home directory +of MBSE BBS, site.doc, xref.doc and stat.doc. Only the file site.doc is more +or less complete, the other 2 are heavily under construction. These three +files are a complete reference of your BBS setup. Especially the site.doc is +a large document, think at least four times before you send it to a printer. +The document xref.doc will contain lists with data from your setup that +depends on eachother. The file stat.doc will be a listing of all statistic +counters that are present in several data files. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/softinfo.html b/html/setup/softinfo.html new file mode 100644 index 00000000..933e4137 --- /dev/null +++ b/html/setup/softinfo.html @@ -0,0 +1,31 @@ + + + + + + + + +MBSE BBS Setup - Show Software Information. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - Show Software Information.

+

+ +

Introduction

+

+This screen shows the information about the MBSE BBS software, copyright and +release policy. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/taskmgr.html b/html/setup/taskmgr.html new file mode 100644 index 00000000..2f3ec58e --- /dev/null +++ b/html/setup/taskmgr.html @@ -0,0 +1,67 @@ + + + + + + + + +MBSE BBS Setup - Task Manager. + + + +
+
Last update 07-Jul-2001
+

 

+ +

MBSE BBS Setup - Task Manager.

+

+ +

Introduction

+

+The task manager is the daemon which controls the MBSE BBS. It watches semafore's and spawns +programs in the background. The behaviour is setup in this screen. +

+ +

Edit Task Manager

+

+

+Mailout   Action for semafore mailout.
+Mailin    Action for semafore mailin.
+Newnews   Action for semafore newnews.
+Index 1   Nodelist compiler 1 for semafore mbindex.
+Index 2   Nodelist compiler 2 for semafore mbindex.
+Index 3   Nodelist compiler 3 for semafore mbindex.
+Msglink   Action for semafore msglink.
+Reqindex  Action for semafore reqindex.
+ISP conn  Not in use yet!
+ISP disc  Not in use yet!
+Ping #1   IP address of node to ping to check the internet.
+Ping #2   IP address of second node to ping to check the internet.
+ISP blks  Set to true if you have internet dialup and if it blocks normal dial.
+Max Load  Max system load until processing is suspended.
+ZMH start Start of Zone Mail Hour in UTC time.
+ZMH end   End of Zone Mail Hour in UTC time.
+Debug     Enable debug logging.
+Max POTS  Maximum simultaneous outgoing calls (for now ISDN + POTS + TCP/IP).
+Max ISDN  Not in use yet!
+Max TCP   Not in use yet!
+
+

+Default are the original MBSE commands filled in, but you could also call +shell scripts. As you can see, the task manager is not yet finished. +

+The two IP addresses to ping need to be IP addresses, not hostnames. This is the +most reliable way to check the connection. You should enter the IP addresses of +the nameservers of your own ISP here. One of these will always be up, so if one +of these can be reached, the internet connection is assumed to be alive. +

+ +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/tic.html b/html/setup/tic.html new file mode 100644 index 00000000..d23d0bb7 --- /dev/null +++ b/html/setup/tic.html @@ -0,0 +1,37 @@ + + + + + + + + +MBSE BBS Setup - File Echo's Setup. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - File Echo's Setup.

+

+ +

File Echo's Setup.

+

+The File Echo's Setup is split in the following sections: +

+ +

    +
  1. File echo groups +
  2. File echo areas +
  3. Hatch manager +
  4. Magic files +
+ +Back Back to index  +Home Back to main index +
+ + + diff --git a/html/setup/timebank.html b/html/setup/timebank.html new file mode 100755 index 00000000..1e29c545 --- /dev/null +++ b/html/setup/timebank.html @@ -0,0 +1,29 @@ + + + + + + + + +MBSE BBS Setup - BBS Setup - TimeBank. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Setup - TimeBank.

+

+This is meant to edit the users personal timebank records. This is not +available yet. +

+ +Back Back to BBS index  +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/ttyinfo.html b/html/setup/ttyinfo.html new file mode 100644 index 00000000..4bd62e2b --- /dev/null +++ b/html/setup/ttyinfo.html @@ -0,0 +1,73 @@ + + + + + + + + +MBSE BBS Setup - TTY Lines. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - TTY Lines.

+

+ +

Introduction.

+

+For each line your bbs has you must setup a tty line. This also includes +console lines (for local login), network lines for internet and lan connections +and X-terminal connections, ISDN lines, and Analogue modem lines. If a call +comes in over a tty you didn't define, that call is refused. So if you are +directly connected to the internet, and have only 5 network tty's defined, +then maximum 5 users are allowed to telnet to your bbs via the internet. +

+One thing about the portspeed, this is only needed for devices connected to +serial ports such as modems and external ISDN adapters. For network tty's and +internal ISDN cards this should be set to zero. If you set it to some other value, +things still word but you will get error messages in the logs. +

+A note about the EMSI flags, this must match your modem capabilities, if +not dialout will not work correct. It is used to see which line to use to call +a certain node. If you add the X75 flag on an analogue line, your system will try to +call ISDN nodes using an analogue modem. So these are not your nodelist flags as they +may represent combined ISDN and analogue flags but the flags that belong to a modem. +

 

+ +

Setup a line.

+

+

+Comment      A description for this line.
+TTY device   The tty device name without /dev/
+Phone nr.    The phone number on this line.
+Line Speed   The maximum line speed for this line.
+Fido Flags   The EMSI flags for this line, include your modem flags here!
+Line Type    Can be POTS, ISDN, Network and Local.
+Available    Is this line available for use.
+Auth. log    Not in use yet.
+Honor ZMH    Deny users during ZMH on this line.
+Deleted      If this line must be deleted.
+Callout      Allow calling other systems from this line.
+Portspeed    The "locked" modemspeed, 0 to 4000000 baud, only for serial ports.
+Modemtype    The modem connected to this line.
+EMSI name    The EMSI name presented for this (modem) line.
+
+

 

+ +

Some examples.

+

+

+

+

+

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/users.html b/html/setup/users.html new file mode 100644 index 00000000..82cd3a18 --- /dev/null +++ b/html/setup/users.html @@ -0,0 +1,80 @@ + + + + + + + + +MBSE BBS Setup - BBS Users. + + + +
+
Last update 30-Jan-2001
+

 

+ +

MBSE BBS Setup - BBS Users.

+

+ +

Introduction.

+

+This screen lets you edit some settings of the BBS users. Note that the users +database will never be packed and users will always keep their record number. +If a user is deleted the record will be blanked. New users will get a blank +record if it exists, otherwise the database will be expanded. The reason for +this is the LastRead pointers of the message areas, BBS systems who do it +in another method mostly can't keep track of LastRead pointers and records, +and they mix all users LastRead pointers. Fields that +can be changed by the users themselves are marked with a *. +

 

+ +

Edit User

+

+

+Full Name    The full (Fidonet) name of the user.
+Handle     * The nickname of the user.
+Location   * The location of the user.
+Address n  * The address of the user (3 lines).
+Voicephone * The voice phonenumber of the user.
+dataphone  * The data phonenumber of the user.
+Security     The security level of the user.
+Birthdate  * The birthdate of the user DD-MM-YYYY.
+Expirydate   The expiry date of the user DD-MM-YYYY.
+Expiry Sec   The security level the user gets after expiry.
+Unix uid     The unix username of the user.
+Comment      The comment about this user.
+Password   * Change password for this user.
+Sex        * Users sex, male or female.
+Credit       The users credit.
+Protocol   * The selected file transfer protocol.
+Archiver   * The selected archiver.
+Hidden       If the user is hidden from listings etc.
+Hotkeys    * Hotkeys on/off.
+Color      * Color on/off.
+Deleted      User must be deleted.
+No Kill      User can never be deleted.
+Fs Chat    * Use fullscreen chat on/off.
+Locked       Locked out of the BBS.
+Silent     * Do not disturb on/off.
+CLS        * Sent clearscreen codes on/off.
+More       * More prompt on/off.
+Fs Edit    * Use fullscreen editor on/off.
+MailScan   * Scan for new mail at logon on/off.
+Guest        Is this a "guest" account on/off.
+ShowNews   * Show "news" screens on/off.
+NewFiles   * New files scan at logon on/off.
+Ext Info     Send ^aKLUDGES with BlueWave downloads.
+Email        If this user has an email address.
+
+

+ + +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/setup/virscan.html b/html/setup/virscan.html new file mode 100644 index 00000000..6a585198 --- /dev/null +++ b/html/setup/virscan.html @@ -0,0 +1,52 @@ + + + + + + + + +MBSE BBS Setup - Virus scanners. + + + +
+
Last update 29-Jan-2001
+

 

+ +

MBSE BBS Setup - virus scanners

+

+Once upon a time there was no DOS and no computer virusses. But since DOS was +invented as a small OS which was easily extensible, virus writers saw their +chance to easy spread their hacks. Although running a Linux system is +relative safe, most of the files that you have available on your bbs +are DOS based programs. And before you put them available for download, they +should be checked for virusses. Macro virusses are a relative new danger, +this can also hurt Unix/Linux users.

+There are several scanners for Linux available. Default only two of them +are setup. You may consult +http://www.openantivirus.org for more scanner mentioned in a mini-FAQ +maintained by Rainer Link. +

+NAI Virus Scan (uvscan) for Unix (Linux) made by +Network Associates, USA. +Not free for personal use. Uses the same DAT files as for Windows and DOS. +

+AntiVir/Linux made by +H+BEDV Datentechnik GmbH. +Can also be installed in sendmail or Postfix to scan incoming +and outgoing email. This may be a good idea if you run a email gateway. +This version can be registered for personal use. +

+As soon as you have made a scanner available in the setup and you receive files +in tic areas where the scan flag is set, then these files will be checked. +As soon as one of the scanners detects a virus the received file will not be imported. +Uploads from users will be checked with the installed virus scanners as well. +

+ +Back Back to index  +Home Back to main index +

+ + + diff --git a/html/ups.html b/html/ups.html new file mode 100644 index 00000000..e225b5c6 --- /dev/null +++ b/html/ups.html @@ -0,0 +1,45 @@ + + + + + + + + +Using UPS semafore's. + + + +
+
Last update 08-Jun-2001
+

 

+

MBSE BBS - Using UPS semafore's.

+

+ + +If you have a UPS and you are able to let your UPS software create semafore's when powerfail conditions +occur then read on. The MBSE BBS taskmanager and a lot of utilities will act on two special semafore's, +they are: + +

    +
  1. upsalarm, this semafore should be set when there is no mains power, but there is enough + power left to operate your system. All background tasks will be suspended as long as this condition + is true. If the power comes back, the UPS software should remove this semafore. +
  2. upsdown, this semafore should be set when the UPS sofware signals your system to go down. + This is a fatal condition and there is no way back. Even if the power comes back your system should + shutdown and the UPS will disconnect the power to your system. After a while it will turn the power on + again and your system boots. MBSE BBS will if this semafore is seen kick users out of the bbs, and the + system shutdown script will try to close MBSE BBS as quick as possible. Normal the close timeout is + one hour to let users normal finnish what they were doing, now it is only 30 seconds and if they were + not logged out, they will be disconnected anyway. +
+I know not all UPS software can do this but most UPS software is open source so you can change it to create +these semafore's. It is not a problem that UPS semafore's still excist if the systems boots, the MBSE BBS +startup scripts will remove them before the bbs is started. +

 

+ + +Back Go Back + + + diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..e9de2384 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/lang/Language.xref b/lang/Language.xref new file mode 100644 index 00000000..f2dfa9d4 --- /dev/null +++ b/lang/Language.xref @@ -0,0 +1,472 @@ +0 user.c newuser.c |Please enter your First and Last name: +1 user.c |Please enter your Last name: +2 user.c |Disconnecting user ... +3 user.c |Scanning User File ... +4 user.c YN|Did you spell your name correctly? [Y/n] +5 user.c |Name Entered: +6 user.c |This is a PRIVATE System. Type "off" to leave +7 filesub.c |Mark file number or press to stop +8 user.c filesub.c |Password: +9 user.c |Maximum login attempts have been exceeded ... +10 user.c |Either your NAME or PASSWORD is incorrect +11 bank.c | MBSE BBS System Bank +12 bank.c |Bank Account: +13 bank.c |Time in account +14 bank.c |Bytes in account +15 bank.c |Time deposited today +16 bank.c |Bytes deposited today +17 bank.c |Time withdrawn today +18 bank.c |Bytes withdrawn today +19 bank.c DWQ|(D)eposit, (W)ithdraw, (Q)uit: +20 bank.c |Bank > +21 bank.c TBQ|(T)ime, (B)ytes, (Q)uit : +22 bank.c |You must have at least 5 minutes remaining to deposit +23 bank.c |How much time. Minutes available to you is +24 bank.c |You have tried to deposit more than the maximum limit today. +25 bank.c |Maximum allowed minutes to deposit per day: +26 bank.c |You have exeeded your account balance. +27 bank.c |Maximum allowable minutes in bank account is: +28 bank.c |You are allowed to deposit: +29 bank.c |You have tried to withdraw more than the maximum limit today. +30 bank.c |Maximum allowed to withdraw per day: +31 bank.c |You have tried to withdraw more time than is in your bank account. +32 bank.c |Current bank balance: +33 bank.c |Maximum allowed kilobytes to deposit per day: +34 bank.c |You have exeeded your account balance. +35 bank.c |Maximum allowable kilobytes in bank account is: +36 bank.c |How many kilobytes. KBytes available to you is +37 newuser.c |MBSE Bulletin Board System - NEW USER REGISTRATION +38 newuser.c |Use this name: +39 newuser.c |Please enter new password : +40 newuser.c user.c |Please enter password again : +41 newuser.c user.c |Your passwords do not match! Try again. +42 newuser.c change.c user.c |Your password must contain at least +43 newuser.c change.c user.c |characters! Try again. +44 newuser.c YN|Do you want ANSI and graphics mode [Y/n]: +45 newuser.c change.c |Please enter you Voice Number +46 mail.c |Message exported to your private directory as: +47 newuser.c change.c |Please enter a proper phone number +48 newuser.c change.c |Please enter you Data Number +49 newuser.c change.c |Please enter your location: +50 newuser.c |Please enter a longer location +51 newuser.c MF|What is your sex? (M)ale or (F)emale: +52 newuser.c |Male +53 newuser.c |Female +54 newuser.c |Please answer M or F +55 newuser.c |Unknown +56 newuser.c change.c |Please enter your Date of Birth DD-MM-YYYY: +57 newuser.c |Sorry you entered this year by mistake. +58 newuser.c |Please enter the correct date format +59 chat.c |*** Sysop is starting chat *** +60 chat.c |*** Sysop has terminated chat *** +61 mail.c misc.c YN=|More (Y/n/=) +62 newuser.c YN|Would you like Hot-Keyed menus? [Y/n]: +63 newuser.c |Please answer Y or N +64 change.c |Please enter your Screen Length? [24]: +65 newuser.c |None +66 offline.c |Tag Offline Reader message areas +67 newuser.c |Your user account has been created: +68 newuser.c |Login Name : +69 newuser.c |Password : +70 newuser.c |not displayed +71 newuser.c |New user registration completed. +72 misc.c |Could not find +73 change.c |Old Location: +74 change.c |Please enter a longer location (min +75 change.c |Ansi Mode turned ON +76 change.c |Ansi Mode turned OFF +77 mail.c |Message doesn't exist +78 change.c |News bulletins turned ON +79 change.c |News bulletins turned OFF +80 change.c |Screen length is 24 +81 change.c |Screen length is now set to: +82 mail.c |Private message, not owner +83 change.c |Please enter the correct date format +84 misc.c |Todays Callers to +85 misc.c |# User Name Device TimeOn Calls Location +86 safe.c |Safe Cracker Door +87 safe.c |Please press a key to continue: +88 safe.c |In the safe lies ... +89 safe.c |Please enter three numbers consisting from 1 to +90 safe.c |Please enter three combinations. +91 safe.c |1st digit: +92 safe.c |Please try again! You must input a number greater than Zero and less than +93 safe.c |2nd digit: +94 safe.c |3rd digit: +95 safe.c | Left: +96 safe.c |Right: +97 safe.c YN|Attempt to open safe with this combination [Y/n]: +98 safe.c |You have won the following... +99 safe.c |Sorry - You didn't open the safe! +100 safe.c |The safe code was: +101 safe.c YN|Do you want to try again ? [Y/n]: +102 safe.c YN|Do you want to open the safe ? [Y/n]: +103 safe.c |THE SAFE IS CURRENTLY LOCKED +104 safe.c |has cracked the safe. +105 safe.c |The safe will remain locked until the sysop rewards the user. +106 safe.c |Maximum trys per day Exceeded! +107 nextuser.c |Message to Nextuser Door +108 nextuser.c |The FROM, TO and SUBJECT fields are optional. +109 nextuser.c | From: +110 nextuser.c | To: +111 nextuser.c |Subject: +112 nextuser.c | Type up to 10 lines 74 Characters per line +113 nextuser.c |Functions available: +114 nextuser.c LREAS|(L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave +115 nextuser.c |Select: +116 nextuser.c file.c |Aborting... +117 nextuser.c |Returning to +118 nextuser.c |Edit which line: +119 nextuser.c |Line does not exist. +120 change.c |Old Password: +121 change.c |New password: +122 change.c |Confirm new password: +123 change.c |Passwords do not match! +124 change.c |Password Change Successful +125 change.c |Old password incorrect! +126 funcs.c |User List +127 funcs.c |Enter Username search string or (Enter) for all users: +128 funcs.c |Name Location Last On Calls +129 funcs.c |Could not find search string ... +130 timecheck.c |Time limit exceeded ... disconnecting! +131 filesub.c YN=M|More (Y/n/=) M=Mark +132 filesub.c |Scanning +133 filesub.c |with +134 funcs.c |TIME STATISTICS for +135 funcs.c mbsebbs.c |on +136 funcs.c |Current Time : +137 funcs.c |Current Date : +138 funcs.c |Connect time : +139 funcs.c |Time used today : +140 funcs.c |Time remaining today : +141 funcs.c |Daily time limit : +142 mail.c |You have +143 mail.c YN|messages, read your mail now? [Y/n]: +144 mail.c |You have no new mail in your mail box ... +145 change.c |Hotkeys are now ON +146 change.c |Hotkeys are now OFF +147 funcs.c |On +148 funcs.c |Off +149 newuser.c |User name already exists +150 mail.c |Checking your mail box ... +151 page.c | MBSE BBS Chat +152 page.c |The SysOp is currently speaking to somebody else on +153 page.c |Try paging him again in a few minutes ... +154 page.c ||You have paged the Sysop the maximum times allowed. +155 page.c |Sysop currently is not available ... please leave a comment +156 mail.c |Posting message in area: +157 mail.c |From : +158 mail.c |To : +159 mail.c |Verifying user ... +160 mail.c |User not found. Try again, or (Enter) to quit +161 mail.c |Subject : +162 mail.c YN|Abort Message [y/N] ?: +163 mail.c YN|Private [y/N]: +164 lineedit.c |Begin your message now, Blank line to end +165 lineedit.c |Maximum of 60 lines, 73 characters per line +166 lineedit.c |Maximum message length exceeded +167 lineedit.c |Functions available: (Current Message: +168 lineedit.c |Lines) +169 lineedit.c |L - List message S - Save message C - Continue message +170 lineedit.c |Q - Quit message D - Delete line I - Insert line +171 lineedit.c |T - Text edit E - Edit line R - Replace line +172 lineedit.c LSCQDITERZ|Z - Center line +173 lineedit.c |Select +174 lineedit.c |Continue +175 lineedit.c file.c |Delete +176 lineedit.c |Delete starting at line +177 lineedit.c |Aborted. +178 lineedit.c |Please enter a number in the range of +179 lineedit.c |Delete ending at line +180 lineedit.c |Edit +181 lineedit.c |Enter line # to edit +182 lineedit.c |Insert +183 lineedit.c |Enter line # to insert text before +184 lineedit.c |List +185 lineedit.c |Enter line # to replace +186 lineedit.c nextuser.c |Line reads: +187 lineedit.c |Unchanged. +188 lineedit.c |Line now reads: +189 lineedit.c mail.c |Quit +190 lineedit.c YN|Are you sure [y/N]: +191 lineedit.c |Message aborted. +192 lineedit.c |No +193 lineedit.c |Text Edit +194 lineedit.c |Enter line # to edit +195 lineedit.c nextuser.c |Text to replace : +196 lineedit.c nextuser.c |Replacement text : +197 lineedit.c |Line now reads: +198 lineedit.c |Save +199 filesub.c |Possible VIRUS found! +200 filesub.c offline.c |Ok +201 filesub.c offline.c |Unpacking archive +202 mail.c |Saving message to disk +203 lineedit.c |Enter line # to center +204 lineedit.c |Line is maximum length and cannot be centered +205 mail.c |There are no messages in this area. +206 mail.c |Date : +207 mail.c file.c YN=|More (Y/n/=/Area #): +208 mail.c |To : +209 mail.c |From : +210 mail.c |Subject : +211 mail.c |Next reply: +212 mail.c |Reply to: +213 mail.c |messages in +214 mail.c ANLREQDX|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port +215 mail.c |(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port +216 mail.c |Next +217 filesub.c offline.c |ERROR +218 mail.c RNQ|(R)eply, (N)ext, (Q)uit: +219 mail.c |Enter to keep Subject. +220 mail.c |# From To Subject +221 mail.c |Message area +222 mail.c |contains +223 mail.c |messages. +224 mail.c |Please enter a message between +225 mail.c |Message number [ +226 mail.c |Area Type description Messages Personal +227 mail.c |thread +228 offline.c |Enter the name of the conference, or ? for a list: +229 offline.c |Conference Area Msgs Description +230 mail.c |Deleting message +231 mail.c | Message Areas +232 file.c mail.c |Select Area: +233 file.c mail.c |Invalid area specified - Please try again ... +234 file.c mail.c |Password is incorrect +235 file.c mail.c |Password is correct +236 file.c |You don't have enough security to list this area +237 filesub.c |Can't open file database for this area +238 filesub.c file.c |Uploaded by: +239 file.c |D E L E T E D +240 file.c |M I S S I N G +241 mail.c YN|Node not known, continue anayway [y/N]: +242 file.c |Total Files: +243 filesub.c |FATAL: Unable to open areas database +244 filesub.c |You do not have enough access to download from this area. +245 file.c mail.c |Please enter filename: +246 file.c |No filename entered, Aborting. +247 file.c offline.c |Illegal Filename! +248 file.c |Sorry that file is unavailable for download +249 file.c filesub.c |You have +250 file.c filesub.c |extra download KBytes. +251 filesub.c |You do not have enough time to download that file. +252 filesub.c |You do not have enough bytes to download " +253 filesub.c |You must upload before you can download. +254 filesub.c |Kilobytes currently available: +255 file.c |Checking your marked downloads, please wait... +256 offline.c |Untag Offline Reader message areas +257 filesub.c |Found FILEID.DIZ in +258 file.c |No files marked for download. +259 filesub.c |extra minutes. +260 offline.c |You have selected the following Conference(s): +261 file.c |Filename Size Date +262 change.c |Protocol: Can't open protocol file. +263 change.c |Select your preferred file transfer protcol +264 change.c |Select Protocol (Enter to Quit): +265 change.c |Ivalid selection, please try again! +266 change.c |Protocol now set to: +267 file.c |Enter keyword to use for Search: +268 file.c |File Search by Keyword +269 file.c |Accepts wildcards such as : *.zip, *.gz, .tar* +270 file.c | : *.zip is the same as .zip +271 file.c |Enter filename to search for : +272 file.c |File Search by Filename +273 file.c YN|Search for new since your last call [Y/n]: +274 file.c |Enter new date to search for [DD-MM-YYYY]: +275 file.c |File Search by Date +276 file.c offline.c |Please enter file to upload: +277 offline.c |Offline Reader Download +278 file.c |You do not have enough access to upload to this area. +279 file.c |You have not enough diskspace free to copy this file +280 file.c |files( +281 file.c |bytes) marked for download. +282 file.c |The file already exists on the system +283 file.c offline.c |Please start your upload now ... +284 filesub.c |Upload was unsuccessful for: +285 filesub.c YN|Do you want to password protect your upload ? [y/N]: +286 filesub.c |REMEMBER: Passwords are "CaSe SeNsITiVe!" +287 filesub.c |Please enter description of file +288 filesub.c |Your upload time has been returned to you. Thank you for your upload! +289 file.c |Start copy: +290 file.c |Can't open directory for listing: +291 file.c |Home directory listing for +292 file.c |Please enter filename to delete: +293 file.c |Sorry you may not delete hidden files ... +294 file.c |Unable to delete file ... +295 file.c |Invalid filename, please try again ... +296 file.c |File does not exist, please try again ... +297 offline.c |Forum Description Msgs. Pers. +298 file.c | File Areas +299 file.c |Please enter Area Password: +300 bbslist.c |Adding BBS +301 bbslist.c |BBS Name: +302 bbslist.c |Response needed ... +303 bbslist.c |Phone Number: +304 bbslist.c |Sysop Name: +305 bbslist.c |BBS Software: +306 bbslist.c |Storage (GigaByte): +307 bbslist.c |Speeds: +308 bbslist.c YN|Would you like to add a extended discription? [Y/n]: +309 bbslist.c |Please a enter discription for +310 bbslist.c |BBS Listing +311 bbslist.c |# BBS Name Number Software GigaByte Speed +312 bbslist.c |Search for a BBS +313 bbslist.c |Please enter 3 letters of BBS to search for: +314 bbslist.c |I need at least 3 letters ... +315 bbslist.c YN|View this BBS? [Y/n]: +316 bbslist.c |Could not find the BBS Listed ... +317 bbslist.c |Show a BBS +318 bbslist.c |Please enter number to list: +319 bbslist.c oneline.c |Record does not exist +320 bbslist.c | Record : +321 bbslist.c | BBS Name : +322 bbslist.c | Number : +323 bbslist.c | Software : +324 bbslist.c | GigaByte : +325 bbslist.c | Speeds : +326 bbslist.c | Sysop Name : +327 bbslist.c | Available : +328 bbslist.c | Date of Entry : +329 bbslist.c | Entry Name : +330 bbslist.c |Delete BBS +331 bbslist.c oneline.c |Please enter number to delete: +332 bbslist.c oneline.c |Record +333 bbslist.c oneline.c |does not belong to you. +334 bbslist.c oneline.c |already marked for deletion +335 bbslist.c |marked for deletion +336 bbslist.c |The Sysop will purge the list once he has +337 bbslist.c |seen you have marked a record for deletion. +338 offline.c |Total messages found: +339 menu.c |Unknown Menu Command! +340 nextuser.c |Saving... +341 oneline.c |MBSE BBS Oneliners will randomly appear on the main menu. +342 oneline.c |Obscene or libellous oneliners will be deleted!! +343 oneline.c |Please enter your oneliner below. You have 75 characters. +344 oneline.c |Oneliner added +345 oneline.c | # A Date User Description +346 oneline.c | # Description +347 oneline.c |Please enter number to list: +348 mbsebbs.c |Connected on port +349 file.c |File(s) : +350 file.c |Size : +351 file.c |Protocol : +352 file.c |Updating download counter, please wait ... +353 file.c |Failed! +354 file.c |Bytes +355 file.c | # Area Active File Size Cost +356 file.c lineedit.c |Yes +357 file.c |No +358 file.c TE|(T)oggle active, (E)rase all, (ENTER) to continue: +359 file.c |Enter file number, 1.. +360 filesub.c |Marked: +361 file.c |No files tagged. +362 lineedit.c |Replace +363 newuser.c |Loading BBS, please wait ... +364 offline.c |New or deleted mail areas at +365 offline.c |Area State Type Description +366 change.c |New Mail check is now ON +367 change.c |New Mail check is now OFF +368 file.c |Delete file: +369 file.c YN|Are you Sure? [Y/n]: +370 change.c |New Files check is now ON +371 change.c |New Files check is now OFF +372 change.c |Fullscreen Editor is now ON +373 change.c |Fullscreen Editor is now OFF +374 offline.c |No messages found to download! +375 funcs4.c |Press (Enter) to continue: +376 lineedit.c |Center +377 offline.c |Too much messages. Only the first +378 change.c |Select your preferred language +379 change.c |Select Language: +380 change.c |Language now set to: +381 funcs4.c |The system will now ask you for a "Unix Account" +382 funcs4.c |Your "Unix Account" is created, you may use it the next time you call. +383 funcs4.c |Please enter a login name (Maximum 8 characters) +384 funcs4.c |ie. John Doe, login = jdoe +385 funcs4.c |login > +386 funcs4.c |That login name already exists, please choose another one. +387 | +388 newuser.c |Your new Unix and BBS password will be the same. +389 user.c |FATAL ERROR: You are not in the BBS users file. +390 user.c | Please run 'newuser' to create an account +391 offline.c |New +392 offline.c |Local +393 offline.c |Netmail +394 offline.c |Echomail +395 offline.c |News +396 offline.c |E-Mail +397 offline.c |Del +398 funcs4.c |Jan +399 funcs4.c |Feb +400 funcs4.c |Mar +401 funcs4.c |Apr +402 funcs4.c |May +403 funcs4.c |Jun +404 funcs4.c |Jul +405 funcs4.c |Aug +406 funcs4.c |Sep +407 funcs4.c |Oct +408 funcs4.c |Nov +409 funcs4.c |Dec +410 newuser.c timeout.c |Autologout: idletime reached. +411 offline.c |will be packed! +412 newuser.c change.c |Enter your handle (Enter for none): +413 user.c |You are now ready to use the bbs +414 exitinfo.c |Callers On-Line to +415 exitinfo.c |Name Device Status Location +416 change.c |Do not disturb turned OFF +417 change.c |Do not disturb turned ON +418 exitinfo.c |Browsing +419 exitinfo.c |Downloading +420 exitinfo.c |Uploading +421 exitinfo.c |Msg Section +422 exitinfo.c |External Door +423 exitinfo.c |Chatting +424 exitinfo.c |Listing Files +425 offline.c YN|Do you want to download these messages [Y/n]? +426 exitinfo.c |Banking Door +427 exitinfo.c |Safe Door +428 exitinfo.c |WhosOn List +429 exitinfo.c |Idle +430 exitinfo.c |Please enter username to send message to: +431 exitinfo.c |Sorry, there is no user on +432 exitinfo.c |doesn't wish to be disturbed +433 exitinfo.c |Please enter in message to send (Max 76 Characters) +434 misc.c |** Message ** from +435 user.c |Your password is expired, new password : +436 funcs.c |Press ENTER to continue +437 mail.c |Posting not allowed, this area is Read Only! +438 |notdefined +439 offline.c |Offline Reader Upload +440 offline.c |Invalid packet received +441 offline.c |Unknown compression type +442 offline.c |Archiver not available +443 offline.c |Unknown type mailpacket +444 offline.c |BlueWave Offline download +445 offline.c |Preparing packet +446 offline.c |Packing with +447 offline.c |Download failed +448 offline.c |Download successfull +449 offline.c |Updating lastread pointers +450 offline.c |Processing BlueWave reply packet +451 offline.c |ERROR in packet +452 offline.c |Import messages +453 offline.c |No Write access to area +454 offline.c |Messages imported +455 offline.c |Processing Offline Configuration +456 offline.c |Message areas selected +457 offline.c |Processing file requests +458 offline.c |QWK Offline Download +459 offline.c |Processing QWK reply packet +460 offline.c |ASCII Offline Download +461 mail.c YN|Crash [y/N]: +462 mail.c YN|Warning: node is not CM, send immediate [y/N]: +463 mail.c YN|Attach file [y/N]: +464 mail.c |File +465 mail.c |will be attached +466 mail.c |File not within +467 email.c |mailbox - Incoming and outgoing email +468 email.c |archive - Archive of your email +469 email.c |trash - Trashcan, your old email +470 email.c |Area # +471 funcs.c |minutes. diff --git a/lang/Makefile.am b/lang/Makefile.am new file mode 100644 index 00000000..ca7040e0 --- /dev/null +++ b/lang/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in +## There are special tricks in this one .... + +SUBDIRS = . +LIBS = + +EXTRA_DIST = Language.xref + +CONFIG_CLEAN_FILES = english.lang dutch.lang italian.lang spanish.lang + +noinst_PROGRAMS = english.lang dutch.lang italian.lang spanish.lang + +english_lang_SOURCES = english.txt +dutch_lang_SOURCES = dutch.txt +italian_lang_SOURCES = italian.txt +spanish_lang_SOURCES = spanish.txt + + + +install-exec-local: + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 english.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 dutch.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 italian.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 spanish.lang $(sysconfdir) + +english.lang: english.txt + ../mbsebbs/mblang english.lang english.txt + +dutch.lang: dutch.txt + ../mbsebbs/mblang dutch.lang dutch.txt + +italian.lang: italian.txt + ../mbsebbs/mblang italian.lang italian.txt + +spanish.lang: spanish.txt + ../mbsebbs/mblang spanish.lang spanish.txt + diff --git a/lang/Makefile.in b/lang/Makefile.in new file mode 100644 index 00000000..d95fb97e --- /dev/null +++ b/lang/Makefile.in @@ -0,0 +1,372 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +LIBS = + +EXTRA_DIST = Language.xref + +CONFIG_CLEAN_FILES = english.lang dutch.lang italian.lang spanish.lang + +noinst_PROGRAMS = english.lang dutch.lang italian.lang spanish.lang + +english_lang_SOURCES = english.txt +dutch_lang_SOURCES = dutch.txt +italian_lang_SOURCES = italian.txt +spanish_lang_SOURCES = spanish.txt +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +english_lang_OBJECTS = +english_lang_LDADD = $(LDADD) +english_lang_DEPENDENCIES = +english_lang_LDFLAGS = +dutch_lang_OBJECTS = +dutch_lang_LDADD = $(LDADD) +dutch_lang_DEPENDENCIES = +dutch_lang_LDFLAGS = +italian_lang_OBJECTS = +italian_lang_LDADD = $(LDADD) +italian_lang_DEPENDENCIES = +italian_lang_LDFLAGS = +spanish_lang_OBJECTS = +spanish_lang_LDADD = $(LDADD) +spanish_lang_DEPENDENCIES = +spanish_lang_LDFLAGS = +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(english_lang_SOURCES) $(dutch_lang_SOURCES) $(italian_lang_SOURCES) $(spanish_lang_SOURCES) +OBJECTS = $(english_lang_OBJECTS) $(dutch_lang_OBJECTS) $(italian_lang_OBJECTS) $(spanish_lang_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lang/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lang + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 english.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 dutch.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 italian.lang $(sysconfdir) + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0444 spanish.lang $(sysconfdir) + +english.lang: english.txt + ../mbsebbs/mblang english.lang english.txt + +dutch.lang: dutch.txt + ../mbsebbs/mblang dutch.lang dutch.txt + +italian.lang: italian.txt + ../mbsebbs/mblang italian.lang italian.txt + +spanish.lang: spanish.txt + ../mbsebbs/mblang spanish.lang spanish.txt + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lang/README b/lang/README new file mode 100644 index 00000000..57121f46 --- /dev/null +++ b/lang/README @@ -0,0 +1,28 @@ + LANGUAGE SOURCES FOR MBSE BBS. + ============================== + + +This directory contains the language sources for MBSE BBS. The file +Language.xref is only a reference file with linenumbers and source +references. The files english.txt, dutch.txt and italian.txt are the +real language sources. The resulting files dutch.lang, english.lang +and italian.lang are placed in the ~/etc directory where the bbs +will expect them to be. + +If you make your own language files, use Language.xref as a guide. +The syntax for each language line is: + +KEYS|Language line + +The keys are the keys that the users must press for the right response. +Order is important. The "|" character is a seperator, the rest of the +language line is the line shown to the user. Trailing spaces are important! + +If you do create language sources then I would like that you make them +public available and send them to me so I can include them in the +source distribution. + +The Italian language was translated by nervous@nervous.it + +Michiel. + diff --git a/lang/dutch.txt b/lang/dutch.txt new file mode 100644 index 00000000..acf3a3f0 --- /dev/null +++ b/lang/dutch.txt @@ -0,0 +1,472 @@ +|Geef Voor en Achternaam: +|Geef Achternaam: +|Verbreken gebruiker ... +|Doorzoeken gebruikers bestand ... +JN|Is Uw naam juist gespeld? [J/n] +|Opgegeven naam: +|Dit is een PRIVE Systeem. Tik "off" om eruit te gaan +|Markeer bestand nummer of toets voor stop +|Wachtwoord: +|Maximum aantal inlog pogingen overschreden ... +|Of Uw NAAM of Uw WACHTWOORD is fout +| MBSE BBS Systeem Bank +|Bank Rekening: +|Tijd op de rekening +|Bytes op de rekening +|Tijd gestort vandaag +|Bytes gestort vandaag +|Tijd opgenomen vandaag +|Bytes opgenomen vandaag +SOE|(S)torten, (O)pnemen, (E)inde: +|Bank > +TBE|(T)ijd, (B)ytes, (E)inde: +|U moet minstens 5 minuten tijd over hebben om te storten +|Hoeveel tijd. Aantal minuten beschikbaars is +|U heeft geprobeerd meer dan de dagelijkse limiet te storten. +|Maximaal aantal te storten minuten per dag: +|U heeft Uw rekening balans overschreden. +|Maximaal aantal minuten op de bankrekening is: +|U mag storten: +|U heeft geprobeerd meer dan de dagelijkse limiet op te nemen. +|Maximaal per dag op te nemen: +|U heeft geprobeert meer tijd op te nemen dan op de rekening staat. +|Huidige bank balans: +|Maximaal aantal kilobytes te storten per dag: +|U heeft Uw bank balans overschreden. +|Maximaal aantal kilobytes op de bankrekening is: +|Hoeveel kilobytes. Aantal Kilobytes beschikbaar is +|MBSE Bulletin Board Systeem - NIEUWE GEBRUIKER REGISTRATIE +|Gebruik deze naam: +|Geef een nieuw wachtwoord : +|Geef het wachtwoord opnieuw : +|De wachtwoorden zijn niet gelijk! Opnieuw. +|Uw wachtwoord moet minstens +|karakters bevatten! Opnieuw. +JN|Wilt U ANSI karakters en kleuren [J/n]: +|Geef Uw Spraak Telefoonnummer +|Bericht weggeschreven naar Uw prive directory als: +|Geef het nummer in een goed formaat +|Geef Uw Data Telefoonnummer +|Geef Uw woonplaats: +|Geef een langere woonplaats naam +MV|Wat is Uw geslacht? (M)an of (V)rouw: +|Man +|Vrouw +|Antwoord met M of V +|Onbekend +|Geef Uw geboorte datum DD-MM-YYYY: +|Sorry maar dat is dit jaar. +|Gebruik het juiste datum formaat +|*** De Sysop komt erin om te kletsen *** +|*** De Sysop stopt met kletsen *** +JN=|Meer (J/n/=) +JN|Wilt U sneltoets menus? [J/n]: +|Antwoord met J of N +|Wat is Uw scherm lengte? [24]: +|Geen +|Selecteer Offline Reader berichten gebieden +|Uw gebruikers account is gemaakt: +|Inlog naam : +|Wachtwoord : +|onzichtbaar +|Nieuwe gebruiker registratie is klaar. +|Niet gevonden +|Oude woonplaats: +|Geef een langere woonplaats naam (minimaal +|ANSI kleuren staan nu AAN +|ANSI kleuren staan nu UIT +|Bericht bestaat niet +|News berichten staan nu AAN +|News berichten staan nu UIT +|Scherm lengte is 24 +|De scherm lengte staat nu op: +|Prive bericht, niet van U +|Geef het juiste datum formaat +|Bellers vandaag bij +|# Gebruiker Poort Tijd Keren Woonplaats +|Kluis kraker programma +|Druk een toets om verder te gaan: +|In de kluis ligt ... +|Geef drie nummers tussen 1 en +|Geef drie kombinaties. +|Eerste cijfer: +|Probeer opnieuw! U moet een nummer geven groter dan 0 en kleiner dan +|Tweede cijfer: +|Derde cijfer : +| Links: +|Rechts: +JN|Proberen de kluis met deze kombinatie te openenen [J/n]: +|U hebt het volgende gewonnen ... +|Spijtig - U hebt de kluis niet geopend! +|De cijferkombinatie was: +JN|Wilt U het opnieuw proberen ? [J/n]: +JN|Wilt U de kluis openenen ? [J/n]: +|DE KLUIS ZIT NU OP SLOT +|heeft de kluis grkraakt. +|De kluis blijft op slot tot de sysop de gebruiker beloond heeft. +|Maximaal aantal pogingen perdag bereikt! +|Bericht naar volgende gebruiker +|De VAN, AAN en ONDERWERP velden zijn opties. +| Van: +| Aan: +|Onderwerp: +| Type maximaal 10 regels van 74 karakters per regel +|Beschikbare functies: +LVWAB|(L)ijst, (V)ervang tekst, (W)ijzig regel, (A)fbreken, (B)ewaar +|Kies: +|Afbreken ... +|Terug naar +|Wijzig welke regel: +|Regel bestaat niet. +|Oud wachtwoord: +|Nieuw wachtwoord: +|Bevestig nieuw wachtwoord: +|Wachtwoorden zijn niet gelijk! +|Het wachtwoord is gewijzigd +|Oude wachtwoord is fout! +|gebruikers lijst +|Geef gebruikersnaam zoekfragment of (Enter) voor alle gebruikers: +|Naam Woonplaats Laatst hier Hoevaak +|Zoekargument niet gevonden ... +|Tijd limiet overschreden ... verbreken! +JN=M|Meer (J/n/=) M=Markeer +|Scannen +|met +|TIJD STATISTIEK voor +|op +|Huidige tijd : +|Huidige datum : +|Verbindings tijd : +|Tijd gebruikt vandaag : +|Tijd over vandaag : +|Dagelijkse tijdslimiet : +|U heeft +JN|berichten, nu de post lezen? [J/n]: +|Er zijn geen nieuwe berichten in Uw postbus ... +|Sneltoetsen staan nu AAN +|Sneltoetsen staan nu UIT +|Aan +|Uit +|Gebruikersnaam bestaat al +|Even in Uw postbus kijken ... +| MBSE BBS Kletsen +|De Sysop is nu even met iemand anders in gesprek op +|Probeer het opnieuw in enkele minuten ... +|U heeft de Sysop meer dan het maximaal aantal keren geroepen. +|De Sysop is niet aanwezig ... laat een bericht achter +|Nieuw bericht in gebied: +|Van : +|Aan : +|Kontroleren gebruiker ... +|Gebruiker niet gevonden. Opnieuw proberen of (Enter) voor stop +|Onderwerp: +JN|Afbreken bericht [j/N] ?: +JN|Prive [j/N]: +|Begin nu met het bericht, Een lege regel is stoppen +|Maximaal 60 regels, 73 karakters per regel +|maximale berichtlengte overschreden +|Functies beschikbaar: (Huidig bericht: +|Regels) +|L - Lijst bericht B - Bewaar bericht D - Doorgaan bericht +|A - Afbreken W - Wissen regel I - Invoegen regel +|T - Tekst wijzigen R - Regel wijzigen V - Vervang regel +LBDADITRVC|C - Centreer regel +|Kies +|Doorgaan +|Wis +|Wis vanaf regel +|Afgebroken. +|Geef een nummer in het bereik van +|Wissen eindigt met regel +|Wijzig +|Geef regel # te wijzigen +|Invoegen +|Geef het regel # waarvoor in te voegen +|Lijst +|Geef regel # te vervangen +|De regel is: +|Onveranderd. +|De regel is nu: +|Stop +JN|Wet U het zeker [j/N]: +|Bericht afgebroken. +|Nee +|Tekst wijzigen +|Geef regel # te wijzigen +|Oude tekst : +|Nieuwe tekst: +|De regel is nu: +|Bewaar +|Een mogelijk VIRUS gevonden! +|Ok +|Uitpakken archief +|Opslaan bericht op disk +|Geef regel # te centreren +|De regel is op maximale breedte en kan niet worden gecentreerd. +|Er zijn geen breichten in dit gebied. +|Datum : +JN=|Meer (J/n/=/Gebied #): +|Aan : +|Van : +|Onderwerp: +|Reactie: +|Antwoord op: +|berichten in +OVLAPSWX|(O)pnieuw, (V)olgend, (L)aatst, (A)ntwoord, (P)laats, (W)is, (S)top, e(X)port +|(O)pnieuw, (V)olgend, (L)aatst, (A)ntwoord, (P)laats, (S)top, e(X)port +|Volgende +|FOUT +AVS|(A)ntwoord, (V)olgende, (S)top: +|Enter is zelfde onderwerp. +|# Van Aan Onderwerp +|Berichten gebied +|bevat +|berichten. +|Geef een bericht tussen +|Bericht nummer [ +|Nr. Soort Omschrijving Aantal Persoonlijk +|draad +|Geef de naam van de confrentie, of ? voor een lijst: +|Conferentie Gebied Tot. Omschrijving +|Wissen bericht +| Berichten gebieden +|Kies gebied: +|Ongeldig nummer opgegeven - Probeer het opnieuw ... +|Wachtwoord is fout +|Wachtwoord is goed +|U heeft niet genoeg autorisatie voor de lijst in dit gebied +|Kan de database niet openen voor dit gebied +|Upload door: +|GEWIST +|ONTBREEKT +JN|Node onbekend, toch doorgaan [j/N]: +|Aantal bestanden: +|FATAAL: kan de bestanden database niet openen +|U heeft niet genoeg autorisatie om uit dit gebied te downloaden. +|Geef de bestandsnaam: +|Geen bestandsnaam, Afgebroken. +|Ongeldige bestandsnaam! +|Sorry maar dat bestand is niet beschikbaar voor download +|U heeft +|extra download KBytes. +|U heeft niet genoeg tijd om dat bestand te downloaden. +|U heeft niet genoeg bijtes over om te downloaden " +|U moet uploaden vorrdat U kunt downloaden. +|Kilobytes op dit moment beschikbaar: +|Kontroleren gemarkeerde bestanden, een ogenblik ... +|Verwijder selectie Offline Reader berichten gebieden +|FILEID.DIZ gevonden in +|Geen bestanden gemarkeerd voor download. +|extra minuten. +|De volgende conferentie(s) zijn geselecteerd: +|Bestand Grootte Datum +|Protocol: Kan protocollen bestand niet openen. +|Kies Uw favourite overdracht protocol +|Kies Protocol (Enter is Stop): +|Ongeldige keuze, Probeer het opnieuw! +|Het protocol is nu: +|Geef sleutelwoord om op te zoeken : +|Bestanden zoeken op sleutelwoord +|Accepteerd jokers zoals : *.zip, *.gz, .tar* +| : *.zip is hetzelfde als .zip +|Geef bestandsnaam om naar te zoeken : +|Bestanden zoeken op naam +JN|Zoeken naar nieuwe bestanden sinds de laatste keer? [J/n]: +|Geef nieuwe datum om vanaf te zoeken [DD-MM-JJJJ]: +|Bestanden zoeken op datum +|Geef bestandsnaam voor upload: +|Offline Reader Download +|U heeft niet genoeg rechten om in dit gebied te uploaden. +|U heeft niet genoeg vrije diskruimte om dit bestand te kopieren +|bestanden( +|bytes) gemarkeerd voor download. +|Dat bestand bestaat al op het systeem +|Begin u met Uw upload ... +|Upload is mislukt voor : +JN|Wilt U Uw upload beschermen met een wachtwoord ? [j/N]: +|ONTHOUDT: Wachtwoorden zijn "HoOfDLEtTer GeVoElIg!" +|Geef een omschrijving van bestand +|Uw upload tijd is terruggegeven. Bedankt voor de upload! +|Start kopieren: +|Kan de directory niet openen voor de lijst: +|Prive directory lijst voor +|Geef bestandsnaam om te wissen: +|Spijtig, maar verborgen bestanden mag U niet wissen ... +|Kan bestand niet wissen ... +|Ongeldige bestandsnaam, Probeer het opnieuw ... +|Bestand bestaat niet, Probeer het opnieuw ... +|Conferentie Omschrijving Aant. Pers. +| Bestanden gebieden +|Geef gebieds wachtwoord: +|Toevoegen BBS +|BBS Naam: +|Invoer is nodig ... +|Telefoon nummer: +|Sysop Naam: +|BBS Software: +|Diskruimte (GigaByte): +|Snelheden: +JN|Wilt U het BBS uitgebreider omschrijven? [J/n]: +|Geef een omschrijving voor +|BBS Lijst +|# BBS Naam Nummer Software GigaByte Snelheid +|Zoek een BBS +|Geef 3 letters van het BBS om op te zoeken: +|Ik heb minstens 3 letters nodig ... +JN|Bekijk dit BBS? [J/n]: +|Ik kon dat BBS niet vinden ... +|Toon een BBS +|Geef het nummer om te bekijken: +|Record bestaat niet +| Record : +| BBS Naam : +| Nummer : +| Software : +| GigaBytes : +| Snelheden : +| Sysop Naam : +| Beschikbaar : +| Invoer datum : +| Invoer naam : +|Verwijder BBS +|Geef het nummer om te verwijderen: +|Record +|is niet van U. +|is al gemarkeerd om te verwijderen +|gemarkeerd om te verwijderen +|De Sysop zal dit BBS verwijderen zodra hij +|heeft gezien dat er een record gemarkeerd is. +|Totaal aantal berichten gevonden: +|Onbekend menu kommando! +|Bewaren ... +|MBSE BBS Spreuken kunne willekeurig verschijnen. +|Obscene en racistische opmerkingen worden verwijderd!! +|Geef hieronder Uw spreuk. U heeft 75 karakters. +|Spreuk toegevoegd +| # A Datum Gebruiker Omschrijving +| # Omschrijving +|Geef nummer om te bekijken: +|Verbonden via poort +|Bestand(en): +|Grootte : +|Protocol : +|Bijwerken download tellers, een ogenblik ... +|Mislukt! +|Bytes +| # Geb. Aktief Bestand Grootte Kosten +|Ja +|Nee +SV|(S)chakel aktief, (V)erwijder alles, (ENTER) voor doorgaan: +|Geef bestand nummer, 1.. +|Gemarkeerd: +|Geen bestanden gemarkeerd. +|Vervang +|Het BBS wordt geladen, een moment ... +|Nieuwe of verwijderde berichten gebieden bij +|Geb. Status Soort Omschrijving +|Tonen nieuwe Post is nu AAN +|Tonen nieuwe Post is nu UIT +|Verwijder bestand: +JN|Zeker weten? [J/n]: +|Tonen nieuwe Bestanden is nu AAN +|Tonen nieuwe Bestanden is nu UIT +|Schermgestuurde Tekstverwerker is nu AAN +|Schermgestuurde Tekstverwerker is nu UIT +|Geen berichten gevonden voor download! +|Geef (Enter) voor doorgaan: +|Centreer +|Teveel berichten. Alleen de eerste +|Kies Uw favourite taal +|Kies taal: +|De taal is nu: +|Het systeem zal nu een "Unix gebruikersnaam" vragen +|Uw "Unix gerbuikersnaam" is gemaakt, U kunt dit de volgende keer gebruiken. +|Geef een inlog naam (Maximaal 8 karakters, kleine letters) +|bv. Piet Snot, login = psnot +|login > +|Die login naam bestaat al, kies iets anders. +|FATAL: Cannot open language definition file +|Uw nieuwe Unix en BBS wachtwoord worden hetzelfde. +|FATAL ERROR: Niet gevonden in het BBS gebruikers bestand. +| Start 'newuser' om een account te maken +|Nieuw +|Lokaal +|Netmail +|Echomail +|Nieuws +|E-Mail +|Gewist +|Jan +|Feb +|Mrt +|Apr +|Mei +|Jun +|Jul +|Aug +|Sep +|Okt +|Nov +|Dec +|Autologuit: non-aktief tijd bereikt. +|worden ingepakt! +|Geef Uw Alias (Enter voor geen): +|Je kunt het bbs nu gaan gebruiken +|Gebruikers aanwezig bij +|Naam Poort Bezig met Woonplaats +|Niet storen staat nu UIT +|Niet storen staat nu AAN +|Rondkijken +|Downloaden +|Uploaden +|Berichten +|Extern Prog. +|Kletsen +|Bestanden +JN|Wilt U deze berichten downloaden [J/n]? +|Tijd Bank +|Kluis kraken +|Wie is hier +|Vrij +|Geef de gebruikersnaam waar het bericht heen moet: +|Sorry, er is niemand op +|wil niet gestoord worden +|Geef te versturen bericht (Maximaal 76 karakters) +|** Bericht ** van +|Uw wachtwoord is verlopen, geef nieuw wachtwoord: +|Toets ENTER voor doorgaan +|Plaatsen berichten niet toegestaan, dit gebied is alleen lezen! +|Antwoorden is niet toegestaan in dit gebied! +|Offline Reader Upload +|Ongeldig pakket ontvangen +|Onbekende compressie methode +|Compressie programma niet beschikbaar +|Onbekend type mail pakket +|BlueWave Offline download +|Voorbereiden pakket +|Comprimeren met +|Download mislukt +|Download is gelukt +|Bijwerken laatstgelezen wijzers +|Verwerken BlueWave antwoord pakket +|FOUT in pakket +|Inlezen berichten +|Geen schrijftoegang in gebied +|Berichten ingelezen +|Verwerken Offline Configuratie +|Berichten gebieden gelecteerd +|Verwerken bestands verzoeken +|QWK Offline Download +|Verwerken QWK antwoord pakket +|ASCII Offline Download +JN|Direct [j/N]: +JN|Let op: node is niet CM, onmiddelijk sturen [j/N]: +JN|Bestand meesturen [j/N]: +|Bestand +|wordt meegestuurd +|Bestand niet binnen +|mailbox - Inkomende en uitgaande post +|archive - Het archief van Uw email +|trash - De vuilnisbak, oude email. +|Gebied # +|minuten. diff --git a/lang/english.txt b/lang/english.txt new file mode 100644 index 00000000..6b757bb5 --- /dev/null +++ b/lang/english.txt @@ -0,0 +1,472 @@ +|Please enter your First and Last name: +|Please enter your Last name: +|Disconnecting user ... +|Scanning User File ... +YN|Did you spell your name correctly? [Y/n] +|Name Entered: +|This is a PRIVATE System. Type "off" to leave +|Mark file number or press to stop +|Password: +|Maximum login attempts have been exceeded ... +|Either your NAME or PASSWORD is incorrect +| MBSE BBS System Bank +|Bank Account: +|Time in account +|Bytes in account +|Time deposited today +|Bytes deposited today +|Time withdrawn today +|Bytes withdrawn today +DWQ|(D)eposit, (W)ithdraw, (Q)uit: +|Bank > +TBQ|(T)ime, (B)ytes, (Q)uit : +|You must have at least 5 minutes remaining to deposit +|How much time. Minutes available to you is +|You have tried to deposit more than the maximum limit today. +|Maximum allowed minutes to deposit per day: +|You have exeeded your account balance. +|Maximum allowable minutes in bank account is: +|You are allowed to deposit: +|You have tried to withdraw more than the maximum limit today. +|Maximum allowed to withdraw per day: +|You have tried to withdraw more time than is in your bank account. +|Current bank balance: +|Maximum allowed kilobytes to deposit per day: +|You have exeeded your account balance. +|Maximum allowable kilobytes in bank account is: +|How many kilobytes. KBytes available to you is +|MBSE Bulletin Board System - NEW USER REGISTRATION +|Use this name: +|Please enter new password : +|Please enter password again : +|Your passwords do not match! Try again. +|Your password must contain at least +|characters! Try again. +YN|Do you want ANSI and graphics mode [Y/n]: +|Please enter you Voice Number +|Message exported to your private directory as: +|Please enter a proper phone number +|Please enter you Data Number +|Please enter your location: +|Please enter a longer location +MF|What is your sex? (M)ale or (F)emale: +|Male +|Female +|Please answer M or F +|Unknown +|Please enter your Date of Birth DD-MM-YYYY: +|Sorry you entered this year by mistake. +|Please enter the correct date format +|*** Sysop is starting chat *** +|*** Sysop has terminated chat *** +YN=|More (Y/n/=) +YN|Would you like Hot-Keyed menus? [Y/n]: +|Please answer Y or N +|Please enter your Screen Length? [24]: +|None +|Tag Offline Reader message areas +|Your user account has been created: +|Login Name : +|Password : +|not displayed +|Login to the BBS with the above name +|Could not find +|Old Location: +|Please enter a longer location (min +|Ansi Mode turned ON +|Ansi Mode turned OFF +|Message doesn't exist +|News bulletins turned ON +|News bulletins turned OFF +|Screen length is 24 +|Screen length is now set to: +|Private message, not owner +|Please enter the correct date format +|Todays Callers to +|# User Name Device TimeOn Calls Location +|Safe Cracker Door +|Please press a key to continue: +|In the safe lies ... +|Please enter three numbers consisting from 1 to +|Please enter three combinations. +|1st digit: +|Please try again! You must input a number greater than Zero and less than +|2nd digit: +|3rd digit: +| Left: +|Right: +YN|Attempt to open safe with this combination [Y/n]: +|You have won the following... +|Sorry - You didn't open the safe! +|The safe code was: +YN|Do you want to try again ? [Y/n]: +YN|Do you want to open the safe ? [Y/n]: +|THE SAFE IS CURRENTLY LOCKED +|has cracked the safe. +|The safe will remain locked until the sysop rewards the user. +|Maximum trys per day Exceeded! +|Message to Nextuser Door +|The FROM, TO and SUBJECT fields are optional. +| From: +| To: +|Subject: +| Type up to 10 lines 74 Characters per line +|Functions available: +LREAS|(L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave +|Select: +|Aborting... +|Returning to +|Edit which line: +|Line does not exist. +|Old Password: +|New password: +|Confirm new password: +|Passwords do not match! +|Password Change Successful +|Old password incorrect! +|User List +|Enter Username search string or (Enter) for all users: +|Name Location Last On Calls +|Could not find search string ... +|Time limit exceeded ... disconnecting! +YN=M|More (Y/n/=) M=Mark +|Scanning +|with +|TIME STATISTICS for +|on +|Current Time : +|Current Date : +|Connect time : +|Time used today : +|Time remaining today : +|Daily time limit : +|You have +YN|messages, read your mail now? [Y/n]: +|You have no new mail in your mail box ... +|Hotkeys are now ON +|Hotkeys are now OFF +|On +|Off +|User name already exists +|Checking your mail box ... +| MBSE BBS Chat +|The SysOp is currently speaking to somebody else on +|Try paging him again in a few minutes ... +|You have paged the Sysop the maximum times allowed. +|Sysop currently is not available ... please leave a comment +|Posting message in area: +|From : +|To : +|Verifying user ... +|User not found. Try again, or (Enter) to quit +|Subject : +YN|Abort Message [y/N] ?: +YN|Private [y/N]: +|Begin your message now, Blank line to end +|Maximum of 60 lines, 73 characters per line +|Maximum message length exceeded +|Functions available: (Current Message: +|Lines) +|L - List message S - Save message C - Continue message +|Q - Quit message D - Delete line I - Insert line +|T - Text edit E - Edit line R - Replace line +LSCQDITERZ|Z - Center line +|Select +|Continue +|Delete +|Delete starting at line +|Aborted. +|Please enter a number in the range of +|Delete ending at line +|Edit +|Enter line # to edit +|Insert +|Enter line # to insert text before +|List +|Enter line # to replace +|Line reads: +|Unchanged. +|Line now reads: +|Quit +YN|Are you sure [y/N]: +|Message aborted. +|No +|Text Edit +|Enter line # to edit +|Text to replace : +|Replacement text : +|Line now reads: +|Save +|Possible VIRUS found! +|Ok +|Unpacking archive +|Saving message to disk +|Enter line # to center +|Line is maximum length and cannot be centered +|There are no messages in this area. +|Date : +YN=|More (Y/n/=/Area #): +|To : +|From : +|Subject : +|Next reply: +|Reply to: +|messages in +ANLREQDX|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)el, (Q)uit, e(X)port +|(A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port +|Next +|ERROR +RNQ|(R)eply, (N)ext, (Q)uit: +|Enter to keep Subject. +|# From To Subject +|Message area +|contains +|messages. +|Please enter a message between +|Message number [ +|Area Type Description Messages Personal +|thread +|Enter the name of the conference, or ? for a list: +|Conference Area Msgs Description +|Deleting message +| Message Areas +|Select Area: +|Invalid area specified - Please try again ... +|Password is incorrect +|Password is correct +|You don't have enough security to list this area +|Can't open file database for this area +|Uploaded by: +|D E L E T E D +|M I S S I N G +YN|Node not known, continue anyway [y/N]: +|Total Files: +|FATAL: Unable to open areas database +|You do not have enough access to download from this area. +|Please enter filename: +|No filename entered, Aborting. +|Illegal Filename! +|Sorry that file is unavailable for download +|You have +|extra download KBytes. +|You do not have enough time to download that file. +|You do not have enough bytes to download " +|You must upload before you can download. +|Kilobytes currently available: +|Checking your marked downloads, please wait... +|Untag Offline Reader message areas +|Found FILEID.DIZ in +|No files marked for download. +|extra minutes. +|You have selected the following Conference(s): +|Filename Size Date +|Protocol: Can't open protocol file. +|Select your preferred file transfer protcol +|Select Protocol (Enter to Quit): +|Ivalid selection, please try again! +|Protocol now set to: +|Enter keyword to use for Search: +|File Search by Keyword +|Accepts wildcards such as : *.zip, *.gz, .tar* +| : *.zip is the same as .zip +|Enter filename to search for : +|File Search by Filename +YN|Search for new since your last call [Y/n]: +|Enter new date to search for [DD-MM-YYYY]: +|File Search by Date +|Please enter file to upload: +|Offline Reader Download +|You do not have enough access to upload to this area. +|You have not enough diskspace free to copy this file +|files( +|bytes) marked for download. +|The file already exists on the system +|Please start your upload now ... +|Upload was unsuccessful for: +YN|Do you want to password protect your upload ? [y/N]: +|REMEMBER: Passwords are "CaSe SeNsITiVe!" +|Please enter description of file +|Your upload time has been returned to you. Thank you for your upload! +|Start copy: +|Can't open directory for listing: +|Home directory listing for +|Please enter filename to delete: +|Sorry you may not delete hidden files ... +|Unable to delete file ... +|Invalid filename, please try again ... +|File does not exist, please try again ... +|Forum Description Msgs. Pers. +| File Areas +|Please enter Area Password: +|Adding BBS +|BBS Name: +|Response needed ... +|Phone Number: +|Sysop Name: +|BBS Software: +|Storage (GigaByte): +|Speeds: +YN|Would you like to add a extended discription? [Y/n]: +|Please a enter discription for +|BBS Listing +|# BBS Name Number Software GigaByte Speed +|Search for a BBS +|Please enter 3 letters of BBS to search for: +|I need at least 3 letters ... +YN|View this BBS? [Y/n]: +|Could not find the BBS Listed ... +|Show a BBS +|Please enter number to list: +|Record does not exist +| Record : +| BBS Name : +| Number : +| Software : +| GigaBytes : +| Speeds : +| Sysop Name : +| Available : +| Date of Entry : +| Entry Name : +|Delete BBS +|Please enter number to delete: +|Record +|does not belong to you. +|already marked for deletion +|marked for deletion +|The Sysop will purge the list once he has +|seen you have marked a record for deletion. +|Total messages found: +|Unknown Menu Command! +|Saving... +|MBSE BBS Oneliners will randomly appear on the main menu. +|Obscene or libellous oneliners will be deleted!! +|Please enter your oneliner below. You have 75 characters. +|Oneliner added +| # A Date User Description +| # Description +|Please enter number to list: +|Connected on port +|File(s) : +|Size : +|Protocol : +|Updating download counters, please wait ... +|Failed! +|Bytes +| # Area Active File Size Cost +|Yes +|No +TE|(T)oggle active, (E)rase all, (ENTER) to continue: +|Enter file number, 1.. +|Marked: +|No files tagged. +|Replace +|Loading BBS, please wait ... +|New or deleted mail areas at +|Area State Type Description +|New Mail check is now ON +|New Mail check is now OFF +|Delete file: +YN|Are you Sure? [Y/n]: +|New Files check is now ON +|New Files check is now OFF +|Fullscreen Editor is now ON +|Fullscreen Editor is now OFF +|No messages found to download! +|Press (Enter) to continue: +|Center +|Too much messages. Only the first +|Select your preferred language +|Select Language: +|Language now set to: +|The system will now ask you for a "Unix Account" +|Your "Unix Account" is created, you may use it the next time you call. +|Please enter a login name (Maximum 8 characters) +|ie. John Doe, login = jdoe +|login > +|That login name already exists, please choose another one. +|FATAL: Cannot open language definition file +|Your new Unix and BBS password will be the same. +|FATAL ERROR: You are not in the BBS users file. +| Please run 'newuser' to create an account +|New +|Local +|Netmail +|Echomail +|News +|E-Mail +|Del +|Jan +|Feb +|Mar +|Apr +|May +|Jun +|Jul +|Aug +|Sep +|Oct +|Nov +|Dec +|Autologout: idletime reached. +|Will be packed! +|Enter your handle (Enter for none): +|You are now ready to use the bbs +|Callers On-Line to +|Name Device Status Location +|Do not disturb turned OFF +|Do not disturb turned ON +|Browsing +|Downloading +|Uploading +|Msg Section +|External Door +|Chatting +|Listing Files +YN|Do you want to download these messages [Y/n]? +|Banking Door +|Safe Door +|WhosOn List +|Idle +|Please enter username to send message to: +|Sorry, there is no user on +|doesn't wish to be disturbed +|Please enter in message to send (Max 76 Characters) +|** Message ** from +|Your password is expired, new password : +|Press ENTER to continue +|Posting not allowed, this area is Read Only! +|Replies are not allowed in this area! +|Offline Reader Upload +|Invalid packet received +|Unknown compression type +|Archiver not available +|Unknown type mailpacket +|BlueWave Offline download +|Preparing packet +|Packing with +|Download failed +|Download successfull +|Updating lastread pointers +|Processing BlueWave reply packet +|ERROR in packet +|Import messages +|No Write access to area +|Messages imported +|Processing Offline Configuration +|Message areas selected +|Processing file requests +|QWK Offline Download +|Processing QWK reply packet +|ASCII Offline Download +YN|Crash [y/N]: +YN|Warning: node is not CM, send immediate [y/N]: +YN|Attach file [y/N]: +|File +|will be attached +|File not within +|mailbox - Incoming and outgoing email +|archive - Archive of your email +|trash - Trashcan, your old email +|Area # +|minutes. diff --git a/lang/italian.txt b/lang/italian.txt new file mode 100644 index 00000000..2fbb93ac --- /dev/null +++ b/lang/italian.txt @@ -0,0 +1,472 @@ +|Digita Nome e Cognome: +|Digita il tuo Cognome: +|Scollegamento in corso ... +|Controllo User File in corso... +SN|Hai scritto il tuo nome e cognome correttamente? [S/n] +|Nome inserito: +|Questo e' un sistema telematico PRIVATO. Scrivi "off" per uscire ora +|Scegli il numero del file o premi per interrompere +|Password: +|Numero massimo di tentativi per il login raggiunto ... +|Hai inserito un NOME o una PASSWORD errata +| MBSE BBS Banca di Sistema +|Account bancario di : +|Tempo disponibile : +|Byte disponibili : +|Tempo depositato oggi: +|Byte depositati oggi : +|Tempo prelevato oggi : +|Byte prelevati oggi : +DPE|(D)eposita, (P)releva, (E)sci: +|Banca > +TBE|(T)empo, (B)yte, (E)sci : +|Devi avere almeno 5 minuti restanti per poter depositare +|Scegli la quantita di tempo. Hai a disposizione minuti +|Hai cercato di depositare piu del limite massimo oggi. +|Massimo numero di minuti che puoi depositare ogni giorno: +|Hai superato il limite per il tuo account. +|Massimo numero di minuti disponibili nel tuo account: +|Puoi depositare: +|Hai cercato di prelevare piu del limite massimo oggi. +|Massimo numero di minuti che puoi prelevare ogni giorno: +|You have tried to withdraw more time than is in your bank account. +|Stato attuale del tuo account: +|Numero massimo di KB che puoi depositare ogni giorno: +|Hai superato il limite per il tuo account. +|Numero massimo di KB che puoi tenere nel tuo account: +|Scegli la quantita di KB. KB disponibili: +|MBSE Bulletin Board System - REGISTRAZIONE DEI NUOVI UTENTI +|Usa questo nome: +|Inserisci una nuova password: +|Verifica la nuova password : +|Le password inserite non sono uguali! Prova ancora. +|La password deve contenere almeno +|caratteri! Prova ancora. +SN|Vuoi usare la grafica ANSI [S/n]: +|Inserisci il tuo numero di telefono voce +|Messaggio esportato nella tua home con nome: +|Inserisci un numero di telefono corretto +|Inserisci il tuo numero di telefono dati +|Inserisci la localita da cui chiami +|La localita' inserita e' troppo breve +MF|Sesso? (M)aschio o (F)emmina: +|Maschio +|Femmina +|Per favore rispondi con M o F +|Sconosciuto +|Inserisci la tua data di nascita nel formato: GG-MM-AAAA: +|Mi dispiace, hai inserito un anno errato. +|Per favore inserisci la data nel formato corretto +|*** Il Sysop sta lanciando la chat *** +|*** Il Sysop ha chiuso la chat *** +SN=|Ancora (S/n/=) +SN|Vuoi abilitare le Hot-Key? [S/n]: +|Per favore rispondi con S o N +|Scegli la lunghezza in righe delle schermate? [24]: +|Nessuno +|Marca le aree messaggi dell'Offline Reader +|Il tuo account e' stato creato il: +|Nome utente : +|Password : +|riservato +|Loggati nella BBS usando il nome utente sopra riportato. +|Non trovo +|Vecchia Localita': +|Per favore inserisci un nome piu' lungo (almeno +|La modalita' ANSI ora e': ON +|La modalita' ANSI ora e': OFF +|Il messaggio non esiste +|Le News ora sono: ON +|Le News ora sono: OFF +|Il numero di righe per schermata e' 24 +|Il numero di righe per schermata e' ora fissato a: +|Messaggio privati, non sei autorizzato +|Per favore usa il formato corretto per la data +|Hanno chiamato oggi +|# Nome Utente Linea Durata Calls Localita' +|Apri la cassaforte DOOR +|Premi un tasto per continuare: +|In the safe lies ... +|Per favore inserisci 3 numeri compresi tra 1 e +|Devi indovinare la combinazione della cassaforte. +|Prima cifra: +|Prova ancora! Devi scegliere un numero maggiore di 0 e minore di +|Seconda cifra: +|Terza cifra: +| Sinistra: +| Destra: +SN|Provo a aprire la cassaforte con questa combinazione [S/n]: +|Hai vinto... +|Mi dispiace - Non sei riuscito a aprire la cassaforte! +|La combinazione giusta era: +SN|Vuoi provare ancora ? [S/n]: +SN|Vuoi aprire la cassaforte ? [S/n]: +|LA CASSAFORTE AL MOMENTO RISULTA BLOCCATA +|ha aperto la cassaforte. +|La cassaforte restera' chiusa finche' il SysOp non consegnera' il premio. +|Numero massimo di tentativi giornalieri raggiunto! +|Messaggio per il prossimo utente DOOR +|I campi DA, A e OGGETTO sono facoltativi. +| Da: +| A: +|Oggetto: +| Scrivi fino a un massimo di 10 righe con 74 caratteri per riga +|Funzioni disponibili: +MREAS|(M)ostra, (R)impiazza testo, (E)dita la linea, (A)nnulla, (S)alva +|Seleziona: +|Messaggio annullato... +|Sto ritornando a +|Numero linea da editare: +|Quella linea non esiste. +|Vecchia Password: +|Nuova Password: +|Verifica la nuova Password: +|Le Password non corrispondono! +|Cambio Password accettato +|La vecchia password e' errata! +|Lista Utenti +|Inserisci una stringa da cercare o premi (Invio) per la lista completa: +|Nome Localita' Ultima volta Chiamate +|Non ho trovato corrispondenze ... +|Tempo massimo raggiunto ... scollegamento in corso! +SN=M|Ancora (S/n/=) M=Marca +|Sto cercando +|con +|STATISTICHE del tempo per +|il +|Ora attuale : +|Data attuale : +|Ora di connessione : +|Tempo usato oggi : +|Tempo rimasto per oggi : +|Limite di tempo odierno: +|Hai +SN|nuovi messaggi, vuoi leggere la posta ora? [S/n]: +|Non hai nuovi messaggi nella tua mail box ... +|Hotkeys ABILITATE +|Hotkeys DISABILITATE +|On +|Off +|Nome utente gia' in uso +|Sto controllando la tua mail box ... +| MBSE BBS Chat +|Il SysOp sta parlando con un altro utente su +|Prova a chiamarlo di nuovo fra pochi minuti ... +|Hai gia' chiamato il SysOp per il massimo numero di volte consentito. +|Il SysOp non e' al momento disponibile ... lascia un messaggio +|Area di destinazione: +|Da : +|A : +|Controllo nome utente ... +|Nome utente non trovato. Prova ancora, o premi (Enter) per uscire +|Oggetto : +SN|Annulla Messaggio [s/N] ?: +SN|Privato [s/N]: +|Comincia a scrivere il messaggio, lascia una riga vuota per terminare +|Massimo 60 righe da 73 caratteri ciascuna +|Lunghezza massima del messaggio raggiunta +|Funzioni disponibili: (Messaggio attuale: +|Righe) +|L - Leggi messaggio S - Salva messaggio C - Continua messaggio +|A - Abbandona D - Cancella riga I - Inserisci riga +|M - Edita tutto E - Edita riga R - Rimpiazza riga +LSCADIMERZ|Z - Linea centrale +|Seleziona +|Continua +|Cancella +|Cancella a partire dalla riga +|Abbandonato. +|Inserisci un numero nell'intervallo +|Cancella fino a alla riga +|Edita +|Inserisci il numero della riga da editare +|Inserisci +|Inserisci il numero della riga prima della quale inserire il testo +|Leggi +|Inserisci il numero della riga da rimpiazzare +|La linea contiene: +|Immutato. +|La linea e' diventata: +|Esci +SN|Confermi [s/N]: +|Messaggio annullato. +|No +|Edita il Testo +|Inserisci la linea da modificare +|Testo da rimpiazzare : +|Nuovo testo : +|La linea e' diventata: +|Salva +|Possibile VIRUS rilevato! +|Ok +|Decompressione archivio +|Salvataggio del messaggio su disco +|Inserisci la linea da centrare +|La linea e' troppo lunga per essere centrata +|Non ci sono messaggi in quest'area. +|Data : +SN=|Ancora (S/n/=/Area #): +|A : +|Da : +|Oggetto : +|Prossima risposta: +|Rispondi a: +|messaggi in +APURSCEO|(A)ncora,(P)rossimo,(U)ltimo,(R)ispondi,(S)rivi,(C)ancella,(E)sci,esp(O)rta +|(A)ncora, (P)rossimo, (U)ltimo, (R)ispondi, (S)crivi, (E)sci, esp(O)rta +|Prossimo +|ERRORE +RPE|(R)ispondi, (P)rossimo, (E)sci: +|Premi Invio per mantenere il Subject. +|# Da A Oggetto +|Area messaggi +|contiene +|messaggi. +|Per favore scegli un messaggio tra +|Numero Messaggio [ +|Area Tipo Descrizione Messaggi Personali +|thread +|Inserisci il nome della conferenza o premi ? per avere la lista: +|Conferenza Area Msgs Descrizione +|Cancello il messaggio +| Aree Messaggi +|Seleziona Area: +|Area specificata non valida - Prova di nuovo ... +|Password errata +|Password corretta +|Non hai livello d'accesso sufficiente per sfogliare quest'area +|Non trovo il database dei file di quest'area +|Uploadato da: +|C A N C E L L A T O +|M A N C A N T E +SN|Nodo sconosciuto, continua lo stesso [s/N]: +|File Totali: +|FATAL: Non trovo il database dell'area +|Non hai livello d'accesso sufficiente per scaricare da quest'area. +|Digita il nome del file: +|Nome del file non valido, operazione annullata. +|Filename non valido! +|Mi dispiace quel file non e' disponibile per il download +|Ora hai +|KBytes in piu' da scaricare. +|Non hai abbastanza tempo per scaricare quel file. +|Non hai abbastanza crediti per scaricare " +|Devi uplodare prima di scaricare. +|Kilobytes disponibili: +|Controllo della lista di download in corso, attendere prego... +|Untag aree messaggi per l'Offline Reader +|Trovato FILEID.DIZ in +|Nessun file selezionato per il download. +|minuti extra. +|Hai selezionato le seguenti Conferenze: +|Filename Dimensione Data +|Protocollo: Non posso aprire il file del protocollo. +|Seleziona il tuo protocollo di trasferimento preferito +|Seleziona Protocollo (Invio per uscire): +|Selezione errata, per favore prova ancora! +|Protocollo impostato su: +|Inserisci la parola da cercare: +|Ricerca file per parola chiave +|Accetto caratteri jolly come : *.zip, *.gz, .tar* +| : *.zip e' equivalente a .zip +|Scegli il filename da cercare: +|Ricerca per nome del file +SN|Cerca nuovi file dall'ultima chiamata [S/n]: +|Scegli una data per la ricerca dei nuovi file [GG-MM-AAAA] +|Ricerca per data +|Scegli il file da uploadare: +|Offline Reader Download +|Non hai livello di accesso sufficiente per uploadare in quest'area. +|Non hai abbastanza spazio libero per copiare questo file +|file( +|byte) marcati per il download. +|Il file e' gia' presente nel sistema +|Per favore comincia l'upload ... +|Upload terminato con successo: +SN|Vuoi proteggere con password il tuo upload ? [s/N]: +|RICORDA: Le password sono "CaSe SeNsITiVe!" +|Inserisci una descrizione per il file +|Il tempo impiegato per l'upload ti e' stato restituito. +|Inizia la copia: +|Non posso aprire la directory in lettura: +|Contenuto della Home per +|Scegli il nome del file da cancellare: +|Mi dispiace non puoi cancellare i file nascosti ... +|Impossibile cancellare il file ... +|Nome del file errato, prova ancora ... +|File non trovato, prova ancora ... +|Forum Descrizione Msgs. Pers. +| Aree File +|Inserisci la password per l'Area: +|Aggiungo la BBS +|Nome BBS: +|E' richiesta una risposta ... +|Numero di telefono: +|Nome del SysOp: +|BBS Software: +|Capacita' (GigaByte): +|Velocita' connessione: +SN|Vuoi aggiungere una ulteriore descrizione? [S/n]: +|Per favore inserisci una descrizione per +|Lista BBS +|# Nome BBS Numero Software GigaByte Velocita' +|Cerca una BBS +|Inserisci le prime 3 lettere del nome da cercare: +|Ho bisogno di almeno 3 lettere ... +SN|Mostra questa BBS? [S/n]: +|Non ho trovato la BBS nella lista ... +|Mostra una BBS +|Inserisci il numero da mostrare: +|Elemento non presente in lista +| Record : +| Nome BBS : +| Numero : +| Software : +| GigaByte : +| Velocita' : +| Nome SySop : +| Attiva : +| Data : +| Nome entry : +|Cancella BBS +|Inserisci il numero da cancellare: +|Record +|non appartiene a te. +|e' gia' marcata per l'eliminazione +|marcata per l'eliminazione +|The SySop pulira' la lista una volta accortosi +|che una BBS e' stata marcata per l'eliminazione. +|Totale messaggi trovati: +|Comando sconosciuto! +|Sto salvando... +|MBSE BBS Oneliners appariranno sul menu principale. +|Non sono ammesse frasi oscene o offensive!! +|Inserisci la tua frase. Hai a disposizione 75 caratteri. +|Oneliner aggiunto +| # A Data Utente Descrizione +| # Descrizione +|Inserisci il numero della corrispondeza da mostrare: +|Connesso sulla porta +|File : +|Dimensione: +|Protocollo: +|Aggiornamento del contatore dei download, attendere ... +|Fallito! +|Byte +| # Area Attivo File Size Costo +|Si +|No +CE|(C)ambia aree attive, (E)limina tutto, (INVIO) per continuare: +|Scegli il numero del file, 1.. +|Marcati: +|Nessun file marcato. +|Rimpiazza +|Sto caricando la BBS, attendere prego ... +|Nuove aree o aree cancellate su ... +|Area Stato Tipo Descrizione +|Controllo per posta in arrivo ATTIVATO +|Controllo per posta in arrivo DISATTIVATO +|Cancella file: +SN|Sei sicuro? [S/n]: +|Controllo per i nuovi file ATTIVATO +|Controllo per i nuovi file DISATTIVATO +|Editor a schermo pieno ATTIVATO +|Editor a schermo pieno DISATTIVATO +|Nessun messaggio da scaricare trovato! +|Premi (Invio) per continuare: +|Centra +|Troppi messaggi. Solo il primo +|Segli la lingua preferita +|Seleziona Lingua: +|Lingua impostata su: +|Ti verra' ora chiesto di scegliere un "Account Unix" +|L' Account Unix e' stato creato, dovrai usarlo la prossima volta che chiami. +|Scegli uno username per il login (Massimo 8 caratteri) +|es. Mario Rossi, login = mrossi +|login > +|Quel login esiste gia', scegline uno leggermente diverso. +|FATAL: Non riesco a aprire il file per quella lingua +|La tua password per l' "Account Unix" e la BBS saranno identiche. +|FATAL ERROR: Non sei nel database degli utenti della BBS. +| Lancia 'newuser' per creare un account +|Nuovo +|Locale +|Netmail +|Echomail +|News +|E-Mail +|Canc +|Gen +|Feb +|Mar +|Apr +|Mag +|Giu +|Lug +|Ago +|Set +|Ott +|Nov +|Dic +|Autologout: tempo di inattivita' massimo raggiunto. +|Sara' impachettato! +|Inserisci il tuo soprannome (Invio se non ne vuoi uno): +|Sei pronto per usare la BBS +|Utenti online per +|Nome Device Stato Localita' +|Modalita' "Do not disturb" DISATTIVATA +|Modalita' "Do not disturb" ATTIVATA +|Esplorazione +|Downloading +|Uploading +|Sezione Msg +|Door Esterna +|Chatting +|Lista File +SN|Vuoi scaricare questi messaggi [S/n]? +|Banking Door +|Safe Door +|WhosOn +|Idle +|Digita il nome della persona a cui inviare il messaggio: +|Mi dispiace, non c'e' tale utente +|l'utente non vuole essere disturbato +|Scrivi il messaggio da spedire (Max 76 Caratteri) +|** Messaggio ** da +|La tua password e' scaduta, nuova password : +|Premi INVIO per continuare +|Posting non consentito, quest'area e' in sola lettura! +|Non e' consentito rispondere in quest'area! +|Offline Reader Upload +|Ricevuto pacchetto non valido +|Algoritmo di compressione sconosciuto +|Compressore non disponibile +|Tipo di pacchetto di posta sconosciuto +|BlueWave Offline download +|Preparo il pacchetto +|Impacchetto con +|Download fallito +|Download completato +|Aggiornamento puntatori all'ultimo messaggio +|Processo il pacchetto BlueWave delle risposte +|ERRORE nel pacchetto +|Importa messaggi +|Non hai accesso in scrittura all'area +|Messaggi importati +|Sto processando la configurazione per la lettura Offline +|Aree messaggi selezionate +|Sto processando i file request +|QWK Offline Download +|Processo il pacchetto QWK delle risposte +|ASCII Offline Download +SN|Crash [s/N]: +SN|Attenzione: il nodo non e' in CM, spedisci immediatamente [s/N]: +SN|Allega file [s/N]: +|Il File +|sara' allegato +|File non e' all'interno +|mailbox - Email in arrivo e in uscita +|archive - Archivio delle tue email +|trash - Cestino, la tua posta vecchia +|Area # +|minuti. diff --git a/lang/spanish.txt b/lang/spanish.txt new file mode 100644 index 00000000..0169ebb2 --- /dev/null +++ b/lang/spanish.txt @@ -0,0 +1,472 @@ +|Por favor teclee su nombre y apellidos: +|Por favor teclee sus apellidos: +|Desconectando usuario ... +|Explorando fichero de usuarios ... +SN|¨Has escrito correctamente tu nombre? [S/n] +|Nombre escrito: +|Este es un sistema PRIVADO. Teclea "off" para salir +|Teclee n£mero de fichero o para terminar : +|Password: +|El n£mero de errores permitidos se ha sobrepasado ... +|Tu nombre o tu PASSWORD son incorrectos +| Banco de PAROLAS BBX +|Cuenta: +|Tiempo en la cuenta : +|Bytes en la cuenta : +|Tiempo depositado hoy : +|Bytes depositados hoy : +|Tiempo retirado hoy : +|Bytes retirados hoy : +DRS|(D)epositar, (R)etirar, (S)alir : +|Banco > +TBS|(T)iempo, (B)ytes, (S)alir : +|Debes tener al menos 5 minutos para poder depositar +|¨Cuanto tiempo?. Disponible en minutos : +|Has intentado depositar mas del m ximo permitido para hoy. +|M ximo tiempo diario que se puede depositar: +|Has excedido el saldo de tu cuenta. +|Minutos disponibles en tu cuenta : +|Se te permite depositar: +|Has intentado retirar m s del l¡mite m ximo diario. +|M ximo permitido diario para retirar: +|Has intentado retirar m s tiempo del que tienes en tu cuenta. +|El saldo de tu cuenta es : +|M ximo de Kb permitido depositar diariamente: +|Has excedido el saldo de tu cuenta. +|Kilobytes disponible en tu cuenta : +|¨Cuantos kilobytes. Dispones de +|Parolas BBX - REGISTRO DE NUEVO USUARIO +|Use este nombre: +|Por favor teclee el nuevo password : +|Por favor tecleelo de nuevo...... : +|­No coinciden! Vuelta a empezar... +|El password debe tener como m¡nimo +|caracteres. Vuelta a empezar... +SN|¨Quieres gr ficos ANSI [S/n]: +|Teclea tu n£mero de tel‚fono de VOZ +|Mensaje exportado a tu directorio privado como: +|N£mero de tel‚fono incorrecto. Repite... +|Teclea tu n£mero de tel‚fono de MODEM +|¨Donde vives? (Ciudad): +|El nombre de tu ciudad es demasiado corto. Repite por favor +HM|¨Tu que eres (H)ombre o (M)ujer: +|Hombre +|Mujer +|Responde solo H o M +|Desconocido +|Fecha de nacimiento (DD-MM-AAAA): +|Has tecleado este a¤o por error. +|Teclea la fecha en formato correcto (DD-MM-AAAA) +|*** Atenci¢n: Te habla el SysOp *** +|*** Fin de la charla. Que tengas un buen d¡a *** +SN=|M s (S/n/=) +SN|¨Quieres men£s r pidos? [S/n]: +|Por favor contesta S ¢ N +|Longitud en l¡neas de tu pantalla [24]: +|Nada +|Marcar  reas para lectura Off-Line +|Tu cuenta de usuario ha sido creada: +|Nombre de Login : +|Password : +|no visualizable +|Puedes entrar en la BBS con el nombre anterior +|No encuentro +|Localidad anterior : +|Localidad demasiado corta: (min. +|Modo ANSI activado +|Modo ANSI desactivado +|No existe el mensaje +|Noticias activadas +|Noticias desactivadas +|Lineas de pantalla 24 +|Lineas de pantalla : +|Mensaje privado, y no es tuyo +|Teclee el formato de fecha correcto +|Hoy llamaron a +|# Usr. Nombre Puerto Tiempo Llams Localidad +|Juego de Robar la Caja Fuerte +|Pulse una tecla para seguir: +|En la caja hay ... +|Teclee tres n£meros de 1 a +|Teclee tres combinaciones. +|1er digito: +|­Repita! Debe ser un n£mero mayor que cero y menor que +|2§ digito : +|3er digito: +|Izquierda : +| Derecha : +SN|Intento abrir con esta combinaci¢n [S/n]: +|Has ganado ... +|­Ohhh! - No se abre... +|La combinaci¢n era: +SN|¨Quieres volver a intentarlo? [S/n]: +SN|¨Quieres intentar abrir la caja? [S/n]: +|LA CAJA ESTA BLOQUEADA. +|ha abierto la caja. +|la caja permanecer  bloqueada hasta que el SysOp recompense al usuario. +|­Has excedido el m ximo n£mero de intentos diarios! +|Mensaje al siguiente usuario: +|Los campos De, Para y Asunto son opcionales. +| De: +| Para: +| Asunto: +| Teclea hasta 10 lineas de 74 Caracteres por linea +|Funciones disponibles: +LCEAG|(L)istar, (C)ambiar texto, (E)ditar linea, (A)bandonar (G)uardar +|Elija: +|Abandonando... +|Volviendo a +|Editar la linea n§: +|Esa no existe. +|Password viejo: +|Password nuevo: +|Repite el nuevo: +|­No coinciden! +|Password cambiado. No lo olvides... +|­Password viejo incorrecto! +|Lista de usuarios +|Buscar un nombre (Enter para listar todos): +|Nombre Localidad U.Llamada Llamadas +|No lo encuentro ... +|Limite de tiempo sobrepasado ... desconectando! +SN=M|M s (S/n/=) M=Marcar +|Buscando +|con +|Estad¡sticas de TIEMPO de +|en +|Hora Actual : +|Fecha Actual : +|Tiempo de conexion : +|Tiempo usado hoy : +|Tiempo que queda : +|L¡mite diario : +|Tienes +SN|mensajes, ¨Quieres leerlos ahora? [S/n]: +|No tienes correo nuevo a tu nombre ... +|Men£s r pidos activados +|Men£s r pidos desactivados +|Activado +|Desactivado +|El nombre ya existe +|Buscando correo nuevo ... +| Charla de PAROLAS BBS +|El Sysop est  hablando con otro usuario en +|Intenta llamarlo de nuevo dentro de un rato ... +|Ya has llamado muchas veces. +|El SysOp no est  ... ¨por que no le dejas un mensaje? +|Poniendo mensaje en el  rea: +|De : +|Para : +|Verificando usuario... +|Usuario no existe. Repite, o (Enter) para salir +|Asunto : +SN|¨ Cancelar Mensaje [s/N] ?: +SN|Privado [s/N]: +|Comienza a escribir tu mensaje. (Enter) en una nueva linea para salir. +|M ximo 60 lineas, 73 caracteres por linea +|Longitud m xima sobrepasada +|Funciones disponibles: (Mensaje Actual: +|Lineas) +|L - Listar mensaje G - Guardar mensaje C - Continuar escribiendo +|A - Abandonar B - Borrar l¡neas I - Insertar linea +|T - editar Texto E - Editar l¡nea S - Sustituir linea +LGCABITESZ|Z - Centrar linea +|Elija +|Continuar +|Borrar +|Borrar desde la l¡nea +|Abandonar. +|Teclee un n£mero comprendido entre +|Borrar hasta la l¡nea +|Editar +|N§ de linea a editar +|Insertar +|Insertar antes de la l¡nea n§ +|Listar +|N§ de Linea a susutituir +|La linea dice: +|No modificada. +|La linea ahora dice: +|Abandonar. +SN|¨Est s seguro? [s/N]: +|Mensaje anulado. +|No +|Editar texto +|N§ de l¡nea a editar +|Texto a cambiar : +|Texto nuevo : +|La l¡nea ahora dice: +|Guardar +|­Posible VIRUS encontrado! +|Ok +|Descomprimiendo +|Guardando mensaje en disco +|N§ de linea # a centrar +|La linea es demasiado larga y no se puede centrar +|No hay mensajes en esta  rea. +|Fecha : +SN=|M s (S/n/=/n§  rea): +|Para : +|De : +|Asunto : +|Sig. resp.: +|Resp. a: +|mensajes en +OSARETBX|(O)tra vez (S)ig. (A)nt. (R)esp. (E)ntrar (B)orrar (T)erminar e(X)port. +|(O)tra vez (S)ig. (A)nt. (R)esponder (E)ntrar (T)erminar e(X)portar +|Siguiente +|ERROR +RST|(R)esponder, (S)iguiente, (T)erminar: +|Enter para mantener el mismo asunto +|n§ De Para Asunto +|El  rea +|tiene +|mensajes. +|Teclee un mensaje entre +|N£mero de mensaje [ +|Area Tipo Descripci¢n Mensajes Personal +|hilo +|Teclee TAG del  rea, ? para ver lista: +|TAG Area Msjs Descripci¢n +|Borrando mensaje +| Areas de Mensajes +|Elija un  rea: +| rea elegida no v lida - Elija otra ... +|Password incorrecto +|Password correcto +|No tienes permiso para listar esta  rea +|No puedo abrir la base de ficheros de esta  rea +|Enviado por: +|B O R R A D O +|P E R D I D O +SN|Nodo desconocido. ¨Continuar? [s/N]: +|Total Fichs: +|FATAL: Imposible abrir base de  reas +|No tienes permiso para descargar ficheros de esta  rea. +|Nombre del fichero: +|Nombre vac¡o, cancelando. +|­Nombre de fichero no v lido! +|Ese fichero no est  disponible para descargar +|Tienes +|KBytes extra para descargar. +|No tienes tiempo suficiente para descargar ese fichero. +|No tienes suficiente cr‚dito para descargar " +|Debes enviar algo antes de descargar. +|Kilobytes disponibles: +|Verificando ficheros marcados, espera un poco... +|Desmarcar  reas para lectura Off-Line +|Encontrado FILEID.DIZ en +|No hay ficheros marcados. +|minutos extra. +|Has deleccionado las siguientes  reas: +|Fichero Tama¤o Fecha +|Protocolo: No puedo abrir fichero de protocolos. +|Elija el protocolo de transferencia predeterminado +|Elija Protocolo (Enter para salir): +|Ese no vale, ­Elija otro! +|Protocolo predeterminado: +|Palabra a buscar: +|Buscar fichero por una palabra +|Se aceptan comodines como : *.zip, *.gz, .tar* +| : *.zip es lo mismo que .zip +|Nombre de fichero a buscar: +|Buscar fichero por nombre +SN|Buscar nuevos ficheros desde tu £ltima llamada [S/n]: +|Fecha desde la que buscar [DD-MM-YYYY]: +|Buscar ficheros por fecha +|Nombre del fichero a enviar: +|Descargar Correo para lectura OFF-LINE +|No tienes permiso para enviar ficheros a esta  rea. +|No hay suficiente espacio libre para copiar este fichero +|ficheros( +|bytes) marcados para descargar. +|El fichero ya existe en este sistema +|Comienza a enviar ahora ... +|Env¡o no completado por: +SN|¨Quieres proteger con password el fichero enviado? [s/N]: +|­RECUERDA! La password es "CaSe SeNsITiVe!" +|Teclee la descripci¢n del fichero +|El tiempo del env¡o se te devuelve. ­Gracias por tu fichero! +|Copiando a directorio personal : +|No puedo abrir directorio para listar: +|Listado del directorio personal de +|Nombre del fichero a borrar: +|No puedes borrar ficheros ocultos ... +|Imposible borrar fichero ... +|Nombre no v lido, prueba otra vez ... +|El fichero no existe, prueba otra vez ... +|Area Descripci¢n Msgs. Pers. +| Areas de ficheros +|Teclee password del  rea: +|A¤adiendo BBS +|Nombre de la BBS: +|Respuesta obligatoria ... +|N£mero de tel‚fono: +|Nombre del SysOp: +|Software de BBS: +|Almacenamiento (GigaBytes): +|Velocidades: +SN|¨Quieres a¤adir una descripcion? [S/n]: +|Teclea la descripci¢n de +|Listado de BBSs +|n§ Nombre BBS N£mero Software GigaByte Veloc. +|Buscar una BBS +|Teclee 3 letras de la BBS que quiere buscar: +|Necesito al menos 3 letras ... +SN|¨Ver esta BBS? [S/n]: +|No puedo encontrar BBS ... +|Mostrar una BBS +|N£mero a listar: +|Registro inexistente +| Registro : +| Nombre BBS : +| N£mero : +| Software : +| GigaBytes : +| Velocidades : +| SysOp : +| Disponible : +| Fecha entrada : +| Entrada por : +|Borrar BBS +|Teclee n£mero de BBS a borrar: +|El Registro +|no te pertenece. +|ya estaba marcado para borrar +|queda marcado para borrar +|El SysOp eliminar  de la lista un d¡a de estos +|todos los registros marcados para borrar. +|Total de mensajes encontrados: +|­Comando desconocido! +|Guardando... +|Oneliners: Aparecer n de forma aleatoria en el men£ de la BBS. +|Los textos obscenos u ofensivos ser n borrados +|Teclee su 'oneliner' abajo. Máx 75 caracteres. +|Oneliner añadida +|nº A Fecha Usuario Descripci¢n +| # Descripci¢n +|Teclee n£mero a listar: +|Connectado en puerto +|Ficheros : +|Tama¤o : +|Protocolo : +|Actualizando contadores de descarga... +|­FALLO! +|Bytes +| n§ Area Activa Fichero Tam. Coste +|Si +|No +AT|(A)ctivar/desactivar, desactivar (T)odos, (ENTER) para seguir: +|N£mero de fichero, 1.. +|Marcado: +|No hay ficheros marcados. +|Replace +|Cargando BBS, espere por favor ... +|Areas de correo nuevas o borradas en +|Area Estado Tipo Descripci¢n +|Comprobar correo nuevo ACTIVADO +|Comprobar correo nuevo DESACTIVADO +|Borrar fichero: +SN|¨Est s seguro? [S/n]: +|Comprobar ficheros nuevos ACTIVADO +|Comprobar ficheros nuevos DESACTIVADO +|Editor a pantalla completa ACTIVADO +|Editor a pantalla completa DESACTIVADO +|Demasiados mensajes. S¢lo los primeros +|Pulsa (Enter) para seguir: +|Centrar +|Idioma: No puedo abrir fichero de idiomas. +|Elija su Idioma / Escolla idioma / Select language +|Elija Idioma: +|Idioma: +|El sistema va a crear tu cuenta UNIX. Se te preguntar n unos datos: +|Tu "Cuenta UNIX" ha sido creada. Puedes usarla para entrar en el 'Login'. +|Teclea un nombre de login (M ximo 8 caracteres) por ejemplo si te llamas +|'Elena Nito del Bosque ' puedes usar 'enitob', 'elenanb' o 'enbosque' +|login > +|Ese nombre de LOGIN ya existe. Elije otro... +|FATAL: No puedo abrir fichero de idioma +|El password de su Login será igual que el de la BBS. +|ERROR FATAL: No est s en el fichero de usuarios de la BBS. +| Ejecuta 'newuser' para crear un nuevo usuario +|New +|Local +|Netmail +|Echomail +|News +|E-Mail +|Del +|Ene +|Feb +|Mar +|Abr +|May +|Jun +|Jul +|Ago +|Sep +|Oct +|Nov +|Dic +|Autologout: ¨Te has dormido o es que se ha cortado? +|se empaquetar n. +|Alias (Enter si no quieres ninguno): +|Hala, Ya puedes usar la BBS +|Usuarios conectados a +|Nombre Puerto Estado Localidad +|'No molesten' DESACTIVADO +|'No molesten' ACTIVADO +|Navegando +|Descargando +|Enviando +|S. Mensajes +|Door Externa +|Charlando +|Lst. Ficheros +SN|¨Quieres descargar estos mensajes [S/N]? +|En el Banco +|Safe Door +|L. Conectados +|Desocupado +|Teclea usuario al que enviar un aviso: +|No hay usuario en +|No quiere ser molestado +|Teclea texto del aviso (Max 76 Caracteres) +|** Mensaje ** de +|Tu password ha caducado, nuevo password : +|Pulsa ENTER para seguir +|No puedes escribir, ­esta  rea es de Solo Lectura! +|!No se permite responder en esta  rea! +|Upload de correo Off-Line +|El paquete recibido no es v lido +|Comprimido con un compresor desconocido +|El compresor no est  disponible +|Paquete de correo de tipo desconocido +|Descarga de BlueWave +|Preparando paquete +|Comprimiendo con +|Descarga fallida +|Descarga completa +|Actualizando punteros de lectura +|Procesando paquete de respuestas BlueWave +|ERROR en el paquete +|Importando mensajes +|Imposible escribir en  rea +|Mensajes importados +|Procesando Configuraci¢n Off-Line +|Areas seleccionadas +|Procesando peticiones de ficheros +|Descarga de QWK +|Procesando paquete de respuestas QWK +|Descarga ASCII +SN|Crash [s/N]: +SN|Aviso: el nodo no es CM, enviar immediato [s/N]: +YN|Adjuntar fichero [s/N]: +|Fichero +|adjuntado +|El fichero no esta en +|buzon - Email entrante/saliente +|archivo - Email Archivado +|papelera - Papelera, Email borrado +|Area # +|minutos. diff --git a/lib/FAQ b/lib/FAQ new file mode 100644 index 00000000..a585c759 --- /dev/null +++ b/lib/FAQ @@ -0,0 +1,106 @@ +Frequently Asked Questions for memwatch + +Q. I'm not getting any log file! What's wrong?? + +A. Did you define MEMWATCH when compiling all files? + Did you include memwatch.h in all the files? + If you did, then...: + + Memwatch creates the file when it initializes. If you're not + getting the log file, it's because a) memwatch is not + initializing or b) it's initializing, but can't create the + file. + + Memwatch has two functions, mwInit() and mwTerm(), that + initialize and terminate memwatch, respectively. They are + nestable. You USUALLY don't need to call mwInit() and + mwTerm(), since memwatch will auto-initialize on the first + call to a memory function, and then add mwTerm() to the + atexit() list. + + You can call mwInit() and mwTerm() manually, if it's not + initializing properly or if your system doesn't support + atexit(). Call mwInit() as soon as you can, and mwTerm() at + the logical no-error ending of your program. Call mwAbort() + if the program is stopping due to an error; this will + terminate memwatch even if more than one call to mwTerm() is + outstanding. + + If you are using C++, remember that global and static C++ + objects constructors execute before main() when considering + where to put mwInit(). Also, their destructors execute after + main(). You may want to create a global object very early + with mwInit() in the constructor and mwTerm() in the + destructor. Too bad C++ does not guarantee initialization + order for global objects. + + If this didn't help, try adding a call to mwDoFlush(1) after + mwInit(). If THAT didn't help, then memwatch is unable to + create the log file. Check write permissions. + + If you can't use a log file, you can still use memwatch by + redirecting the output to a function of your choice. See the + next question. + +Q. I'd like memwatch's output to pipe to my fave debugger! How? + +A. Call mwSetOutFunc() with the addres of a "void func(int c)" + function. You should also consider doing something about + the ARI handler, see memwatch.h for more details about that. + +Q. Why isn't there any C++ support? + +A. Because C++ is for sissies! =) Just kidding. + C++ comes with overridable allocation/deallocation + built-in. You can define your own new/delete operators + for any class, and thus circumvent memwatch, or confuse + it to no end. Also, the keywords "new" and "delete" may + appear in declarations in C++, making the preprocessor + replacement approach shaky. You can do it, but it's not + very stable. + + If someone were to write a rock solid new/delete checker + for C++, there is no conflict with memwatch; use them both. + +Q. I'm getting "WILD free" errors, but the code is bug-free! + +A. If memwatch's free() recieves a pointer that wasn't allocated + by memwatch, a "WILD free" message appears. If the source of + the memory buffer is outside of memwatch (a non-standard + library function, for instance), you can use mwFree_() to + release it. mwFree_() calls free() on the pointer given if + memwatch can't recognize it, instead of blocking it. + + Another source of "WILD free" messages is that if memwatch + is terminated before all memory allocated is freed, memwatch + will have forgotten about it, and thus generate the errors. + This is commonly caused by having memwatch auto-initialize, + and then using atexit() to clean up. When auto-initializing, + memwatch registers mwTerm() with atexit(), but if mwTerm() + runs before all memory is freed, then you will get "unfreed" + and "WILD free" messages when your own atexit()-registered + cleanup code runs, and frees the memory. + +Q. I'm getting "unfreed" errors, but the code is bug-free! + +A. You can get erroneous "unfreed" messages if memwatch + terminates before all memory has been freed. Try using + mwInit() and mwTerm() instead of auto-initialization. + + If you _are_ using mwInit() and mwTerm(), it may be that + some code in your program executes before mwInit() or + after mwTerm(). Make sure that mwInit() is the first thing + executed, and mwTerm() the last. + +Q. When compiling memwatch I get these 'might get clobbered' + errors, and something about a longjmp() inside memwatch. + +A. You are using a non-Win32 platform, and most likely using + gcc or egcs, and is probably running with the highest + possible warning levels. This is a Good Thing. + + Unfortunately, it seems some compilers get a bit too + paranoid at those levels. There is nothing wrong with + memwatch's code. Nothing that matters will get + clobbered, if the compiler adheres to the ANSI C + standard. Just ignore the warnings. diff --git a/lib/Makefile.am b/lib/Makefile.am new file mode 100644 index 00000000..cff62867 --- /dev/null +++ b/lib/Makefile.am @@ -0,0 +1,35 @@ +## Makefile.am for mbsebbs ./lib + +SUBDIRS = . + +EXTRA_DIST = README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org + +CONFIG_CLEAN_FILES = ftscprod.c + +noinst_HEADERS = libs.h structs.h records.h mbse.h ansi.h bluewave.h + +noinst_LIBRARIES = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a + +libclcomm_a_SOURCES = clcomm.c client.c crc.c semafore.c signame.c clcomm.h + +libcommon_a_SOURCES = ftscprod.c attach.c charconv_utf.c falists.c hdr.c msgflags.c parsedate.c rfcmsg.c unpacker.c \ +batchrd.c charset.c ftn.c nodelist.c pktname.c \ +charconv.c dostran.c ftnmsg.c mbfile.c nodelock.c rawio.c strcasestr.c \ +charconv_hz.c execute.c expipe.c getheader.c mime.c noderecord.c rfcaddr.c strutil.c \ +charconv_jp.c faddr.c gmtoffset.c packet.c rfcdate.c term.c common.h + +libdbase_a_SOURCES = dbcfg.c dbdupe.c dbftn.c dbmsgs.c dbnode.c dbtic.c dbuser.c \ +dbcfg.h dbdupe.h dbftn.h dbmsgs.h dbnode.h dbtic.h dbuser.h + +libmsgbase_a_SOURCES = jam.h jammsg.c jammsg.h jamsys.h msg.c msg.h msgtext.c msgtext.h + +libmbinet_a_SOURCES = mbinet.h nntp.c pop3.c smtp.c + +libmemwatch_a_SOURCES = memwatch.c memwatch.h + +BUILT_SOURCES = ftscprod.c + +ftscprod.c: ftscprod.??? + @AWK@ -F, -f mkprod.awk ftscprod.??? >ftscprod.c + + diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 00000000..4484a319 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,504 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = README ftscprod.006 mkprod.awk FAQ README.memwatch USING test.c memwatch.c.org + +CONFIG_CLEAN_FILES = ftscprod.c + +noinst_HEADERS = libs.h structs.h records.h mbse.h ansi.h bluewave.h + +noinst_LIBRARIES = libclcomm.a libcommon.a libdbase.a libmsgbase.a libmbinet.a libmemwatch.a + +libclcomm_a_SOURCES = clcomm.c client.c crc.c semafore.c signame.c clcomm.h + +libcommon_a_SOURCES = ftscprod.c attach.c charconv_utf.c falists.c hdr.c msgflags.c parsedate.c rfcmsg.c unpacker.c batchrd.c charset.c ftn.c nodelist.c pktname.c charconv.c dostran.c ftnmsg.c mbfile.c nodelock.c rawio.c strcasestr.c charconv_hz.c execute.c expipe.c getheader.c mime.c noderecord.c rfcaddr.c strutil.c charconv_jp.c faddr.c gmtoffset.c packet.c rfcdate.c term.c common.h + + +libdbase_a_SOURCES = dbcfg.c dbdupe.c dbftn.c dbmsgs.c dbnode.c dbtic.c dbuser.c dbcfg.h dbdupe.h dbftn.h dbmsgs.h dbnode.h dbtic.h dbuser.h + + +libmsgbase_a_SOURCES = jam.h jammsg.c jammsg.h jamsys.h msg.c msg.h msgtext.c msgtext.h + +libmbinet_a_SOURCES = mbinet.h nntp.c pop3.c smtp.c + +libmemwatch_a_SOURCES = memwatch.c memwatch.h + +BUILT_SOURCES = ftscprod.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libclcomm_a_LIBADD = +libclcomm_a_OBJECTS = clcomm.o client.o crc.o semafore.o signame.o +libcommon_a_LIBADD = +libcommon_a_OBJECTS = ftscprod.o attach.o charconv_utf.o falists.o \ +hdr.o msgflags.o parsedate.o rfcmsg.o unpacker.o batchrd.o charset.o \ +ftn.o nodelist.o pktname.o charconv.o dostran.o ftnmsg.o mbfile.o \ +nodelock.o rawio.o strcasestr.o charconv_hz.o execute.o expipe.o \ +getheader.o mime.o noderecord.o rfcaddr.o strutil.o charconv_jp.o \ +faddr.o gmtoffset.o packet.o rfcdate.o term.o +libdbase_a_LIBADD = +libdbase_a_OBJECTS = dbcfg.o dbdupe.o dbftn.o dbmsgs.o dbnode.o dbtic.o \ +dbuser.o +libmsgbase_a_LIBADD = +libmsgbase_a_OBJECTS = jammsg.o msg.o msgtext.o +libmbinet_a_LIBADD = +libmbinet_a_OBJECTS = nntp.o pop3.o smtp.o +libmemwatch_a_LIBADD = +libmemwatch_a_OBJECTS = memwatch.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(libclcomm_a_SOURCES) $(libcommon_a_SOURCES) $(libdbase_a_SOURCES) $(libmsgbase_a_SOURCES) $(libmbinet_a_SOURCES) $(libmemwatch_a_SOURCES) +OBJECTS = $(libclcomm_a_OBJECTS) $(libcommon_a_OBJECTS) $(libdbase_a_OBJECTS) $(libmsgbase_a_OBJECTS) $(libmbinet_a_OBJECTS) $(libmemwatch_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libclcomm.a: $(libclcomm_a_OBJECTS) $(libclcomm_a_DEPENDENCIES) + -rm -f libclcomm.a + $(AR) cru libclcomm.a $(libclcomm_a_OBJECTS) $(libclcomm_a_LIBADD) + $(RANLIB) libclcomm.a + +libcommon.a: $(libcommon_a_OBJECTS) $(libcommon_a_DEPENDENCIES) + -rm -f libcommon.a + $(AR) cru libcommon.a $(libcommon_a_OBJECTS) $(libcommon_a_LIBADD) + $(RANLIB) libcommon.a + +libdbase.a: $(libdbase_a_OBJECTS) $(libdbase_a_DEPENDENCIES) + -rm -f libdbase.a + $(AR) cru libdbase.a $(libdbase_a_OBJECTS) $(libdbase_a_LIBADD) + $(RANLIB) libdbase.a + +libmsgbase.a: $(libmsgbase_a_OBJECTS) $(libmsgbase_a_DEPENDENCIES) + -rm -f libmsgbase.a + $(AR) cru libmsgbase.a $(libmsgbase_a_OBJECTS) $(libmsgbase_a_LIBADD) + $(RANLIB) libmsgbase.a + +libmbinet.a: $(libmbinet_a_OBJECTS) $(libmbinet_a_DEPENDENCIES) + -rm -f libmbinet.a + $(AR) cru libmbinet.a $(libmbinet_a_OBJECTS) $(libmbinet_a_LIBADD) + $(RANLIB) libmbinet.a + +libmemwatch.a: $(libmemwatch_a_OBJECTS) $(libmemwatch_a_DEPENDENCIES) + -rm -f libmemwatch.a + $(AR) cru libmemwatch.a $(libmemwatch_a_OBJECTS) $(libmemwatch_a_LIBADD) + $(RANLIB) libmemwatch.a + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +attach.o: attach.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +batchrd.o: batchrd.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +charconv.o: charconv.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h clcomm.h +charconv_hz.o: charconv_hz.c libs.h ../config.h memwatch.h structs.h \ + common.h clcomm.h +charconv_jp.o: charconv_jp.c libs.h ../config.h memwatch.h structs.h \ + common.h +charconv_utf.o: charconv_utf.c libs.h ../config.h memwatch.h structs.h \ + common.h +charset.o: charset.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +clcomm.o: clcomm.c libs.h ../config.h memwatch.h clcomm.h +client.o: client.c libs.h ../config.h memwatch.h clcomm.h +crc.o: crc.c libs.h ../config.h memwatch.h clcomm.h +dbcfg.o: dbcfg.c libs.h ../config.h memwatch.h mbse.h structs.h \ + records.h dbcfg.h +dbdupe.o: dbdupe.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + dbdupe.h +dbftn.o: dbftn.c libs.h ../config.h memwatch.h structs.h records.h \ + dbcfg.h dbftn.h +dbmsgs.o: dbmsgs.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbmsgs.h +dbnode.o: dbnode.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbnode.h +dbtic.o: dbtic.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h dbcfg.h dbtic.h +dbuser.o: dbuser.c libs.h ../config.h memwatch.h structs.h records.h \ + dbcfg.h dbuser.h +dostran.o: dostran.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h +execute.o: execute.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +expipe.o: expipe.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +faddr.o: faddr.c libs.h ../config.h memwatch.h structs.h common.h +falists.o: falists.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +ftn.o: ftn.c libs.h ../config.h memwatch.h structs.h records.h clcomm.h \ + dbftn.h common.h +ftnmsg.o: ftnmsg.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +ftscprod.o: ftscprod.c libs.h ../config.h memwatch.h structs.h common.h +getheader.o: getheader.c libs.h ../config.h memwatch.h structs.h \ + records.h clcomm.h common.h +gmtoffset.o: gmtoffset.c libs.h ../config.h memwatch.h structs.h \ + common.h +hdr.o: hdr.c libs.h ../config.h memwatch.h structs.h common.h +jammsg.o: jammsg.c libs.h ../config.h memwatch.h clcomm.h msgtext.h \ + msg.h jam.h jamsys.h jammsg.h +mbfile.o: mbfile.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +memwatch.o: memwatch.c ../config.h libs.h memwatch.h memwatch.h +mime.o: mime.c libs.h ../config.h memwatch.h structs.h clcomm.h common.h +msg.o: msg.c libs.h ../config.h memwatch.h msgtext.h msg.h jammsg.h +msgflags.o: msgflags.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +msgtext.o: msgtext.c libs.h ../config.h memwatch.h msgtext.h msg.h +nntp.o: nntp.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +nodelist.o: nodelist.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +nodelock.o: nodelock.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +noderecord.o: noderecord.c libs.h ../config.h memwatch.h structs.h \ + records.h dbnode.h common.h +packet.o: packet.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h dbnode.h +parsedate.o: parsedate.c libs.h ../config.h memwatch.h structs.h \ + common.h +pktname.o: pktname.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +pop3.o: pop3.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +rawio.o: rawio.c libs.h ../config.h memwatch.h structs.h common.h +rfcaddr.o: rfcaddr.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h +rfcdate.o: rfcdate.c libs.h ../config.h memwatch.h structs.h common.h \ + clcomm.h +rfcmsg.o: rfcmsg.c libs.h ../config.h memwatch.h structs.h records.h \ + common.h clcomm.h +semafore.o: semafore.c libs.h ../config.h memwatch.h structs.h clcomm.h \ + common.h +signame.o: signame.c libs.h ../config.h memwatch.h clcomm.h +smtp.o: smtp.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h mbinet.h +strcasestr.o: strcasestr.c libs.h ../config.h memwatch.h +strutil.o: strutil.c libs.h ../config.h memwatch.h structs.h common.h +term.o: term.c libs.h ../config.h memwatch.h structs.h ansi.h records.h \ + common.h +unpacker.o: unpacker.c libs.h ../config.h memwatch.h structs.h records.h \ + clcomm.h common.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(LIBRARIES) $(HEADERS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs-am \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +ftscprod.c: ftscprod.??? + @AWK@ -F, -f mkprod.awk ftscprod.??? >ftscprod.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lib/README b/lib/README new file mode 100644 index 00000000..f5a3b123 --- /dev/null +++ b/lib/README @@ -0,0 +1,35 @@ + Database structures. + + +Most databases have a structure with a header record. The header record +is at the beginning of the datafile and contains information about the +size of the header record and size of the database records. When a data +file is opened for reading the first thing to read the header record. +The field recsize contains the size of the datarecords and the field +hdrsize the offset to the first datarecord in the file. + +If in the structure the size of the datarecords changes (grows), we can +allways read the old format in the correct way. + +When a datafile is changed the datafile has to be rewritten completly. +Of course the new format is used then, and the new size must be stored in +the header. + +The advantage of this technique is that updates can be performed automatic. +There is no need for free space for future use in the datarecords, the files +are thus smaller. + + +One other important thing, with some DOS based bbs'es, mail/tic processors +are using index files together with the data files to speed up the search in +the databases. Also some of them use internal memory cache for the data records. +I choose not to do this for two reasons, Linux like other Unices handles +file I/O very fast and when your system is not low on memory the kernel will +buffer all disk I/O in memory. Also Linux disks are very low fragmented due to +the design of the ext2fs. Whith all this in mind, using index files is only +extra overhead. +However, because of this you should not put the data files on a msdos +dos partition or on a nfs server. + +The only exeption that uses index files are the nodelists. + diff --git a/lib/README.memwatch b/lib/README.memwatch new file mode 100644 index 00000000..a15ca538 --- /dev/null +++ b/lib/README.memwatch @@ -0,0 +1,98 @@ +README for MEMWATCH 2.62 + + This file should be enough to get you started, and should be + enough for small projects. For more info, see the files USING + and the FAQ. If this is not enough, see memwatch.h, which is + well documented. + + If you choose to use memwatch to validate your projects, I + would love to hear about it. Please drop me a line at + johan@link-data.com about the project itself, the hardware, + operating system, compiler and any URL(s) you feel is + appropriate. I will then post it at: + + http://www.link-data.com/memwatchusers.html + +***** To run the test program: + + Look at the source code for test.c first. It does some really + nasty things, and I want you to be aware of that. If memwatch + can't capture SIGSEGV (General Protection Fault for Windoze), + your program will dump core (crash for Windoze). + + Once you've done that, you can build the test program. + + Linux and other *nixes with gcc: + + gcc -o test -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c + + Windows 95, Windows NT with MS Visual C++: + + cl -DMEMWATCH -DMEMWATCH_STDIO test.c memwatch.c + + Then simply run the test program. + + ./test + + +***** Quick-start instructions: + + 1. Make sure that memwatch.h is included in all of the + source code files. If you have an include file that + all of the source code uses, you might be able to include + memwatch.h from there. + + 2. Recompile the program with MEMWATCH defined. See your + compiler's documentation if you don't know how to do this. + The usual switch looks like "-DMEMWATCH". To have MEMWATCH + use stderr for some output (like, "Abort, Retry, Ignore?"), + please also define MW_STDIO (or MEMWATCH_STDIO, same thing). + + 3. Run the program and examine the output in the + log file "memwatch.log". If you didn't get a log file, + you probably didn't do step 1 and 2 correctly, or your + program crashed before memwatch flushed the file buffer. + To have memwatch _always_ flush the buffer, add a call + to "mwDoFlush(1)" at the top of your main function. + + 4. There is no fourth step... but remember that there + are limits to what memwatch can do, and that you need + to be aware of them: + +***** Limits to memwatch: + + Memwatch cannot catch all wild pointer writes. It can catch + those it could make itself due to your program trashing + memwatch's internal data structures. It can catch, sort of, + wild writes into No Mans Land buffers (see the header file for + more info). Anything else and you're going to get core dumped, + or data corruption if you're lucky. + + There are other limits of course, but that one is the most + serious one, and the one that you're likely to be suffering + from. + +***** Can use memwatch with XXXXX? + + Probably the answer is yes. It's been tested with several + different platforms and compilers. It may not work on yours + though... but there's only one way to find out. + +***** Need more assistance? + + I don't want e-mail on "how to program in C", or "I've got a + bug, help me". I _do_ want you to send email to me if you + find a bug in memwatch, or if it won't compile cleanly on your + system (assuming it's an ANSI-C compiler of course). + + If you need help with using memwatch, read the header file. + If, after reading the header file, you still can't resolve the + problem, please mail me with the details. + + I can be reached at "johan@link-data.com". + + The latest version of memwatch should be found at + "http://www.link-data.com/". + + Johan Lindh + diff --git a/lib/USING b/lib/USING new file mode 100644 index 00000000..571fde7b --- /dev/null +++ b/lib/USING @@ -0,0 +1,169 @@ +Using memwatch +============== + +What is it? + + Memwatch is primarily a memory leak detector for C. Besides + detecting leaks, it can do a bunch of other stuff, but lets + stay to the basics. If you _really_ want to know all the + gory details, you should check out the header file, + memwatch.h, and the source code. It's actually got some + comments! (Whoa, what a concept!) + +How do I get the latest version? + + http://www.link-data.com/sourcecode.html + ftp://ftp.link-data.com/pub/memwatch/ + +How does it work? + + Using the C preprocessor, memwatch replaces all your + programs calls to ANSI C memory allocation functions with + calls to it's own functions, which keeps a record of all + allocations. + + Memwatch is very unobtrusive; unless the define MEMWATCH is + defined, memwatch removes all traces of itself from the + code (using the preprocessor). + + Memwatch normally writes it's data to the file + memwatch.log, but this can be overridden; see the section + on I/O, later. + +Initialization and cleanup + + In order to do it's work in a timely fashion, memwatch + needs to do some startup and cleanup work. mwInit() + initializes memwatch and mwTerm() terminates it. Memwatch + can auto-initialize, and will do so if you don't call + mwInit() yourself. If this is the case, memwatch will use + atexit() to register mwTerm() to the atexit-queue. + + The auto-init technique has a caveat; if you are using + atexit() yourself to do cleanup work, memwatch may + terminate before your program is done. To be on the safe + side, use mwInit() and mwTerm(). + + mwInit() and mwTerm() is nestable, so you can call mwInit() + several times, requiring mwTerm() to be called an equal + number of times to terminate memwatch. + + In case of the program aborting in a controlled way, you + may want to call mwAbort() instead of mwTerm(). mwAbort() + will terminate memwatch even if there are outstanding calls + to mwTerm(). + +I/O operations + + During normal operations, memwatch creates a file named + memwatch.log. Sometimes, memwatch.log can't be created; + then memwatch tries to create files name memwatNN.log, + where NN is between 01 and 99. If that fails, no log will + be produced. + + If you can't use a file log, or don't want to, no worry. + Just call mwSetOutFunc() with the address of a "void + func(int c)" function, and all output will be directed + there, character by character. + + Memwatch also has an Abort/Retry/Ignore handler that is + used when an ASSERT or VERIFY fails. The default handler + does no I/O, but automatically aborts the program. You can + use any handler you want; just send the address of a "int + func(const char*)" to mwSetAriFunc(). For more details on + that, see memwatch.h. + +TRACE/ASSERT/VERIFY macros + + Memwatch defines (if not already defined) the macros TRACE, + ASSERT and VERIFY. If you are already using macros with + these names, memwatch 2.61 and later will not override + them. Memwatch 2.61 and later will also always define the + macros mwTRACE, mwASSERT and mwVERIFY, so you can use these + to make sure you're talking to memwatch. Versions previous + to 2.61 will OVERRIDE TRACE, ASSERT and VERIFY. + + To make sure that existing TRACE, ASSERT and VERIFY macros + are preserved, you can define MW_NOTRACE, MW_NOASSERT and + MW_NOVERIFY. All versions of memwatch will abide by these. + +Stress-testing the application + + You can simulate low-memory conditions using mwLimit(). + mwLimit() takes the maximum number of bytes to be + allocated; when the limit is hit, allocation requests will + fail, and a "limit" message will be logged. + + If you hit a real low-memory situation, memwatch logs that + too. Memwatch itself has some reserve memory tucked away so + it should continue running even in the worst conditions. + +Hunting down wild writes and other Nasty Things + + Wild writes are usually caused by using pointers that arent + initialized, or that were initialized, but then the memory + they points to is moved or freed. The best way to avoid + these kind of problems is to ALWAYS initialize pointers to + NULL, and after freeing a memory buffer, setting all + pointers that pointed to it to NULL. + + To aid in tracking down uninitialized pointers memwatch + zaps all memory with certain values. Recently allocated + memory (unless calloc'd, of course), contains 0xFE. + Recently freed memory contains 0xFD. So if your program + crashes when using memwatch and not without memwatch, it's + most likely because you are not initializing your allocated + buffers, or using the buffers after they've been freed. + + In the event that a wild pointer should damage memwatch's + internal data structures, memwatch employs checksums, + multiple copies of some values, and can also repair it's + own data structures. + + If you are a paranoid person, and as programmer you should + be, you can use memwatch's mwIsReadAddr() and + mwIsSafeAddr() functions to check the accessibility of + memory. These are implemented for both ANSI C systems and + Win32 systems. Just put an mwASSERT() around the check and + forget about it. + +Can I help? + + Well, sure. For instance, I like memwatch to compile + without any warnings or errors. If you are using an ANSI C + compliant compiler, and are getting warnings or errors, + please mail me the details and instructions on how to fix + them, if you can. + + Another thing you can do if you decide to use memwatch is + to mail me the name of the project(s) (and URL, if any), + hardware and operating system, compiler and what user + (organization). I will then post this info on the list of + memwatch users. + (http://www.link-data.com/memwatchusers.html) + +Top five problems using memwatch + + 5. Passed a non-memwatch allocated pointer to memwatch's + free(). Symtom: Causes an erroneous "WILD free" log + entry to appear. Cure: Either include memwatch.h for + the file that allocates, or use mwFree_() to free it. + + 4. Relied on auto-initialization when using atexit(). + Symptom: Causes incorrect "unfreed" and "WILD free" + messages. Cure: Use mwInit() and mwTerm(). + + 3. Forgot to include memwatch.h in all files. Symptom: + Tends to generate "WILD free" and "unfreed" messages. + Cure: Make sure to include memwatch.h! + + 2. No write permissions in currect directory. Symptom: + Seems like memwatch 'just aint working'. Cure: Use + mwSetOutFunc() to redirect output. + + ...and the number one problem is... + + 1. Didn't define MEMWATCH when compiling. Symptom: + Memwatch dutifully disables itself. Cure: Try adding + -DMEMWATCH to the command line. + diff --git a/lib/ansi.h b/lib/ansi.h new file mode 100644 index 00000000..f52e90fc --- /dev/null +++ b/lib/ansi.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * + * File ..................: mbse.h + * Purpose ...............: ANSI Screen definitions + * Last modification date : 10-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _ANSI_H +#define _ANSI_H + + +#define ANSI_RED "\x1B[31;1m" +#define ANSI_YELLOW "\x1B[33;1m" +#define ANSI_BLUE "\x1B[34;1m" +#define ANSI_GREEN "\x1B[32;1m" +#define ANSI_WHITE "\x1B[37;1m" +#define ANSI_CYAN "\x1B[36;1m" +#define ANSI_MAGENTA "\x1B[35m" + +#define ANSI_HOME "\x1B[H" +#define ANSI_UP "\x1B[A" +#define ANSI_DOWN "\x1B[B" +#define ANSI_RIGHT "\x1B[C" +#define ANSI_LEFT "\x1B[D" + +#define ANSI_BOLD "\x1B[1m" +#define ANSI_NORMAL "\x1B[0m" +#define ANSI_CLEAR "\x1B[2J" +#define ANSI_CLREOL "\x1B[K" + + +#endif diff --git a/lib/attach.c b/lib/attach.c new file mode 100644 index 00000000..29655218 --- /dev/null +++ b/lib/attach.c @@ -0,0 +1,113 @@ +/***************************************************************************** + * + * File ..................: common/attach.c + * Purpose ...............: Attach files to outbound + * Last modification date : 25-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + + +int attach(faddr noden, char *ofile, int mode, char flavor) +{ + FILE *fp; + char *flofile; + + if (ofile == NULL) + return FALSE; + + flofile = calloc(PATH_MAX, sizeof(char)); + sprintf(flofile, "%s", floname(&noden, flavor)); + + /* + * Check if outbound directory exists and + * create if it doesn't exist. + */ + mkdirs(ofile); + + /* + * Attach file to .flo + * + * Not that mbcico when connected to a node opens the file "r+", + * locks it with fcntl(F_SETLK), F_RDLCK, whence=0, start=0L, len=0L. + * It seems that this lock is released after the files in the .flo + * files are send. I don't know what will happen if we add entries + * to the .flo files, this must be tested! + */ + if ((fp = fopen(flofile, "a+")) == NULL) { + WriteError("$Can't open %s", flofile); + WriteError("May be locked by mbcico"); + free(flofile); + return FALSE; + } + + switch (mode) { + case LEAVE: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "%s\r\n", ofile); + } + break; + case KFS: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "^%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "^%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "^%s\r\n", ofile); + } + break; + + case TFS: + if (strlen(CFG.dospath)) { + if (CFG.leavecase) + fprintf(fp, "#%s\r\n", Unix2Dos(ofile)); + else + fprintf(fp, "#%s\r\n", tu(Unix2Dos(ofile))); + } else { + fprintf(fp, "#%s\r\n", ofile); + } + break; + } + + fclose(fp); + free(flofile); + return TRUE; +} + + + diff --git a/lib/batchrd.c b/lib/batchrd.c new file mode 100644 index 00000000..6b2c8b33 --- /dev/null +++ b/lib/batchrd.c @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * File ..................: common/batchrd.c + * Purpose ...............: Batch reading + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +static long counter = 0L; +static int batchmode = -1; +int usetmp = 0; + +char *bgets(char *buf, int count, FILE *fp) +{ + if (usetmp) { + return fgets(buf,count,fp); + } + + if ((batchmode == 1) && (counter > 0L) && (counter < (long)(count-1))) + count=(int)(counter+1L); + if (fgets(buf,count,fp) == NULL) + return NULL; + + switch (batchmode) { + case -1: if (!strncmp(buf,"#! rnews ",9) || !strncmp(buf,"#!rnews ",8)) { + batchmode=1; + sscanf(buf+8,"%ld",&counter); + Syslog('m', "first chunk of input batch: %ld",counter); + if (counter < (long)(count-1)) + count=(int)(counter+1L); + if (fgets(buf,count,fp) == NULL) + return NULL; + else { + counter -= strlen(buf); + return(buf); + } + } else { + batchmode=0; + return buf; + } + + case 0: return buf; + + case 1: if (counter <= 0L) { + while (strncmp(buf,"#! rnews ",9) && strncmp(buf,"#!rnews ",8)) { + Syslog('+', "batch out of sync: %s",buf); + if (fgets(buf,count,fp) == NULL) + return NULL; + } + sscanf(buf+8,"%ld",&counter); + Syslog('m', "next chunk of input batch: %ld",counter); + return NULL; + } else { + counter -= (long)strlen(buf); + Syslog('m', "bread \"%s\", %ld left of this chunk", buf,counter); + return buf; + } + } + return buf; +} + + diff --git a/lib/bluewave.h b/lib/bluewave.h new file mode 100644 index 00000000..dc3d2027 --- /dev/null +++ b/lib/bluewave.h @@ -0,0 +1,1162 @@ +/*****************************************************************************/ +/* */ +/* The Blue Wave Offline Mail System Packet Structures */ +/* Copyright 1990-1995 by Cutting Edge Computing. All rights reserved. */ +/* Created by George Hatchew */ +/* */ +/* Version 3 - November 30, 1995 */ +/* */ +/* --------------------------------------------------------- */ +/* DISTRIBUTION OF THIS FILE IS LIMITED BY THE TERMS */ +/* SPECIFIED IN THE BLUE WAVE STRUCTURE DOCUMENTATION! */ +/* --------------------------------------------------------- */ +/* */ +/* These data structures should be usable with any C compiler that */ +/* supports the 1989 ANSI/ISO C language standard. They are NOT */ +/* guaranteed to be usable with older compilers, which largely relied */ +/* on the definition of the language as specified in Kernighan & Ritchie's */ +/* _The C Programming Language (1st Edition)_. */ +/* */ +/*****************************************************************************/ + +#ifndef __BLUEWAVE_H /* An extra safeguard to prevent this header from */ +#define __BLUEWAVE_H /* being included twice in the same source file */ + + +#define PACKET_LEVEL 3 /* The current mail packet revision level, */ + /* used in the "ver" field of the *.INF */ + /* file header. */ + + +/* +** This header defines the data structures for the following files in the +** official Blue Wave offline mail specification: +** +** Door: *.INF BBS and message area information +** *.MIX Quick index to *.FTI records +** *.FTI Information for all packet messages +** *.DAT Packet message text +** +** Reader: *.NET NetMail reply message information +** *.UPI Information for all other reply messages +** *.UPL Reply message information +** (alternative to *.NET and *.UPI) +** *.REQ List of files to download from BBS +** *.PDQ Offline door configuration information +** (packet version 2 and earlier) +** *.OLC Offline door configuration information +** (packet version 3 and later) +** +** Misc: *.MSG Fido-style message header +** (used *only* in the *.NET structure) +** *.XTI Extended message packet information +** (not an official part of the Blue Wave +** packet specification; is used by the Blue +** Wave reader only) +** +** The door files (plus individual files for BBS bulletins) comprise a Blue +** Wave message packet, and the reader files (plus individual files for each +** message) comprise a Blue Wave reply packet. +** +** In order to cover ALL BASES, and to be able to say that you were warned, +** *ALL* unused fields should be set to ASCII NUL (0). Any future +** implementation of reserved fields will rely on the premise that the field +** will be 0 if not implemented! The same warning follows for BITMAPPED +** fields. If a bit is not implemented or is not used, TURN IT OFF (0). +** (Clearing an entire structure can be easily accomplished via the memset() +** function. Example: "memset(&ftirec, 0, sizeof(FTI_REC))".) +*/ + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>>>>> DATA TYPE DEFINITIONS <<<<<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** The data type definitions below help make these structures a little more +** universal between environments. The 8-bit, 16-bit, and 32-bit data types +** defined below can be used as-is with virtually all MS-DOS and OS/2 C/C++ +** compilers, but can be changed if necessary should your compiler define +** data types in a different fashion. (Note that the tCHAR and tINT types +** are currently not used; they are included simply for completeness.) +** +** If you are programming for a system that employs a CPU which stores multi- +** byte integers in a manner other than in Intel format (LSB-MSB, or "little +** endian"), simply #define BIG_ENDIAN before #including this header. As +** shown below, this will define the data types as arrays of bytes; the +** drawback is that *YOU* will have to write functions to convert the data, +** since the Blue Wave packet specification requires the data to be in Intel- +** style little-endian format. +** +** IMPORTANT NOTE ABOUT COMPILERS AND STRUCTURES: +** All structures *must* be "packed" (i.e., the compiler MUST NOT insert +** padding bytes between structure elements in order to force elements onto +** word boundaries). The Blue Wave products expect them to be packed; if +** they aren't, you're bound to get some *very* interesting results. +*/ + +//#ifdef BIG_ENDIAN + +//typedef signed char tCHAR; /* 8 bit signed values */ +//typedef unsigned char tBYTE; /* 8 bit unsigned values */ +//typedef unsigned char tINT[2]; /* little-endian 16 bit signed */ +//typedef unsigned char tWORD[2]; /* little-endian 16 bit unsigned */ +//typedef unsigned char tLONG[4]; /* little-endian 32 bit signed */ +//typedef unsigned char tDWORD[4]; /* little-endian 32 bit unsigned */ + +//#else + +typedef signed char tCHAR; /* 8 bit signed values */ +typedef unsigned char tBYTE; /* 8 bit unsigned values */ +typedef signed short tINT; /* 16 bit signed values */ +typedef unsigned short tWORD; /* 16 bit unsigned values */ +typedef signed long tLONG; /* 32 bit signed values */ +typedef unsigned long tDWORD; /* 32 bit unsigned values */ + +//#endif + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>>> DOOR DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.INF +** +** Description: The *.INF file is the source of information for just about +** everything from the host BBS, as well as definitions for +** all of the message areas that are available to the user +** and their status (Local, EchoMail, NetMail, Read Only, +** etc.). +** +** File format: INF_HEADER { only included one time! } +** INF_AREA_INFO { repeated for as many msg bases } +** INF_AREA_INFO { as are available to the user } +** ... +*/ + +/* Bit-masks for INF_HEADER.UFLAGS field */ + +#define INF_HOTKEYS 0x0001 /* User uses "hotkeys" in door prompts */ +#define INF_XPERT 0x0002 /* Short menus displayed in door */ +#define INF_RES1 0x0004 /* RESERVED -- DO NOT USE! */ +#define INF_GRAPHICS 0x0008 /* Enable ANSI control sequences in door */ +#define INF_NOT_MY_MAIL 0x0010 /* Do not bundle mail from user */ +#define INF_EXT_INFO 0x0020 /* Download extended info with messages */ + /* (* VERSION 3 AND LATER ONLY *) */ +#define INF_NUMERIC_EXT 0x0040 /* Use numeric extensions on packets */ + /* (* VERSION 3 AND LATER ONLY *) */ + +/* Bit-masks for INF_HEADER.NETMAIL_FLAGS field */ + +#define INF_CAN_CRASH 0x0002 /* Allow Crash status */ +#define INF_CAN_ATTACH 0x0010 /* Allow File Attach messages */ +#define INF_CAN_KSENT 0x0080 /* Allow Kill/Sent status */ +#define INF_CAN_HOLD 0x0200 /* Allow Hold status */ +#define INF_CAN_IMM 0x0400 /* Allow Immediate status */ +#define INF_CAN_FREQ 0x0800 /* Allow File Request messages */ +#define INF_CAN_DIRECT 0x1000 /* Allow Direct status */ + +/* Bit-masks for INF_HEADER.CTRL_FLAGS field */ + +#define INF_NO_CONFIG 0x0001 /* Do not allow offline configuration */ +#define INF_NO_FREQ 0x0002 /* Do not allow file requesting */ + +/* Values for INF_HEADER.FILE_LIST_TYPE field */ + +#define INF_FLIST_NONE 0 /* Door does not generate a list file */ +#define INF_FLIST_TEXT 1 /* Door generates plain text list file */ +#define INF_FLIST_ANSI 2 /* Door generates ANSI list file */ + +typedef struct /* INF_HEADER */ +{ + tBYTE ver; /* Packet version type (currently 2) */ + tBYTE readerfiles[5][13]; /* Files to be displayed by reader */ + tBYTE regnum[9]; /* User's registration number */ + tBYTE mashtype; /* Currently unused (door fills with 0) */ + /* Reserved for Blue Wave reader to store */ + /* the compression type the packet uses. */ + tBYTE loginname[43]; /* Name user types at BBS login */ + tBYTE aliasname[43]; /* User's "other" name */ + tBYTE password[21]; /* Password */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, */ + /* but it does prevent "TYPE *.INF" from */ + /* showing the password. */ + tBYTE passtype; /* Password type */ + /* 0=none 1=door 2=reader 3=both */ + tWORD zone; /* Main network address of host BBS */ + tWORD net; /* (zone:net/node.point) */ + tWORD node; + tWORD point; + tBYTE sysop[41]; /* Name of SysOp of host BBS */ + tWORD ctrl_flags; /* Flags to control reader capabilities */ + /* (* VERSION 3 AND LATER ONLY *) */ + tBYTE systemname[65]; /* Name of host BBS */ + tBYTE maxfreqs; /* Max number of file requests allowed */ + tWORD is_QWK; /* Whether *.INF belongs to a QWK packet */ + tBYTE obsolete2[4]; /* OBSOLETE -- DO NOT USE! */ + tWORD uflags; /* Bit-mapped door options/toggles */ + tBYTE keywords[10][21]; /* User's entire set of door keywords */ + tBYTE filters[10][21]; /* User's entire set of door filters */ + tBYTE macros[3][80]; /* User's door bundling command macros */ + tWORD netmail_flags; /* Bit-mapped NetMail options */ + tWORD credits; /* NetMail credits */ + tWORD debits; /* NetMail debits */ + tBYTE can_forward; /* 0=Message forwarding not allowed */ + tWORD inf_header_len; /* Size of INF_HEADER structure */ + tWORD inf_areainfo_len; /* Size of INF_AREA_INFO structure */ + tWORD mix_structlen; /* Size of MIX_REC structure */ + tWORD fti_structlen; /* Size of FTI_REC structure */ + tBYTE uses_upl_file; /* If this field is not zero, the door that */ + /* created this packet can receive reply */ + /* packets in the new *.UPL file format. */ + /* Otherwise, the old *.UPI and *.NET */ + /* files must be used. */ + tBYTE from_to_len; /* The maximum length of the FROM: and TO: */ + /* fields that the host BBS can support. */ + /* If this value is 0 or is greater than */ + /* 35, then 35 must be used (the upload */ + /* file formats only allow for a maximum */ + /* of 35 characters). */ + tBYTE subject_len; /* The maximum length of the SUBJECT: field */ + /* that the host BBS can support. If */ + /* this value is 0 or is greater than 71, */ + /* then 71 must be used (the upload file */ + /* formats only allow for a maximum of 71 */ + /* characters). */ + tBYTE packet_id[9]; /* Original root name of the mail packet, */ + /* as specified by the mail door. All */ + /* files in the packet that are created */ + /* by the mail door will use this root */ + /* name, as will the reader when creating */ + /* the upload files. Thus, even if the */ + /* packets themselves are renamed to */ + /* something completely different, the */ + /* mail doors and readers will still be */ + /* able to work with the proper files. */ + tBYTE file_list_type; /* New file listing type */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies the type of new file list */ + /* that is generated by the door (see */ + /* INF_FLIST_xxx, above). This field is */ + /* intended for use with offline config. */ + tBYTE auto_macro[3]; /* Auto-macro indicator flags */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies which macros are auto macros */ + /* (i.e. execute automatically after mail */ + /* is scanned). */ + tINT max_packet_size; /* Maximum size of uncompressed packet */ + /* (* VERSION 3 AND LATER ONLY *) */ + /* Specifies, in K, the maximum size of */ + /* an uncompressed mail packet. A value */ + /* of 0 indicates no maximum length. */ + /* This field is intended for use with */ + /* offline config. */ + tBYTE reserved[228]; /* RESERVED FOR FUTURE USE */ + /* This field MUST be filled with ASCII */ + /* NUL (0x00) characters in order for */ + /* future additional features to work */ + /* properly! */ +} +INF_HEADER; + +/* +** Notes about the INF_HEADER.XXXXX_LEN fields, above: +** +** Door authors should take the few extra lines of code to fill in the +** structure lengths defined above. Doing so will make the Blue Wave data +** structures extensible and adaptable to almost any kind of file change that +** may be required in the future. The readers that use this mail packet +** format should contain code to handle a structure length that is longer or +** shorter than they expect. +** +** Reader authors need to take the time to code for possible extensions to +** this file format. If the data fields are LONGER than expected, simply do +** a seek to move to the next record, and ignore the extra information. If +** the data fields are SHORTER than expected, a simple "Please upgrade your +** reader" should suffice. However, you should never encounter a +** record size smaller than the ones defined here. Any extra information +** that is sent in the packets probably would not be crucial, and you may be +** able to continue with reading the packet anyway. +** +** It should be noted that all current Blue Wave doors set these fields to 0, +** as this extensibility was not added until recently. If the structure +** sizes are 0, the reader will assume that all records are of the sizes +** defined here. (Blue Wave readers below version 2.10 do NOT allow for +** extensible data files. Version 2.10, and all subsequent versions, WILL +** handle them properly.) DO NOT EXTEND THESE STRUCTURE FORMATS WITHOUT +** NOTIFYING CUTTING EDGE COMPUTING FIRST! If the extended information will +** benefit programs/users, it will be officially added to the packet format. +** +** The original values for the INF_HEADER.XXXXX_LEN structures are as below, +** defined as macros which you can use in your programs. Remember, if the +** value in INF_HEADER.XXXXX_LEN is 0, you must use these values instead! +*/ + +#define ORIGINAL_INF_HEADER_LEN 1230 /* Original *.INF header len */ +#define ORIGINAL_INF_AREA_LEN 80 /* Original *.INF area rec len */ +#define ORIGINAL_MIX_STRUCT_LEN 14 /* Original *.MIX record len */ +#define ORIGINAL_FTI_STRUCT_LEN 186 /* Original *.FTI record len */ + +/* +** Below is some sample C code for reading in the variable length *.INF +** structure, which is the most "difficult" one to do. Note the sections of +** code which use the ORIGINAL_XXXXX_LEN macros; these are the sections that +** determine the proper structure length. (Comments are preceeded by "#" +** signs, since using C comment symbols would make most compilers think that +** nested comments are in use, a practice which normally is not allowed.) +** +** int read_inf_file(void) +** { +** INF_HEADER inf_header; +** INF_AREA_INFO inf_info; +** FILE *inf_file=NULL; +** tWORD record_num=0u; +** tWORD inf_header_slen, inf_area_slen; +** tLONG seek_pos=0L; +** +** inf_file = fopen("WILDBLUE.INF", "rb"); +** if (inf_file == NULL) +** return 0; +** +** fread(&inf_header, sizeof(INF_HEADER), 1, inf_file); +** puts(inf_header.loginname); +** puts(inf_header.aliasname); +** +** # Test and verify the validity of the structure lengths. +** +** if (inf_header.inf_header_len < ORIGINAL_INF_HEADER_LEN) +** inf_header_slen = ORIGINAL_INF_HEADER_LEN; +** else +** inf_header_slen = inf_header.inf_header_len; +** +** if (inf_header.inf_areainfo_len < ORIGINAL_INF_AREA_LEN) +** inf_area_slen = ORIGINAL_INF_AREA_LEN; +** else +** inf_area_slen = inf_header.inf_areainfo_len; +** +** # now, move to the END of the header, since it may be longer +** # than we expect it to be. Use fseek()... +** +** fseek(inf_file, (long)inf_header_slen, SEEK_SET); +** +** record_num = 0U; +** while(fread(&inf_info, sizeof(INF_AREA_INFO), 1, inf_file)) +** { +** puts(inf_info.title); +** record_num++; +** +** # we need to seek past the header, and then [record_num] +** # number of recs. +** +** seek_pos = (long)(inf_header_slen+(record_num*inf_area_slen)); +** fseek(inf_file, seek_pos, SEEK_SET); +** } +** +** fclose(inf_file); +** return 1; +** } +*/ + +/* Bit-masks for INF_AREA_INFO.AREA_FLAGS field */ + +#define INF_SCANNING 0x0001 /* On=User is active for area */ +#define INF_ALIAS_NAME 0x0002 /* On=Alias name, Off=Login name */ + /* If ON, use INF_HEADER.ALIASNAME when */ + /* addressing new mail or replies for the */ + /* message area. If OFF, the reader uses */ + /* the INF_HEADER.LOGINNAME for this */ + /* purpose. */ +#define INF_ANY_NAME 0x0004 /* On=Allow any name to be entered */ + /* If ON, any name can be entered in the */ + /* From: field when addressing new mail */ + /* or replies for the message area. If */ + /* OFF, the normal rules apply. */ +#define INF_ECHO 0x0008 /* On=Network mail, Off=Local mail */ +#define INF_NETMAIL 0x0010 /* On=E-mail, Off=Conference mail */ + /* Refer to the chart below (the values */ + /* for the NETWORK_TYPE field) for info */ + /* on how these two flags should be set */ + /* for message areas. */ +#define INF_POST 0x0020 /* On=User can post, Off=User CANNOT post */ +#define INF_NO_PRIVATE 0x0040 /* On=Private messages are NOT allowed */ +#define INF_NO_PUBLIC 0x0080 /* On=Public messages are NOT allowed */ +#define INF_NO_TAGLINE 0x0100 /* On=Taglines are not allowed */ +#define INF_NO_HIGHBIT 0x0200 /* On=ASCII 1-127 only, Off=ASCII 1-255 */ + /* If ON, only ASCII values 1 to 127 are */ + /* allowed in messages. If OFF, all */ + /* values from 1 to 255 are allowed. Due */ + /* to the fact that ASCII value 0 is used */ + /* in C as a string terminator, the value */ + /* 0 should not be allowed in messages at */ + /* all. */ +#define INF_NOECHO 0x0400 /* On=User can prevent messages from being */ + /* sent through the network */ +#define INF_HASFILE 0x0800 /* On=User can attach files to messages */ +#define INF_PERSONAL 0x1000 /* On=User is downloading only personal */ + /* msgs in this message area. The flag */ + /* INF_SCANNING also needs to be ON. */ + /* (* VERSION 3 AND LATER ONLY *) */ +#define INF_TO_ALL 0x2000 /* On=User is downloading messages to "All" */ + /* and personal messages only in this */ + /* area. The flag INF_SCANNING also */ + /* needs to be ON. INF_PERSONAL should */ + /* *not* be set, as this flag implies the */ + /* downloading of personal messages also. */ + /* (* VERSION 3 AND LATER ONLY *) */ + +/* Values for INF_AREA_INFO.NETWORK_TYPE field */ + +#define INF_NET_FIDONET 0 /* FidoNet-style E-mail and conferences */ + /* Local = INF_ECHO=off, NETMAIL=off */ + /* EchoMail = INF_ECHO=on, NETMAIL=off */ + /* GroupMail = INF_ECHO=on, NETMAIL=off */ + /* NetMail = INF_ECHO=on, NETMAIL=on */ +#define INF_NET_INTERNET 1 /* Internet E-mail and Usenet newsgroups */ + /* Local = INF_ECHO=off, NETMAIL=off */ + /* Newsgroup = INF_ECHO=on, NETMAIL=off */ + /* E-mail = INF_ECHO=on, NETMAIL=on */ + +typedef struct /* INF_AREA_INFO */ +{ + tBYTE areanum[6]; /* Area number this record corresponds to */ + tBYTE echotag[21]; /* Area tag name (*.BRD name for Telegard) */ + tBYTE title[50]; /* Area description/title */ + tWORD area_flags; /* Bit-mapped area options */ + tBYTE network_type; /* Network mail type (see above) */ +} +INF_AREA_INFO; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.MIX +** +** Description: The *.MIX file is a very small file, with one record for +** every message area that was scanned. It contains the +** information to get into the *.FTI file. +** +** File format: MIX_REC { repeated for each message area scanned } +** MIX_REC +** ... +*/ + +typedef struct /* MIX_REC */ +{ + tBYTE areanum[6]; /* Area number this record corresponds to */ + /* This is the ASCII representation of the */ + /* actual area number shown on the host BBS. */ + tWORD totmsgs; /* Total number of messages for this area */ + tWORD numpers; /* Total number of personal messages in this area */ + tLONG msghptr; /* Pointer to first message header in *.FTI file */ +} +MIX_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.FTI +** +** Description: The *.FTI file contains the information for each message +** in the packet. Each record includes all of the +** information about the message, including the pointer to +** the actual message text in the *.DAT file. +** +** NOTE: Messages in the *.FTI file will ALWAYS be in area +** number order. That is to say, if the MIX_REC +** indicates there are 100 messages for this area, +** all 100 messages will follow in sequential order. +** +** File format: FTI_REC { repeated for as many messages } +** FTI_REC { as obtained from the host BBS } +** ... +*/ + +/* Bit-masks for FTI_REC.FLAGS field */ + +#define FTI_MSGPRIVATE 0x0001 /* Private = For addressee ONLY */ +#define FTI_MSGCRASH 0x0002 /* Crash = High priority mail */ +#define FTI_MSGREAD 0x0004 /* Read = Message read by addressee */ +#define FTI_MSGSENT 0x0008 /* Sent = Message sent */ +#define FTI_MSGFILE 0x0010 /* File Attach = Send file(s) */ +#define FTI_MSGFWD 0x0020 /* Forward = Message to/from others */ +#define FTI_MSGORPHAN 0x0040 /* Orphan = Message destination unknown */ +#define FTI_MSGKILL 0x0080 /* Kill/Sent = Delete after sending */ +#define FTI_MSGLOCAL 0x0100 /* Local = Message originated here */ +#define FTI_MSGHOLD 0x0200 /* Hold = Hold for pickup, don't send */ +#define FTI_MSGIMMEDIATE 0x0400 /* Immediate = Send message NOW */ +#define FTI_MSGFRQ 0x0800 /* File Request = Request file(s) */ +#define FTI_MSGDIRECT 0x1000 /* Direct = Send direct, no routing */ +#define FTI_MSGUNUSED1 0x2000 /* */ +#define FTI_MSGUNUSED2 0x4000 /* */ +#define FTI_MSGURQ 0x8000 /* Update Request = Req updated file(s) */ + +typedef struct /* FTI_REC */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subject[72]; /* Subject/title of message */ + tBYTE date[20]; /* Origin date of message */ + /* Depending on the host BBS's date storage */ + /* format, the EXACT format of this field */ + /* will change. Some will take all 19 bytes, */ + /* others may take only 10. */ + tWORD msgnum; /* Number of THIS message on BBS */ + tWORD replyto; /* "This is a reply to #xx" */ + /* Not used for every message. When non- */ + /* zero, there is a previous message in */ + /* the thread. */ + tWORD replyat; /* "There is a reply at #xx" */ + /* Not used for every message. When non- */ + /* zero, there is a reply to this message. */ + tLONG msgptr; /* Offset to start of message in *.DAT file */ + /* Seek to this exact offset in the *.DAT */ + /* file, then read "msglength" bytes from */ + /* the file to load the entire message text. */ + tLONG msglength; /* Length of message text (in bytes) */ + tWORD flags; /* Bit-mapped message status flags */ + tWORD orig_zone; /* Origin address of message */ + /* These three fields will most likely be 0, */ + /* unless the current message belongs to a */ + /* NetMail message base. */ + tWORD orig_net; + tWORD orig_node; +} +FTI_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.DAT +** +** Description: The *.DAT file is an unstructured file which contains the +** text of every message obtained from the host BBS. +** Valid messages begin with an ASCII space (0x20) character +** (which is NOT to be considered part of the message!) +** followed by zero or more bytes which constitute the +** message text. The pointer to the text for each message is +** stored in FTI_REC.MSGPTR, and the length of the text for +** each message is stored in FTI_REC.MSGLENGTH. +** +** File format: Unstructured +*/ + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>> MISCELLANEOUS DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.MSG +** +** Description: The Fido *.MSG message (named for the BBS program on which +** it originated) has become a de-facto standard among BBS +** implementations, due to the sheer number of utilities +** available that operate with *.MSG messages. It is as +** close to a universal message format as one can get in +** FidoNet (and FidoNet-style networks), and is the reason +** why it is used here (well, the *.MSG header, anyway). +** +** NOTE: Most of the fields in the FTI_REC structure (shown +** above) correspond to similar fields in MSG_REC. +** This was done deliberately, in order to make +** *.FTI file processing a little more intuitive for +** programmers. Also note that MSG_REC is only used +** by the NET_REC structure, which will soon become +** obsolete (replaced by UPL_REC). +** +** File format: MSG_REC { only included one time! } +** message text { text can be terminated by an ASCII NUL } +** { character (0x00), or by an ASCII CR, } +** { LF, NUL (0x0D 0x0A 0x00) sequence } +*/ + +/* Bit-masks for MSG_REC.ATTR field */ + +#define MSG_NET_PRIVATE 0x0001 /* Private */ +#define MSG_NET_CRASH 0x0002 /* Crash mail */ +#define MSG_NET_RECEIVED 0x0004 /* Received */ +#define MSG_NET_SENT 0x0008 /* Sent */ +#define MSG_NET_FATTACH 0x0010 /* File attached */ +#define MSG_NET_INTRANSIT 0x0020 /* In-transit */ +#define MSG_NET_ORPHAN 0x0040 /* Orphaned */ +#define MSG_NET_KILL 0x0080 /* Kill after sending */ +#define MSG_NET_LOCAL 0x0100 /* Local message */ +#define MSG_NET_HOLD 0x0200 /* Hold for pickup */ +#define MSG_NET_RESERVED 0x0400 /* RESERVED */ +#define MSG_NET_FREQ 0x0800 /* File request */ +#define MSG_NET_RREQ 0x1000 /* Return receipt request */ +#define MSG_NET_RECEIPT 0x2000 /* Return receipt message */ +#define MSG_NET_AREQ 0x4000 /* Audit request */ +#define MSG_NET_FUREQ 0x8000 /* File update request */ + +typedef struct /* MSG_REC (will soon be obsolete) */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subj[72]; /* Subject/title of message */ + tBYTE date[20]; /* Creation date/time */ + /* This date/time is usually in either of the */ + /* Fido-sanctioned formats "DD MMM YY HH:MM:SS" */ + /* or "WWW DD MMM YY HH:MM", but due to the */ + /* chaotic nature of FidoNet-compatible software, */ + /* this CANNOT be relied upon! */ + tWORD times; /* Number of times read (fairly obsolete) */ + tWORD dest; /* Destination node (of net/node) */ + tWORD orig; /* Origin node (of net/node) */ + tWORD cost; /* Cost of sending message (usually in US cents) */ + tWORD orig_net; /* Origin net (of net/node) */ + tWORD destnet; /* Destination net (of net/node) */ + tLONG unused1; /* Undefined */ + tLONG unused2; /* Some software (Opus and Maximus, for example) */ + /* uses these fields to store the sent/received */ + /* date/time as bit-packed fields, using the same */ + /* format used in MS-DOS directory entries. */ + tWORD reply; /* Message # that this message replies to */ + tWORD attr; /* Message attributes and behavior flags */ + tWORD up; /* Message # that replies to this message */ +} +MSG_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.XTI +** +** Description: The *.XTI file contains extended information for each +** message in the packet. The number of records in the *.XTI +** file will always equal the number of messages in the +** packet, with each record corresponding to a record in the +** *.FTI file (i.e. record #1 in the *.XTI file corresponds +** to record #1 in the *.FTI file, and so on). +** +** NOTE: This file is currently created ONLY by the Blue +** Wave reader, and is not a part of the official +** Blue Wave packet specification; it is merely +** documented here for third party programmers to use +** if they so desire. How other readers store which +** messages have been read/replied-to/marked is left +** as an option to be implemented by the individual +** reader authors. You may use this method if you so +** desire; however, PLEASE do not name any external +** files not conforming to this specification as +** .XTI, due to the fact that the Blue +** Wave reader will expect the file to be in the +** format described. If it's not in the expected +** format, things will get interesting. :-) +** +** File format: XTI_REC { repeated for as many messages } +** XTI_REC { as obtained from the host BBS } +** ... +*/ + +/* Bit-masks for XTI_REC.FLAGS field */ + +#define XTI_HAS_READ 0x01 /* Message has been read */ +#define XTI_HAS_REPLIED 0x02 /* Message has been replied to */ +#define XTI_IS_PERSONAL 0x04 /* Message is personal */ +#define XTI_IS_TAGGED 0x08 /* Message has been 'tagged' */ +#define XTI_HAS_SAVED 0x10 /* Message has been saved */ +#define XTI_HAS_PRINTED 0x20 /* Message has been printed */ + +/* Bit-masks for XTI_REC.MARKS field */ + +#define XTI_MARK_SAVE 0x01 /* Message marked for saving */ +#define XTI_MARK_REPLY 0x02 /* Message marked for replying */ +#define XTI_MARK_PRINT 0x04 /* Message marked for printing */ +#define XTI_MARK_DELETE 0x08 /* Message marked for deletion */ + +typedef struct /* XTI_REC */ +{ + tBYTE flags; /* Bit-mapped message flags */ + tBYTE marks; /* Bit-mapped message markers */ +} +XTI_REC; + + +/*****************************************************************************/ +/* >>>>>>>>>>>>>>>>>>>> READER DATA FILE STRUCTURES <<<<<<<<<<<<<<<<<<<<<< */ +/*****************************************************************************/ + + +/* +** Name of file: *.NET +** +** Description: The *.NET file is created ONLY when there is NetMail to be +** sent. It contains the FULL header of the Fido-style *.MSG +** structure plus the fields defined below (which aren't part +** of the standard *.MSG structure yet required by the door). +** +** NOTE: Readers should only generate a *.NET file if +** INF_HEADER.USES_UPL_FILE is not set *AND* the +** mail packet format is version 2 or earlier. +** Doors should process *.NET files *ONLY* in cases +** where a *.UPL file is not present. +** +** File format: NET_REC { repeated for as many NetMail } +** NET_REC { messages as exist in the packet } +** ... +*/ + +typedef struct /* NET_REC */ +{ + MSG_REC msg; /* The Fido-style *.MSG header */ + tBYTE fname[13]; /* Filename the message text is in */ + tBYTE echotag[21]; /* NetMail area tag (*.BRD name for Telegard) */ + tWORD zone; /* Destination zone (of zone:net/node.point) */ + tWORD point; /* Destination point (of zone:net/node.point) */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted */ + /* to the date/time storage method used by */ + /* the host BBS. */ +} +NET_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.UPI +** +** Description: The *.UPI file contains the information for each message +** in the reply packet, as well as information on the reader +** version and registration numbers. Each record includes +** all of the information about the message. +** +** NOTE: Readers should only generate a *.UPI file if +** INF_HEADER.USES_UPL_FILE is not set *AND* the +** mail packet format is version 2 or earlier. +** Doors should process *.UPI files *ONLY* in cases +** where a *.UPL file is not present. +** +** File format: UPI_HEADER { only included one time! } +** UPI_REC { repeated for as many msg bases } +** UPI_REC { as are available to the user } +** ... +*/ + +typedef struct /* UPI_HEADER */ +{ + tBYTE regnum[9]; /* Reader registration number */ + tBYTE vernum[13]; /* Reader version number */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, but it */ + /* does prevent "TYPE *.UPI" from showing the */ + /* version number. */ + tBYTE future[33]; /* RESERVED FOR FUTURE USE */ +#ifdef PAD_SIZES_EVEN + tBYTE evenpad; /* If your compiler pads structures out to even */ + /* numbered sizes, define PAD_SIZES_EVEN */ + /* before including this header. When the */ + /* *.UPI file is written, be sure to write */ + /* sizeof(UPI_HEADER) - 1 bytes, otherwise */ + /* your compiler may insert an extra byte not */ + /* explicitly specified here. */ +#endif +} +UPI_HEADER; + +/* Bit-masks for UPI_REC.FLAGS field */ + +#define UPI_RES1 0x01 /* RESERVED FOR FUTURE USE */ +#define UPI_RES2 0x02 /* RESERVED FOR FUTURE USE */ +#define UPI_RES3 0x04 /* RESERVED FOR FUTURE USE */ +#define UPI_RES4 0x08 /* RESERVED FOR FUTURE USE */ +#define UPI_RES5 0x10 /* RESERVED FOR FUTURE USE */ +#define UPI_RES6 0x20 /* RESERVED FOR FUTURE USE */ +#define UPI_PRIVATE 0x40 /* Message is PRIVATE */ +#define UPI_NO_ECHO 0x80 /* Message is NOT to be echoed */ + /* This feature is not yet implemented in */ + /* the Blue Wave reader or doors, as none */ + /* of the currently supported BBS software */ + /* has support for this feature. */ + +typedef struct /* UPI_REC */ +{ + tBYTE from[36]; /* Person message is from */ + tBYTE to[36]; /* Person message is to */ + tBYTE subj[72]; /* Subject/title of message */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted */ + /* to the date/time storage method used by */ + /* the host BBS. */ + tBYTE fname[13]; /* Filename the message text is in */ + tBYTE echotag[21]; /* Area tag name (*.BRD name for Telegard) */ + tBYTE flags; /* Bit-mapped flags */ + tBYTE reedit; /* INTERNAL USE ONLY! */ + /* This flag is used internally by the Blue */ + /* Wave reader. Doors should ignore this */ + /* field during reply packet processing. */ +} +UPI_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.UPL +** +** Description: The *.UPL file contains the information for each message +** in the reply packet, as well as information on the reader +** version and registration numbers. Each record includes +** all of the information about the message. +** +** NOTE: Readers should only generate a *.UPL file if +** INF_HEADER.USES_UPL_FILE is set *AND/OR* the mail +** packet format is version 3 or later. Doors should +** process *.UPL files in all cases where one is +** present. +** +** File format: UPL_HEADER { only included one time! } +** UPL_REC { repeated for as many messages } +** UPL_REC { as are included in the packet } +** ... +*/ + +typedef struct /* UPL_HEADER */ +{ + tBYTE regnum[10]; /* Reader registration number (if desired) */ + tBYTE vernum[20]; /* Reader version number as a string. */ + /* All bytes should be the actually ASCII */ + /* value plus 10. Lame security, yes, but it */ + /* does prevent "TYPE *.UPL" from showing the */ + /* version number. */ + /* Examples: "2.10a Beta" */ + /* "2.11" */ + tBYTE reader_major; /* Major version of the reader (number to the */ + /* left of the decimal point) */ + tBYTE reader_minor; /* Minor version of the reader (number to the */ + /* right of the decimal point) */ + tBYTE reader_name[80]; /* String containing name of the reader, such */ + /* as "The Blue Wave Offline Mail Reader". */ + /* This is provided for door programmers that */ + /* wish to display the name of the reader */ + /* that created the reply packet. (Filling */ + /* it is mandatory but using it is optional.) */ + tWORD upl_header_len; /* Size of UPL_HEADER structure */ + tWORD upl_rec_len; /* Size of UPL_REC structure */ + /* NOTE: Refer to the INF_HEADER section for */ + /* more information on using the size */ + /* fields. */ + tBYTE loginname[44]; /* Name found in INF_HEADER.LOGINNAME. This is */ + /* provided for door authors as a security */ + /* measure to implement as they wish. */ + tBYTE aliasname[44]; /* Name found in INF_HEADER.ALIASNAME */ + tBYTE reader_tear[16]; /* String containing abbreviated name of the */ + /* reader, such as "Blue Wave", "Q-Blue", */ + /* "Wave Rider", etc. This is provided for */ + /* doors programmers that wish to add to the */ + /* tear line the name of the reader that */ + /* created the reply packet. (Filling it is */ + /* mandatory but using it is optional.) If */ + /* this field is blank, the tear line to be */ + /* generated is left to the discretion of the */ + /* door author. */ + tBYTE compress_type; /* Compression type required for mail packet */ + /* The Blue Wave reader uses this internally */ + /* to store the compression type required for */ + /* this particular mail packet. */ + tBYTE flags; /* Reader processing flags */ + /* The Blue Wave reader uses this internally */ + /* to store flags required for later */ + /* processing. */ + /* 0x01 = Was a .QWK packet. */ + /* 0x02 = Host requires a *.UPI file */ + tBYTE not_registered; /* Reader is not registered to user */ + /* If this byte is set to a non-zero value, */ + /* the Blue Wave doors will assume that the */ + /* user's reader was not registered, and will */ + /* place "[NR]" at the end of the tear line. */ + /* Third-party doors may use this flag for */ + /* the same purpose; its use is optional by */ + /* mail readers (especially if you don't care */ + /* whether or not "[NR]" shows up on the tear */ + /* line ). */ + tBYTE pad[33]; /* RESERVED FOR FUTURE USE, and to pad struct */ + /* out to a 'nice' 256 bytes */ +} +UPL_HEADER; + +/* Bit-masks for UPL_REC.MSG_ATTR field */ + +#define UPL_INACTIVE 0x0001 /* Message is INACTIVE */ + /* Doors should NOT attempt to import this */ + /* message. */ +#define UPL_PRIVATE 0x0002 /* Message is PRIVATE */ +#define UPL_NO_ECHO 0x0004 /* Message is NOT to be echoed */ + /* This feature is not yet implemented in */ + /* the Blue Wave reader or doors, as none */ + /* of the currently supported BBS software */ + /* has support for this feature. */ +#define UPL_HAS_FILE 0x0008 /* Message has file "attached" to it */ + /* It is up to the door to check the */ + /* validity of this flag. If the file is */ + /* contained in the mail packet, great. */ + /* If not, the door should probably prompt */ + /* the user to begin uploading the file */ + /* after importing the messages. (Not yet */ + /* implemented in the Blue Wave reader.) */ +#define UPL_NETMAIL 0x0010 /* Message is network mail */ + /* Indicates NetMail/E-mail message. The */ + /* NETWORK_TYPE field (see below) will */ + /* indicate which fields should be used */ + /* for addressing the message. */ +#define UPL_IS_REPLY 0x0020 /* Indicates that the message is a reply to */ + /* an existing message, rather than being */ + /* a completely new message. */ +#define UPL_MRES7 0x0040 /* RESERVED FOR FUTURE USE */ +#define UPL_MRES8 0x0080 /* RESERVED FOR FUTURE USE */ + /* All of the other 8 bits of this field are */ + /* also reserved for future use. This */ + /* should provide for plenty of expansion */ + /* for future development. */ + +/* Bit-masks for UPL_REC.NETMAIL_ATTR field */ + +#define UPL_NRES1 0x0001 /* RESERVED FOR FUTURE USE */ +#define UPL_NETCRASH 0x0002 /* Crash = High priority mail */ +#define UPL_NRES2 0x0004 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES3 0x0008 /* RESERVED FOR FUTURE USE */ +#define UPL_NETFILE 0x0010 /* File Attach = Send file(s) listed */ + /* in Subject field */ +#define UPL_NRES4 0x0020 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES5 0x0040 /* RESERVED FOR FUTURE USE */ +#define UPL_NETKILL 0x0080 /* Kill/Sent = Delete after sending */ +#define UPL_NETLOCAL 0x0100 /* Local = Message originated here */ +#define UPL_NETHOLD 0x0200 /* Hold = Hold for pickup, do not send */ +#define UPL_NETIMMEDIATE 0x0400 /* Immediate = Send message NOW */ +#define UPL_NETFRQ 0x0800 /* File Request = Request file(s) */ + /* listed in Subject field */ +#define UPL_NETDIRECT 0x1000 /* Direct = Send direct, no routing */ +#define UPL_NRES6 0x2000 /* RESERVED FOR FUTURE USE */ +#define UPL_NRES7 0x4000 /* RESERVED FOR FUTURE USE */ +#define UPL_NETURQ 0x8000 /* Update Request = Request updated */ + /* file(s) listed in Subject field */ + +/* Values for UPL_REC.NETWORK_TYPE field */ + +#define UPL_NET_FIDONET 0 /* FidoNet-style E-mail and conferences */ + /* UPL_NETMAIL=off - Local, Echo, Group */ + /* UPL_NETMAIL=on - NetMail */ +#define UPL_NET_INTERNET 1 /* Internet E-mail and Usenet newsgroups */ + /* UPL_NETMAIL=off - Local, Newsgroup */ + /* UPL_NETMAIL=on - E-mail */ + +typedef struct /* UPL_REC */ +{ + tBYTE from[36]; /* Person message is from */ + /* NOTE: Doors should validate this field! */ + tBYTE to[36]; /* Person message is to (non-Internet) */ + /* For Internet E-mail, the NET_DEST field */ + /* should be used to store the destination */ + /* name/address, leaving this field blank. */ + /* For Usenet newsgroups, this field should be */ + /* left blank, as newsgroups don't use a "To:" */ + /* field. */ + tBYTE subj[72]; /* Subject/Title of message */ + tWORD destzone; /* Destination address (FidoNet only) */ + /* If the message is not a FidoNet NetMail */ + /* message, this field (and the subsequent */ + /* three fields as well) should be set to */ + /* zero. */ + tWORD destnet; + tWORD destnode; + tWORD destpoint; + tWORD msg_attr; /* Bit-mapped message attributes */ + tWORD netmail_attr; /* Bit-mapped NetMail attributes (FidoNet only) */ + /* If the message is not a FidoNet NetMail */ + /* message, this field should not be used. */ + tLONG unix_date; /* Date/time of message */ + /* This Unix-style date/time value (number */ + /* of seconds since 01/01/70) is converted to */ + /* the date/time storage method used by the */ + /* host BBS. */ + tDWORD replyto; /* This unsigned long word stores the message # */ + /* that this message is a reply to. This */ + /* should be the same as FTI.MSGNUM. Note, */ + /* however, that FTI.MSGNUM is a word. C */ + /* programmers especially will need to */ + /* properly typecast the value (i.e. */ + /* upl.replyto=(tDWORD)fti.msgnum). As */ + /* messaging/BBS systems become more complex, */ + /* FTI.MSGNUM may become obsolete, and a */ + /* tDWORD variable may be used in its place. */ + tBYTE filename[13]; /* Filename the message text is in */ + /* If this file does not exist in the upload */ + /* packet then doors should consider this an */ + /* invalid record. */ + tBYTE echotag[21]; /* Area tag the message goes in */ + /* This must correspond exactly to the */ + /* INF_AREA_INFO.ECHOTAG field for the message */ + /* area this message belongs to. Simple area */ + /* number matching has proven not to work */ + /* simply because sysops are finicky people, */ + /* and seem to constantly renumber/change the */ + /* message area numbers on the host BBS. */ + /* Using an echotag helps to alleviate this */ + /* problem. C_ECHO will be C_ECHO on the BBS, */ + /* whether it is msg area 17 on the host BBS */ + /* or whether it is area 207. Doors should do */ + /* a case-INSENSITIVE compare on this field to */ + /* find where the message belongs. */ + tWORD area_flags; /* The Blue Wave Offline Mail Reader uses this */ + /* word internally to store the same value as */ + /* in INF_AREA_INFO.AREA_FLAGS. The purpose */ + /* of this word is to hold the original */ + /* information about the message area so that */ + /* later message editing processes can be */ + /* controlled properly. For example, if a */ + /* user later wanted to edit this message, the */ + /* reader would know instantly whether this is */ + /* a NETMAIL area, whether PVT messages are */ + /* allowed, etc. This allows re-editing of */ + /* the message, even when there is not a */ + /* corresponding *.INF file laying around, or */ + /* the area is not listed in the *.INF file */ + /* you currently have to work with. DOOR */ + /* AUTHORS SHOULD IGNORE THIS FIELD WHEN */ + /* IMPORTING MESSAGES! */ + tBYTE f_attach[13]; /* If the UPL_HAS_FILE flag is set, this field */ + /* will contain the file name that is attached */ + /* to the message. */ + tBYTE user_area[6]; /* User-defined storage. Doors should ignore */ + /* this field, and reader authors should feel */ + /* free to utilize this field for their own */ + /* internal use, if necessary. */ + tBYTE network_type; /* Indicates the network type. This field must */ + /* hold the same value as the NETWORK_TYPE */ + /* field in INF_AREA_INFO, allowing doors and */ + /* readers to properly handle the message. */ + /* (Values duplicated as UPL_NET_xxx, above.) */ + /* For FidoNet NetMail and Internet E-mail, it */ + /* also indicates which fields should be used */ + /* for addressing and status information (as */ + /* indicated in comments above and below). */ + tBYTE net_dest[100]; /* Network destination address (non-FidoNet) */ + /* Internet E-mail messages should use this */ + /* field to store the destination address. */ +} +UPL_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.REQ +** +** Description: The *.REQ file is simply a list of filenames the user +** wants to request from the host BBS. Wildcard characters +** ("*" and "?" under MS-DOS) are allowed, but are not +** guaranteed to produce accurate results on all door +** implementations. +** +** NOTE: Current Blue Wave doors do not accept wildcard +** characters in filenames, and will consider any +** filenames which contain them as being invalid. +** Additionally, if there are more than 10 entries in +** the *.REQ file, current Blue Wave doors will read +** the first 10 and discard the rest. These are +** limitations of the Blue Wave doors, not of the +** Blue Wave format itself. +** +** File format: REQ_REC { repeated for as many files as } +** REQ_REC { requested from the host BBS } +** ... +*/ + +typedef struct /* REQ_REC */ +{ + tBYTE filename[13]; /* Name of file to request */ +} +REQ_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.PDQ +** +** Description: The *.PDQ file contains the information used for the +** offline configuration feature of the mail door. After the +** header is a series of records which indicate the message +** areas to enable for scanning the next time a mail packet +** is requested. +** +** NOTE: Readers should generate a *.PDQ file *ONLY* if +** the mail packet format is version 2 or earlier; +** otherwise, a *.OLC file should be generated. +** Doors should process *.PDQ files *ONLY* in cases +** where a *.OLC file is not present. +** +** If the AREA_CHANGES flag in PDQ_HEADER.FLAGS is +** set, the door should process the offline +** configuration as well as changes to the list of +** areas the user wants to download. In the Blue +** Wave door, this is done by first turning OFF all +** message areas that were active, then turning ON +** the ones specified in the *.PDQ file. This seems +** to be the simplest, most straight-forward method +** of accomplishing this task, though other, more +** complex schemes could easily have been devised. +** +** File format: PDQ_HEADER { only included one time! +** PDQ_REC { repeated for as many message areas } +** PDQ_REC { as the user wishes to enable } +** ... +*/ + +/* Bit-masks for PDQ_HEADER.FLAGS field */ + +#define PDQ_HOTKEYS 0x0001 /* Toggle "hotkeys" in prompts */ +#define PDQ_XPERT 0x0002 /* Toggle expert mode (menu displays) */ +#define PDQ_AREA_CHANGES 0x0004 /* Change active message areas */ +#define PDQ_GRAPHICS 0x0008 /* Toggle IBM 8-bit ASCII characters */ +#define PDQ_NOT_MY_MAIL 0x0010 /* Toggle bundling mail from user */ + +typedef struct /* PDQ_HEADER */ +{ + tBYTE keywords[10][21]; /* User's entire set of door keywords */ + tBYTE filters[10][21]; /* User's entire set of door filters */ + tBYTE macros[3][78]; /* User's door bundling command macros */ + tBYTE password[21]; /* Password */ + tBYTE passtype; /* Password type */ + /* 0=none 1=door 2=reader 3=both */ + tWORD flags; /* Bit-mapped flags */ +} +PDQ_HEADER; + +typedef struct /* PDQ_REC */ +{ + tBYTE echotag[21]; /* Echo tag of message area to activate */ + /* With Telegard systems, this should */ + /* be the name of the *.BRD file, rather */ + /* than the actual echo tag. */ +} +PDQ_REC; + +/*---------------------------------------------------------------------------*/ + +/* +** Name of file: *.OLC +** +** Description: The *.OLC file contains the information used for the +** offline configuration feature of the mail door. +** +** NOTE: Readers should generate a *.OLC file *ONLY* if +** the mail packet format is version 3 or later; +** otherwise, a *.PDQ file should be generated. +** Doors should process *.OLC files in all cases +** where one is present. +** +** File format: ASCII text (lines terminated with CRLF) +** +** Comments: Refer to the Blue Wave Developer's Kit documentation +** for details on the exact format of the *.OLC file. +*/ + +/*---------------------------------------------------------------------------*/ + +#endif /* __BLUEWAVE_H */ + diff --git a/lib/charconv.c b/lib/charconv.c new file mode 100644 index 00000000..b7e69d2d --- /dev/null +++ b/lib/charconv.c @@ -0,0 +1,723 @@ +/***************************************************************************** + * + * File ..................: common/charconv.c + * Purpose ...............: Common utilities + * Last modification date : 21-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" +#include "clcomm.h" + + +#ifndef BUFSIZ +#define BUFSIZ 512 +#endif + + +char *oldfilemap=NULL; +char maptab[] = { +"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" +"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" +"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" +"\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" +"\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" +"\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" +"\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" +"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" +"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" +"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" +"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" +"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" +"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" +"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" +"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + + + +static int ctoi(char *); +static int ctoi(char *s) +{ + int i; + + if (!strncmp(s,"0x",2)) + sscanf(s+2,"%x",&i); + else if (*s == '0') + sscanf(s,"%o",&i); + else if (strspn(s,"0123456789") == strlen(s)) + sscanf(s,"%d",&i); + else + i=0; + return i; +} + + + +static int getmaptab(char *); +static int getmaptab(char *maptab_name) +{ + FILE *fp; + char buf[BUFSIZ], *p, *q; + int in, on; + + Syslog('M', "getmaptab: %s\n", maptab_name); + if ((fp = fopen(maptab_name, "r")) == NULL) { + WriteError("$can't open mapchan file \"%s\" ", maptab_name); + return 0; + } + + while (fgets(buf, sizeof(buf)-1, fp)) { + p = strtok(buf," \t\n#"); + q = strtok(NULL," \t\n#"); + if (p && q) { + in = ctoi(p); + on = ctoi(q); + if (in && on) + maptab[in] = on; + } + } + fclose(fp); + + return 0; +} + + + +char *strnkconv(const char *src, int incode, int outcode, int n) +{ + char ki[10], ko[10]; + int kolen; + static char *dest; + int destlen; + int i; + + outcode = getkcode(outcode, ki, ko); + kolen = strlen(ko); + + dest = strkconv(src, incode, outcode); + destlen = strlen(dest); + + if(destlen >= kolen && destlen > strlen(src)) { + for(i = 0; i < kolen; i++) + *(dest + n - 1 + i) = ko[i]; + *(dest + n) = '\0'; + } + + return dest; +} + + + +char *strkconv(const char *src, int incode, int outcode) +{ + static char *dest; + + if ((incode==outcode) && (incode!=CHRS_NOTSET) && (incode!=CHRS_AUTODETECT)) + return (char *)src; + + if (!src) + return NULL; + + if((incode == CHRS_AUTODETECT) || (incode == CHRS_NOTSET)) { + if (LANG_BITS == 16) { + incode = iso2022_detectcode((char *)src,incode); + } + } + + if(dest) + free(dest); + /* FIXME: should be + * dest = (char *)malloc((strlen(src) + 1) + (6 * "number of \n + 1")); + */ + dest = (char *)malloc(((strlen(src) + 1) * 2) + 6 ); + + kconv((char *)src, &dest, incode, outcode); + return dest; +} + + + +void kconv(char *in, char **out, int incode, int outcode) +{ + char ki[10], ko[10]; + + outcode = getkcode(outcode, ki, ko); + if (incode == outcode) + noconv(in,out); + else { + switch (incode) { + case CHRS_NOTSET : noconv(in,out); + break; + case CHRS_ASCII : noconv(in,out); + break; + case CHRS_BIG5 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_CP424 : + switch (outcode) { + case CHRS_CP862 : eight2eight(in,out,(char *)CP424__CP862); break; + case CHRS_ISO_8859_8 : eight2eight(in,out,(char *)CP424__ISO_8859_8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP437 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)CP437__ISO_8859_1); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)CP437__MACINTOSH); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP850 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)CP850__ISO_8859_1); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)CP850__MACINTOSH); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP852 : + switch (outcode) { + case CHRS_FIDOMAZOVIA : eight2eight(in,out,(char *)CP852__FIDOMAZOVIA); break; + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)CP852__ISO_8859_2); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP862 : + switch (outcode) { + case CHRS_CP424 : eight2eight(in,out,(char *)CP862__CP424); break; + case CHRS_ISO_8859_8 : eight2eight(in,out,(char *)CP862__ISO_8859_8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP866 : + switch (outcode) { + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)CP866__ISO_8859_5); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)CP866__KOI8); break; + default : noconv(in,out); break; + } + break; + case CHRS_CP895 : + switch (outcode) { + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)CP895__ISO_8859_2); break; + case CHRS_CP437 : eight2eight(in,out,(char *)CP895__CP437); break; + default : noconv(in,out); break; + } + break; + case CHRS_EUC_JP : + switch (outcode) { + case CHRS_EUC_JP : euc2euc(in,out,incode,0); break; + case CHRS_ISO_2022_JP : euc2seven(in,out,incode,ki,ko); break; + case CHRS_NEC : euc2seven(in,out,incode,ki,ko); break; + case CHRS_SJIS : euc2shift(in,out,incode,0); break; + default : noconv(in,out); break; + } + break; + case CHRS_EUC_KR : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_FIDOMAZOVIA : + switch (outcode) { + case CHRS_CP852 : eight2eight(in,out,(char *)FIDOMAZOVIA__CP852); break; + case CHRS_ISO_8859_2 : eight2eight(in,out,(char *)FIDOMAZOVIA__ISO_8859_2); break; + default : noconv(in,out); break; + } + break; + case CHRS_GB : + switch (outcode) { + case CHRS_HZ : gb2hz(in,out); break; + default : noconv(in,out); break; + } + case CHRS_HZ : + switch (outcode) { + case CHRS_GB : hz2gb(in,out); break; + default : noconv(in,out); break; + } + case CHRS_ISO_11 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_11__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_4 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_4__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_60 : + switch (outcode) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)ISO_60__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_CN : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_JP : + switch (outcode) { + case CHRS_EUC_JP : seven2euc(in,out); break; + case CHRS_ISO_2022_JP : seven2seven(in,out,ki,ko); break; + case CHRS_NEC : seven2seven(in,out,ki,ko); break; + case CHRS_SJIS : seven2shift(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_KR : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_2022_TW : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (outcode) { + case CHRS_CP437 : eight2eight(in,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(in,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(in,out,(char *)ISO_8859_1__MACINTOSH); break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: noconv(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_2 : + switch (outcode) { + case CHRS_CP852 : eight2eight(in,out,(char *)ISO_8859_2__CP852); break; + case CHRS_CP895 : eight2eight(in,out,(char *)ISO_8859_2__CP895); break; + case CHRS_FIDOMAZOVIA : eight2eight(in,out,(char *)ISO_8859_2__FIDOMAZOVIA); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_3 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_4 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (outcode) { + case CHRS_CP866 : eight2eight(in,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(in,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_6 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_7 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (outcode) { + case CHRS_CP424 : eight2eight(in,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(in,out,(char *)ISO_8859_8__CP862); break; + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_9 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_10 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_ISO_8859_11 : + switch (outcode) { + default : noconv(in,out); break; + } + break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : + switch (outcode) { + case CHRS_CP866 : eight2eight(in,out,(char *)KOI8__CP866); break; + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)KOI8__ISO_8859_5); break; + case CHRS_MIK_CYR : eight2eight(in,out,(char *)KOI8__MIK_CYR); break; + default : noconv(in,out); break; + } + break; + case CHRS_MACINTOSH : + switch (outcode) { + case CHRS_CP437 : eight2eight(in,out,(char *)MACINTOSH__CP437); break; + case CHRS_CP850 : eight2eight(in,out,(char *)MACINTOSH__CP850); break; + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: eight2eight(in,out,(char *)MACINTOSH__ISO_8859_1); break; + default : noconv(in,out); break; + } + break; + case CHRS_MIK_CYR : + switch (outcode) { + case CHRS_ISO_8859_5 : eight2eight(in,out,(char *)MIK_CYR__ISO_8859_5); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(in,out,(char *)MIK_CYR__KOI8); break; + default : noconv(in,out); break; + } + break; + case CHRS_NEC : + switch (outcode) { + case CHRS_EUC_JP : seven2euc(in,out); break; + case CHRS_ISO_2022_JP : seven2seven(in,out,ki,ko); break; + case CHRS_NEC : seven2seven(in,out,ki,ko); break; + case CHRS_SJIS : seven2shift(in,out); break; + default : noconv(in,out); break; + } + break; + case CHRS_SJIS : + switch (outcode) { + case CHRS_EUC_JP : shift2euc(in,out,incode,0); break; + case CHRS_ISO_2022_JP : shift2seven(in,out,incode,ki,ko); break; + case CHRS_NEC : shift2seven(in,out,incode,ki,ko); break; + case CHRS_SJIS : shift2shift(in,out,incode,0); break; + default : noconv(in,out); break; + } + break; + case CHRS_UTF_7 : + utf7_to_eight(in,out,&outcode); + break; + case CHRS_UTF_8 : + utf8_to_eight(in,out,&outcode); + break; + + case CHRS_ZW : + switch (outcode) { + case CHRS_HZ : zw2hz(in,out); break; + case CHRS_GB : zw2gb(in,out); break; + default : noconv(in,out); break; + } + break; + default : noconv(in,out); break; + } + } +} + + + +int getkcode(int code,char ki[],char ko[]) +{ + if (code == CHRS_ISO_2022_CN) { + strcpy(ki,"$A"); + strcpy(ko,"(T"); + } else if (code == CHRS_ISO_2022_JP) { + strcpy(ki,"$B"); + strcpy(ko,"(B"); + } else if (code == CHRS_ISO_2022_KR) { + strcpy(ki,"$(C"); + strcpy(ko,"(B"); + } else if (code == CHRS_ISO_2022_TW) { + strcpy(ki,"$(G"); + strcpy(ko,"(B"); + } + return code; +} + + + +int SkipESCSeq(FILE *in,int temp,int *intwobyte) +{ + int tempdata; + + tempdata = *intwobyte; + if (temp == '$' || temp == '(') + fgetc(in); + if (temp == 'K' || temp == '$') + *intwobyte = TRUE; + else + *intwobyte = FALSE; + if (tempdata == *intwobyte) + return FALSE; + else + return TRUE; +} + + + +void noconv(char *in, char **out) +{ + char *p; + + p=*out; + while (*in) + *p++=*in++; + *p='\0'; +} + + + +void eight2eight(char *in,char **out, char *filemap) +{ + char *p; + int i; + + if (oldfilemap != filemap) { + oldfilemap = filemap; + filemap = xstrcpy(getenv("MBSE_ROOT")); + filemap = xstrcat(filemap, (char *)"/etc/maptabs/"); + filemap = xstrcat(filemap, oldfilemap); + + for (i = 0; i < 256; i++) + maptab[i] = (unsigned char)i; + + getmaptab(filemap); + } + p=*out; + while (*in) { + *p=maptab[*in & 0xff]; + in++; + p++; + } + *p='\0'; +} + + + +int iso2022_detectcode(char *in,int whatcode) +{ + int c=0; + + while (((whatcode == CHRS_NOTSET) || (whatcode==CHRS_AUTODETECT)) && (*in)) { + if ((c = (unsigned int)(*in++))) { + if (c == ESC) { + c = (unsigned int)(*in++); + if (c == '$') { + c = (unsigned int)(*in++); + switch (c) { + case 'A' : whatcode = CHRS_ISO_2022_CN; break; + case 'B' : + case '@' : whatcode = CHRS_ISO_2022_JP; break; + case '(' : + case ')' : c = (unsigned int)(*in++); + switch (c) { + case 'A' : whatcode = CHRS_ISO_2022_CN; break; + case 'C' : whatcode = CHRS_ISO_2022_KR; break; + case 'D' : whatcode = CHRS_ISO_2022_JP; break; + case 'E' : whatcode = CHRS_ISO_2022_CN; break; + case 'G' : + case 'H' : + case 'I' : + case 'J' : + case 'K' : + case 'L' : + case 'M' : whatcode = CHRS_ISO_2022_TW; break; + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + case '*' : c = (unsigned int)(*in++); + switch (c) { + case 'H' : + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + case '+' : c = (unsigned int)(*in++); + switch (c) { + case 'H' : + case 'I' : + case 'J' : + case 'K' : + case 'L' : + case 'M' : + case 'X' : whatcode = CHRS_ISO_2022_CN; break; + default: break; + } + break; + default: break; + } + } + } else if (whatcode == CHRS_NOTSET) + return whatcode; +#if (LANG_DEFAULT == LANG_JAPAN) + else if ((c >= 129 && c <= 141) || (c >= 143 && c <= 159)) + whatcode = CHRS_SJIS; + else if (c == 142) { + c = (unsigned int)(*in++); + if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160) || (c >= 224 && c <= 252)) + whatcode = CHRS_SJIS; + else if (c >= 161 && c <= 223) + whatcode = CHRS_AUTODETECT; + } else if (c >= 161 && c <= 223) { + c = (unsigned int)(*in++); + if (c >= 240 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 161 && c <= 223) + whatcode = CHRS_AUTODETECT; + else if (c >= 224 && c <= 239) { + whatcode = CHRS_AUTODETECT; + while (c >= 64 && c != EOF && whatcode == CHRS_AUTODETECT) { + if (c >= 129) { + if (c <= 141 || (c >= 143 && c <= 159)) + whatcode = CHRS_SJIS; + else if (c >= 253 && c <= 254) + whatcode = CHRS_EUC_JP; + } + c = (unsigned int)(*in++); + } + } else if (c <= 159) + whatcode = CHRS_SJIS; + } else if (c >= 240 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 224 && c <= 239) { + c = (unsigned int)(*in++); + if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160)) + whatcode = CHRS_SJIS; + else if (c >= 253 && c <= 254) + whatcode = CHRS_EUC_JP; + else if (c >= 161 && c <= 252) + whatcode = CHRS_AUTODETECT; + } +#endif /* (LANG_DEFAULT == LANG_JAPAN) */ + } + } + return whatcode; +} + + + +char *hdrnconv(char *s, int incode, int outcode, int n) +{ + char ki[10],ko[10]; + int kolen; + static char *dest; + int destlen; + int i; + + getkcode(outcode, ki, ko); + kolen = strlen(ko); + dest = hdrconv(s, incode, outcode); + destlen = strlen(dest); + + if(destlen >= kolen && destlen > n) { + for(i = 0; i < kolen; i++) + *(dest + n - 1 - kolen + i) = ko[i]; + *(dest + n) = '\0'; + } + + return dest; +} + + + +char *hdrconv(char *s, int incode, int outcode) +{ +#define BCODAGE 1 +#define QCODAGE 2 + + char ttbuf[1024]; + char *iptr, *tptr; + char *xbuf=NULL, *buf=NULL, *q; + int codage; + +// Syslog('N', "hdrconv(%s, %d, %d)", s, incode, outcode); + + iptr = s; + while (*iptr) { + if (!strncmp(iptr,"=?",2)) { +// Syslog('N', "hdrconv =?"); + q=strchr(iptr+2,'?'); + if (q) { + incode=getcode(iptr+2); + if (incode==CHRS_NOTSET) + return s; + iptr=q; + } else { + return s; + } + if (!strncasecmp(iptr,"?Q?",3)) { + codage = QCODAGE; + iptr+=3; + } else if (!strncasecmp(iptr,"?B?",3)) { + codage = BCODAGE; + iptr+=3; + } else { + iptr=xstrcpy(iptr); + *(iptr+3)='\0'; + Syslog('+', "mimehdr_decode: unknown codage %s",iptr); + return s; + } + tptr = ttbuf; + while ((*iptr) && (strncmp(iptr,"?=",2))) + *tptr++ = *iptr++; + *tptr = '\0'; + if (!strncmp(iptr,"?=",2)) { + iptr++; + iptr++; + } + if (codage==QCODAGE) { + while ((q = strchr(ttbuf, '_'))) + *q=' '; + xbuf=xstrcat(xbuf,qp_decode(ttbuf)); + } else if (codage==BCODAGE) { + xbuf=xstrcat(xbuf,b64_decode(ttbuf)); + } + } else { /* not coded */ +// Syslog('N', "hdrconv not coded 1"); + *ttbuf=*iptr; +// Syslog('N', "hdrconv not coded 2"); + *(ttbuf+1)='\0'; +// Syslog('N', "hdrconv not coded 3"); + xbuf=xstrcat(xbuf,ttbuf); +// Syslog('N', "hdrconv not coded 4"); + iptr++; +// Syslog('N', "hdrconv not coded 5"); + } + } +// Syslog('N', "hdrconv call strkconv"); + buf=strkconv(xbuf, incode, outcode); +// Syslog('N', "hdrconv return"); + return buf; +} + diff --git a/lib/charconv_hz.c b/lib/charconv_hz.c new file mode 100644 index 00000000..93f2545d --- /dev/null +++ b/lib/charconv_hz.c @@ -0,0 +1,482 @@ +/***************************************************************************** + * + * File ..................: common/charconv_hz.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +int LF2CR = FALSE; /* flag for converting ASCII to */ +int CR2LF=FALSE; /* flag for converting ASCII to */ +int pass8 = FALSE; /* flat for parsing all 8 bits of a character */ +int termStyle = FALSE; /* flag for ignoring line-continuation markers */ +int MAXLEN = 77; /* default maximum line length in the above style */ +int MINLEN = 7; /* minimum line length in the above style */ +int errorCount = 0; /* number of parsing errors detected */ + +/* + * internal functions + */ +void EOFerror(void); +void ESCerror(int c); +void GBerror(int c1,int c2); +void GBerror1(int c); +void GBtoSGB(int hi, int lo, int *hi1, int *lo1); +void mac2gb(int hi, int lo, int *hi1, int *lo1); +void dos2gb(int hi, int lo, int *hi1, int *lo1); + + +void zw2gb(char *src,char **dest) +{ + char *buf; + + buf=(char*)malloc(strlen(*dest) * sizeof(char)); + + zw2hz(src,&buf); + hz2gb(buf,dest); + + free(buf); +} + + + +void zw2hz(char *src,char **dest) +{ +/* + Copyright (C) 1989, 1992 Fung F. Lee + + zw2hz 2.0: do a straightforward conversion from a zW file into a HZ file + + This version was an update of version 1.1, because the specification of + zW had been changed by the original authors. + + Since the set of all zW files is a proper subset of the set of all + HZ (HGB) files, it is always possible to do perfect translation from + zW to HZ (HGB); but not vice versa. + * HGB - High-bit-set GB, as used in CCDOS, Macintosh System 6.0.x and later. + + As for error handling, I took the lazy approach. For example, if the + original zW file contains invalid GB codes, they will also show up in + the output HZ file, and can be detected by "hz2gb -v". + + This program is free for general distribution. +*/ + +/* As we do not want to impose any limit of line length (such as 80 characters + per line), we parse the input stream on a character by character basis, + because in the worst case, a line can be as long as a file. + Although in practice the line length (with or without soft CR marker at + its end) is likely to be about 80 characters or so, I am not sure what + the maximum line length is enforced by the zW standard, nor do I think + it is a necessary assumption for proper decoding. + */ + int c1, c2; + int ASCIImode = TRUE; + int lineStart = TRUE; + FILE *fin, *fout; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1 = fgetc(fin)) != EOF) { + if (ASCIImode) { + if (c1 == '\n') { + fputc('\n', fout); + lineStart = TRUE; + } else if (lineStart && c1 == 'z') { + c2 = fgetc(fin); + if (c2 == EOF) { + fputc(c1, fout); + break; + } + if (c2 == 'W') { + fprintf(fout, "~{"); + ASCIImode = FALSE; + } else { + fputc(c1, fout); + fputc(c2, fout); + } + lineStart = FALSE; + } else { + fputc(c1, fout); + lineStart = FALSE; + } + } else { /* GBmode */ + c2 = fgetc(fin); + if (c1 == '\n') { + ungetc(c2, fin); + fprintf(fout, "~}~\n"); /* soft CR - with line continuation */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c2 == EOF) { + fputc(c1, fout); + break; + } else if (c1 == '#' && c2 == '\n') { + fprintf(fout, "~}\n"); /* hard CR */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c2 == '\n') { /* This may be an invalid zW sequence, ... */ + /* anyway, for robustness, I choose ... */ + /* eat c1 */ /* c1 may be ' ' or something else */ + fprintf(fout, "~}\n"); /* hard CR */ + lineStart = TRUE; + ASCIImode = TRUE; + } else if (c1 == '#' && c2 == ' ') { + fprintf(fout, "~} ~{"); /* temporary escape and back */ + } else if (c1 == ' ') { /* 0x20?? is now for ASCII characters */ + fprintf(fout, "~}%c~{", c2); /* temporary escape and back */ + } else { /* ASSUME they are GB codes, and fix them in program hz2gb */ + fputc(c1, fout); fputc(c2, fout); + } + } + } + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +void hz2gb(char *src,char **dest) +{ +/* + Copyright (C) 1989, 1992 Fung F. Lee + + hz2gb 2.0: convert a HZ file into a Macintosh* / CCDOS SGB file. + *For Macintosh pre-6.0.x Simplified Chinese Operating System. + Later versions use the same internal code (High-bit-set GB) as CCDOS does. + + The HZ specification does not dictate how to convert invalid HZ files, + just as the definition of a programming language usually does not specify + how a compiler should handle illegal programming constructs. + The error recovery procedure of this HZ decoder was designed after + examination of the conversion errors reported by hz2gb 1.1 of some of the + "HZ" files posted on the news group alt.chinese.text. I suspected that + most of the errors occured due to improper manual insertion of escape + sequences, and/or using invalid GB codes, such as those for "space" ($2121). + Such errors should not have occured if the files were first properly edited + as GB codes, and then converted by an HZ encoder, such as gb2hz (preferably + with the -t option.) + + To prevent some hanzi displayers from ill behaviour, the output stream + should be or should be corrected to be valid mixed ASCII and GB sequences. + + The error recovery procedure is by no means unique, and may change in the + future. Users should NOT regard the error recovery features as part of the + HZ specification. + + This program is free for general distribution. +*/ + FILE *fin, *fout; + int c1, c2, c3, c4; + int ASCIImode = TRUE; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1=fgetc(fin)) != EOF) { + if (!pass8) + c1 = CLEAN7(c1); + if (ASCIImode) { + if (c1 == '~') { + if ((c2 = fgetc(fin)) == EOF) { + EOFerror(); + break; + } + if (!pass8) + c2 = CLEAN7(c2); + switch (c2) { + case '~' : fputc('~', fout); + break; + case '{' : ASCIImode = FALSE; + break; + case '\n': /* line-continuation marker: eat it unless ... */ + if (termStyle) + fputc('\n', fout); + break; + default : ESCerror(c2); + fputc('~', fout); + fputc(c2, fout); + break; + } + } else { + if (LF2CR && c1=='\n') + c1 = '\r'; + fputc(c1, fout); + } + } else { /* GBmode */ + if (isprint(c1)) { + if ((c2 = fgetc(fin)) == EOF) { + EOFerror(); + break; + } + if (!pass8) + c2 = CLEAN7(c2); + if (isGB1(c1) && isGB2(c2)) { + GBtoSGB(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + } else if (c1 == '~' && c2 == '}') { /* 0x7E7D */ + ASCIImode = TRUE; + } else if (isGB1U(c1) && isGB2(c2)) { /* 0x78?? - 0x7D?? */ + GBerror(c1, c2); /* non-standard extended code? */ + fputc(HI(BOX), fout); + fputc(LO(BOX), fout); + } else if (c1 == '~') { /* 0x7E */ + GBerror(c1, c2); /* undefined shift-out code? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + fputc(c2, fout); + } else if (c1 == ' ') { /* 0x20 */ + GBerror(c1, c2); /* looks like artifacts of zwdos? */ + fputc(c2, fout); + } else if (c2 == ' ') { /* 0x20 */ + GBerror(c1, c2); /* null image looks like "sp"? */ + fputc(HI(SPACE), fout); + fputc(LO(SPACE), fout); + } else { /* isprint(c1) && !isprint(c2)) */ + GBerror(c1, c2); /* premature shift-out? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + fputc(c2, fout); + } + } else { /* !isprint(c1) */ + GBerror1(c1); /* premature shift-out? */ + ASCIImode = TRUE; /* safer assumption? */ + fputc(c1, fout); + } + } + } + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +void GBtoSGB(int hi, int lo, int *hi1, int *lo1) +{ +#ifdef DOS + *hi1 = 0x80 | hi; + *lo1 = 0x80 | lo; +#endif +#ifdef MAC + *hi1 = 0x81 + (hi - 0x21)/2; + if (hi%2 != 0) { + *lo1 = 0x40 + (lo - 0x21); + if (*lo1 >= 0x7F) + *lo1 += 1; + } else + *lo1 = 0x9F + (lo - 0x21); +#endif +} + + + +void EOFerror() +{ + errorCount++; + Syslog('m', "hz2gb: Unexpected EOF"); +} + + +void ESCerror(int c) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid ASCII escape sequence:\"~%c\"", c); +} + + +void GBerror(int c1, int c2) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid GB code:\"%c%c\"(0x%4x)", c1,c2, DB(c1,c2)); +} + + + +void GBerror1(int c) +{ + errorCount++; + Syslog('m', "hz2gb: Invalid GB code first byte:'%c'(0x%2x)", c, c); +} + + + +void gb2hz(char *src,char **dest) +{ +/* + Copyright (C) 1989 Fung F. Lee + + sgb2hz: convert a Macintosh/CCDOS SGB file into a HZ file. + + This program is free for general distribution. + +*/ + FILE *fin, *fout; + int c1, c2, c3, c4; +#ifdef MAC + int hi; +#endif + int GBmode = FALSE; + int len = 0; + + OPENINOUTFILES(&fin,&fout,src); + + while ((c1=fgetc(fin)) != EOF) { + if (notAscii(c1)) +#ifdef MAC + { + hi = c1 & 0xF0; + switch (hi) { + case 0x80: + case 0x90: + case 0xA0: + if (termStyle) { + if (GBmode && len>MAXLEN-5) { + fprintf(fout, "~}~\n"); + GBmode = FALSE; + len = 0; + } else if (!GBmode && len>MAXLEN-7) { + fprintf(fout, "~\n"); + GBmode = FALSE; len = 0; + } + } + if (!GBmode) { /* switch to GB mode */ + fprintf(fout, "~{"); + len += 2; + } + GBmode = TRUE; + c2 = fgetc(fin); + mac2gb(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + len += 2; + break; + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + WriteError("gb2hz: ignored non-Ascii character: %2x\n", c1); + break; + case 0xF0: + switch (c1) { + case 0xFD: + case 0xFE: + case 0xFF: + WriteError("gb2hz: ignored non-Ascii character: %2x\n", c1); + break; + default: + c2 = fgetc(fin); + WriteError("gb2hz: ignored user defined SGB code: %2x%2x\n", c1, c2); + break; + } + } + } +#endif +#ifdef DOS + { + if (termStyle) { + if (GBmode && len>MAXLEN-5) { + fprintf(fout, "~}~\n"); + GBmode = FALSE; + len = 0; + } else if (!GBmode && len>MAXLEN-7) { + fprintf(fout, "~\n"); + GBmode = FALSE; len = 0; + } + } + if (!GBmode) { /* switch to GB mode */ + fprintf(fout, "~{"); + len += 2; + } + GBmode = TRUE; + c2 = fgetc(fin); + dos2gb(c1, c2, &c3, &c4); + fputc(c3, fout); + fputc(c4, fout); + len += 2; + } +#endif + /* c1 is ASCII */ + else { + if (GBmode) { + fprintf(fout, "~}"); + len += 2; + } + /* assert(len<=MAXLEN-1) */ + if (termStyle && (len>MAXLEN-2 || (len>MAXLEN-3 && c1=='~'))) { + fprintf(fout, "~\n"); + len = 0; + } + GBmode = FALSE; + if (CR2LF && c1=='\r') + c1 = '\n'; + fputc(c1, fout); + len++; + if (c1=='\n') + len=0; + else if (c1== '~') { + fputc('~', fout); + len++; + } + } + } + if (GBmode) + fprintf(fout, "~}"); + + CLOSEINOUTFILES(&fin,&fout,dest); +} + + + +#ifdef MAC +void mac2gb(int hi, int lo, int *hi1, int *lo1) +{ + if (lo >= 0x9F) { + *hi1 = 0x21 + (hi - 0x81) * 2 + 1; + *lo1 = 0x21 + (lo - 0x9F); + } else { + *hi1 = 0x21 + (hi - 0x81) * 2; + if (lo > 0x7F) + lo--; + *lo1 = 0x21 + (lo - 0x40); + } +} +#endif + + + +#ifdef DOS +void dos2gb(int hi, int lo, int *hi1, int *lo1) +{ + *hi1 = hi - 0x80; + *lo1 = lo - 0x80; +} +#endif + diff --git a/lib/charconv_jp.c b/lib/charconv_jp.c new file mode 100644 index 00000000..c191a5ad --- /dev/null +++ b/lib/charconv_jp.c @@ -0,0 +1,806 @@ +/***************************************************************************** + * + * File ..................: charconv_jp.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +/* ### Modified by P. Saratxaga on 26 Oct 95 ### + * This is the kcon.c taken from JE version (code from T. Tanaka) + * I've modified it to support 8bit -> 8bit transcoding in addition of + * japanese (16 bits) ones. + * Also the codings are not readen from a config file but taken from the + * charset values in Header lines. + */ + + + +void OPENINOUTFILES(FILE **in, FILE **out, char *src) +{ + *in=tmpfile(); + *out=tmpfile(); + fwrite(src, sizeof(char), strlen(src), *in); + rewind(*in); +} + + + +void CLOSEINOUTFILES(FILE **in, FILE **out,char **dest) +{ + int destlen, c; + char *p; + + rewind(*out); + for(destlen = 0; (c = fgetc(*out)) != EOF; destlen++); + rewind(*out); + if(*dest) + free(*dest); + *dest = (char *)malloc((destlen + 1) * sizeof(char)); + for(p = *dest; (c = fgetc(*out)) != EOF; p++) + *p = (char)(c & 0xff); + *p = '\0'; + fclose(*in); + fclose(*out); +} + + + +void sjis2jis(int *p1,int *p2) +{ + register unsigned char c1 = *p1; + register unsigned char c2 = *p2; + register int adjust = c2 < 159; + register int rowOffset = c1 < 160 ? 112 : 176; + register int cellOffset = adjust ? (31 + (c2 > 127)) : 126; + + *p1 = ((c1 - rowOffset) << 1) - adjust; + *p2 -= cellOffset; +} + + + +void jis2sjis(int *p1,int *p2) +{ + register unsigned char c1 = *p1; + register unsigned char c2 = *p2; + register int rowOffset = c1 < 95 ? 112 : 176; + register int cellOffset = c1 % 2 ? 31 + (c2 > 95) : 126; + + *p1 = ((c1 + 1) >> 1) + rowOffset; + *p2 = c2 + cellOffset; +} + + + +void shift2seven(char *src,char **dest,int incode,char ki[],char ko[]) +{ + int p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case NUL : + case FF : + break; + case CR : + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",NL); + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) { + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } else if HANKATA(p1) { + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + fprintf(out,"%c%c",p1,p2); + } else { + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + } + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void shift2euc(char *src, char **dest, int incode, int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case CR : + case NL : + fprintf(out,"%c",NL); + break; + case NUL : + case FF : + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) { + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } + fprintf(out,"%c%c",p1,p2); + } else if HANKATA(p1) { + if (tofullsize) { + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } else { + p2 = p1; + p1 = 142; + } + fprintf(out,"%c%c",p1,p2); + } else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2seven(char *src,char **dest,int incode,char ki[],char ko[]) +{ + int p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) { + p1 -= 128; + p2 -= 128; + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if HANKATA(p2) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + if (!intwobyte) { + intwobyte = TRUE; + fprintf(out,"%c%s",ESC,ki); + } + } + fprintf(out,"%c%c",p1,p2); + } + else { + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + } + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2shift(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) { + p1 -= 128; + p2 -= 128; + jis2sjis(&p1,&p2); + } + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if HANKATA(p2) { + if (tofullsize) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + fprintf(out,"%c%c",p1,p2); + } + else { + p1 = p2; + fprintf(out,"%c",p1); + } + } + else + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + + + +void euc2euc(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case FF : + break; + default : + if ISEUC(p1) { + p2 = fgetc(in); + if ISEUC(p2) + fprintf(out,"%c%c",p1,p2); + } + else if (p1 == 142) { + p2 = fgetc(in); + if (HANKATA(p2) && tofullsize) { + p1 = p2; + han2zen(in,&p1,&p2,incode); + sjis2jis(&p1,&p2); + p1 += 128; + p2 += 128; + } + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void shift2shift(char *src,char **dest,int incode,int tofullsize) +{ + int p1,p2; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case CR : + case NL : + fprintf(out,"%c",NL); + break; + case NUL : + case FF : + break; + default : + if SJIS1(p1) { + p2 = fgetc(in); + if SJIS2(p2) + fprintf(out,"%c%c",p1,p2); + } + else if (HANKATA(p1) && tofullsize) { + han2zen(in,&p1,&p2,incode); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2shift(char *src,char **dest) +{ + int temp,p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + SkipESCSeq(in,temp,&intwobyte); + break; + case NL : + if (intwobyte) + intwobyte = FALSE; + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + jis2sjis(&p1,&p2); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2euc(char *src, char **dest) +{ + int temp,p1,p2,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + SkipESCSeq(in,temp,&intwobyte); + break; + case NL : + if (intwobyte) + intwobyte = FALSE; + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + p1 += 128; + p2 += 128; + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + CLOSEINOUTFILES(&in,&out,dest); +} + +void seven2seven(char *src,char **dest,char ki[],char ko[]) +{ + int temp,p1,p2,change,intwobyte = FALSE; + FILE *in, *out; + + OPENINOUTFILES(&in,&out,src); + + while ((p1 = fgetc(in)) != EOF) { + switch (p1) { + case ESC : + temp = fgetc(in); + change = SkipESCSeq(in,temp,&intwobyte); + if ((intwobyte) && (change)) + fprintf(out,"%c%s",ESC,ki); + else if (change) + fprintf(out,"%c%s",ESC,ko); + break; + case NL : + if (intwobyte) { + intwobyte = FALSE; + fprintf(out,"%c%s",ESC,ko); + } + fprintf(out,"%c",p1); + break; + case FF : + break; + default : + if (intwobyte) { + p2 = fgetc(in); + fprintf(out,"%c%c",p1,p2); + } + else + fprintf(out,"%c",p1); + break; + } + } + if (intwobyte) + fprintf(out,"%c%s",ESC,ko); + CLOSEINOUTFILES(&in,&out,dest); +} + +void han2zen(FILE *in,int *p1,int *p2,int incode) +{ + int junk,maru,nigori; + + maru = nigori = FALSE; + if (incode == CHRS_SJIS) { + *p2 = fgetc(in); + if (*p2 == 222) { + if (ISNIGORI(*p1) || *p1 == 179) + nigori = TRUE; + else + ungetc(*p2,in); + } + else if (*p2 == 223) { + if ISMARU(*p1) + maru = TRUE; + else + ungetc(*p2,in); + } + else + ungetc(*p2,in); + } + else if (incode == CHRS_EUC_JP) { + junk = fgetc(in); + if (junk == 142) { + *p2 = fgetc(in); + if (*p2 == 222) { + if (ISNIGORI(*p1) || *p1 == 179) + nigori = TRUE; + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else if (*p2 == 223) { + if ISMARU(*p1) + maru = TRUE; + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else { + ungetc(*p2,in); + ungetc(junk,in); + } + } + else + ungetc(junk,in); + } + switch (*p1) { + case 161 : + *p1 = 129; + *p2 = 66; + break; + case 162 : + *p1 = 129; + *p2 = 117; + break; + case 163 : + *p1 = 129; + *p2 = 118; + break; + case 164 : + *p1 = 129; + *p2 = 65; + break; + case 165 : + *p1 = 129; + *p2 = 69; + break; + case 166 : + *p1 = 131; + *p2 = 146; + break; + case 167 : + *p1 = 131; + *p2 = 64; + break; + case 168 : + *p1 = 131; + *p2 = 66; + break; + case 169 : + *p1 = 131; + *p2 = 68; + break; + case 170 : + *p1 = 131; + *p2 = 70; + break; + case 171 : + *p1 = 131; + *p2 = 72; + break; + case 172 : + *p1 = 131; + *p2 = 131; + break; + case 173 : + *p1 = 131; + *p2 = 133; + break; + case 174 : + *p1 = 131; + *p2 = 135; + break; + case 175 : + *p1 = 131; + *p2 = 98; + break; + case 176 : + *p1 = 129; + *p2 = 91; + break; + case 177 : + *p1 = 131; + *p2 = 65; + break; + case 178 : + *p1 = 131; + *p2 = 67; + break; + case 179 : + *p1 = 131; + *p2 = 69; + break; + case 180 : + *p1 = 131; + *p2 = 71; + break; + case 181 : + *p1 = 131; + *p2 = 73; + break; + case 182 : + *p1 = 131; + *p2 = 74; + break; + case 183 : + *p1 = 131; + *p2 = 76; + break; + case 184 : + *p1 = 131; + *p2 = 78; + break; + case 185 : + *p1 = 131; + *p2 = 80; + break; + case 186 : + *p1 = 131; + *p2 = 82; + break; + case 187 : + *p1 = 131; + *p2 = 84; + break; + case 188 : + *p1 = 131; + *p2 = 86; + break; + case 189 : + *p1 = 131; + *p2 = 88; + break; + case 190 : + *p1 = 131; + *p2 = 90; + break; + case 191 : + *p1 = 131; + *p2 = 92; + break; + case 192 : + *p1 = 131; + *p2 = 94; + break; + case 193 : + *p1 = 131; + *p2 = 96; + break; + case 194 : + *p1 = 131; + *p2 = 99; + break; + case 195 : + *p1 = 131; + *p2 = 101; + break; + case 196 : + *p1 = 131; + *p2 = 103; + break; + case 197 : + *p1 = 131; + *p2 = 105; + break; + case 198 : + *p1 = 131; + *p2 = 106; + break; + case 199 : + *p1 = 131; + *p2 = 107; + break; + case 200 : + *p1 = 131; + *p2 = 108; + break; + case 201 : + *p1 = 131; + *p2 = 109; + break; + case 202 : + *p1 = 131; + *p2 = 110; + break; + case 203 : + *p1 = 131; + *p2 = 113; + break; + case 204 : + *p1 = 131; + *p2 = 116; + break; + case 205 : + *p1 = 131; + *p2 = 119; + break; + case 206 : + *p1 = 131; + *p2 = 122; + break; + case 207 : + *p1 = 131; + *p2 = 125; + break; + case 208 : + *p1 = 131; + *p2 = 126; + break; + case 209 : + *p1 = 131; + *p2 = 128; + break; + case 210 : + *p1 = 131; + *p2 = 129; + break; + case 211 : + *p1 = 131; + *p2 = 130; + break; + case 212 : + *p1 = 131; + *p2 = 132; + break; + case 213 : + *p1 = 131; + *p2 = 134; + break; + case 214 : + *p1 = 131; + *p2 = 136; + break; + case 215 : + *p1 = 131; + *p2 = 137; + break; + case 216 : + *p1 = 131; + *p2 = 138; + break; + case 217 : + *p1 = 131; + *p2 = 139; + break; + case 218 : + *p1 = 131; + *p2 = 140; + break; + case 219 : + *p1 = 131; + *p2 = 141; + break; + case 220 : + *p1 = 131; + *p2 = 143; + break; + case 221 : + *p1 = 131; + *p2 = 147; + break; + case 222 : + *p1 = 129; + *p2 = 74; + break; + case 223 : + *p1 = 129; + *p2 = 75; + break; + } + if (nigori) { + if ((*p2 >= 74 && *p2 <= 103) || (*p2 >= 110 && *p2 <= 122)) + (*p2)++; + else if (*p1 == 131 && *p2 == 69) + *p2 = 148; + } + else if (maru && *p2 >= 110 && *p2 <= 122) + *p2 += 2; +} diff --git a/lib/charconv_utf.c b/lib/charconv_utf.c new file mode 100644 index 00000000..896be839 --- /dev/null +++ b/lib/charconv_utf.c @@ -0,0 +1,267 @@ +/***************************************************************************** + * + * File ..................: charconv_utf.c + * Purpose ...............: Common utilities + * Last modification date : 29-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +char Base_64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + +/* returns numeric value from a Base64Code[] digit */ +static int index_hex2[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1,0x3e, -1, -1, -1,0x3f, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b, + 0x3c,0x3d, -1, -1, -1, -1, -1, -1, + -1,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19, -1, -1, -1, -1, -1, + -1,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20, + 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30, + 0x31,0x32,0x33, -1, -1, -1, -1, -1 +}; + + + +void utf7_to_eight(char *in,char **out,int *code) +{ + int isb64,l_code=CHRS_AUTODETECT; + char *p, *q, *buf; + + buf=malloc(strlen(in)*sizeof(char)); + + isb64=0; + for (p = in, q = buf; *p != '\0';) { + + if (isb64) { /* we are in B64 encoding, that is in utf-7 */ + int bit_buffer=0; + int nbits=0; + int i,l,result,offset=0; + + /* find the lenght of the B64 string */ + l=strspn(p,Base_64Code); + for (i=0;i= 8) { + nbits -= 8; + result = ((bit_buffer >> nbits)&0xff); + /* if the charset code is unknown try to find it. + * it only works for latin1 (iso-8859-1), cyrillic, greek, + * arabic and hebrew (iso-8859-[5678]), as for other latin + * encodings it is harder, iso-8859-2 is assumed as it is + * the most common + */ + if ((l_code==CHRS_AUTODETECT) || (l_code==CHRS_ISO_8859_1)) { + if (result == 0x00) l_code=CHRS_ISO_8859_1; + else if (result == 0x01) l_code=CHRS_ISO_8859_2; + else if (result == 0x03) l_code=CHRS_ISO_8859_7; + else if (result == 0x04) l_code=CHRS_ISO_8859_5; + else if (result == 0x05) l_code=CHRS_ISO_8859_8; + else if (result == 0x06) l_code=CHRS_ISO_8859_6; + } + /* what to add to next byte to convert to iso-8859-* + * note that it doesn't work for iso-8859-{2,3,4,9,10} + * as the offset changes for almost each char + */ + if (result == 0x00) offset=0x00; + else if (result == 0x03) offset=0x30; + else if (result == 0x04) offset=0xa0; + else if (result == 0x05) offset=0x10; + else if (result == 0x06) offset=0xa0; + + /* convert to the right 8bit char by adding offset */ + if (result < 0x06) *q++ = (char)((bit_buffer & 0xff) + offset); + else *q++ = (char)(bit_buffer & 0xff); + } + } + /* end of B64 encoding */ + if (*p == '-') p++; + isb64=0; + } else if (*p == '+') { /* '+' is the beginning of a new B64 section */ + isb64=1; + p++; + } else { /* ascii encoding */ + *q++=*p++; + } + } + *q = '\0'; + + /* now we know the 8bit charset that was encoded whith utf-7, + * so ask again to see if a conversion to FTN charset is needed + */ + if (*code==CHRS_AUTODETECT || *code==CHRS_NOTSET) + *code=getoutcode(l_code); + switch (l_code) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (*code) { + case CHRS_CP437 : eight2eight(buf,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(buf,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(buf,out,(char *)ISO_8859_1__MACINTOSH); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (*code) { + case CHRS_CP866 : eight2eight(buf,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(buf,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(buf,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (*code) { + case CHRS_CP424 : eight2eight(buf,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(buf,out,(char *)ISO_8859_8__CP862); break; + default : noconv(buf,out); break; + } + break; + default : noconv(in,out); break; + } +} + +/* + * UNICODE UTF-8 + * ------------- ------------------------------------ + * 0000 -> 007F = 7 bits = 0xxxxxxx + * 0080 -> 07FF = 11 bits = 110xxxxx 10xxxxxx + * 0800 -> FFFF = 16 bits = 1110xxxx 10xxxxxx 10xxxxxx + */ +void utf8_to_eight(char *in,char **out,int *code) +{ + int is8bit,l_code=CHRS_AUTODETECT; + char *p, *q, *buf; + + buf=malloc(strlen(in)*sizeof(char)); + + is8bit=0; + for (p = in, q = buf; *p != '\0';) { + int bit_buffer=0; + int nbits=0; + int result,offset=0; + + if ((*p & 0xff) >= 0xe0) { /* 16 bits = 1110xxxx 10xxxxxx 10xxxxxx */ + bit_buffer=((*p++ & 0xff) & 0x0f); + bit_buffer=(bit_buffer << 4); + bit_buffer+=((*p++ & 0xff) & 0xbf); + bit_buffer=(bit_buffer << 6); + bit_buffer+=((*p++ & 0xff) & 0x3f); + nbits=16; + } else if ((*p & 0xff) >= 0xc0) { /* 11 bits = 110xxxxx 10xxxxxx */ + bit_buffer=((*p++ & 0xff) & 0x2f); + bit_buffer=(bit_buffer << 6); + bit_buffer+=((*p++ & 0xff) & 0x3f); + nbits=11; + } else { /* 7 bits = 0xxxxxxx */ + bit_buffer=(*p++ & 0xff); + nbits=7; + } + + if (nbits >= 8) { + result = ((bit_buffer >> 8)&0xff); + /* if the charset code is unknown try to find it. + * it only works for latin1 (iso-8859-1), cyrillic, greek, + * arabic and hebrew (iso-8859-[5678]), as for other latin + * encodings it is harder, iso-8859-2 is assumed as it is + * the most common + */ + if ((l_code==CHRS_AUTODETECT) || (l_code==CHRS_ISO_8859_1)) { + if (result == 0x00) l_code=CHRS_ISO_8859_1; + else if (result == 0x01) l_code=CHRS_ISO_8859_2; + else if (result == 0x03) l_code=CHRS_ISO_8859_7; + else if (result == 0x04) l_code=CHRS_ISO_8859_5; + else if (result == 0x05) l_code=CHRS_ISO_8859_8; + else if (result == 0x06) l_code=CHRS_ISO_8859_6; + } + /* what to add to next byte to convert to iso-8859-* + * note that it doesn't work for iso-8859-{2,3,4,9,10} + * as the offset changes for almost each char + */ + if (result == 0x00) offset=0x00; + else if (result == 0x03) offset=0x30; + else if (result == 0x04) offset=0xa0; + else if (result == 0x05) offset=0x10; + else if (result == 0x06) offset=0xa0; + /* convert to the right 8bit char by adding offset */ + if (result < 0x06) *q++ = (char)((bit_buffer & 0xff) + offset); + else *q++ = (char)(bit_buffer & 0xff); + } else { /* ascii encoding */ + *q++ = (char)(bit_buffer & 0xff); + } + } + *q = '\0'; + /* now we know the 8bit charset that was encoded whith utf-7, + * so ask again to see if a conversion to FTN charset is needed + */ + if (*code==CHRS_AUTODETECT || *code==CHRS_NOTSET) + *code=getoutcode(l_code); + switch (l_code) { + case CHRS_ISO_8859_1 : + case CHRS_ISO_8859_15: + switch (*code) { + case CHRS_CP437 : eight2eight(buf,out,(char *)ISO_8859_1__CP437); break; + case CHRS_CP850 : eight2eight(buf,out,(char *)ISO_8859_1__CP850); break; + case CHRS_MACINTOSH : eight2eight(buf,out,(char *)ISO_8859_1__MACINTOSH); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_5 : + switch (*code) { + case CHRS_CP866 : eight2eight(buf,out,(char *)ISO_8859_5__CP866); break; + case CHRS_KOI8_R : + case CHRS_KOI8_U : eight2eight(buf,out,(char *)ISO_8859_5__KOI8); break; + case CHRS_MIK_CYR : eight2eight(buf,out,(char *)ISO_8859_5__MIK_CYR); break; + default : noconv(buf,out); break; + } + break; + case CHRS_ISO_8859_8 : + switch (*code) { + case CHRS_CP424 : eight2eight(buf,out,(char *)ISO_8859_8__CP424); break; + case CHRS_CP862 : eight2eight(buf,out,(char *)ISO_8859_8__CP862); break; + default : noconv(buf,out); break; + } + break; + default : noconv(in,out); break; + } +} + + diff --git a/lib/charset.c b/lib/charset.c new file mode 100644 index 00000000..d60d5411 --- /dev/null +++ b/lib/charset.c @@ -0,0 +1,424 @@ +/***************************************************************************** + * + * File ..................: charset.c + * Purpose ...............: Common utilities + * Last modification date : 09-Sep-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +/* ### Created by P.Saratxaga on 7 Nov 1995 ### + * Functions for charset reading + * - bugfix for bad Content-Type lines lacking ";". By Marc Schaeffer. + */ + +int defaultrfcchar = CHRS_DEFAULT_RFC; +int defaultftnchar = CHRS_DEFAULT_FTN; +int toftnchar = CHRS_NOTSET; + + +//#ifndef HAVE_STRCASESTR +//char *strcasestr(char *, char *); +//#endif + + +/* tailor getoutcode() and getincode() to show your transcodage preferences */ + +int getoutcode(int code) /* rfc -> FTN */ +{ + if ((code==CHRS_MACINTOSH) && (toftnchar!=CHRS_NOTSET)) + return toftnchar; + else if (code==CHRS_MACINTOSH) return CHRS_ISO_8859_1; + else if ((toftnchar!=CHRS_NOTSET) && (code==defaultrfcchar)) + return toftnchar; + else if (code==CHRS_UTF_7||code==CHRS_UTF_8) return CHRS_AUTODETECT; + else if (code==CHRS_ZW) return CHRS_GB; + else return code; +} + + + +int getincode(int code) /* FTN -> rfc */ +{ + if (code==CHRS_CP437) return CHRS_ISO_8859_1; + else if (code==CHRS_CP850) return CHRS_ISO_8859_1; + else if (code==CHRS_CP852) return CHRS_ISO_8859_2; + else if (code==CHRS_CP862) return CHRS_ISO_8859_8; + else if (code==CHRS_CP866) return CHRS_KOI8_R; + else if (code==CHRS_CP895) return CHRS_ISO_8859_2; + else if (code==CHRS_EUC_JP) return CHRS_ISO_2022_JP; +/* else if (code==CHRS_EUC_KR) return CHRS_ISO_2022_KR; */ + else if (code==CHRS_FIDOMAZOVIA) return CHRS_ISO_8859_2; + else if (code==CHRS_ISO_11) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_4) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_60) return CHRS_ISO_8859_1; + else if (code==CHRS_ISO_8859_1_QP) return CHRS_ISO_8859_1_QP; + else if (code==CHRS_MACINTOSH) return CHRS_ISO_8859_1; + else if (code==CHRS_MIK_CYR) return CHRS_ISO_8859_5; + else if (code==CHRS_SJIS) return CHRS_ISO_2022_JP; + else if (code==defaultftnchar) return CHRS_AUTODETECT; + else return code; +} + + + +char *getcharset(int code) +{ + char *charset; + + if (code==CHRS_ASCII) charset=(char *)"us-ascii"; + else if (code==CHRS_BIG5) charset=(char *)"x-CN-Big5"; + else if (code==CHRS_CP424) charset=(char *)"x-cp424"; + else if (code==CHRS_CP437) charset=(char *)"x-cp437"; + else if (code==CHRS_CP850) charset=(char *)"x-cp850"; + else if (code==CHRS_CP852) charset=(char *)"x-cp852"; + else if (code==CHRS_CP862) charset=(char *)"x-cp862"; + else if (code==CHRS_CP866) charset=(char *)"x-cp866"; + else if (code==CHRS_CP895) charset=(char *)"x-cp895"; + else if (code==CHRS_EUC_JP) charset=(char *)"EUC-jp"; + else if (code==CHRS_EUC_KR) charset=(char *)"EUC-kr"; + else if (code==CHRS_FIDOMAZOVIA) charset=(char *)"x-FIDOMAZOVIA"; + else if (code==CHRS_GB) charset=(char *)"x-CN-GB"; + else if (code==CHRS_HZ) charset=(char *)"x-HZ"; + else if (code==CHRS_ISO_2022_CN) charset=(char *)"iso-2022-cn"; + else if (code==CHRS_ISO_2022_JP) charset=(char *)"iso-2022-jp"; + else if (code==CHRS_ISO_2022_KR) charset=(char *)"iso-2022-kr"; + else if (code==CHRS_ISO_2022_TW) charset=(char *)"iso-2022-tw"; + else if (code==CHRS_ISO_8859_1) charset=(char *)"iso-8859-1"; + else if (code==CHRS_ISO_8859_1_QP) charset=(char *)"iso-8859-1"; + else if (code==CHRS_ISO_8859_2) charset=(char *)"iso-8859-2"; + else if (code==CHRS_ISO_8859_3) charset=(char *)"iso-8859-3"; + else if (code==CHRS_ISO_8859_4) charset=(char *)"iso-8859-4"; + else if (code==CHRS_ISO_8859_5) charset=(char *)"iso-8859-5"; + else if (code==CHRS_ISO_8859_6) charset=(char *)"iso-8859-6"; + else if (code==CHRS_ISO_8859_7) charset=(char *)"iso-8859-7"; + else if (code==CHRS_ISO_8859_8) charset=(char *)"iso-8859-8"; + else if (code==CHRS_ISO_8859_9) charset=(char *)"iso-8859-5"; + else if (code==CHRS_ISO_8859_10) charset=(char *)"iso-8859-10"; + else if (code==CHRS_ISO_8859_11) charset=(char *)"iso-8859-11"; + else if (code==CHRS_ISO_8859_15) charset=(char *)"iso-8859-15"; + else if (code==CHRS_KOI8_R) charset=(char *)"koi8-r"; + else if (code==CHRS_KOI8_U) charset=(char *)"koi8-u"; + else if (code==CHRS_MACINTOSH) charset=(char *)"x-mac-roman"; + else if (code==CHRS_MIK_CYR) charset=(char *)"x-mik-cyr"; + else if (code==CHRS_NEC) charset=(char *)"x-NEC-JIS"; + else if (code==CHRS_SJIS) charset=(char *)"x-sjis"; + else if (code==CHRS_UTF_7) charset=(char *)"utf-7"; + else if (code==CHRS_UTF_8) charset=(char *)"utf-8"; + else if (code==CHRS_VISCII_11) charset=(char *)"viscii"; + else if (code==CHRS_ZW) charset=(char *)"x-zW"; + else charset=(char *)"us-ascii"; /* mime default */ + + return charset; +} + + + +int getcode(char *p) +{ + int code; + + while (*p && isspace(*p)) p++; + if (strncmp(p,"\"",1) == 0) p++; +/* if (strncasecmp(p,"us-ascii",8) == 0) code=CHRS_ASCII; */ +/* most newsreaders/mail user agents are misconfigured and put "us-ascii" when + in fact they use the local charset. */ + if (strncasecmp(p,"us-ascii",8) == 0) code=defaultrfcchar; + else if (strncasecmp(p,"CN-GB",5) == 0) code=CHRS_GB; + else if (strncasecmp(p,"CN-Big5",7) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"EUC-jp",6) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"EUC-kr",6) == 0) code=CHRS_EUC_KR; + else if (strncasecmp(p,"iso-2022-cn",11) == 0) code=CHRS_ISO_2022_CN; + else if (strncasecmp(p,"iso-2022-jp",11) == 0) code=CHRS_ISO_2022_JP; + else if (strncasecmp(p,"iso-2022-kr",11) == 0) code=CHRS_ISO_2022_KR; + else if (strncasecmp(p,"iso-2022-tw",11) == 0) code=CHRS_ISO_2022_TW; + else if (strncasecmp(p,"iso8859-1",9) == 0) code = CHRS_ISO_8859_1; /* erroneous iso8859-1 */ + else if (strncasecmp(p,"iso-8859-10",11) == 0) code=CHRS_ISO_8859_10; + else if (strncasecmp(p,"iso-8859-11",11) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"iso-8859-15",11) == 0) code=CHRS_ISO_8859_15; + else if (strncasecmp(p,"iso-8859-1",10) == 0) code = CHRS_ISO_8859_1; + else if (strncasecmp(p,"iso-8859-2",10) == 0) code=CHRS_ISO_8859_2; + else if (strncasecmp(p,"iso-8859-3",10) == 0) code=CHRS_ISO_8859_3; + else if (strncasecmp(p,"iso-8859-4",10) == 0) code=CHRS_ISO_8859_4; + else if (strncasecmp(p,"iso-8859-5",10) == 0) code=CHRS_ISO_8859_5; + else if (strncasecmp(p,"iso-8859-6",10) == 0) code=CHRS_ISO_8859_6; + else if (strncasecmp(p,"iso-8859-7",10) == 0) code=CHRS_ISO_8859_7; + else if (strncasecmp(p,"iso-8859-8",10) == 0) code=CHRS_ISO_8859_8; + else if (strncasecmp(p,"iso-8859-9",10) == 0) code=CHRS_ISO_8859_9; + else if (strncasecmp(p,"koi8-r",6) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"koi8-u",6) == 0) code=CHRS_KOI8_U; + else if (strncasecmp(p,"macintosh",9) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"Shift_JIS",9) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"utf-7",5) == 0) code=CHRS_UTF_7; + else if (strncasecmp(p,"utf-8",5) == 0) code=CHRS_UTF_8; + else if (strncasecmp(p,"viscii",6) == 0) code=CHRS_VISCII_11; + else if (strncasecmp(p,"x-cp424",7) == 0) code=CHRS_CP424; + else if (strncasecmp(p,"x-cp437",7) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"x-cp850",7) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"x-cp852",7) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"x-cp862",7) == 0) code=CHRS_CP862; + else if (strncasecmp(p,"x-cp866",7) == 0) code=CHRS_CP866; + else if (strncasecmp(p,"x-cp895",7) == 0) code=CHRS_CP895; + else if (strncasecmp(p,"x-CN-GB",7) == 0) code=CHRS_GB; + else if (strncasecmp(p,"x-CN-Big5",9) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"x-EUC-jp",8) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"x-FIDOMAZ",9) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"x-gb2312",8) == 0) code=CHRS_GB; + else if (strncasecmp(p,"x-HZ",4) == 0) code=CHRS_HZ; + else if (strncasecmp(p,"x-mac-roman",11) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"x-MAZOVIA",9) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"x-mik",5) == 0) code=CHRS_MIK_CYR; + else if (strncasecmp(p,"x-NEC-JIS",9) == 0) code=CHRS_NEC; + else if (strncasecmp(p,"x-Shift-JIS",11) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"x-sjis",6) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"x-tis620",8) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"x-x-big5",8) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"x-zW",4) == 0) code=CHRS_ZW; + /* only intended to be in Areas file. So we can try to found the + * from the values of chars in message itself */ + else if (strncasecmp(p,"AUTODETECT",10) == 0) code=CHRS_AUTODETECT; + else if (strncasecmp(p,"default",7) == 0) code=CHRS_NOTSET; + else { code=CHRS_NOTSET; Syslog('+', "Unknown charset: %s",p); } + return code; +} + + + +int readcharset(char *p) +{ + int code; + + if (!strchr(p, ';')) /* foolproof MSC96 */ + return CHRS_NOTSET; + else if ((strcasestr(p,(char *)"text/plain")) && (strcasestr(p,(char *)"charset="))) + code=getcode(strcasestr(strchr(p,';'),(char *)"charset=")+8); + else if ((strcasestr(p,(char *)"text/html")) && (strcasestr(p,(char *)"charset="))) + code=getcode(strcasestr(strchr(p,';'),(char *)"charset=")+8); + else code=CHRS_NOTSET; + return code; +} + + + +/* readchrs() is also used to read outcode in Areas file (if JE defined) */ + +int readchrs(char *p) +{ + int code; + + while (*p && isspace(*p)) p++; + if (strncasecmp(p,"8859",4) == 0) code=CHRS_ISO_8859_1; + /* for X-FTN-CODEPAGE: */ + else if (strncasecmp(p,"437",3) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"850",3) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"Arabic",6) == 0) code=CHRS_ISO_8859_6; + else if (strncasecmp(p,"ASCII",5) == 0) code=CHRS_ASCII; + else if (strncasecmp(p,"BIG",3) == 0) code=CHRS_BIG5; + else if (strncasecmp(p,"CP 852",6) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"CP424",5) == 0) code=CHRS_CP424; + else if (strncasecmp(p,"CP437",5) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"CP850",5) == 0) code=CHRS_CP850; + else if (strncasecmp(p,"CP852",5) == 0) code=CHRS_CP852; + else if (strncasecmp(p,"CP862",5) == 0) code=CHRS_CP862; + else if (strncasecmp(p,"CP866",5) == 0) code=CHRS_CP866; /* ??? */ + else if (strncasecmp(p,"CP895",5) == 0) code=CHRS_CP895; + else if (strncasecmp(p,"CP932",5) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"CP942",5) == 0) code=CHRS_SJIS; + else if (strncasecmp(p,"Cyrillic",8) == 0) code=CHRS_ISO_8859_5; + else if (strncasecmp(p,"EUC-JP",6) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"EUC-KR",6) == 0) code=CHRS_EUC_KR; + else if (strncasecmp(p,"EUC",3) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"FIDOMAZ",7) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"GB",2) == 0) code=CHRS_GB; + else if (strncasecmp(p,"Greek",5) == 0) code=CHRS_ISO_8859_7; + else if (strncasecmp(p,"Hebrew",6) == 0) code=CHRS_ISO_8859_8; + else if (strncasecmp(p,"HZ",2) == 0) code=CHRS_HZ; + /* Some FTN programs are misconfigured and use "IBMPC 2" kludge + * for the local DOS charset, even if it is DOS cyrillic or other + * so we will assume defaultftnchar here + */ + else if (strncasecmp(p,"IBMPC",5) == 0) code=defaultftnchar; + else if (strncasecmp(p,"IBM",3) == 0) code=CHRS_CP437; /* "IBMPC 1" "IBMPC 2" "IBM CMP" */ + else if (strncasecmp(p,"ISO-11",6) == 0) code=CHRS_ISO_11; + else if (strncasecmp(p,"ISO-2022-CN",11) == 0) code=CHRS_ISO_2022_CN; + else if (strncasecmp(p,"ISO-2022-KR",11) == 0) code=CHRS_ISO_2022_KR; + else if (strncasecmp(p,"ISO-2022-TW",11) == 0) code=CHRS_ISO_2022_TW; + else if (strncasecmp(p,"ISO-4",5) == 0) code=CHRS_ISO_4; + else if (strncasecmp(p,"ISO-60",6) == 0) code=CHRS_ISO_60; + else if (strncasecmp(p,"ISO-8859",8) == 0) code=CHRS_ISO_8859_1; + else if (strncasecmp(p,"JIS",3) == 0) code=CHRS_ISO_2022_JP; /* ??? - JE */ + else if (strncasecmp(p,"Kanji",5) == 0) code=CHRS_ISO_2022_JP; + else if (strncasecmp(p,"KOI8-R",6) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"KOI8-U",6) == 0) code=CHRS_KOI8_U; + else if (strncasecmp(p,"KOI8",4) == 0) code=CHRS_KOI8_R; + else if (strncasecmp(p,"LATIN-0",7) == 0) code=CHRS_ISO_8859_15; + else if (strncasecmp(p,"LATIN1QP",8) == 0) code=CHRS_ISO_8859_1_QP; + else if (strncasecmp(p,"LATIN-1",7) == 0) code=CHRS_ISO_8859_1; + else if (strncasecmp(p,"Latin-2",7) == 0) code=CHRS_ISO_8859_2; + else if (strncasecmp(p,"Latin-3",7) == 0) code=CHRS_ISO_8859_3; + else if (strncasecmp(p,"Latin-4",7) == 0) code=CHRS_ISO_8859_4; + else if (strncasecmp(p,"Latin-5",7) == 0) code=CHRS_ISO_8859_9; + else if (strncasecmp(p,"Latin-6",7) == 0) code=CHRS_ISO_8859_10; + else if (strncasecmp(p,"MAC",3) == 0) code=CHRS_MACINTOSH; + else if (strncasecmp(p,"MIK",3) == 0) code=CHRS_MIK_CYR; + else if (strncasecmp(p,"MAZOVIA",7) == 0) code=CHRS_FIDOMAZOVIA; + else if (strncasecmp(p,"NEC",3) == 0) code=CHRS_NEC; /* ??? - JE */ + else if (strncasecmp(p,"PC-8",4) == 0) code=CHRS_CP437; + else if (strncasecmp(p,"SJIS",4) == 0) code=CHRS_SJIS; /* ??? - JE */ + else if (strncasecmp(p,"Thai",4) == 0) code=CHRS_ISO_8859_11; + else if (strncasecmp(p,"UJIS",4) == 0) code=CHRS_EUC_JP; + else if (strncasecmp(p,"UTF-7",5) == 0) code=CHRS_UTF_7; + else if (strncasecmp(p,"UTF-8",5) == 0) code=CHRS_UTF_8; + else if (strncasecmp(p,"VISCII",6) == 0) code=CHRS_VISCII_11; + else if (strncasecmp(p,"ZW",2) == 0) code=CHRS_ZW; + /* only intended to be in Areas file. So we can try to found the + * from the values of chars in message itself */ + else if (strncasecmp(p,"AUTODETECT",10) == 0) code=CHRS_AUTODETECT; + else if (strncasecmp(p,"default",7) == 0) code=CHRS_NOTSET; + else { code=CHRS_NOTSET; Syslog('+', "Unknown CHRS: %s",p); } + return code; +/* if you know of other CHRS: values which are in use, let me know so I can + include them. Mail me to srtxg@chanae.alphanet.ch or srtxg (2:293/2219) */ +} + + + + +char *getchrs(int code) +{ + char *chrs=NULL; + + if (code == CHRS_ASCII) chrs=(char *)"ASCII 2"; + else if (code == CHRS_BIG5) chrs=(char *)"BIG5"; /* ??? */ + else if (code == CHRS_CP424) chrs=(char *)"CP424"; /* ??? */ + else if (code == CHRS_CP437) chrs=(char *)"IBMPC 2"; + else if (code == CHRS_CP850) chrs=(char *)"CP850 2"; + else if (code == CHRS_CP852) chrs=(char *)"CP852"; /* ??? */ + else if (code == CHRS_CP862) chrs=(char *)"CP862"; /* ??? */ + else if (code == CHRS_CP866) chrs=(char *)"CP866"; + else if (code == CHRS_CP895) chrs=(char *)"CP895 2"; + else if (code == CHRS_EUC_JP) chrs=(char *)"UJIS"; /* ??? */ + else if (code == CHRS_EUC_KR) chrs=(char *)"EUC-KR"; /* ??? */ + else if (code == CHRS_FIDOMAZOVIA) chrs=(char *)"FIDOMAZ 2"; + else if (code == CHRS_GB) chrs=(char *)"GB"; /* ??? */ + else if (code == CHRS_HZ) chrs=(char *)"HZ 2"; /* ??? */ + else if (code == CHRS_ISO_2022_CN) chrs=(char *)"ISO-2022-CN"; /* ??? */ + else if (code == CHRS_ISO_2022_JP) chrs=(char *)"JIS"; + else if (code == CHRS_ISO_2022_KR) chrs=(char *)"ISO-2022-KR"; /* ??? */ + else if (code == CHRS_ISO_2022_TW) chrs=(char *)"ISO-2022-TW"; /* ??? */ + else if (code == CHRS_ISO_8859_1) chrs=(char *)"LATIN-1 2"; + else if (code == CHRS_ISO_8859_1_QP) chrs=(char *)"LATIN-1 2"; + else if (code == CHRS_ISO_8859_2) chrs=(char *)"Latin-2 3"; + else if (code == CHRS_ISO_8859_3) chrs=(char *)"Latin-3 3"; + else if (code == CHRS_ISO_8859_4) chrs=(char *)"Latin-4 3"; + else if (code == CHRS_ISO_8859_5) chrs=(char *)"Cyrillic 3"; /* ??? */ + else if (code == CHRS_ISO_8859_6) chrs=(char *)"Arabic 3"; /* ??? */ + else if (code == CHRS_ISO_8859_7) chrs=(char *)"Greek 3"; /* ??? */ + else if (code == CHRS_ISO_8859_8) chrs=(char *)"Hebrew 3"; /* ??? */ + else if (code == CHRS_ISO_8859_9) chrs=(char *)"Latin-5 3"; + else if (code == CHRS_ISO_8859_10) chrs=(char *)"Latin-6 3"; + else if (code == CHRS_ISO_8859_11) chrs=(char *)"Thai 3"; + else if (code == CHRS_ISO_8859_15) chrs=(char *)"LATIN-0 2"; + else if (code == CHRS_KOI8_R) chrs=(char *)"KOI8-R"; /* ??? */ + else if (code == CHRS_KOI8_U) chrs=(char *)"KOI8-U"; /* ??? */ + else if (code == CHRS_MACINTOSH) chrs=(char *)"MAC 2"; + else if (code == CHRS_MIK_CYR) chrs=(char *)"MIK-CYR"; + else if (code == CHRS_NEC) chrs=(char *)"NEC-JIS"; /* ??? */ + else if (code == CHRS_SJIS) chrs=(char *)"SJIS"; /* ??? */ + else if (code == CHRS_UTF_7) chrs=(char *)"UTF-7"; + else if (code == CHRS_UTF_8) chrs=(char *)"UTF-8"; + else if (code == CHRS_VISCII_11) chrs=(char *)"VISCII 3"; + else if (code == CHRS_ZW) chrs=(char *)"ZW"; /* ??? */ + else chrs=NULL; + + return chrs; +} + + + +void writechrs(int code, FILE *pkt, int ispkt) +{ + char *akludge,*endline,*chrs=NULL; + + akludge = endline = NULL; + + if (ispkt==0) { + akludge=(char *)"X-FTN-"; endline=(char *)"\n"; + } else if (ispkt==1) { + akludge=(char *)"\1"; endline=(char *)"\r"; + } else if (ispkt==2) { + akludge=(char *)"X-FTN-ORIG"; endline=(char *)"\n"; + } else if (ispkt==3) { + akludge=(char *)"\1"; endline=(char *)"\n"; + } + chrs=getchrs(code); + if (chrs) fprintf(pkt,"%sCHRS: %s%s",akludge,chrs,endline); +} + + +// WORDT NIET GEBRUIKT ?? +void writecharset(int code, FILE *pip, rfcmsg *msg, rfcmsg *kmsg) +{ + char *p, *charset=NULL; + + charset=getcharset(code); + + if ((p=hdr((char *)"Mime-Version",msg))) fprintf(pip,(char *)"Mime-Version:%s",p); + else if ((p=hdr((char *)"RFC-Mime-Version",kmsg))) fprintf(pip,(char *)"Mime-Version: %s",p); + else if ((p=hdr((char *)"Mime-Version",kmsg))) fprintf(pip,(char *)"Mime-Version: %s",p); + else if ((charset) && (code != CHRS_NOTSET)) fprintf(pip,"Mime-Version: 1.0\n"); + + if ((p=hdr((char *)"Content-Type",msg))) fprintf(pip,"Content-Type:%s",p); + else if ((p=hdr((char *)"RFC-Content-Type",kmsg))) fprintf(pip,"Content-Type: %s",p); + else if ((p=hdr((char *)"Content-Type",kmsg))) fprintf(pip,"Content-Type: %s",p); + else if ((charset) && (code != CHRS_NOTSET)) + { + if ((p=hdr((char *)"FSCHTML",kmsg)) || (p=hdr((char *)"HTML",kmsg))) + fprintf(pip,"Content-Type: text/html; charset=%s\n",charset); + else + fprintf(pip,"Content-Type: text/plain; charset=%s\n",charset); + } + + if ((p=hdr((char *)"Content-Length",msg))) fprintf(pip,"Content-Length%s",p); + else if ((p=hdr((char *)"RFC-Content-Length",kmsg))) fprintf(pip,"Content-Length: %s",p); + else if ((p=hdr((char *)"Content-Length",kmsg))) fprintf(pip,"Content-Length: %s",p); + + if ((p=hdr((char *)"Content-Transfer-Encoding",msg))) fprintf(pip,"Content-Transfer-Encoding:%s",p); + else if ((p=hdr((char *)"RFC-Content-Transfer-Encoding",kmsg))) fprintf(pip,"Content-Transfer-Encoding: %s",p); + else if ((p=hdr((char *)"Content-Transfer-Encoding",kmsg))) fprintf(pip,"Content-Transfer-Encoding: %s",p); + else if ((charset) && (code == CHRS_ISO_8859_1_QP)) fprintf(pip,"Content-Transfer-Encoding: quoted-printable\n"); + else if ((charset) && (code != CHRS_NOTSET)) { fprintf(pip,"Content-Transfer-Encoding: "); + if ((code == CHRS_ASCII || code == CHRS_UTF_7)) fprintf(pip,"7bit\n"); + else if (strncasecmp(charset,"iso-2022-",9) == 0) fprintf(pip,"7bit\n"); + else fprintf(pip,"8bit\n"); /* all others are 8 bit */ + } +} + diff --git a/lib/clcomm.c b/lib/clcomm.c new file mode 100644 index 00000000..e5b9f9f3 --- /dev/null +++ b/lib/clcomm.c @@ -0,0 +1,462 @@ +/***************************************************************************** + * + * File ..................: clcomm.c + * Purpose ...............: Client/Server communications + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +int do_quiet = FALSE; /* Quiet flag */ +int show_log = FALSE; /* Show loglines on screen */ +int most_debug = FALSE; /* Toggle normal/most debugging */ +char progname[21]; /* Program name */ +char logfile[PATH_MAX]; /* Normal logfile */ +char errfile[PATH_MAX]; /* Error logfile */ +long loggrade; /* Logging grade */ +pid_t mypid; /* Original parent pid if child */ +unsigned long lcrc = 0, tcrc = 1; /* CRC value of logstring */ +int lcnt = 0; /* Same message counter */ +static char *pbuff = NULL; +extern char cpath[108]; +extern char spath[108]; + + +char *xmalloc(size_t size) +{ + char *tmp; + + tmp = malloc(size); + if (!tmp) + abort(); + + return tmp; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = xmalloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + + +void InitClient(char *user, char *myname, char *where, char *log, long loggr, char *err) +{ + if ((getenv("MBSE_ROOT")) == NULL) { + printf("Could not get the MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n"); + printf("\"MBSE_ROOT=/opt/mbse; export MBSE_ROOT\"\n\n"); + exit(1); + } + + sprintf(progname, "%s", myname); + sprintf(logfile, "%s", log); + sprintf(errfile, "%s", err); + loggrade = loggr; + + sprintf(cpath, "%s/tmp/%s%d", getenv("MBSE_ROOT"), progname, getpid()); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Store my pid in case a child process is forked and wants to do + * some communications with the mbsed server. + */ + mypid = getpid(); + if (socket_connect(user, myname, where) == -1) { + printf("PANIC: cannot access socket\n"); + exit(1); + } +} + + + +void ExitClient(int errcode) +{ + if (socket_shutdown(mypid) == -1) + printf("PANIC: unable to shutdown socket\n"); + unlink(cpath); + fflush(stdout); + fflush(stdin); + + if (pbuff) + free(pbuff); + +#ifdef MEMWATCH + mwTerm(); +#endif + exit(errcode); +} + + + +void SockS(const char *format, ...) +{ + char *out; + va_list va_ptr; + + out = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + socket_receive(); + + free(out); +} + + + +char *SockR(const char *format, ...) +{ + static char buf[SS_BUFSIZE]; + char *out; + va_list va_ptr; + + memset(&buf, 0, SS_BUFSIZE); + out = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + sprintf(buf, "%s", socket_receive()); + + free(out); + return buf; +} + + + +void WriteError(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + int i; + + outputstr = calloc(10240, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + for (i = 0; i < strlen(outputstr); i++) + if (outputstr[i] == '\r' || outputstr[i] == '\n') + outputstr[i] = ' '; + + if (*outputstr == '$') + sprintf(outputstr+strlen(outputstr), ": %s", strerror(errno)); + + if (strlen(outputstr) > (SS_BUFSIZE - 64)) { + outputstr[SS_BUFSIZE - 65] = ';'; + outputstr[SS_BUFSIZE - 64] = '\0'; + } + tcrc = StringCRC32(outputstr); + if (tcrc == lcrc) { + lcnt++; + free(outputstr); + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,%s,%s,%d,?,Last message repeated %d times;", logfile, progname, mypid, lcnt); + SockS("ALOG:5,%s,%s,%d,?,Last message repeated %d times;", errfile, progname, mypid, lcnt); + } + lcnt = 0; + } + + SockS("ALOG:5,%s,%s,%d,?,%s;", logfile, progname, mypid, *outputstr == '$' ? outputstr+1 : outputstr); + SockS("ALOG:5,%s,%s,%d,?,%s;", errfile, progname, mypid, *outputstr == '$' ? outputstr+1 : outputstr); + free(outputstr); +} + + + +void Syslog(int level, const char *format, ...) +{ + char *outstr; + va_list va_ptr; + + outstr = calloc(10240, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + Syslogp(level, outstr); + free(outstr); +} + + + +void Syslogp(int level, char *outstr) +{ + long mask = 0; + int i, upper; + + upper = isupper(level); + switch(tolower(level)) { + case ' ' : mask = DLOG_ALLWAYS; break; + case '?' : mask = DLOG_ERROR; break; + case '!' : mask = DLOG_ATTENT; break; + case '+' : mask = DLOG_NORMAL; break; + case '-' : mask = DLOG_VERBOSE; break; + case 'a' : mask = DLOG_TCP; break; + case 'b' : mask = DLOG_BBS; break; + case 'c' : mask = DLOG_CHAT; break; + case 'd' : mask = DLOG_DEVIO; break; + case 'e' : mask = DLOG_EXEC; break; + case 'f' : mask = DLOG_FILEFWD; break; + case 'h' : mask = DLOG_HYDRA; break; + case 'i' : mask = DLOG_IEMSI; break; + case 'l' : mask = DLOG_LOCK; break; + case 'm' : mask = DLOG_MAIL; break; + case 'n' : mask = DLOG_NEWS; break; + case 'o' : mask = DLOG_OUTSCAN; break; + case 'p' : mask = DLOG_PACK; break; + case 'r' : mask = DLOG_ROUTE; break; + case 's' : mask = DLOG_SESSION; break; + case 't' : mask = DLOG_TTY; break; + case 'x' : mask = DLOG_XMODEM; break; + case 'z' : mask = DLOG_ZMODEM; break; + } + + if (((loggrade | DLOG_ALLWAYS | DLOG_ERROR) & mask) == 0) + return; + + /* + * Don't log uppercase debug levels when most_debug is FALSE + */ + if (upper && !most_debug) + return; + + for (i = 0; i < strlen(outstr); i++) + if (outstr[i] == '\r' || outstr[i] == '\n') + outstr[i] = ' '; + if (strlen(outstr) > (SS_BUFSIZE - 64)) + outstr[SS_BUFSIZE - 64] = '\0'; + + tcrc = StringCRC32(outstr); + if (tcrc == lcrc) { + lcnt++; + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,%s,%s,%d,%c,Last message repeated %d times;", logfile, progname, mypid, level, lcnt); + } + lcnt = 0; + } + + if (show_log) + printf("%c %s\n", level, outstr); + + if (*outstr == '$') + SockS("ALOG:5,%s,%s,%d,%c,%s: %s;", logfile, progname, mypid, level, outstr+1, strerror(errno)); + else + SockS("ALOG:5,%s,%s,%d,%c,%s;", logfile, progname, mypid, level, outstr); +} + + + +void IsDoing(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(SS_BUFSIZE, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + SockS("ADOI:2,%d,%s;", mypid, outputstr); + free(outputstr); +} + + + +void SetTTY(char *tty) +{ + SockS("ATTY:2,%d,%s;", mypid, tty); +} + + + +void UserCity(pid_t pid, char *user, char *city) +{ + SockS("AUSR:3,%d,%s,%s;", pid, user, city); +} + + + +void DoNop() +{ + SockS("GNOP:1,%d;", mypid); +} + + + +static time_t nop = 0; + +/* + * This function can be called very often but will only send once a minute + * a NOP to the server. This is a simple solution to keep server trafic low. + */ +void Nopper(void) +{ + time_t now; + + now = time(NULL); + if (((time_t)now - (time_t)nop) > 60) { + nop = now; + SockS("GNOP:1,%d;", mypid); + } +} + + + +/* + * Set new alarmtime for Client/Server connection, + * if zero set the default time. + */ +void Altime(int altime) +{ + if (altime) + SockS("ATIM:2,%d,%d;", mypid, altime); + else + SockS("ADEF:1,%d;", mypid); +} + + + +unsigned long sequencer() +{ + char *buf, *res; + unsigned long seq = 0; + + buf = calloc(SS_BUFSIZE, sizeof(char)); + sprintf(buf, "SSEQ:0;"); + + if (socket_send(buf) == 0) { + free(buf); + buf = socket_receive(); + res = strtok(buf, ","); + res = strtok(NULL, ";"); + seq = atol(res); + } + + return seq; +} + + + +char *printable(char *s, int l) +{ + int len; + char *p; + + if (pbuff) + free(pbuff); + pbuff=NULL; + + if (s == NULL) + return (char *)"(null)"; + + if (l > 0) + len=l; + else if (l == 0) + len=strlen(s); + else { + len=strlen(s); + if (len > -l) + len=-l; + } + + pbuff=(char*)xmalloc(len*4+1); + p=pbuff; + while (len--) { + if (*(unsigned char*)s >= ' ') + *p++=*s; + else switch (*s) { + case '\\': *p++='\\'; *p++='\\'; break; + case '\r': *p++='\\'; *p++='r'; break; + case '\n': *p++='\\'; *p++='n'; break; + case '\t': *p++='\\'; *p++='t'; break; + case '\b': *p++='\\'; *p++='b'; break; + default: sprintf(p,"\\%03o",*s); p+=4; break; + } + s++; + } + *p='\0'; + return pbuff; +} + + + +char *printablec(char c) +{ + return printable(&c,1); +} + + diff --git a/lib/clcomm.h b/lib/clcomm.h new file mode 100644 index 00000000..abeb62ca --- /dev/null +++ b/lib/clcomm.h @@ -0,0 +1,113 @@ +#ifndef _CLCOMM_H +#define _CLCOMM_H + + +#pragma pack(1) + +#define SS_BUFSIZE 1024 /* Socket buffersize */ +#define MBSE_SS(x) (x)?(x):"(null)" + +/* + * Logging flagbits, ' ' ? ! + - + */ +#define DLOG_ALLWAYS 0x00000001 +#define DLOG_ERROR 0x00000002 +#define DLOG_ATTENT 0x00000004 +#define DLOG_NORMAL 0x00000008 +#define DLOG_VERBOSE 0x00000010 + + + +/* + * Debug levels: A B C D E F H I L M N O P R S T X Z + */ +#define DLOG_TCP 0x00000020 +#define DLOG_BBS 0x00000040 +#define DLOG_CHAT 0x00000080 +#define DLOG_DEVIO 0x00000100 +#define DLOG_EXEC 0x00000200 +#define DLOG_FILEFWD 0x00000400 +#define DLOG_HYDRA 0x00001000 +#define DLOG_IEMSI 0x00002000 +#define DLOG_LOCK 0x00010000 +#define DLOG_MAIL 0x00020000 +#define DLOG_NEWS 0x00040000 +#define DLOG_OUTSCAN 0x00080000 +#define DLOG_PACK 0x00100000 +#define DLOG_ROUTE 0x00400000 +#define DLOG_SESSION 0x00800000 +#define DLOG_TTY 0x01000000 +#define DLOG_XMODEM 0x10000000 +#define DLOG_ZMODEM 0x40000000 + + + +typedef struct _srv_auth { + struct _srv_auth *next; + char *hostname; + char *authcode; +} srv_auth; + + +extern char SigName[32][16]; + + +/* + * From clcomm.c + */ +char *xmalloc(size_t); +char *xstrcpy(char *); +char *xstrcat(char *, char *); +void InitClient(char *, char *, char *, char *, long, char *); +void ExitClient(int); +void SockS(const char *, ...); +char *SockR(const char *, ...); +void WriteError(const char *, ...); +void Syslog(int, const char *, ...); +void Syslogp(int, char *); +void IsDoing(const char *, ...); +void SetTTY(char *); +void UserCity(pid_t, char *, char *); +void DoNop(void); +void Nopper(void); +void Altime(int); +unsigned long sequencer(void); +char *printable(char *, int); +char *printablec(char); + + + +/* + * From client.c + */ +int socket_connect(char *, char *, char *); +int socket_send(char *); +char *socket_receive(void); +int socket_shutdown(pid_t); + + + +/* + * From crc.c + */ +unsigned long crc32ccitt(char *, int); +unsigned short crc16ccitt(char *, int); +unsigned long str_crc32(char *str); +unsigned long StringCRC32(char *); +unsigned long upd_crc32(char *buf, unsigned long crc, int len); +unsigned long norm_crc32(unsigned long crc); +unsigned short crc16xmodem(char *, int); +unsigned char checksum(char *, int); + + + +/* + * from semafore.c + */ +void CreateSema(char *); +void RemoveSema(char *); +int IsSema(char *); + + +#endif + diff --git a/lib/client.c b/lib/client.c new file mode 100644 index 00000000..ed63d50a --- /dev/null +++ b/lib/client.c @@ -0,0 +1,211 @@ +/***************************************************************************** + * + * File ..................: client.c + * Purpose ...............: MBSE Deamon Client + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1993-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + +static int sock = -1; /* Unix Datagram socket */ +struct sockaddr_un clntaddr; /* Client socket address */ +struct sockaddr_un servaddr; /* Server socket address */ +struct sockaddr_un from; /* From socket address */ +int fromlen; +static char *myname='\0'; /* my program name */ +char spath[108]; /* Server socket path */ +char cpath[108]; /* Client socket path */ + + +/************************************************************************ + * + * Connect to Unix Datagram socket, return -1 if error or socket no. + */ + +int socket_connect(char *user, char *prg, char *city) +{ + int s; + static char buf[SS_BUFSIZE]; + char tty[18]; + + myname = prg; + + /* + * Create Unix Datagram socket for the client. + */ + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s == -1) { + perror(myname); + printf("Unable to create Unix Datagram socket\n"); + return -1; + } + + /* + * Client will bind to an address so the server will get + * an address in its recvfrom call and use it to send + * data back to the client. + */ + memset(&clntaddr, 0, sizeof(clntaddr)); + clntaddr.sun_family = AF_UNIX; + strcpy(clntaddr.sun_path, cpath); + + if (bind(s, &clntaddr, sizeof(clntaddr)) < 0) { + close(s); + perror(myname); + printf("Can't bind socket %s\n", cpath); + return -1; + } + + /* + * If running seteuid as another user, chown to mbse.bbs + */ + if (getuid() != geteuid()) { + chown(cpath, getuid(), getgid()); + } + + /* + * Setup address structure for the server socket. + */ + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, spath); + + /* + * Now that we have an connection, we gather + * information to tell the server who we are. + */ + if (isatty(1) && (ttyname(1) != NULL)) { + strcpy(tty, ttyname(1)); + if (strchr(tty, 'p')) + strcpy(tty, index(tty, 'p')); + else if (strchr(tty, 't')) + strcpy(tty, index(tty, 't')); + else if (strchr(tty, 'c')) + strcpy(tty, index(tty, 'c')); + } else { + strcpy(tty, "-"); + } + sock = s; + + /* + * Send the information to the server. + */ + sprintf(buf, "AINI:5,%d,%s,%s,%s,%s;", getpid(), tty, user, prg, city); + if (socket_send(buf) != 0) { + sock = -1; + return -1; + } + + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) != 0) { + printf("AINI not acknowledged by the server\n"); + sock = -1; + return -1; + } + + return s; +} + + + +/* + * Send data via internet domain socket + */ +int socket_send(char *buf) +{ + if (sock == -1) + return -1; + + if (sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) != strlen(buf)) { + printf("Socket send failed error %d\n", errno); + return -1; + } + return 0; +} + + + +/* + * Return an empty buffer if somthing went wrong, else the complete + * dataline is returned. + */ +char *socket_receive(void) +{ + static char buf[SS_BUFSIZE]; + int rlen; + + memset((char *)&buf, 0, SS_BUFSIZE); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, SS_BUFSIZE, 0, &from, &fromlen); + if (rlen == -1) { + perror("recv"); + printf("Error reading socket\n"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + return buf; +} + + + +/*************************************************************************** + * + * Shutdown the socket, first send the server the close command so this + * application will be removed from the servers active clients list. + * There must be a parameter with the pid so that client applications + * where the shutdown will be done by a child process is able to give + * the parent pid as an identifier. + */ + +int socket_shutdown(pid_t pid) +{ + static char buf[SS_BUFSIZE]; + + if (sock == -1) + return 0; + + sprintf(buf, "ACLO:1,%d;", pid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "107:0;", 6) != 0) { + printf("Shutdown not acknowledged by the server\n"); + printf("Got \"%s\"\n", buf); + } + } + + if (shutdown(sock, 1) == -1) { + perror(myname); + printf("Cannot shutdown socket\n"); + return -1; + } + + sock = -1; + return 0; +} + + diff --git a/lib/common.h b/lib/common.h new file mode 100644 index 00000000..818f442b --- /dev/null +++ b/lib/common.h @@ -0,0 +1,914 @@ +#ifndef _COMMON_H +#define _COMMON_H + +#include "../config.h" + +#pragma pack(1) + +#define LEAVE 0 +#define KFS 1 +#define TFS 2 +#define DSF 3 + + +#define MAXNAME 35 +#define MAXUFLAGS 16 + + +#define METRIC_EQUAL 0 +#define METRIC_POINT 1 +#define METRIC_NODE 2 +#define METRIC_NET 3 +#define METRIC_ZONE 4 +#define METRIC_DOMAIN 5 +#define METRIC_MAX METRIC_DOMAIN + + + +/* + * Fidonet message status bits + */ +#define M_PVT 0x0001 +#define M_CRASH 0x0002 +#define M_RCVD 0x0004 +#define M_SENT 0x0008 +#define M_FILE 0x0010 +#define M_TRANSIT 0x0020 +#define M_ORPHAN 0x0040 +#define M_KILLSENT 0x0080 +#define M_LOCAL 0x0100 +#define M_HOLD 0x0200 +#define M_REQ 0x0800 +#define M_RRQ 0x1000 +#define M_IRR 0x2000 +#define M_AUDIT 0x4000 +#define M_FILUPD 0x8000 + + + +/* + * Analogue Modem flag values, order is important, first the + * compresion capabilities, then the linespeeds. This is late + * tested by portsel to find the fastest common connection + * speed for a given line if you have multiple dialout modems. + */ +#define NL_MNP 0x00000001L +#define NL_V42 0x00000002L +#define NL_V42B 0x00000004L +#define NL_V22 0x00000008L +#define NL_V29 0x00000010L +#define NL_V32 0x00000020L +#define NL_H96 0x00000040L +#define NL_HST 0x00000080L +#define NL_MAX 0x00000100L +#define NL_PEP 0x00000200L +#define NL_CSP 0x00000400L +#define NL_V32B 0x00000800L +#define NL_H14 0x00001000L +#define NL_V32T 0x00002000L +#define NL_H16 0x00004000L +#define NL_ZYX 0x00008000L +#define NL_Z19 0x00010000L +#define NL_VFC 0x00020000L +#define NL_V34 0x00040000L +#define NL_X2C 0x00080000L +#define NL_X2S 0x00100000L +#define NL_V90C 0x00200000L +#define NL_V90S 0x00400000L + + + +/* + * ISDN Flags + */ +#define ND_V110L 0x00000001L +#define ND_V110H 0x00000002L +#define ND_V120L 0x00000004L +#define ND_V120H 0x00000008L +#define ND_X75 0x00000010L + + + +/* + * TCP/IP flags + */ +#define IP_IBN 0x00000001L +#define IP_IFC 0x00000002L +#define IP_ITN 0x00000004L +#define IP_IVM 0x00000008L +#define IP_IP 0x00000010L +#define IP_IFT 0x00000020L + + + +/* + * Online special flags + */ +#define OL_CM 0x00000001L +#define OL_MO 0x00000002L +#define OL_LO 0x00000004L +#define OL_MN 0x00000008L + + + +/* + * Request flags + */ +#define RQ_RQMODE 0x0000000fL +#define RQ_RQ_BR 0x00000001L +#define RQ_RQ_BU 0x00000002L +#define RQ_RQ_WR 0x00000004L +#define RQ_RQ_WU 0x00000008L +#define RQ_XA (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XB (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR ) +#define RQ_XC (RQ_RQ_BR | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XP (RQ_RQ_BR | RQ_RQ_BU ) +#define RQ_XR (RQ_RQ_BR | RQ_RQ_WR ) +#define RQ_XW ( RQ_RQ_WR ) +#define RQ_XX ( RQ_RQ_WR | RQ_RQ_WU) + + + +/* + * Returned function keys + */ +#define KEY_BACKSPACE 8 +#define KEY_LINEFEED 10 +#define KEY_ENTER 13 +#define KEY_ESCAPE 27 +#define KEY_RUBOUT 127 +#define KEY_UP 200 +#define KEY_DOWN 201 +#define KEY_LEFT 202 +#define KEY_RIGHT 203 +#define KEY_HOME 204 +#define KEY_END 205 +#define KEY_INS 206 +#define KEY_DEL 207 +#define KEY_PGUP 208 +#define KEY_PGDN 209 + + +#define LINES 24 +#define COLS 80 + + +/* + * ANSI colors + */ +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define LIGHTGRAY 7 +#define DARKGRAY 8 +#define LIGHTBLUE 9 +#define LIGHTGREEN 10 +#define LIGHTCYAN 11 +#define LIGHTRED 12 +#define LIGHTMAGENTA 13 +#define YELLOW 14 +#define WHITE 15 + + +#define MAXSUBJ 71 +#define MSGTYPE 2 + + +/* +#define FLG_PVT 0x0001 +#define FLG_CRS 0x0002 +#define FLG_RCV 0x0004 +#define FLG_SNT 0x0008 +#define FLG_ATT 0x0010 +#define FLG_TRN 0x0020 +#define FLG_ORP 0x0040 +#define FLG_K_S 0x0080 +#define FLG_LOC 0x0100 +#define FLG_HLD 0x0200 +#define FLG_RSV 0x0400 +#define FLG_FRQ 0x0800 +#define FLG_RRQ 0x1000 +#define FLG_RRC 0x2000 +#define FLG_ARQ 0x4000 +#define FLG_FUP 0x8000 +*/ + + +typedef struct _parsedaddr { + char *target; + char *remainder; + char *comment; +} parsedaddr; + + +#define ADDR_NESTED 1 +#define ADDR_MULTIPLE 2 +#define ADDR_UNMATCHED 4 +#define ADDR_BADTOKEN 8 +#define ADDR_BADSTRUCT 16 +#define ADDR_ERRMAX 5 + +/* + * From rfcaddr.c + */ +char *addrerrstr(int); +void tidyrfcaddr(parsedaddr); +parsedaddr parserfcaddr(char *); + + +typedef struct _faddr { + char *name; + unsigned int point; + unsigned int node; + unsigned int net; + unsigned int zone; + char *domain; +} faddr; + + + +typedef struct _fa_list { + struct _fa_list *next; + faddr *addr; + int force; +} fa_list; + + + +typedef struct _ftnmsg { + int flags; + int ftnorigin; + faddr *to; + faddr *from; + time_t date; + char *subj; + char *msgid_s; + char *msgid_a; + unsigned long msgid_n; + char *reply_s; + char *reply_a; + unsigned long reply_n; + char *origin; + char *area; +} ftnmsg; + + + +extern struct _ftscprod { + unsigned short code; + char *name; +} ftscprod[]; + + + +/* + * Nodelist entry + */ +typedef struct _node { + faddr addr; /* Node address */ + unsigned short upnet; /* Uplink netnumber */ + unsigned short upnode; /* Uplink nodenumber */ + unsigned short region; /* Region belongin to */ + unsigned char type; + unsigned char pflag; + char *name; /* System name */ + char *location; /* System location */ + char *sysop; /* Sysop name */ + char *phone; /* Phone number */ + unsigned speed; /* Baudrate */ + unsigned long mflags; /* Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + unsigned long oflags; /* Online flags */ + unsigned long xflags; /* Request flags */ + char *uflags[MAXUFLAGS]; /* User flags */ +} node; + + + +extern struct _fkey { + char *key; + unsigned long flag; +} fkey[]; + + + +extern struct _dkey { + char *key; + unsigned long flag; +} dkey[]; + + + +extern struct _ikey { + char *key; + unsigned long flag; +} ikey[]; + + + +extern struct _okey { + char *key; + unsigned long flag; +} okey[]; + + + +extern struct _xkey { + char *key; + unsigned long flag; +} xkey[]; + + + +extern struct _nodelist { + char *domain; + FILE *fp; +} *nodevector; + + + +struct _ixentry { + unsigned short zone; + unsigned short net; + unsigned short node; + unsigned short point; +}; + + + +extern struct _pkey { + char *key; + unsigned char type; + unsigned char pflag; +} pkey[]; + + +extern char SigName[32][16]; + + +int ttyfd; /* Filedescriptor for raw mode */ +struct termio tbuf, tbufsav; /* Structure for raw mode */ + + + +/* + * From attach.c + */ +int attach(faddr, char *, int, char); + + + +/* + * From dostran.c + */ +char *Dos2Unix(char *); +char *Unix2Dos(char *); + + + +/* + * From execute.c + */ +int execute(char *, char *, char *, char *, char *, char *); +int execsh(char *, char *, char *, char *); + + + +/* + * From expipe.c + */ +FILE *expipe(char *, char *, char *); +int exclose(FILE *); + + + +/* + * From faddr.c + */ +char *aka2str(fidoaddr aka); +fidoaddr str2aka(char *addr); + + + +/* + * From falists.c + */ +void tidy_falist(fa_list **); +void fill_list(fa_list **,char *,fa_list **, int); +void fill_path(fa_list **,char *); +void sort_list(fa_list **); +void uniq_list(fa_list **); +int in_list(faddr *,fa_list **, int); + + + + +/* + * From ftn.c + */ +faddr *parsefnode(char *); +faddr *parsefaddr(char *); +char *ascinode(faddr *,int); +char *ascfnode(faddr *,int); +void tidy_faddr(faddr *); +int metric(faddr *, faddr *); +faddr *fido2faddr(fidoaddr); +fidoaddr *faddr2fido(faddr *); +faddr *bestaka_s(faddr *); +int is_local(faddr *); +int chkftnmsgid(char *); + + + +/* + * From getheader.c + */ +int getheader(faddr *, faddr *, FILE *, char *); + + + +/* + * From gmtoffset.c + */ +long gmt_offset(time_t); +char *gmtoffset(time_t); +char *str_time(time_t); +char *t_elapsed(time_t, time_t); + + +/* + * From mbfile.c + */ +int file_cp(char *from, char *to); +int file_rm(char *path); +int file_mv(char *oldpath, char *newpath); +int file_exist(char *path, int mode); +long file_size(char *path); +long file_crc(char *path, int); +time_t file_time(char *path); +int mkdirs(char *name); +int diskfree(int); + + +/* + * From nodelist.c + */ +int initnl(void); +node *getnlent(faddr *); +void olflags(unsigned long); +void rqflags(unsigned long); +void moflags(unsigned long); +void diflags(unsigned long); +void ipflags(unsigned long); + + + +/* + * From nodelock.c + */ +int nodelock(faddr *); +int nodeulock(faddr *); + + +/* + * From noderecord.c + */ +int noderecord(faddr *); + + + +/* + * From pktname.c + */ +char *prepbuf(faddr *); +char *pktname(faddr *, char); +char *reqname(faddr *); +char *floname(faddr *, char); +char *splname(faddr *); +char *bsyname(faddr *); +char *stsname(faddr *); +char *polname(faddr *); +char *dayname(void); +char *arcname(faddr *, unsigned short, int); + + + +/* + * From rawio.c + */ +void Setraw(void); /* Set raw mode */ +void Unsetraw(void); /* Unset raw mode */ +unsigned char Getone(void); /* Get one raw character */ +int Speed(void); /* Get (locked) tty speed */ +int Waitchar(unsigned char *, int); /* Wait n * 10mSec for char */ +int Escapechar(unsigned char *); /* Escape sequence test */ +unsigned char Readkey(void); /* Read a translated key */ + + + +/* + * From strutil.c + */ +char *padleft(char *str, int size, char pad); +char *tl(char *str); +void Striplf(char *String); +void tlf(char *str); +char *tu(char *str); +char *tlcap(char *); +char *Hilite(char *, char *); +void Addunderscore(char *); +void strreplace(char *, char *, char*); +char *GetLocalHM(void); +char *StrTimeHM(time_t); +char *StrTimeHMS(time_t); +char *GetLocalHMS(void); +char *StrDateMDY(time_t *); +char *StrDateDMY(time_t); +char *GetDateDMY(void); + + + +/* + * From term.c + */ +void TermInit(int); +void Enter(int); +void pout(int, int, char *); +void poutCR(int, int, char *); +void poutCenter(int,int,char *); +void colour(int, int); +void Center(char *); +void clear(void); +void locate(int, int); +void fLine(int); +void sLine(void); +void mvprintw(int, int, const char *, ...); + + + +/* + * From unpacker.c + */ +char *unpacker(char *); +int getarchiver(char *); + + + +/* + * From packet.c + */ +FILE *openpkt(FILE *, faddr *, char); +void closepkt(void); + + + +/* + * From ftnmsg.c + */ +char *ftndate(time_t); +FILE *ftnmsghdr(ftnmsg *,FILE *,faddr *,char, char *); +void tidy_ftnmsg(ftnmsg *); + + + +/* + * From rfcdate.c + */ +time_t parsefdate(char *, void *); +char *rfcdate(time_t); + + +/* + * Frome mime.c + */ +char *qp_decode(char *); +/* int=0 for text (normal mode), int=1 for headers and gatebau MSGID */ +char *qp_encode(char *,int); +char *b64_decode(char *); +char *b64_encode(char *); + + + +/* + * From rfcmsg.c + */ + +typedef struct _rfcmsg { + struct _rfcmsg *next; + char *key; + char *val; +} rfcmsg; + +rfcmsg *parsrfc(FILE *); +void tidyrfc(rfcmsg *); +void dumpmsg(rfcmsg *,FILE *); + + +/* + * From hdr.c + */ +char *hdr(char *, rfcmsg *); + + + +/* + * From batchrd.c + */ +char *bgets(char *, int, FILE *); + + + +/* + * recognized charsets + */ +#define CHRS_AUTODETECT -1 +#define CHRS_NOTSET 0 +#define CHRS_ASCII 1 /* us-ascii */ +#define CHRS_BIG5 2 /* Chinese Big5 charset */ +#define CHRS_CP424 3 /* hebrew EBCDIC */ +#define CHRS_CP437 4 /* Latin-1 MS codage (cp437) */ +#define CHRS_CP850 5 /* Latin-1 MS codage (cp850) */ +#define CHRS_CP852 6 /* Polish MS-DOS codage */ +#define CHRS_CP862 7 /* Hebrew PC */ +#define CHRS_CP866 8 /* Cyrillic Alt-PC (cp866) */ +#define CHRS_CP895 9 /* Kamenicky (DOS charset in CZ & SK) */ +#define CHRS_EUC_JP 10 /* Japanese EUC */ +#define CHRS_EUC_KR 11 /* Korean EUC */ +#define CHRS_FIDOMAZOVIA 12 /* Polish "FIDOMAZOVIA" charset */ +#define CHRS_GB 13 /* Chinese GB 2312 8 bits */ +#define CHRS_HZ 14 /* Chinese HZ coding */ +#define CHRS_ISO_2022_CN 15 /* Chinese GB 2312 7 bits */ +#define CHRS_ISO_2022_JP 16 /* Japanese iso-2022-jp */ +#define CHRS_ISO_2022_KR 17 /* Korean iso-2022-kr */ +#define CHRS_ISO_2022_TW 18 /* Taiwanese iso-2022-tw */ +#define CHRS_ISO_8859_1 19 /* Latin-1, Western Europe, America */ +#define CHRS_ISO_8859_1_QP 20 +#define CHRS_ISO_8859_2 21 /* Latin-2, Eastern Europe */ +#define CHRS_ISO_8859_3 22 /* Latin-3, Balkanics languages */ +#define CHRS_ISO_8859_4 23 /* Latin-4, Scandinavian, Baltic */ +#define CHRS_ISO_8859_5 24 /* Cyrillic (iso-8859-5) */ +#define CHRS_ISO_8859_6 25 /* Arabic (iso-8859-6) */ +#define CHRS_ISO_8859_7 26 /* Greek (iso-8859-7) */ +#define CHRS_ISO_8859_8 27 /* Hebrew (iso-8859-8) */ +#define CHRS_ISO_8859_9 28 /* Latin-5, Turkish */ +#define CHRS_ISO_8859_10 29 /* Latin-6, Lappish/Nordic/Eskimo */ +#define CHRS_ISO_8859_11 30 /* Thai (iso-8859-11, aka TIS620) */ +#define CHRS_ISO_8859_15 31 /* Latin-0 (Latin-1 + a few letters) */ +#define CHRS_KOI8_R 32 /* Cyrillic Koi8 (Russian) */ +#define CHRS_KOI8_U 33 /* Cyrillic Koi8 (Ukranian) */ +#define CHRS_MACINTOSH 34 /* Macintosh */ +#define CHRS_MIK_CYR 35 /* Bulgarian "Mik" cyrillic charset */ +#define CHRS_NEC 36 /* Japanese NEC-JIS charset */ +#define CHRS_SJIS 37 /* Japanese Shift-JIS (MS codage) */ +#define CHRS_UTF_7 38 /* Unicode in UTF-7 encoding */ +#define CHRS_UTF_8 39 /* Unicode in UTF-8 encoding */ +#define CHRS_VISCII_10 40 /* VISCII 1.0 */ +#define CHRS_VISCII_11 41 /* VISCII 1.1 */ +#define CHRS_ZW 42 /* Chinese Zw encoding */ + +#define CHRS_ISO_11 91 +#define CHRS_ISO_4 92 +#define CHRS_ISO_60 93 + + + +/* + * languages (used for LANG_DEFAULT definition) + */ +#define LANG_WEST 1 /* West-European languages */ +#define LANG_EAST 2 /* East-Eurpean languages */ +#define LANG_JAPAN 3 /* japanese */ +#define LANG_KOREA 4 /* korean */ +#define LANG_CHINA 5 /* chinese */ +#define LANG_CYRILLIC 6 /* Cyrillic based languages */ + + + +/* + * Define these according to the values used in your country + */ +#define CHRS_DEFAULT_FTN CHRS_CP437 +#define CHRS_DEFAULT_RFC CHRS_ISO_8859_1 +#define LANG_DEFAULT LANG_WEST + +#if (LANG_DEFAULT==LANG_JAPAN || LANG_DEFAULT==LANG_KOREA || LANG_DEFAULT==LANG_CHINA) +#define LANG_BITS 16 +#else +#define LANG_BITS 8 +#endif + + + +/* + * used to recognize pgpsigned messages + */ +#define PGP_SIGNED_BEGIN "-----BEGIN PGP SIGNED MESSAGE-----" +#define PGP_SIG_BEGIN "-----BEGIN PGP SIGNATURE-----" +#define PGP_SIG_END "-----END PGP SIGNATURE-----" + + + +/* + * charset reading functions + */ +int getoutcode(int); +int getincode(int); +char *getcharset(int); +char *getchrs(int); +int getcode(char *); +int readchrs(char *); +int readcharset(char *); +void writechrs(int,FILE *,int); + + + +/* + * some special chars values + */ +#define NUL 0 +#define NL 10 +#define FF 12 +#define CR 13 +#define ESC 27 + + +/* ************ general functions ************* */ +char *hdrconv(char *, int, int); +char *hdrnconv(char *, int, int, int); +char *strnkconv(const char *, int, int, int); +char *strkconv(const char *, int, int); +void kconv(char *, char **, int, int); + + +/* ************ 8 bit charsets **************** */ +void noconv(char *, char **); +void eight2eight(char *, char **, char *); + + + +/* + * maptabs names + */ +#define CP424__CP862 "cp424__cp862" +#define CP424__ISO_8859_8 "cp424__iso-8859-8" +#define CP437__ISO_8859_1 "cp437__iso-8859-1" +#define CP437__MACINTOSH "cp437__mac" +#define CP850__ISO_8859_1 "cp437__iso-8859-1" +#define CP850__MACINTOSH "cp437__mac" +#define CP852__FIDOMAZOVIA "cp852__fidomazovia" +#define CP852__ISO_8859_2 "cp852__iso-8859-2" +#define CP862__CP424 "cp862__cp424" +#define CP862__ISO_8859_8 "cp862__iso-8859-8" +#define CP866__ISO_8859_5 "mik__iso-8859-5" +#define CP866__KOI8 "cp866__koi8" +#define CP895__CP437 "cp895__cp437" +#define CP895__ISO_8859_2 "cp895__iso-8859-2" +#define FIDOMAZOVIA__CP852 "fidomazovia__cp852" +#define FIDOMAZOVIA__ISO_8859_2 "fidomazovia__iso-8859-2" +#define ISO_11__ISO_8859_1 "iso-11__iso-8859-1" +#define ISO_4__ISO_8859_1 "iso-4__iso-8859-1" +#define ISO_60__ISO_8859_1 "iso-60__iso-8859-1" +#define ISO_8859_1__CP437 "iso-8859-1__cp437" +#define ISO_8859_1__MACINTOSH "iso-8859-1__mac" +#define ISO_8859_1__CP850 "iso-8859-1__cp437" +#define ISO_8859_2__CP852 "iso-8859-2__cp852" +#define ISO_8859_2__CP895 "iso-8859-2__cp895" +#define ISO_8859_2__FIDOMAZOVIA "iso-8859-2__fidomazovia" +#define ISO_8859_5__CP866 "iso-8859-5__mik" +#define ISO_8859_5__KOI8 "iso-8859-5__koi8" +#define ISO_8859_5__MIK_CYR "iso-8859-5__mik" +#define ISO_8859_8__CP424 "iso-8859-8__cp424" +#define ISO_8859_8__CP862 "iso-8859-8__cp862" +#define KOI8__CP866 "koi8__cp866" +#define KOI8__ISO_8859_5 "koi8__iso-8859-5" +#define KOI8__MIK_CYR "koi8__mik" +#define MACINTOSH__CP437 "mac__cp437" +#define MACINTOSH__CP850 "mac__cp437" +#define MACINTOSH__ISO_8859_1 "mac__iso-8859-1" +#define MIK_CYR__ISO_8859_5 "mik__iso-8859-5" +#define MIK_CYR__KOI8 "mik__koi8" + + +/* ??? */ +int SkipESCSeq(FILE *, int, int *); +int getkcode(int, char [],char []); +int iso2022_detectcode(char *, int); + + +#define DOS +#define SPACE 0xA1A1 /* GB "space" symbol */ +#define BOX 0xA1F5 /* GB "blank box" symbol */ +#define isGB1(c) ((c)>=0x21 && (c)<=0x77) /* GB 1st byte */ +#define isGB1U(c) ((c)>=0x78 && (c)<=0x7D) /* GB 1st byte unused*/ +#define isGB2(c) ((c)>=0x21 && (c)<=0x7E) /* GB 2nd byte */ +#define HI(code) (((code) & 0xFF00)>>8) +#define LO(code) ((code) & 0x00FF) +#define DB(hi,lo) ((((hi)&0xFF) << 8) | ((lo)&0xFF)) +#define CLEAN7(c) ((c) & 0x7F) /* strip MSB */ +#define notAscii(c) ((c)&0x80) + + +/* Chinese charsets */ +void gb2hz(char *in, char **out); +void hz2gb(char *in, char **out); +void zw2hz(char *in, char **out); +void zw2gb(char *in, char **out); + + + +#define SJIS1(A) ((A >= 129 && A <= 159) || (A >= 224 && A <= 239)) +#define SJIS2(A) (A >= 64 && A <= 252) +#define HANKATA(A) (A >= 161 && A <= 223) +#define ISEUC(A) (A >= 161 && A <= 254) +#define ISMARU(A) (A >= 202 && A <= 206) +#define ISNIGORI(A) ((A >= 182 && A <= 196) || (A >= 202 && A <= 206)) + +void OPENINOUTFILES(FILE **, FILE **, char *); +void CLOSEINOUTFILES(FILE **, FILE **, char **); +void han2zen(FILE *, int *, int *, int); +void sjis2jis(int *, int *); +void jis2sjis(int *, int *); + +/* ************ 16 bits charsets ************* */ +/* japanese charsets */ +void shift2seven(char *, char **, int, char [], char []); +void shift2euc(char *, char **, int, int); +void euc2seven(char *, char **, int, char [], char []); +void euc2euc(char *, char **, int, int); +void shift2shift(char *, char **, int, int); +void euc2shift(char *, char **, int, int); +void seven2shift(char *, char **); +void seven2euc(char *, char **); +void seven2seven(char *, char **, char [], char []); + + + +void utf7_to_eight(char *, char **, int *); +void utf8_to_eight(char *, char **, int *); + + + +/* + * parsedate.c + */ +typedef struct _TIMEINFO { + time_t time; + long usec; + long tzone; +} TIMEINFO; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} CYYSTYPE; + +#define tDAY 257 +#define tDAYZONE 258 +#define tMERIDIAN 259 +#define tMONTH 260 +#define tMONTH_UNIT 261 +#define tSEC_UNIT 262 +#define tSNUMBER 263 +#define tUNUMBER 264 +#define tZONE 265 + + +extern CYYSTYPE cyylval; + + +time_t parsedate(char *, TIMEINFO *); + + +/* + * msgflags.c + */ +int flag_on(char *,char *); +int flagset(char *); +char *compose_flags(int,char *); +char *strip_flags(char *); +int flag_on(char *,char *); + + + +/* + * strcasestr.c + */ +#ifndef HAVE_STRCASESTR +char *strcasestr(char *, char *); +#endif + +#endif + diff --git a/lib/crc.c b/lib/crc.c new file mode 100644 index 00000000..cf04918c --- /dev/null +++ b/lib/crc.c @@ -0,0 +1,303 @@ +/***************************************************************************** + * + * File ..................: crc.c + * Purpose ...............: Crc32 and Crc16 calculations + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1993-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + + +unsigned long crc32tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + + +unsigned short crc16xmodemtab[256] = { +0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, +0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, +0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, +0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, +0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, +0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, +0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, +0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, +0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, +0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, +0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, +0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, +0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, +0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, +0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, +0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, +0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, +0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, +0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, +0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, +0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, +0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, +0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, +0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, +0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, +0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, +0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, +0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, +0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, +0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, +0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, +0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + + +unsigned short crc16ccitttab[256] = /* CRC polynomial 0x8408 */ +{ +0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, +0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, +0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, +0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, +0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, +0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, +0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, +0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, +0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, +0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, +0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, +0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, +0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, +0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, +0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, +0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, +0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, +0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, +0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, +0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, +0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, +0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, +0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, +0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, +0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, +0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, +0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, +0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, +0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, +0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, +0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, +0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + + + +unsigned long crc32ccitt(char *str, int l) +{ + unsigned long crc; + + for (crc = 0xffffffffL; l--; str++) + crc = crc32tab[((int) crc ^ (*str)) & 0xff] ^ ((crc >> 8) & 0x00ffffff); + + return crc; +} + + + +unsigned short crc16ccitt(char *str, int l) +{ + unsigned short crc; + + for (crc = 0xffff; l--; str++) + crc = crc16ccitttab[(crc ^ (*str)) & 0xff] ^ ((crc >> 8) & 0x00ff); + + return crc; +} + + + + +/* + * Calculate the CRC of a string. + */ +unsigned long str_crc32(char *str) +{ + unsigned long crc; + + for (crc=0L; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +unsigned long StringCRC32(char *str) +{ + unsigned long crc; + + for (crc = 0xffffffff; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +/* + * Update CRC32, first initialize CRC with 0xffffffff. + */ +unsigned long crc32(int octet, unsigned long crc) +{ + return (crc32tab[((int)crc ^ ((long)octet)) & 0xff] ^ ((((unsigned long)crc) >> 8) & 0x00ffffff)); +} + + + +/* + * Update CRC32, first initialize crc with 0xffffffff + */ +unsigned long upd_crc32(char *buf, unsigned long crc, int len) +{ + int i; + unsigned long cr; + + cr = crc; + for (i = 0; i < len; i++) { + cr = (crc32tab[((int)cr ^ ((long)buf[i])) & 0xff] ^ ((((unsigned long)cr) >> 8) & 0x00ffffff)); + } + return cr; +} + + + +/* + * return normalized CRC32 value, which means put al bytes in the + * normal (not for comms) order. + */ +unsigned long norm_crc32(unsigned long crc) +{ + unsigned long L; + + L = crc & 0x000000ff; + L <<= 8; + L |= ((crc >> 8) & 0x000000ff); + L <<= 8; + L |= ((crc >> 16) & 0x000000ff); + L <<= 8; + L |= ((crc >> 24) & 0x000000ff); + return L; +} + + + +unsigned short crc16xmodem(char *str, int l) +{ + unsigned short crc; + + for (crc = 0; l--; str++) + crc = crc16xmodemtab[(((crc>>8)&0xff)^(*str)) & 0xff] ^ (crc<<8); + return crc; +} + + + +unsigned char checksum(char *str, int l) +{ + unsigned char cs; + + for (cs=0;l--;str++) + cs += (unsigned char)(*str); + return cs; +} + + + diff --git a/lib/dbcfg.c b/lib/dbcfg.c new file mode 100644 index 00000000..eb6f3040 --- /dev/null +++ b/lib/dbcfg.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: dbcfg.c + * Purpose ...............: Config Database. + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "mbse.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" + + + + +void InitConfig(void) +{ + if ((getenv("MBSE_ROOT")) == NULL) { + printf("Could not get MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n"); + printf("\"MBSE_ROOT=/opt/mbse;export MBSE_ROOT\"\n\n"); + exit(1); + } + LoadConfig(); +} + + + +void LoadConfig(void) +{ + FILE *pDataFile; + char *FileName; + + FileName = calloc(PATH_MAX, sizeof(char)); + sprintf(FileName, "%s/etc/config.data", getenv("MBSE_ROOT")); + if ((pDataFile = fopen(FileName, "r")) == NULL) { + perror("\n\nFATAL ERROR:"); + printf(" Can't open %s\n", FileName); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your MBSE_ROOT variable is set to the BBS path!\n\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + free(FileName); + fread(&CFG, sizeof(CFG), 1, pDataFile); + fclose(pDataFile); +} + + + +int IsOurAka(fidoaddr taka) +{ + int i; + + for (i = 0; i < 40; i++) { + if ((taka.zone == CFG.aka[i].zone) && + (taka.net == CFG.aka[i].net) && + (taka.node == CFG.aka[i].node) && + (taka.point == CFG.aka[i].point) && + (CFG.akavalid[i])) + return TRUE; + } + return FALSE; +} + + + diff --git a/lib/dbcfg.h b/lib/dbcfg.h new file mode 100644 index 00000000..4137fe01 --- /dev/null +++ b/lib/dbcfg.h @@ -0,0 +1,11 @@ +#ifndef _DBCFG_H +#define _DBCFG_H + + +void InitConfig(void); /* Initialize and load config */ +void LoadConfig(void); /* Only load config file */ +int IsOurAka(fidoaddr); /* Check if our aka */ + + +#endif + diff --git a/lib/dbdupe.c b/lib/dbdupe.c new file mode 100644 index 00000000..2b842e55 --- /dev/null +++ b/lib/dbdupe.c @@ -0,0 +1,183 @@ +/***************************************************************************** + * + * File ..................: dbdupe.c + * Purpose ...............: Dupe checking. + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "dbdupe.h" + + +typedef struct _dupesrec { + unsigned long *crcs; + int loaded; + int changed; + int count; + int max; + int peak; +} dupesrec; + + +dupesrec dupes[3]; +static char *files[] = {(char *)"echomail", (char *)"fileecho", (char *)"news"}; +void CloseDdb(int); + + + +void InitDupes() +{ + int i; + + for (i = 0; i < 3; i++) { + dupes[i].crcs= NULL; + dupes[i].loaded = FALSE; + dupes[i].changed = FALSE; + dupes[i].count = 0; + dupes[i].max = 0; + } +} + + + +int CheckDupe(unsigned long crc, int idx, int max) +{ + char *dfile; + FILE *fil; + unsigned long test; + int i, size = 0; + + if (!dupes[idx].loaded) { + dfile = calloc(PATH_MAX, sizeof(char)); + sprintf(dfile, "%s/etc/%s.dupe", getenv("MBSE_ROOT"), files[idx]); + if ((fil = fopen(dfile, "r+")) == NULL) { + /* + * Dupe database doesn't exist yet. + */ + if ((fil = fopen(dfile, "w")) == NULL) { + WriteError("$PANIC: dbdupe.c, can't create %s", dfile); + free(dfile); + exit(1); + } + fclose(fil); + fil = fopen(dfile, "r+"); + } else { + fseek(fil, 0L, SEEK_END); + size = ftell(fil) / sizeof(unsigned long); + fseek(fil, 0L, SEEK_SET); + } + + /* + * Reserve some extra memeory and record howmuch. + */ + if (size > max) + dupes[idx].peak = size + 5000; + else + dupes[idx].peak = max + 5000; + dupes[idx].crcs = (unsigned long *)malloc(dupes[idx].peak * sizeof(unsigned long)); + + /* + * Load dupe records + */ + while (fread(&test, sizeof(test), 1, fil) == 1) { + dupes[idx].crcs[dupes[idx].count] = test; + dupes[idx].count++; + } + fclose(fil); + free(dfile); + dupes[idx].loaded = TRUE; + dupes[idx].max = max; + } + + for (i = 0; i < dupes[idx].count; i++) { + if (dupes[idx].crcs[i] == crc) { + return TRUE; + } + } + /* + * Not a dupe, append new crc value + */ + dupes[idx].crcs[dupes[idx].count] = crc; + dupes[idx].count++; + dupes[idx].changed = TRUE; + + /* + * If we reach the high limit, flush the current dupelist. + */ + if (dupes[idx].count >= dupes[idx].peak) + CloseDdb(idx); + return FALSE; +} + + + +void CloseDdb(int idx) +{ + int j, start; + char *dfile; + FILE *fil; + + dfile = calloc(PATH_MAX, sizeof(char)); + if (dupes[idx].loaded) { + if (dupes[idx].changed) { + if (dupes[idx].count > dupes[idx].max) + start = dupes[idx].count - dupes[idx].max; + else + start = 0; + sprintf(dfile, "%s/etc/%s.dupe", getenv("MBSE_ROOT"), files[idx]); + if ((fil = fopen(dfile, "w"))) { + for (j = start; j < dupes[idx].count; j++) + fwrite(&dupes[idx].crcs[j], sizeof(unsigned long), 1, fil); + fclose(fil); + } else { + WriteError("$Can't write %s", dfile); + } + } + + dupes[idx].changed = FALSE; + dupes[idx].loaded = FALSE; + dupes[idx].count = 0; + dupes[idx].max = 0; + dupes[idx].peak = 0; + free(dupes[idx].crcs); + dupes[idx].crcs = NULL; + } + free(dfile); +} + + + +void CloseDupes() +{ + int i; + + for (i = 0; i < 3; i++) + CloseDdb(i); +} + diff --git a/lib/dbdupe.h b/lib/dbdupe.h new file mode 100644 index 00000000..5c73e460 --- /dev/null +++ b/lib/dbdupe.h @@ -0,0 +1,12 @@ +#ifndef _DBDUPE_H +#define _DBDUPE_H + +typedef enum {D_ECHOMAIL, D_FILEECHO, D_NEWS} DUPETYPE; + +void InitDupes(void); +int CheckDupe(unsigned long, int, int); +void CloseDupes(void); + +#endif + + diff --git a/lib/dbftn.c b/lib/dbftn.c new file mode 100644 index 00000000..8e61384c --- /dev/null +++ b/lib/dbftn.c @@ -0,0 +1,101 @@ +/***************************************************************************** + * + * File ..................: dbftn.c + * Purpose ...............: Fidonetrecord Access + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" +#include "dbftn.h" + + + + +int InitFidonet(void) +{ + FILE *fil; + + memset(&fidonet, 0, sizeof(fidonet)); + LoadConfig(); + + sprintf(fidonet_fil, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(fidonet_fil, "r")) == NULL) + return FALSE; + + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + fseek(fil, 0, SEEK_END); + fidonet_cnt = (ftell(fil) - fidonethdr.hdrsize) / fidonethdr.recsize; + fclose(fil); + + return TRUE; +} + + + +int TestFidonet(unsigned short zone) +{ + int i, ftnok = FALSE; + + for (i = 0; i < 6; i++) { + if (zone == fidonet.zone[i]) + ftnok = TRUE; + } + return(ftnok); +} + + + +int SearchFidonet(unsigned short zone) +{ + FILE *fil; + + /* + * If current record is ok, return immediatly. + */ + if (TestFidonet(zone)) + return TRUE; + + if ((fil = fopen(fidonet_fil, "r")) == NULL) { + return FALSE; + } + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + if (TestFidonet(zone)) { + fclose(fil); + return TRUE; + } + } + fclose(fil); + return FALSE; +} + + + diff --git a/lib/dbftn.h b/lib/dbftn.h new file mode 100644 index 00000000..f9fce5bc --- /dev/null +++ b/lib/dbftn.h @@ -0,0 +1,16 @@ +#ifndef _DBFTN_H +#define _DBFTN_H + + +struct _fidonethdr fidonethdr; /* Header record */ +struct _fidonet fidonet; /* Fidonet datarecord */ +int fidonet_cnt; /* Fidonet records in database */ +char fidonet_fil[81];/* Fidonet database filename */ + +int InitFidonet(void); /* Initialize fidonet database */ +int TestFidonet(unsigned short); /* Test if zone is in memory */ +int SearchFidonet(unsigned short); /* Search specified zone and load */ + + +#endif + diff --git a/lib/dbmsgs.c b/lib/dbmsgs.c new file mode 100644 index 00000000..87678a8d --- /dev/null +++ b/lib/dbmsgs.c @@ -0,0 +1,357 @@ +/***************************************************************************** + * + * File ..................: dbmsgs.c + * Purpose ...............: Message areas record Access + * Last modification date : 14-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbmsgs.h" + + +char msgs_fil[PATH_MAX]; /* Database filename */ +char mgrp_fil[PATH_MAX]; /* Group database filename */ +long msgs_pos = -1; /* Current record position */ +long mgrp_pos = -1; /* Current group position */ +unsigned long msgs_crc = -1; /* CRC value of current record */ +unsigned long mgrp_crc = -1; /* CRC value of group record */ +static long sysstart, sysrecord; + + + +int InitMsgs(void) +{ + FILE *fil; + + memset(&msgs, 0, sizeof(msgs)); + memset(&mgroup, 0, sizeof(mgroup)); + LoadConfig(); + sysstart = -1; + + sprintf(msgs_fil, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + fseek(fil, 0, SEEK_END); + msgs_cnt = (ftell(fil) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + fclose(fil); + + sprintf(mgrp_fil, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + return TRUE; +} + + +int smsgarea(char *w, int); +int smsgarea(char *what, int newsgroup) +{ + FILE *fil; + + if ((fil = fopen(msgs_fil, "r")) == NULL) { + return FALSE; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + + while (fread(&msgs, msgshdr.recsize, 1, fil) == 1) { + /* + * Mark the start of the connected systems records + * for later use and skip the system records. + */ + msgs_pos = ftell(fil) - msgshdr.recsize; + sysstart = ftell(fil); + fseek(fil, msgshdr.syssize, SEEK_CUR); + if (((!strcmp(what, msgs.Tag) && !newsgroup) || (!strcmp(what, msgs.Newsgroup) && newsgroup)) && msgs.Active) { + sysrecord = 0; + fclose(fil); + msgs_crc = 0xffffffff; + msgs_crc = upd_crc32((char *)&msgs, msgs_crc, msgshdr.recsize); + mgrp_pos = -1; + mgrp_crc = -1; + + if (strlen(msgs.Group)) { + if ((fil = fopen(mgrp_fil, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + while ((fread(&mgroup, mgrouphdr.recsize, 1, fil)) == 1) { + if (!strcmp(msgs.Group, mgroup.Name)) { + mgrp_pos = ftell(fil) - mgrouphdr.recsize; + mgrp_crc = 0xffffffff; + mgrp_crc = upd_crc32((char *)&mgroup, mgrp_crc, mgrouphdr.recsize); + break; + } + } + fclose(fil); + } + } else + memset(&mgroup, 0, sizeof(mgroup)); + + return TRUE; + } + } + sysstart = -1; + msgs_crc = -1; + msgs_pos = -1; + fclose(fil); + return FALSE; +} + + + +int SearchMsgs(char *Area) +{ + return smsgarea(Area, FALSE); +} + + + +int SearchMsgsNews(char *Group) +{ + return smsgarea(Group, TRUE); +} + + + +/* + * Check if system is connected + */ +int MsgSystemConnected(sysconnect Sys) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + msgshdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + if ((T.aka.zone == Sys.aka.zone) && + (T.aka.net == Sys.aka.net) && + (T.aka.node == Sys.aka.node) && + (T.aka.point == Sys.aka.point)) { + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +/* + * Change system's status, if the Read or Write flags are clear, + * the connection will be erased, else updated or connected. + */ +int MsgSystemConnect(sysconnect *Sys, int New) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(msgs_fil, "r+")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + msgshdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + + /* + * For a new connection, search an empty slot. + */ + if (New && (!T.aka.zone)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + fwrite(Sys, sizeof(sysconnect), 1, fil); + fclose(fil); + return TRUE; + } + + /* + * If not new it is an update + */ + if ((!New) && (T.aka.zone == Sys->aka.zone) && + (T.aka.net == Sys->aka.net) && (T.aka.node == Sys->aka.node) && + (T.aka.point == Sys->aka.point)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + if ((!Sys->sendto) && (!Sys->receivefrom)) { + /* + * It's a deletion, if the area is mandatory or + * the node is cutoff, refuse the deletion. + */ + if (msgs.Mandatory || T.cutoff) { + fclose(fil); + return FALSE; + } + memset(&T, 0, sizeof(sysconnect)); + fwrite(&T, sizeof(sysconnect), 1, fil); + } else { + /* + * It's a update, refuse it if the node is cutoff. + */ + if (T.cutoff) { + fclose(fil); + return FALSE; + } + fwrite(Sys, sizeof(sysconnect), 1, fil); + } + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +int GetMsgSystem(sysconnect * Sys, int First) +{ + FILE *fil; + + memset(Sys, 0, sizeof(sysconnect)); + if (sysstart == -1) + return FALSE; + + if (First) + sysrecord = 0; + else + sysrecord++; + + if (sysrecord >= CFG.toss_systems) + return FALSE; + + if ((fil = fopen(msgs_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart + (sysrecord * sizeof(sysconnect)), SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + if (fread(Sys, sizeof(sysconnect), 1, fil) == 1) { + fclose(fil); + return TRUE; + } + + fclose(fil); + return FALSE; +} + + + +int SearchNetBoard(unsigned short zone, unsigned short net) +{ + FILE *fil; + + mgrp_pos = -1; + mgrp_crc = -1; + + if ((fil = fopen(msgs_fil, "r")) == NULL) { + return FALSE; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + + while (fread(&msgs, msgshdr.recsize, 1, fil) == 1) { + fseek(fil, msgshdr.syssize, SEEK_CUR); + if ((msgs.Type == NETMAIL) && (msgs.Active) && + (zone == msgs.Aka.zone) && (net == msgs.Aka.net)) { + msgs_pos = ftell(fil) - (msgshdr.recsize + msgshdr.syssize); + msgs_crc = 0xffffffff; + msgs_crc = upd_crc32((char *)&msgs, msgs_crc, msgshdr.recsize); + fclose(fil); + return TRUE; + } + } + fclose(fil); + msgs_pos = -1; + msgs_crc = -1; + sysstart = -1; + return FALSE; +} + + + +void UpdateMsgs() +{ + unsigned long crc = 0xffffffff; + FILE *fil; + + if (msgs_pos == -1) + return; + + crc = upd_crc32((char *)&msgs, crc, msgshdr.recsize); + if (crc != msgs_crc) { + if ((fil = fopen(msgs_fil, "r+")) == NULL) { + msgs_pos = -1; + return; + } + fseek(fil, msgs_pos, SEEK_SET); + fwrite(&msgs, msgshdr.recsize, 1, fil); + fclose(fil); + } + msgs_pos = -1; + msgs_crc = -1; + + if (mgrp_pos == -1) + return; + + crc = 0xffffffff; + crc = upd_crc32((char *)&mgroup, crc, mgrouphdr.recsize); + if (crc != mgrp_crc) { + if ((fil = fopen(mgrp_fil, "r+")) == NULL) { + mgrp_pos = -1; + return; + } + fseek(fil, mgrp_pos, SEEK_SET); + fwrite(&mgroup, mgrouphdr.recsize, 1, fil); + fclose(fil); + } + mgrp_pos = -1; + mgrp_crc = -1; +} + + diff --git a/lib/dbmsgs.h b/lib/dbmsgs.h new file mode 100644 index 00000000..90130e75 --- /dev/null +++ b/lib/dbmsgs.h @@ -0,0 +1,21 @@ +#ifndef _DBMSGS_H +#define _DBMSGS_H + + +struct msgareashdr msgshdr; /* Header record */ +struct msgareas msgs; /* Msgss datarecord */ +struct _mgrouphdr mgrouphdr; /* Group header record */ +struct _mgroup mgroup; /* Group record */ +int msgs_cnt; /* Msgs records in database */ + +int InitMsgs(void); /* Initialize msgs database */ +int SearchMsgs(char *); /* Search specified msg area */ +int SearchMsgsNews(char *); /* Search specified msg area */ +int MsgSystemConnected(sysconnect); /* Is system connected */ +int MsgSystemConnect(sysconnect *, int); /* Connect/change/delete system*/ +int GetMsgSystem(sysconnect *, int);/* Get connected system */ +int SearchNetBoard(unsigned short, unsigned short); /* Search netmail */ +void UpdateMsgs(void); /* Update current messages record */ + +#endif + diff --git a/lib/dbnode.c b/lib/dbnode.c new file mode 100644 index 00000000..d100b22a --- /dev/null +++ b/lib/dbnode.c @@ -0,0 +1,205 @@ +/***************************************************************************** + * + * File ..................: dbnode.c + * Purpose ...............: Noderecord Access + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbnode.h" + + +char nodes_fil[PATH_MAX]; /* Nodes database filename */ +long nodes_pos = -1; /* Noderecord position */ +long nodes_fgp = -1; /* Nodes files group position */ +long nodes_mgp = -1; /* Nodes message group position */ +unsigned long nodes_crc = -1; /* Noderecord crc value */ + + + +int InitNode(void) +{ + FILE *fil; + + memset(&nodes, 0, sizeof(nodes)); + LoadConfig(); + + sprintf(nodes_fil, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(nodes_fil, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, 0, SEEK_END); + nodes_cnt = (ftell(fil) - nodeshdr.hdrsize) / (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + + return TRUE; +} + + + +int TestNode(fidoaddr aka) +{ + int i, nodeok = FALSE; + + for (i = 0; i < 20; i++) { + if (((aka.zone == 0) || (aka.zone = nodes.Aka[i].zone)) && + (aka.net == nodes.Aka[i].net) && + (aka.node == nodes.Aka[i].node) && + (aka.point == nodes.Aka[i].point)) + nodeok = TRUE; + } + return(nodeok); +} + + + +int SearchNode(fidoaddr aka) +{ + FILE *fil; + + nodes_pos = -1; + nodes_crc = -1; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + while (fread(&nodes, nodeshdr.recsize, 1, fil) == 1) { + fseek(fil, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + if (TestNode(aka)) { + nodes_pos = ftell(fil) - (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + nodes_crc = 0xffffffff; + nodes_crc = upd_crc32((char *)&nodes, nodes_crc, nodeshdr.recsize); + return TRUE; + } + } + + memset(&nodes, 0, sizeof(nodes)); + fclose(fil); + return FALSE; +} + + + +/* + * Update current noderecord if changed. + */ +int UpdateNode() +{ + unsigned long crc; + FILE *fil; + + if (nodes_pos == -1) + return FALSE; + + crc = 0xffffffff; + crc = upd_crc32((char *)&nodes, crc, nodeshdr.recsize); + if (crc != nodes_crc) { + if ((fil = fopen(nodes_fil, "r+")) == NULL) + return FALSE; + fseek(fil, nodes_pos, SEEK_SET); + fwrite(&nodes, nodeshdr.recsize, 1, fil); + fclose(fil); + } + + nodes_crc = -1; + nodes_pos = -1; + memset(&nodes, 0, sizeof(nodes)); + return TRUE; +} + + + +char *GetNodeMailGrp(int First) +{ + FILE *fil; + char group[13], *gr; + + if (nodes_pos == -1) + return NULL; + + if (First) + nodes_mgp = nodes_pos + nodeshdr.recsize + nodeshdr.filegrp; + + if (nodes_mgp > (nodes_pos + nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)) + return NULL; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return NULL; + + fseek(fil, nodes_mgp, SEEK_SET); + fread(&group, sizeof(group), 1, fil); + fclose(fil); + + nodes_mgp += sizeof(group); + + if (group[0] == '\0') + return NULL; + + gr = xstrcpy(group); + return gr; +} + + + +char *GetNodeFileGrp(int First) +{ + FILE *fil; + char group[13], *gr; + + if (nodes_pos == -1) + return NULL; + + if (First) + nodes_fgp = nodes_pos + nodeshdr.recsize; + + if (nodes_fgp > (nodes_pos + nodeshdr.recsize + nodeshdr.filegrp)) + return NULL; + + if ((fil = fopen(nodes_fil, "r")) == NULL) + return NULL; + + fseek(fil, nodes_fgp, SEEK_SET); + fread(&group, sizeof(group), 1, fil); + fclose(fil); + + nodes_fgp += sizeof(group); + + if (group[0] == '\0') + return NULL; + + gr = xstrcpy(group); + return gr; +} + + diff --git a/lib/dbnode.h b/lib/dbnode.h new file mode 100644 index 00000000..f49810fb --- /dev/null +++ b/lib/dbnode.h @@ -0,0 +1,18 @@ +#ifndef _DBNODE_H +#define _DBNODE_H + + +struct _nodeshdr nodeshdr; /* Header record */ +struct _nodes nodes; /* Nodes datarecord */ +int nodes_cnt; /* Node records in database */ + +int InitNode(void); /* Initialize nodes database */ +int TestNode(fidoaddr); /* Check if noderecord is loaded */ +int SearchNode(fidoaddr); /* Search specified node and load */ +int UpdateNode(void); /* Update record if changed. */ +char *GetNodeMailGrp(int); /* Get nodes mailgroup record */ +char *GetNodeFileGrp(int); /* Get nodes filegroup record */ + + +#endif + diff --git a/lib/dbtic.c b/lib/dbtic.c new file mode 100644 index 00000000..a020d795 --- /dev/null +++ b/lib/dbtic.c @@ -0,0 +1,305 @@ +/***************************************************************************** + * + * File ..................: dbtic.c + * Purpose ...............: Tic areas record Access + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbcfg.h" +#include "dbtic.h" + + +char tic_fil[PATH_MAX]; /* Database filename */ +char tgrp_fil[PATH_MAX]; /* Group database filename */ +long tic_pos = -1; /* Current record position */ +long tgrp_pos = -1; /* Current group position */ +unsigned long tic_crc = -1; /* CRC value of current record */ +unsigned long tgrp_crc = -1; /* CRC value of group record */ +static long sysstart, sysrecord; + + + +int InitTic(void) +{ + FILE *fil; + + memset(&tic, 0, sizeof(tic)); + memset(&fgroup, 0, sizeof(fgroup)); + LoadConfig(); + sysstart = -1; + + sprintf(tic_fil, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + fread(&tichdr, sizeof(tichdr), 1, fil); + fseek(fil, 0, SEEK_END); + tic_cnt = (ftell(fil) - tichdr.hdrsize) / (tichdr.recsize + tichdr.syssize); + fclose(fil); + + sprintf(tgrp_fil, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + return TRUE; +} + + + +int SearchTic(char *Area) +{ + FILE *fil; + + if ((fil = fopen(tic_fil, "r")) == NULL) { + return FALSE; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + + while (fread(&tic, tichdr.recsize, 1, fil) == 1) { + /* + * Mark the start of the connected systems records + * for later use and skip the system records. + */ + tic_pos = ftell(fil) - tichdr.recsize; + sysstart = ftell(fil); + fseek(fil, tichdr.syssize, SEEK_CUR); + if (!strcmp(Area, tic.Name) && tic.Active) { + sysrecord = 0; + fclose(fil); + tic_crc = 0xffffffff; + tic_crc = upd_crc32((char *)&tic, tic_crc, tichdr.recsize); + tgrp_pos = -1; + tgrp_crc = -1; + + if (strlen(tic.Group)) { + if ((fil = fopen(tgrp_fil, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + while ((fread(&fgroup, fgrouphdr.recsize, 1, fil)) == 1) { + if (!strcmp(tic.Group, fgroup.Name)) { + tgrp_pos = ftell(fil) - fgrouphdr.recsize; + tgrp_crc = 0xffffffff; + tgrp_crc = upd_crc32((char *)&fgroup, tgrp_crc, fgrouphdr.recsize); + break; + } + } + fclose(fil); + } + } else + memset(&fgroup, 0, sizeof(fgroup)); + + return TRUE; + } + } + sysstart = -1; + tic_crc = -1; + tic_pos = -1; + fclose(fil); + return FALSE; +} + + + +/* + * Check if system is connected + */ +int TicSystemConnected(sysconnect Sys) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + tichdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + if ((T.aka.zone == Sys.aka.zone) && + (T.aka.net == Sys.aka.net) && + (T.aka.node == Sys.aka.node) && + (T.aka.point == Sys.aka.point)) { + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +/* + * Change the system's status, if the Read and Write flags are clear, + * the connection will be erased, else updated or connected. + */ +int TicSystemConnect(sysconnect *Sys, int New) +{ + FILE *fil; + sysconnect T; + + if (sysstart == -1) + return FALSE; + + if ((fil = fopen(tic_fil, "r+")) == NULL) + return FALSE; + + if (fseek(fil, sysstart, SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + while (ftell(fil) != (sysstart + tichdr.syssize)) { + fread(&T, sizeof(sysconnect), 1, fil); + + /* + * For a new connection, search an empty slot. + */ + if (New && (!T.aka.zone)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + fwrite(Sys, sizeof(sysconnect), 1, fil); + fclose(fil); + return TRUE; + } + + /* + * If not new it is an update + */ + if ((!New) && (T.aka.zone == Sys->aka.zone) && + (T.aka.node == Sys->aka.node) && + (T.aka.net == Sys->aka.net) && + (T.aka.point == Sys->aka.point)) { + fseek(fil, - sizeof(sysconnect), SEEK_CUR); + if ((!Sys->sendto) && (!Sys->receivefrom)) { + /* + * It's a deletion + */ + if (tic.Mandat) { + fclose(fil); + return FALSE; + } + memset(&T, 0, sizeof(sysconnect)); + fwrite(&T, sizeof(sysconnect), 1, fil); + } else { + /* + * It's a update + */ + fwrite(Sys, sizeof(sysconnect), 1, fil); + } + fclose(fil); + return TRUE; + } + } + + fclose(fil); + return FALSE; +} + + + +int GetTicSystem(sysconnect * Sys, int First) +{ + FILE *fil; + + memset(Sys, 0, sizeof(sysconnect)); + if (sysstart == -1) + return FALSE; + + if (First) + sysrecord = 0; + else + sysrecord++; + + if (sysrecord >= CFG.tic_systems) + return FALSE; + + if ((fil = fopen(tic_fil, "r")) == NULL) + return FALSE; + + if (fseek(fil, sysstart + (sysrecord * sizeof(sysconnect)), SEEK_SET) != 0) { + fclose(fil); + return FALSE; + } + + if (fread(Sys, sizeof(sysconnect), 1, fil) == 1) { + fclose(fil); + return TRUE; + } + fclose(fil); + return FALSE; +} + + + +void UpdateTic() +{ + unsigned long crc = 0xffffffff; + FILE *fil; + + if (tic_pos == -1) + return; + + crc = upd_crc32((char *)&tic, crc, tichdr.recsize); + if (crc != tic_crc) { + if ((fil = fopen(tic_fil, "r+")) == NULL) { + tic_pos = -1; + return; + } + fseek(fil, tic_pos, SEEK_SET); + fwrite(&tic, tichdr.recsize, 1, fil); + fclose(fil); + } + tic_pos = -1; + tic_crc = -1; + + if (tgrp_pos == -1) + return; + + crc = 0xffffffff; + crc = upd_crc32((char *)&fgroup, crc, fgrouphdr.recsize); + if (crc != tgrp_crc) { + if ((fil = fopen(tgrp_fil, "r+")) == NULL) { + tgrp_pos = -1; + return; + } + fseek(fil, tgrp_pos, SEEK_SET); + fwrite(&fgroup, fgrouphdr.recsize, 1, fil); + fclose(fil); + } + tgrp_pos = -1; + tgrp_crc = -1; +} + + diff --git a/lib/dbtic.h b/lib/dbtic.h new file mode 100644 index 00000000..590ce464 --- /dev/null +++ b/lib/dbtic.h @@ -0,0 +1,19 @@ +#ifndef _DBTIC_H +#define _DBTIC_H + + +struct _tichdr tichdr; /* Header record */ +struct _tic tic; /* Tics datarecord */ +struct _fgrouphdr fgrouphdr; /* Group header record */ +struct _fgroup fgroup; /* Group record */ +int tic_cnt; /* Tic records in database */ + +int InitTic(void); /* Initialize tic database */ +int SearchTic(char *); /* Search specified msg are */ +int TicSystemConnected(sysconnect); /* Is system connected */ +int TicSystemConnect(sysconnect *, int); /* Connect/change/delete system*/ +int GetTicSystem(sysconnect *, int);/* Get connected system */ +void UpdateTic(void); /* Update current messages record */ + +#endif + diff --git a/lib/dbuser.c b/lib/dbuser.c new file mode 100644 index 00000000..b286c7de --- /dev/null +++ b/lib/dbuser.c @@ -0,0 +1,101 @@ +/***************************************************************************** + * + * File ..................: dbuser.c + * Purpose ...............: Userrecord Access + * Last modification date : 29-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbcfg.h" +#include "dbuser.h" + + + + +int InitUser(void) +{ + FILE *fil; + + memset(&usr, 0, sizeof(usr)); + LoadConfig(); + + sprintf(usr_fil, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fil = fopen(usr_fil, "r")) == NULL) + return FALSE; + + fread(&usrhdr, sizeof(usrhdr), 1, fil); + fseek(fil, 0, SEEK_END); + usr_cnt = (ftell(fil) - usrhdr.hdrsize) / usrhdr.recsize; + fclose(fil); + + return TRUE; +} + + + +int TestUser(char *Name) +{ + int userok = FALSE; + + if ((strcasecmp(usr.sUserName, Name) == 0) || + ((strlen(usr.sHandle) > 0) && (strcasecmp(usr.sHandle, Name) == 0)) || + (strcmp(usr.Name, Name) == 0)) { + if (!usr.Deleted) + userok = TRUE; + } + return(userok); +} + + + +int SearchUser(char *Name) +{ + FILE *fil; + + /* + * Allways reread the users file. + */ + if ((fil = fopen(usr_fil, "r")) == NULL) { + memset(&usr, 0, sizeof(usr)); + return FALSE; + } + fread(&usrhdr, sizeof(usrhdr), 1, fil); + + while (fread(&usr, usrhdr.recsize, 1, fil) == 1) { + if (TestUser(Name)) { + fclose(fil); + return TRUE; + } + } + fclose(fil); + return FALSE; +} + + + diff --git a/lib/dbuser.h b/lib/dbuser.h new file mode 100644 index 00000000..3c2207fd --- /dev/null +++ b/lib/dbuser.h @@ -0,0 +1,16 @@ +#ifndef _DBUSER_H +#define _DBUSER_H + + +struct userhdr usrhdr; /* Header record */ +struct userrec usr; /* User datarecord */ +int usr_cnt; /* User records in database */ +char usr_fil[81]; /* User database filename */ + +int InitUser(void); /* Initialize user database */ +int TestUser(char *); /* Test if user is in memory */ +int SearchUser(char *); /* Search specified user and load */ + + +#endif + diff --git a/lib/dostran.c b/lib/dostran.c new file mode 100644 index 00000000..0a511df6 --- /dev/null +++ b/lib/dostran.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: dostran.c + * Purpose ...............: DOS to Unix filename translation + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" + + +char *Dos2Unix(char *dosname) +{ + char buf[PATH_MAX]; + static char buf2[PATH_MAX]; + char *p, *q; + + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + sprintf(buf, "%s", dosname); + p = buf; + + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy((char *)buf2, CFG.uxpath); + for (p+=strlen(CFG.dospath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p+=strlen(CFG.uxpath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + } + return buf2; +} + + + +char *Unix2Dos(char *uxname) +{ + char *q; + static char buf[PATH_MAX]; + + memset(&buf, 0, sizeof(buf)); + + if (strlen(CFG.dospath)) { + sprintf(buf, "%s", CFG.dospath); + + if (*(CFG.dospath+strlen(CFG.dospath)-1) != '\\') + buf[strlen(buf)] = '\\'; + + if (*(q=uxname+strlen(CFG.uxpath)) == '/') + q++; + + for (; *q; q++) + buf[strlen(buf)] = (*q == '/')?'\\':*q; + + } else { + sprintf(buf, "%s", uxname); + } + + return buf; +} + + diff --git a/lib/execute.c b/lib/execute.c new file mode 100644 index 00000000..7df4a8aa --- /dev/null +++ b/lib/execute.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: execute.c + * Purpose ...............: Execute subprogram + * Last modification date : 16-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +int e_pid = 0; /* Execute child pid */ + + + +int execute(char *cmd, char *file, char *pkt, char *in, char *out, char *err) +{ + char buf[512]; + char *vector[16]; + int i; + int pid, status, rc; + + if (pkt == NULL) + sprintf(buf, "%s %s", cmd, file); + else + sprintf(buf, "%s %s %s", cmd, file, pkt); + Syslog('+', "Execute: %s",buf); + + i = 0; + vector[i++] = strtok(buf," \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in,O_RDONLY) != 0) { + WriteError("$Reopen of stdin to %s failed", MBSE_SS(in)); + exit(-1); + } + } + if (out) { + close(1); + if (open(out,O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + WriteError("$Reopen of stdout to %s failed", MBSE_SS(out)); + exit(-1); + } + } + if (err) { + close(2); + if (open(err,O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + WriteError("$Reopen of stderr to %s failed", MBSE_SS(err)); + exit(-1); + } + } + errno = 0; + rc = getpriority(PRIO_PROCESS, 0); + if (errno == 0) { + rc = setpriority(PRIO_PROCESS, 0, 15); + if (rc) + WriteError("$execv can't set priority to 15"); + } + rc = execv(vector[0],vector); + WriteError("$execv \"%s\" returned %d", MBSE_SS(vector[0]), rc); + setpriority(PRIO_PROCESS, 0, 0); + exit(-1); + } + + e_pid = pid; + + do { + rc = wait(&status); + e_pid = 0; + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (errno == EINTR))); + + setpriority(PRIO_PROCESS, 0, 0); + switch (rc) { + case -1: + WriteError("$Wait returned %d, status %d,%d", rc,status>>8,status&0xff); + return -1; + case 0: + return 0; + default: + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + if (rc) { + WriteError("Execute: returned error %d", rc); + return rc; + } + } + if (WIFSIGNALED(status)) { + rc = WTERMSIG(status); + WriteError("Wait stopped on signal %d", rc); + return rc; + } + if (rc) + WriteError("Wait stopped unknown, rc=%d", rc); + return rc; + } + return 0; +} + + +#define SHELL "/bin/sh" + + +int execsh(char *cmd, char *in, char *out, char *err) +{ + int pid, status, rc, sverr; + + Syslog('+', "Execute shell: %s", MBSE_SS(cmd)); + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in, O_RDONLY) != 0) { + WriteError("$Reopen of stdin to %s failed",MBSE_SS(in)); + exit(-1); + } + } + if (out) { + close(1); + if (open(out, O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + WriteError("$Reopen of stdout to %s failed",MBSE_SS(out)); + exit(-1); + } + } + if (err) { + close(2); + if (open(err, O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + WriteError("$Reopen of stderr to %s failed",MBSE_SS(err)); + exit(-1); + } + } + + rc = execl(SHELL, "sh", "-c", cmd, NULL); + WriteError("$execl \"%s\" returned %d", MBSE_SS(cmd), rc); + exit(-1); + } + + e_pid = pid; + + do { + rc = wait(&status); + e_pid = 0; + sverr = errno; + if (status) + WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + } + + while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + if (rc == -1) { + WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + return -1; + } + + return status; +} + + diff --git a/lib/expipe.c b/lib/expipe.c new file mode 100644 index 00000000..75b28f6b --- /dev/null +++ b/lib/expipe.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * + * File ..................: expipe.c + * Purpose ...............: MBSE BBS Execute pipe + * Last modification date : 22-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + + +static struct _fppid { + FILE *fp; + int pid; +} fppid[] = { + {NULL, 0}, {NULL, 0}, {NULL, 0} +}; + +#define maxfppid 2 + + + +FILE *expipe(char *cmd, char *from, char *to) +{ + char buf[256], *buflimit; + char *vector[16]; + int i, rc; + char *p, *q, *f=from, *t=to; + int pipedes[2]; + FILE *fp; + int pid, slot; + + buflimit = buf + sizeof(buf) -1 - (f&&t&&(strlen(f)>strlen(t))?strlen(f):t?strlen(t):0); + + for (slot = 0; slot <= maxfppid; slot++) { + if (fppid[slot].fp == NULL) + break; + } + if (slot > maxfppid) { + WriteError("Attempt to pipe more than %d processes", maxfppid + 1); + return NULL; + } + + for (p = cmd, q = buf; (*p); p++) { + if (q > buflimit) { + WriteError("Attempt to pipe too long command"); + return NULL; + } + switch (*p) { + case '$': switch (*(++p)) { + case 'f': + case 'F': if ((f)) + while (*f) + *(q++) = *(f++); + f=from; + break; + case 't': + case 'T': if ((t)) + while (*t) + *(q++) = *(t++); + t=to; + break; + default: *(q++)='$'; + *(q++)=*p; + break; + } + break; + case '\\': *(q++) = *(++p); + break; + default: *(q++) = *p; + break; + } + } + + *q = '\0'; + Syslog('+', "Expipe: %s",buf); + i = 0; + vector[i++] = strtok(buf," \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + if (pipe(pipedes) != 0) { + WriteError("$Pipe failed for command \"%s\"", MBSE_SS(vector[0])); + return NULL; + } + + Syslog('e', "pipe() returned read=%d, write=%d", pipedes[0], pipedes[1]); + if ((pid = fork()) == 0) { + close(pipedes[1]); + close(0); + if (dup(pipedes[0]) != 0) { + WriteError("$Reopen of stdin for command %s failed", MBSE_SS(vector[0])); + exit(-1); + } + rc = execv(vector[0],vector); + WriteError("$Exec \"%s\" returned %d", MBSE_SS(vector[0]), rc); + exit(-1); + } + + close(pipedes[0]); + + if ((fp = fdopen(pipedes[1],"w")) == NULL) { + WriteError("$fdopen failed for pipe to command \"%s\"", MBSE_SS(vector[0])); + } + + fppid[slot].fp = fp; + fppid[slot].pid = pid; + return fp; +} + + + +int exclose(FILE *fp) +{ + int status, rc; + int pid, slot, sverr; + + for (slot = 0; slot <= maxfppid; slot++) { + if (fppid[slot].fp == fp) + break; + } + if (slot > maxfppid) { + WriteError("Attempt to close unopened pipe"); + return -1; + } + pid = fppid[slot].pid; + fppid[slot].fp = NULL; + fppid[slot].pid = 0; + + Syslog('e', "Closing pipe to the child process %d",pid); + if ((rc = fclose(fp)) != 0) { + WriteError("$Error closing pipe to transport (rc=%d)", rc); + if ((rc = kill(pid,SIGKILL)) != 0) + WriteError("$kill for pid %d returned %d",pid,rc); + } + Syslog('e', "Waiting for process %d to finish",pid); + do { + rc = wait(&status); + sverr = errno; + if (status) + Syslog('e', "$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + + switch (rc) { + case -1:WriteError("$Wait returned %d, status %d,%d", rc, status >> 8, status & 0xff); + return -1; + case 0: return 0; + default: + if (WIFEXITED(status)) { + rc = WEXITSTATUS(status); + if (rc) { + WriteError("Expipe: returned error %d", rc); + return rc; + } + } + if (WIFSIGNALED(status)) { + rc = WTERMSIG(status); + WriteError("Wait stopped on signal %d", rc); + return rc; + } + if (rc) + WriteError("Wait stopped unknown, rc=%d", rc); + return rc; + } + return 0; +} + diff --git a/lib/faddr.c b/lib/faddr.c new file mode 100644 index 00000000..ec12727f --- /dev/null +++ b/lib/faddr.c @@ -0,0 +1,100 @@ +/***************************************************************************** + * + * File ..................: faddr.c + * Purpose ...............: Fidonet Address conversions. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1993-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MB BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + +/************************************************************************ + * + * String functions + */ + + +/* + * Fidonet aka to string, returns Z:N/N@domain or Z:N/N.P@domain + */ +char *aka2str(fidoaddr aka) +{ + static char result[43]; + + result[0] = '\0'; + if (aka.point == 0) + sprintf(result, "%d:%d/%d@%s", aka.zone, aka.net, aka.node, aka.domain); + else + sprintf(result, "%d:%d/%d.%d@%s", aka.zone, aka.net, aka.node, aka.point, aka.domain); + + return result; +} + + + +fidoaddr str2aka(char *addr) +{ + char a[256]; + static char b[43]; + char *temp; + fidoaddr n; + + sprintf(b, "%s~", addr); + n.zone = 0; + n.net = 0; + n.node = 0; + n.point = 0; + n.domain[0] = '\0'; + + if ((strchr(b, ':') == NULL) || (strchr(b, '@') == NULL)) + return n; + + /* First split the f:n/n.p and domain part + */ + temp = strtok(b, "@"); + strcpy(n.domain, strtok(NULL, "~")); + + /* Handle f:n/n.p part + */ + strcpy(a, strcat(temp, "~")); + if (strchr(a, '.') == NULL) { + n.zone = atoi(strtok(a, ":")); + n.net = atoi(strtok(NULL, "/")); + n.node = atoi(strtok(NULL, "~")); + } else { + n.zone = atoi(strtok(a, ":")); + n.net = atoi(strtok(NULL, "/")); + n.node = atoi(strtok(NULL, ".")); + n.point = atoi(strtok(NULL, "~")); + } + return n; +} + + + + diff --git a/lib/falists.c b/lib/falists.c new file mode 100644 index 00000000..d461754b --- /dev/null +++ b/lib/falists.c @@ -0,0 +1,228 @@ +/***************************************************************************** + * + * File ..................: falists.c + * Purpose ...............: SEEN-BY and PATH lists + * Last modification date : 25-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + + +void tidy_falist(fa_list **fap) +{ + fa_list *tmp,*old; + + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + tidy_faddr(tmp->addr); + free(tmp); + } + *fap = NULL; +} + + + +int in_list(faddr *addr, fa_list **fap, int fourd) +{ + fa_list *tmp; + + Syslog('M', "in_list: Seeking seen-by match for %s", ascinode(addr,0x06)); + + if (addr->point) { + Syslog('M', "in_list: No seen-by check for point address"); + return 0; + } + + for (tmp = *fap; tmp; tmp = tmp->next) + if ((tmp->addr->net == addr->net) && + ((!fourd) || (fourd && (tmp->addr->zone == addr->zone))) && + ((!fourd) || (fourd && (tmp->addr->point == addr->point))) && + (tmp->addr->node == addr->node)) { + Syslog('M', "in_list: Match found"); + return 1; + } + + Syslog('M', "in_list: Match not found"); + return 0; +} + + + +void fill_list(fa_list **fap, char *str, fa_list **omit, int force) +{ + fa_list *tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q, *r; + int allowskip = 1; + + if ((str == NULL) || (*str == '\0')) + return; + + buf = xstrcpy(str); + r = buf + strlen(buf); + + for (p = strtok(buf," \t\n"), q = p + strlen(p) + 1; + p; + p = (q < r) ? strtok(q, " \t\n"):NULL, q = p ? p + strlen(p) + 1:r) + if ((ta = parsefnode(p))) { + if (ta->net == 0) + ta->net = oldnet; + else + oldnet = ta->net; + if (allowskip && omit && *omit && (metric(ta,(*omit)->addr) == 0)) { + Syslog('m', "fill_list: omit %s", ascfnode(ta,0x1f)); + tmp = *omit; + *omit = (*omit)->next; + tmp->next = NULL; + tidy_falist(&tmp); + } else { + allowskip = 0; + tmp = (fa_list *)malloc(sizeof(fa_list)); + tmp->next = *fap; + tmp->addr = ta; + tmp->force = force; + *fap = tmp; + } + } + + free(buf); + return; +} + + + +void fill_path(fa_list **fap, char *str) +{ + fa_list **tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q, *r; + + if ((str == NULL) || (*str == '\0')) + return; + buf = xstrcpy(str); + for (tmp = fap; *tmp; tmp = &((*tmp)->next)); /*nothing*/ + r = buf + strlen(buf); + + for (p = strtok(buf, " \t\n"), q = p + strlen(p) + 1; + p; + p = (q < r) ? strtok(q, " \t\n") : NULL, q = p ? p + strlen(p) + 1 : r) + if ((ta = parsefnode(p))) { + if (ta->net == 0) + ta->net=oldnet; + else + oldnet=ta->net; + *tmp = (fa_list *)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = ta; + tmp = &((*tmp)->next); + } + free(buf); + return; +} + + + + +int compaddr(fa_list **,fa_list **); + + + +void uniq_list(fa_list **fap) +{ + fa_list *ta, *tan; + + if (*fap == NULL) + return; + for (ta = *fap; ta; ta = ta->next) { + while ((tan = ta->next) && (compaddr(&ta, &tan) == 0)) { + ta->next = tan->next; + tidy_faddr(tan->addr); + free(tan); + } + ta->next = tan; + } +} + + + +void sort_list(fa_list **fap) +{ + fa_list *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + vector = (fa_list **)malloc(n * sizeof(fa_list *)); + i = 0; + + for (ta = *fap; ta; ta = ta->next) { + vector[i++] = ta; + } + qsort(vector,n,sizeof(faddr*), + (int(*)(const void*,const void*))compaddr); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + while ((i < n) && (compaddr(&ta,&(vector[i])) == 0)) + { + tidy_faddr((vector[i])->addr); + free(vector[i]); + i++; + } + if (i < n) + ta->next=vector[i++]; + else + ta->next=NULL; + } + + free(vector); + return; +} + + + +int compaddr(fa_list **fap1, fa_list **fap2) +{ + if ((*fap1)->addr->net != (*fap2)->addr->net) + return ((*fap1)->addr->net - (*fap2)->addr->net); + else + return ((*fap1)->addr->node - (*fap2)->addr->node); +} + + + diff --git a/lib/ftn.c b/lib/ftn.c new file mode 100644 index 00000000..1819ec5f --- /dev/null +++ b/lib/ftn.c @@ -0,0 +1,683 @@ +/***************************************************************************** + * + * File ..................: ftn.c + * Purpose ...............: Fidonet Technology Network functions + * Last modification date : 25-Mar-2001 + * Remark ................: From ifmail with patches from P.Saratxaga + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_FIDONET + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "dbftn.h" +#include "common.h" + + +#ifndef MAXUSHORT +#define MAXUSHORT 65535 +#endif +#ifndef BLANK_SUBS +#define BLANK_SUBS '.' +#endif + + +int addrerror = 0; + +void tidy_faddr(faddr *addr) +{ + if (addr == NULL) + return; + if (addr->name) + free(addr->name); + if (addr->domain) + free(addr->domain); + free(addr); +} + + + +faddr *parsefnode(char *s) +{ + faddr addr, *tmp; + char *buf, *str, *p, *q, *n; + int good = 1; + + if (s == NULL) + return NULL; + + str = buf = xstrcpy(s); + + while (isspace(*str)) + str++; + if (*(p=str+strlen(str)-1) == '\n') + *(p--) ='\0'; + while (isspace(*p)) + *(p--) = '\0'; + + p=str + strlen(str) - 1; + if (((*str == '(') && (*p == ')')) || ((*str == '\"') && (*p == '\"')) || + ((*str == '\'') && (*p == '\'')) || ((*str == '<') && (*p == '>')) || + ((*str == '[') && (*p == ']')) || ((*str == '{') && (*p == '}'))) { + str++; + *p = '\0'; + } + + memset(&addr, 0, sizeof(faddr)); + if ((p = strrchr(str,' '))) { + n = str; + str = p + 1; + while (isspace(*p)) + *(p--) = '\0'; + if (!strcasecmp(p - 2," of")) + *(p-2) = '\0'; + else if (!strcasecmp(p - 1," @")) + *(p-1) = '\0'; + p -= 3; + while (isspace(*p) || (*p == ',')) + *(p--) = '\0'; + if (strlen(n) > MAXNAME) + n[MAXNAME] = '\0'; + if (*n != '\0') + addr.name = xstrcpy(n); + } + + if ((p = strrchr(str, '@'))) + *(p++) = '\0'; + else if ((p = strrchr(str,'%'))) + *(p++) = '\0'; + else if ((q = strrchr(str,'#'))) { + *(q++) = '\0'; + p = str; + str = q; + } else if (addr.name && (strrchr(addr.name,'@'))) { + str = xstrcpy(addr.name); + if ((p=strrchr(str,'@'))) + *(p++) = '\0'; + else if ((p=strrchr(str,'%'))) + *(p++) = '\0'; + } else + p = NULL; + + if (p && ((q = strchr(p,'.')))) + *q = '\0'; + + addr.point = 0; + addr.node = 0; + addr.net = 0; + addr.zone = 0; + addr.domain = xstrcpy(p); + + if ((p = strchr(str, ':'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.zone = atoi(str); + else + if (strcmp(str,"*") == 0) + addr.zone = -1; + else + good = 0; + str = p; + } + + if ((p = strchr(str, '/'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.net = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.net = -1; + else + good = 0; + str = p; + } + + if ((p=strchr(str, '.'))) { + *(p++) = '\0'; + if (strspn(str, "0123456789") == strlen(str)) + addr.node = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.node = -1; + else + good = 0; + str = p; + } else { + if (strspn(str, "0123456789") == strlen(str)) + addr.node = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.node = -1; + else + good = 0; + str = NULL; + } + + if (str) { + if (strspn(str, "0123456789") == strlen(str)) + addr.point = atoi(str); + else + if (strcmp(str, "*") == 0) + addr.point = -1; + else + good = 0; + } + + if (buf) + free(buf); + + if (good) { + tmp = (faddr *)malloc(sizeof(addr)); + tmp->name = NULL; + tmp->domain = addr.domain; + tmp->point = addr.point; + tmp->node = addr.node; + tmp->net = addr.net; + tmp->zone = addr.zone; + return tmp; + } else { + if (addr.name) + free(addr.name); + if (addr.domain) + free(addr.domain); + return NULL; + } +} + + + +faddr *parsefaddr(char *s) +{ + faddr *tmpaddr = NULL; + parsedaddr rfcaddr; + int gotzone = 0, gotnet = 0, gotnode = 0, gotpoint = 0; + int zone = 0, net = 0, noden = 0, point = 0; + char *domain = NULL, *freename = NULL; + long num; + char *p = NULL,*q = NULL,*t = NULL; + int l, quoted; + FILE *fp; + + rfcaddr.target = NULL; + rfcaddr.remainder = NULL; + rfcaddr.comment = NULL; + + t = xstrcpy(s); + if (*(q=t+strlen(t)-1) == '\n') + *q='\0'; + if (((*(p=t) == '(') && (*(q=p+strlen(p)-1) == ')')) || ((*p == '\"') && (*q == '\"'))) { + p++; + *q='\0'; + } + + if (strchr(s,'@') || strchr(s,'%') || strchr(s,'!')) + rfcaddr = parserfcaddr(p); + else { + addrerror = 0; + rfcaddr.target = xstrcpy(p); + } + free(t); + if ((addrerror) || (rfcaddr.target == NULL)) + goto leave; + + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + } else { + free(p); + fread(&domainhdr, sizeof(domainhdr), 1, fp); + p = rfcaddr.target; + + while (fread(&domtrans, domainhdr.recsize, 1, fp) == 1) { + q = p + strlen(p) - strlen(domtrans.intdom); + if ((q >= p) && (strcasecmp(domtrans.intdom, q) == 0)) { + *q = '\0'; + q = malloc(strlen(p) + strlen(domtrans.ftndom) +1); + strcpy(q, p); + strcat(q, domtrans.ftndom); + p = q; + free(rfcaddr.target); + rfcaddr.target = p; + break; + } + } + fclose(fp); + } + + if (((l = strlen(rfcaddr.target)) > 4) && (strcasecmp(rfcaddr.target + l - 4,".ftn") == 0)) { + rfcaddr.target[l-4] = '\0'; + } + + for (p = strtok(rfcaddr.target, "."); p; p = strtok(NULL,".")) { + if (((l = strlen(p + 1)) > 0) && (l <= 5) && + (strspn(p + 1, "0123456789") == l)) { + num = atol(p + 1); + switch (*p) { + case 'z': + case 'Z': + gotzone++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + zone = num; + break; + case 'n': + case 'N': + gotnet++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + net = num; + break; + case 'f': + case 'F': + gotnode++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + noden = num; + break; + case 'p': + case 'P': + gotpoint++; + if (num > MAXUSHORT) + addrerror |= ADDR_BADTOKEN; + point = num; + break; + default: + if (gotnet && gotnode) { + if (domain == NULL) + domain = xstrcpy(p); + } else + addrerror |= ADDR_BADTOKEN; + break; + } + } else { /* not "cNNNN" token */ + if (gotnet && gotnode) { + if (domain == NULL) + domain = xstrcpy(p); + } else + addrerror |= ADDR_BADTOKEN; + } + } + + if ((gotzone > 1) || (gotnet != 1) || (gotnode != 1) || (gotpoint > 1)) { + addrerror |= ADDR_BADSTRUCT; + } + + if (addrerror) + goto leave; + + if (rfcaddr.remainder) { + quoted = 0; + if ((*(p = rfcaddr.remainder) == '\"') && (*(q = p + strlen(p) -1) == '\"')) { + p++; + *q='\0'; + quoted = 1; + } + if (strchr(p,'@') || strchr(p,'%') || strchr(p,'!')) { + if (((q=strrchr(p,'%'))) && !strchr(p,'@')) + *q = '@'; + } else if ((!quoted) && (!strchr(p, ' '))) { + for (q = p; *q; q++) { + if (*q == BLANK_SUBS) + *q = ' '; + else if (*q == '.') + *q = ' '; + else if (*q == '_') + *q = ' '; + } + } + for (q = p; *q; q++) { + if ((*q == '\\') && ((*(q+1) == '"') || ((*(q+1) == '\\') && (!quoted)))) { + *q='\0'; + strcat(p, q+1); + } + } + if (strspn(p," ") != strlen(p)) + freename = xstrcpy(qp_decode(p)); + } + + tmpaddr=(faddr*)malloc(sizeof(faddr)); + + tmpaddr->zone=zone; + tmpaddr->net=net; + tmpaddr->node=noden; + tmpaddr->point=point; + tmpaddr->domain=domain; + domain=NULL; + tmpaddr->name=freename; + freename=NULL; + +leave: + if (domain) + free(domain); + if (freename) + free(freename); + + tidyrfcaddr(rfcaddr); + return tmpaddr; +} + + + +char *ascinode(faddr *a, int fl) +{ + static char buf[128], *f, *t, *p; + static char *q; + int skip, found = FALSE; + FILE *fp; + + if (a == NULL) { + strcpy(buf,""); + return buf; + } + + buf[0]='\0'; + if ((fl & 0x80) && (a->name)) { + if ((strchr(a->name,'.')) || (strchr(a->name,'@')) || + (strchr(a->name,'\'')) || (strchr(a->name,',')) || + (strchr(a->name,'<')) || (strchr(a->name,'>'))) + sprintf(buf+strlen(buf),"\"%s\" <",a->name); + else + sprintf(buf+strlen(buf),"%s <",a->name); + } + + if ((fl & 0x40) && (a->name)) { + f = qp_encode(a->name, 0); + t = buf + strlen(buf); + skip = 0; + if ((!strchr(f,'@')) && ((strchr(f,BLANK_SUBS)) || (strchr(f,'.')) || (strchr(f,'_')))) { + skip = 1; + *t++='"'; + } + while (*f) { + switch (*f) { + case '_': + case '.': *t++=*f; + break; + case ' ': if (!skip) + *t++=BLANK_SUBS; + else { + *t++='='; *t++='2'; *t++='0'; + } + break; + case ',': { /* "," is a problem on mail addr */ + if (!skip) + *t++='\\'; + *t++='='; + *t++='2'; + *t++='c'; + } + case '@': if (skip) { + *t++='"'; + skip=0; + } + *t++='%'; + break; + case '"': *t++='\\'; + *t++=*f; + break; + case '>': + case '<': + case '\'': if (!skip) + *t++='\\'; + *t++=*f; + break; + default: if ((((*f & 0xff) > 0x29) && ((*f & 0xff) < 0x3a)) || + (((*f & 0xff) > 0x40) && ((*f & 0xff) < 0x5b)) || + (((*f & 0xff) > 0x60) && ((*f & 0xff) < 0x7b))) + *t++=*f; + else { + if (!skip) + *t++='\\'; + *t++=*f; + } + break; + } + f++; + } + if (skip) + *t++='"'; + skip = 0; + *t++ = '@'; + *t++ = '\0'; + } + + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),"p%u.",a->point); + if (fl & 0x02) + sprintf(buf+strlen(buf),"f%u.",a->node); + if (fl & 0x04) + sprintf(buf+strlen(buf),"n%u.",a->net); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"z%u.",a->zone); + buf[strlen(buf)-1]='\0'; + + if (fl & 0x10) { + if (a->domain) + sprintf(buf+strlen(buf),".%s",a->domain); + } + + if (fl & 0x20) { + if (a->domain) { + if ((fl & 0x10) == 0) + sprintf(buf+strlen(buf),".%s",a->domain); + } else { + if (SearchFidonet(a->zone)) + sprintf(buf+strlen(buf), ".%s", fidonet.domain); + else + sprintf(buf+strlen(buf),".fidonet"); + } + + p = calloc(128, sizeof(char)); + sprintf(p, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + } else { + fread(&domainhdr, sizeof(domainhdr), 1, fp); + while (fread(&domtrans, domainhdr.recsize, 1, fp) == 1) { + q = buf + strlen(buf) - strlen(domtrans.ftndom); + if ((q >= buf) && (strcasecmp(domtrans.ftndom, q) == 0)) { + strcpy(q, domtrans.intdom); + found = TRUE; + break; + } + } + fclose(fp); + } + free(p); + if (!found) + sprintf(buf + strlen(buf), ".ftn"); + } + + if ((fl & 0x80) && (a->name)) + sprintf(buf+strlen(buf),">"); + + return buf; +} + + + +/* + * Return ASCII string for node, the bits in 'fl' set the + * output format. + */ +char *ascfnode(faddr *a, int fl) +{ + static char buf[128]; + + if (a == NULL) { + strcpy(buf, ""); + return buf; + } + + buf[0] = '\0'; + if ((fl & 0x40) && (a->name)) + sprintf(buf+strlen(buf),"%s of ",a->name); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"%u:",a->zone); + if (fl & 0x04) + sprintf(buf+strlen(buf),"%u/",a->net); + if (fl & 0x02) + sprintf(buf+strlen(buf),"%u",a->node); + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),".%u",a->point); + if ((fl & 0x10) && (a->domain)) + sprintf(buf+strlen(buf),"@%s",a->domain); + return buf; +} + + + +int metric(faddr *a1, faddr *a2) +{ + if ((a1->domain != NULL) && (a2->domain != NULL) && + (strcasecmp(a1->domain,a2->domain) != 0)) + return METRIC_DOMAIN; + if ((a1->zone != 0) && (a2->zone != 0) && + (a1->zone != a2->zone)) return METRIC_ZONE; + if (a1->net != a2->net) return METRIC_NET; + if (a1->node != a2->node) return METRIC_NODE; + if (a1->point != a2->point) return METRIC_POINT; + return METRIC_EQUAL; +} + + + +/* + * Convert mbse style to ifcico style. + */ +faddr *fido2faddr(fidoaddr aka) +{ + faddr *fa; + + fa = (faddr *)malloc(sizeof(faddr)); + fa->name = NULL; + fa->domain = xstrcpy(aka.domain);; + fa->zone = aka.zone; + fa->net = aka.net; + fa->node = aka.node; + fa->point = aka.point; + + return fa; +} + + + +/* + * Convert ifcico style to mbse style + */ +fidoaddr *faddr2fido(faddr *aka) +{ + fidoaddr *Sys; + + Sys = (fidoaddr *)malloc(sizeof(fidoaddr)); + memset(Sys, 0, sizeof(Sys)); + Sys->zone = aka->zone; + Sys->net = aka->net; + Sys->node = aka->node; + Sys->point = aka->point; + if (aka->domain != NULL) + sprintf(Sys->domain, "%s", aka->domain); + + return Sys; +} + + + +faddr *bestaka_s(faddr *addr) +{ + faddr *best = NULL, *tmp; + int i, minmetric, wt; + + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + best = fido2faddr(CFG.aka[i]); + break; + } + } + if (addr == NULL) + return best; + minmetric = metric(addr, best); + + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + tmp = fido2faddr(CFG.aka[i]); + wt = metric(addr, tmp); + tidy_faddr(tmp); + + if ((wt < minmetric) && ((best->point != 0) || (minmetric > METRIC_NODE))) { + /* + * In the same network, use node address even when + * routing to the node where we have a point address + */ + minmetric = wt; + tidy_faddr(best); + best = fido2faddr(CFG.aka[i]); + } + } + } + return best; +} + + + +int is_local(faddr *addr) +{ + int i; + + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (metric(fido2faddr(CFG.aka[i]), addr) == METRIC_EQUAL)) + return TRUE; + } + return FALSE; +} + + + +int chkftnmsgid(char *msgid) +{ + faddr *p; + + if (msgid == NULL) + return 0; + + while (isspace(*msgid)) + msgid++; + if ((p=parsefaddr(msgid))) { + if (p->name && (strspn(p->name,"0123456789") == strlen(p->name))) + return 1; + } else if ((!strncmp(msgid,"tm_sec > 59) + ptm->tm_sec = 59; + + sprintf(buf,"%02d %s %02d %02d:%02d:%02d",ptm->tm_mday, + months[ptm->tm_mon], ptm->tm_year%100, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + return buf; +} + + + +FILE *ftnmsghdr(ftnmsg *fmsg, FILE *pkt, faddr *route, char flavor, char *Pid) +{ + unsigned char buffer[0x0e]; + time_t Now; + faddr *from; + + if ((strlen(fmsg->to->name) > 36) || + (strlen(fmsg->from->name) > 36) || + (strlen(fmsg->subj) > 72)) + return NULL; + + if (route == NULL) + route = fmsg->to; + pkt = openpkt(pkt, route, flavor); + if (pkt == NULL) + return NULL; + + if (fmsg->area) + from = bestaka_s(fmsg->to); + else + from = fmsg->from; + + memset(&buffer, 0, sizeof(buffer)); + buffer[0x00] = 2; + buffer[0x02] = (from->node & 0x00ff); + buffer[0x03] = (from->node & 0xff00) >> 8; + buffer[0x04] = (fmsg->to->node & 0x00ff); + buffer[0x05] = (fmsg->to->node & 0xff00) >> 8; + buffer[0x06] = (from->net & 0x00ff); + buffer[0x07] = (from->net & 0xff00) >> 8; + buffer[0x08] = (fmsg->to->net & 0x00ff); + buffer[0x09] = (fmsg->to->net & 0xff00) >> 8; + buffer[0x0a] = (fmsg->flags & 0x00ff); + buffer[0x0b] = (fmsg->flags & 0xff00) >> 8; + fwrite(buffer, 1, sizeof(buffer), pkt); + + fprintf(pkt, "%s%c", ftndate(fmsg->date), '\0'); + fprintf(pkt, "%s%c", fmsg->to->name?fmsg->to->name:(char *)"Sysop", '\0'); + fprintf(pkt, "%s%c", fmsg->from->name?fmsg->from->name:(char *)"Sysop", '\0'); + fprintf(pkt, "%s%c", fmsg->subj?fmsg->subj:(char *)"", '\0'); + + if (fmsg->area) { + fprintf(pkt, "AREA:%s\r", fmsg->area); + } else { + if (fmsg->to->point) + fprintf(pkt, "\1TOPT %u\r", fmsg->to->point); + if (fmsg->from->point) + fprintf(pkt, "\1FMPT %u\r", fmsg->from->point); + fprintf(pkt, "\1INTL %u:%u/%u %u:%u/%u\r", + fmsg->to->zone, + fmsg->to->net, + fmsg->to->node, + fmsg->from->zone, + fmsg->from->net, + fmsg->from->node + ); + } + + if (fmsg->msgid_s) + fprintf(pkt, "\1MSGID: %s\r", fmsg->msgid_s); + else if (fmsg->msgid_a) + fprintf(pkt, "\1MSGID: %s %08lx\r", + fmsg->msgid_a, + fmsg->msgid_n); + + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\r", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\r", + fmsg->reply_a, + fmsg->reply_n); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + fprintf(pkt, "\001PID: %s %s\r", Pid, VERSION); + fprintf(pkt, "\001TZUTC: %s\r", gmtoffset(Now)); + if (ferror(pkt)) + return NULL; + else + return pkt; +} + + + +void tidy_ftnmsg(ftnmsg *tmsg) +{ + if (tmsg == NULL) + return; + + tmsg->flags = 0; + if (tmsg->to) + tidy_faddr(tmsg->to); + tmsg->to=NULL; + if (tmsg->from) + tidy_faddr(tmsg->from); + tmsg->from=NULL; + if (tmsg->subj) + free(tmsg->subj); + tmsg->subj=NULL; + if (tmsg->msgid_s) + free(tmsg->msgid_s); + tmsg->msgid_s=NULL; + if (tmsg->msgid_a) + free(tmsg->msgid_a); + tmsg->msgid_a=NULL; + if (tmsg->reply_s) + free(tmsg->reply_s); + tmsg->reply_s=NULL; + if (tmsg->reply_a) + free(tmsg->reply_a); + tmsg->reply_a=NULL; + if (tmsg->origin) + free(tmsg->origin); + tmsg->origin=NULL; + if (tmsg->area) + free(tmsg->area); + tmsg->area=NULL; + free(tmsg); +} + + diff --git a/lib/ftscprod.006 b/lib/ftscprod.006 new file mode 100644 index 00000000..03483616 --- /dev/null +++ b/lib/ftscprod.006 @@ -0,0 +1,289 @@ +0000,Fido,MS-DOS,Packer/mailer,Tom_Jennings,1:125/111 +0001,Rover,MS-DOS,Packer/mailer,Bob_Hartman,1:104/501 +0002,SEAdog,MS-DOS,Packer/mailer,Thom_Henderson,1:107/542.1 +0003,WinDog,MS-DOS,Mailer,Solar_Wind_Computing,1:115/333 +0004,Slick-150,HP-150,Packer/mailer,Jerry_Bain,???? +0005,Opus,MS-DOS,Packer/mailer,Doug_Boone,1:124/4227 +0006,Dutchie,MS-DOS,Packer/mailer,Henk_Wevers,2:500/1 +0007,WPL_Library,Amiga,Mailer,Russell_McOrmand,1:163/109 +0008,Tabby,Macintosh,Packer/mailer,Michael_Connick,1:107/412 +0009,SWMail,OS/2,Mailer,Solar_Wind_Computing,1:115/333 +000A,Wolf-68k,CPM-68k,Packer/mailer,Robert_Heller,1:321/153 +000B,QMM,QNX,Packer/mailer,Rick_Duff,1:167/201 +000C,FrontDoor,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17 +000D,GOmail,MS-DOS,Packer,Scott_Green,???? +000E,FFGate,MS-DOS,Packer,Ruedi_Kneubuehler,2:301/580 +000F,FileMgr,MS-DOS,Packer,Erik_van_Emmerik,2:281/611 +0010,FIDZERCP,MS-DOS,Packer,Thorsten_Seidel,2:242/55 +0011,MailMan,MS-DOS,Packer,Ron_Bemis,1:124/1113 +0012,OOPS,MS-DOS,Packer,Tom_Kashuba,1:322/379 +0013,GS-Point,Atari_ST,Packer/mailer,Harry_Lee,1:124/4230 +0014,BGMail,????,????,Ray_Gwinn,1:265/104 +0015,ComMotion/2,OS/2,Packer/mailer,Michael_Buenter,2:301/602 +0016,OurBBS_Fidomailer,MS-DOS/Unix/Coherent,Packer/mailer,Brian_Keahl,1:133/524 +0017,FidoPcb,MS-DOS,Packer,Matjaz_Koce,2:380/100 +0018,WimpLink,Archimedes,Packer/mailer,Remco_de_Vreugd,2:283/307 +0019,BinkScan,MS-DOS,Packer,Shawn_Stoddard,1:362/101 +001A,D'Bridge,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68 +001B,BinkleyTerm,MS-DOS,Mailer,Vince_Perriello,1:343/491 +001C,Yankee,MS-DOS,Packer,Randy_Edwards,???? +001D,uuGate,MS-DOS,Packer,Geoff_Watts,3:690/710 +001E,Daisy,Apple_][,Packer/mailer,Raymond_&_Ken_Lo,3:700/1 +001F,Polar_Bear,????,Packer/mailer,Kenneth_McLeod,1:101/190 +0020,The-Box,MS-DOS/Atari_ST,Packer/mailer,Jac_Kersing/Arjen_Lentz,2:283/333 +0021,STARgate/2,OS/2,Packer/mailer,Shawn_Stoddard,1:362/101 +0022,TMail,MS-DOS,Packer,Larry_Lewis,3:713/600.1701 +0023,TCOMMail,MS-DOS,Packer/mailer,Mike_Ratledge,1:372/888 +0024,GIGO,MS-DOS,Packer,Jason_Fesler,1:203/7707,,940228 +0025,RBBSMail,MS-DOS,Packer,Jan_Terpstra,2:512/10 +0026,Apple-Netmail,Apple_][,Packer/mailer,Bill_Fenner,1:129/87 +0027,Chameleon,Amiga,Mailer,Juergen_Hermann,2:241/2.12 +0028,Majik_Board,MS-DOS,Packer/mailer,Dale_Barnes,1:3601/14.20 +0029,QM,MS-DOS,Packer,George_Peace,1:270/101 +002A,Point_And_Click,Amiga,Packer,Rob_Tillotson,1:201/40.302 +002B,Aurora_Three_Bundler,MS-DOS,Packer,Oliver_McDonald,???? +002C,FourDog,MS-DOS,Packer,Shay_Walters,1:376/12 +002D,MSG-PACK,MS-DOS,Packer,Tom_Hendricks,1:261/662 +002E,AMAX,MS-DOS,Packer,Alan_Applegate,1:104/36 +002F,Domain_Communication_System,????,????,Hal_Duprie,1:101/106 +0030,LesRobot,????,Packer,Lennart_Svensonn,2:501/2 +0031,Rose,MS-DOS,Packer/mailer,Glen_Jackson,1:100/617 +0032,Paragon,Amiga,Packer/mailer,Jon_Radoff,1:322/545 +0033,BinkleyTerm/oMMM/ST,Atari_ST,Packer/mailer,Bill_Scull,1:363/112,,19951209 +0034,StarNet,Atari_ST,Mailer,Eric_Drewry,1:322/566 +0035,ZzyZx,MS-DOS,Packer,Jason_Steck,1:124/424 +0036,QEcho,MS-DOS,Packer,The_QuickBBS_Group,1:363/1701 +0037,BOOM,MS-DOS,Packer,Andrew_Farmer,1:243/1 +0038,PBBS,Amiga,Packer/mailer,Todd_Kover,1:261/1028 +0039,TrapDoor,Amiga,Mailer,Maximilian_Hantsch,2:310/6 +003A,Welmat,Amiga,Mailer,Russell_McOrmand,1:163/109 +003B,NetGate,Unix-386,Packer,David_Nugent,3:632/348 +003C,Odie,MS-DOS,Mailer,Matt_Farrenkopf,1:105/376 +003D,Quick_Gimme,CPM-80/MS-DOS,Packer/mailer,Laeeth_Isaacs,2:254/18 +003E,dbLink,MS-DOS,Packer/mailer,Chris_Irwin,1:18/68 +003F,TosScan,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17 +0040,Beagle,MS-DOS,Mailer,Alexander_Holy,2:310/90 +0041,Igor,MS-DOS,Mailer,Harry_Lee,1:124/4230 +0042,TIMS,MS-DOS,Packer/mailer,Bit_Bucket_Software,1:104/501 +0043,Phoenix,MS-DOS,Packer/mailer,International_Telecommunications,1:296/5,,19930624 +0044,FrontDoor_APX,MS-DOS,Packer/mailer,Joaquim_Homrighausen,2:270/17 +0045,XRS,MS-DOS,Packer,Mike_Ratledge,1:372/888 +0046,Juliet_Mail_System,Amiga,Packer,Gregory_Kritsch,1:163/109.30 +0047,Jabberwocky,Macintosh,Packer,Eric_Larson,1:2605/620 +0048,XST,MS-DOS,Packer,Wayne_Michaels,1:380/100 +0049,MailStorm,Amiga,Packer,Russel_Miranda,1:268/106 +004A,BIX-Mail,????,Mailer,Bob_Hartman,1:104/501 +004B,IMAIL,MS-DOS,Packer,IMAIL_INC.,2:246/47 +004C,FTNGate,MS-DOS,Packer,Jason_Steck,1:104/424 +004D,RealMail,MS-DOS,Packer,Taine_Gilliam,1:372/42 +004E,Lora-CBIS,MS-DOS,Mailer,Marco_Maccaferri,2:332/402 +004F,TDCS,PDP-11,Packer/mailer,Terry_Ebdon,2:254/6 +0050,InterMail,MS-DOS,Packer/mailer,Peter_Stewart,1:369/35 +0051,RFD,MS-DOS,Packer,Doug_Belkofer,1:234/10 +0052,Yuppie!,MS-DOS,Packer,Leo_Moll,2:242/2 +0053,EMMA,MS-DOS,Packer,Johan_Zwiekhorst,2:292/100 +0054,QBoxMail,QDOS,Packer/mailer,Jan_Bredenbeek,2:283/500 +0055,Number_4,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15 +0056,Number_5,MS-DOS,Packer/mailer,Ola_Garstad,2:502/15 +0057,GSBBS,MS-DOS,Packer,Michelangelo_Jones,1:260/244 +0058,Merlin,MS-DOS,Packer/mailer,Mark_Lewis,2:258/25 +0059,TPCS,MS-DOS,Packer,Mikael_Kjellstrom,2:201/211 +005A,Raid,MS-DOS,Packer,George_Peace,1:270/101 +005B,Outpost,MS-DOS,Packer/mailer,Mike_Dailor,???? +005C,Nizze,MS-DOS,Packer,Tomas_Nielsen,2:205/202 +005D,Armadillo,Macintosh,Packer,Erik_Sea,1:221/109 +005E,rfmail,Unix,Packer/mailer,Per_Lindqvist,2:201/332 +005F,Msgtoss,MS-DOS,Packer,Mike_Zakharoff,1:343/36 +0060,InfoTex,MS-DOS,Packer/mailer,Jan_Spooren,2:292/852 +0061,GEcho,MS-DOS,Packer,Gerard_van_der_Land,2:283/555,951209 +0062,CDEhost,MS-DOS,Packer,Dennis_D'Annunzio,1:379/28 +0063,Pktize,MS-DOS,Packer,Joaquim_Homrighausen,2:270/17 +0064,PC-RAIN,MS-DOS,Packer/mailer,Ray_Hyder,1:272/40 +0065,Truffle,MS-DOS/OS2,Mailer,Mike_Rissa,2:504/59 +0066,Foozle,Amiga,Packer,Peer_Hasselmeyer,2:247/4 +0067,White_Pointer,Macintosh,Packer/mailer,Alastair_Rakine,3:680/820 +0068,GateWorks,MS-DOS,Packer,Jamie_Penner,1:153/1025 +0069,Portal_of_Power,MS-DOS,Mailer,Soren_Ager,2:230/12 +006A,MacWoof,Macintosh,Packer/mailer,Craig_Vaughan,1:109/342 +006B,Mosaic,MS-DOS,Packer,Christopher_King,1:103/315 +006C,TPBEcho,MS-DOS,Packer,Gerd_Qualmann,2:242/1 +006D,HandyMail,MS-DOS,Packer/mailer,jim_nutt,1:114/30 +006E,EchoSmith,MS-DOS,Packer,Noel_Crow,1:170/409 +006F,FileHost,MS-DOS,Packer,Mark_Cole,2:252/186 +0070,SFTS,MS-DOS,Packer,Bruce_Anderson,1:3402/6 +0071,Benjamin,MS-DOS,Packer/mailer,Stefan_Graf,2:245/4.5436 +0072,RiBBS,OS9_(COCO),Packer/mailer,Ron_Bihler,1:104/54 +0073,MP,MS-DOS,Packer,Ivan_Leong,6:600/28 +0074,Ping,MS-DOS,Packer,David_Nugent,3:632/348 +0075,Door2Europe,MS-DOS,Packer/mailer,Michaela_Schoebel,2:247/14 +0076,SWIFT,MS-DOS,Packer/mailer,Hanno_van_der_Maas,2:500/2 +0077,WMAIL,MS-DOS,Packer,Silvan_Calarco,2:334/100.2 +0078,RATS,MS-DOS,Packer,Jason_DeCaro,1:260/205 +0079,Harry_the_Dirty_Dog,OS2,Mailer/packer,George_Edwards,3:632/340.7 +007A,Maximus-CBCS,MS-DOS/OS2,Packer,Scott_Dudley,1:249/106 +007B,SwifEcho,MS-DOS,Packer,Dana_Bell,1:3801/8 +007C,GCChost,Amiga,Packer,Davide_Massarenti,2:332/505.3 +007D,RPX-Mail,MS-DOS,Packer,Joerg_Wirtgen,2:241/4034 +007E,Tosser,MS-DOS,Packer,Albert_Ng,6:700/185 +007F,TCL,MS-DOS,Packer,Ulf_Hedlund,2:201/602 +0080,MsgTrack,MS-DOS,Packer,Andrew_Farmer,1:243/1 +0081,FMail,MS-DOS/DOS_DPMI/OS2/WIN32,Packer,Folkert_Wijnstra,2:283/619 +0082,Scantoss,MS-DOS,Packer,Michael_Matter,2:243/44.3443 +0083,Point_Manager,Amiga,Packer,Pino_Aliberti,2:335/602.2,,19931012 +0084,IMBINK,MS-DOS,Packer,Mike_Hartmann,2:246/48 +0085,Simplex,MS-DOS/OS2,Packer,Chris_Laforet,1:152/401 +0086,UMTP,MS-DOS,Packer,Byron_Copeland,1:272/26 +0087,Indaba,MS-DOS,Packer,Pieter_Muller,5:7102/11 +0088,Echomail_Engine,MS-DOS,Packer,Joe_Jared,1:103/200 +0089,DragonMail,OS2,Packer,Patrick_O'Riva,1:143/37 +008A,Prox,MS-DOS,Packer,Gerhard_Hoogterp,2:283/1.2 +008B,Tick,MS-DOS/OS2,Packer,Barry_Geller,1:266/12 +008C,RA-Echo,MS-DOS,Packer,Roger_Kirchhoff,2:245/4 +008D,TrapToss,Amiga,Packer,Maximilian_Hantsch,2:310/6 +008E,Babel,MS-DOS/OS2,Packer,Jorgen_Abrahamsen,2:230/100.9 +008F,UMS,Amiga,Packer,Martin_Horneffer,2:242/7.9 +0090,RWMail,MS-DOS,Packer,Remko_Westrik,2:285/309.5 +0091,WildMail,MS-DOS,Packer,Derek_Koopowitz,1:161/502 +0092,AlMAIL,MS-DOS,Packer,Alan_Leung,1:348/207 +0093,XCS,MS-DOS,Packer,Rudi_Kusters,2:512/34.4 +0094,Fone-Link,MS-DOS,Packer/mailer,Chris_Sloyan,1:269/602 +0095,Dogfight,MS-DOS,Packer,Chris_Tyson,2:256/36 +0096,Ascan,MS-DOS,Packer,Arjen_van_Loon,2:281/1.397 +0097,FastMail,MS-DOS,Packer,Jan_Berends,2:282/5 +0098,DoorMan,MS-DOS,Mailer,Christopher_Dean,1:105/70 +0099,PhaedoZap,Atari_ST,Packer,Jeff_Mitchell,1:229/422 +009A,SCREAM,MS-DOS,Packer/mailer,Jem_Miller,1:147/33 +009B,MoonMail,MS-DOS,Packer/mailer,Hasse_Wigdahl,2:206/101 +009C,Backdoor,Sinclair_QL,Packer,Erik_Slagter,2:283/500.3 +009D,MailLink,Archimedes,Packer/mailer,Jan-Jaap_v._d._Geer,2:500/133.1138 +009E,Mail_Manager,MS-DOS,Packer,Andreas_Brodowski,2:241/4006 +009F,Black_Star,Xenix_386,Packer/mailer,Jac_Kersing,2:283/333 +00A0,Bermuda,Atari_ST/MS-DOS,Packer,Jac_Kersing,2:283/333 +00A1,PT,MS-DOS,Packer/mailer,Jerry_Andrew,1:109/426 +00A2,UltiMail,MS-DOS,Mailer,Brett_Floren,1:363/1000 +00A3,GMD,MS-DOS,Packer,John_Souvestre,1:396/1 +00A4,FreeMail,MS-DOS,Packer,Chad_Nelson,1:109/536 +00A5,Meliora,MS-DOS,Packer,Erik_van_Riper,1:107/230 +00A6,Foodo,CPM-80,Packer/mailer,Ron_Murray,3:690/640.7 +00A7,MSBBS,CPM-80,Packer,Marc_Newman,1:106/601 +00A8,Boston_BBS,MS-DOS,Packer/mailer,Tom_Bradford,1:101/625 +00A9,XenoMail,MS-DOS,Packer/mailer,Noah_Wood,1:284/14 +00AA,XenoLink,Amiga,Packer/mailer,Jonathan_Forbes,1:250/642 +00AB,ObjectMatrix,MS-DOS,Packer,Roberto_Ceccarelli,2:332/305.1 +00AC,Milquetoast,Win3/MS-DOS,Mailer,Vince_Perriello,1:343/491 +00AD,PipBase,MS-DOS,Packer,Roberto_Piola,2:334/306 +00AE,EzyMail,MS-DOS,Packer,Peter_Davies,3:636/204 +00AF,FastEcho,MS-DOS,Packer,Tobias_Burchhardt,2:245/39 +00B0,IOS,Atari_ST/TT,Packer,Rinaldo_Visscher,2:280/3.1 +00B1,Communique,MS-DOS,Packer,Ian_Harris,3:620/251 +00B2,PointMail,MS-DOS,Packer,Michele_Clinco,2:331/302.11 +00B3,Harvey's_Robot,MS-DOS,Packer,Harvey_Parisien,1:249/114 +00B4,2daPoint,MS-DOS,Packer,Ron_Pritchett,1:376/74 +00B5,CommLink,MS-DOS,Mailer,Steve_Shapiro,1:382/35 +00B6,fronttoss,MS-DOS,Packer,Dirk_Astrath,2:241/5603 +00B7,SysopPoint,MS-DOS,Packer,Rudolf_Heeb,2:243/44 +00B8,PTMAIL,MS-DOS,Packer,Arturo_Krogulski,2:341/27.7 +00B9,MHS,MS-DOS/OS2/WINNT,Packer/mailer,Matthias_Hertzog,2:301/402,,19940310 +00BA,DLGMail,Amiga,Packer,Steve_Lewis,1:114/52 +00BB,GatePrep,MS-DOS,Packer,Andrew_Allen,1:382/92 +00BC,Spoint,MS-DOS,Packer,Conrad_Thompson,1:130/29.106 +00BD,TurboMail,MS-DOS,Packer,B._J._Weschke,1:2606/403 +00BE,FXMAIL,MS-DOS,Packer,Kenneth_Roach,1:208/401 +00BF,NextBBS,MS-DOS,Packer/mailer,Tomas_Hood,1:352/777 +00C0,EchoToss,MS-DOS,Packer,Mikel_Beck,1:107/218 +00C1,SilverBox,Amiga,Packer,David_Lebel,1:240/516 +00C2,MBMail,MS-DOS,Packer,Ruud_Uphoff,2:500/116.1928 +00C3,SkyFreq,Amiga,Packer,Luca_Spada,2:331/106 +00C4,ProMailer,Amiga,Mailer,Ivan_Pintori,2:335/311.21 +00C5,Mega_Mail,MS-DOS,Packer/mailer,Mirko_Mucko,2:242/94 +00C6,YaBom,MS-DOS,Packer,Berin_Lautenbach,3:620/248 +00C7,TachEcho,MS-DOS,Packer,Tom_Zacios,1:107/376 +00C8,XAP,MS-DOS,Packer,Jeroen_Smulders,2:512/1.8 +00C9,EZMAIL,MS-DOS,Packer,Torben_Paving,2:234/41 +00CA,Arc-Binkley,Archimedes,Mailer,Geoff_Riley,2:250/208 +00CB,Roser,MS-DOS,Packer,Chan_Kafai,6:700/158 +00CC,UU2,MS-DOS,Packer,Dmitri_Zavalishin,2:5020/32 +00CD,NMS,MS-DOS,Packer/mailer,Michiel_de.Bruijn,2:285/505.2 +00CE,BBCSCAN,Archimedes,Packer/mailer,E._G._Snel,2:512/222.17 +00CF,XBBS,MS-DOS,Packer,Mark_Kimes,1:380/16 +00D0,LoTek_Vzrul,,Packer/mailer,Kevin_Gates,gates@sasknet.sk.ca,19951229,20000122 +00D1,Private_Point_Project,MS-DOS,Packer,Oliver_von_Bueren,2:301/701 +00D2,NoSnail,MS-DOS,Packer,Eddie_Rowe,1:19/124 +00D3,SmlNet,MS-DOS,Packer,Steve_T._Gove,1:106/6 +00D4,STIR,MS-DOS,Packer,Paul_Martin,2:250/107.3 +00D5,RiscBBS,Archimedes,Packer,Carl_Declerck,2:292/500.10 +00D6,Hercules,Amiga,Packer/mailer,Andrew_Gray,1:231/590 +00D7,AMPRGATE,MS-DOS,Packer/mailer,Mike_Bilow,1:323/120.1 +00D8,BinkEMSI,MS-DOS,Mailer,Tobias_Burchhardt,2:245/39 +00D9,EditMsg,MS-DOS,Packer,G._K._Pace,1:374/26 +00DA,Roof,Amiga,Packer,Robert_Williamson,1:167/104 +00DB,QwkPkt,MS-DOS,Packer,Ross_West,1:250/412 +00DC,MARISCAN,MS-DOS,Packer,Mario_Elkati,2:341/14.9 +00DD,NewsFlash,MS-DOS,Packer,Chris_Lueders,2:241/5306 +00DE,Paradise,MS-DOS,Packer/mailer,Kenneth_Wall,1:300/5 +00DF,DogMatic-ACB,N/A,Packer/mailer,Martin_Allard,2:245/48 +00E0,T-Mail,MS-DOS,Packer/mailer,Andy_Elkin,2:5030/15 +00E1,JetMail,Atari_ST/STE/TT,Packer,Daniel_Roesen,2:243/93.8 +00E2,MainDoor,MS-DOS,Packer/mailer,Francisco_Sedano,2:341/20 +00E3,Starnet_Products,MS-DOS/OS2,Mailer/Packer,Starnet_Software_Development,1:102/925,,19951209 +00E4,BMB,Amiga,Packer,Dentato_Remo,2:335/311.33 +00E5,BNP,MS-DOS,Packer,Nathan_Moschkin,1:109/427 +00E6,MailMaster,MS-DOS,Packer/mailer,Gary_Murphy,1:130/85 +00E7,Mail_Manager_+Plus+,MS-DOS,Packer,Chip_Morrow,1:226/1240 +00E8,BloufGate,Atari_ST/Unix,Packer,Vincent_Pomey,2:320/100.2 +00E9,CrossPoint,MS-DOS,Packer/mailer,Peter_Mandrella,2:2454/97.80,19920713,19960601 +00EA,DeltaEcho,MS-DOS,Packer,Mikael_Staldal,2:201/337 +00EB,ALLFIX,MS-DOS,Packer,Harald_Harms,2:512/145 +00EC,NetWay,Archimedes,Mailer,Steve_Haslam,2:250/116.3 +00ED,MARSmail,Atari_ST,Packer,Folkert_val_Heusden,2:285/750.2,,19940122 +00EE,ITRACK,MS-DOS/OS2,Packer,Frank_Prade,2:2480/55,,19990119 +00EF,GateUtil,MS-DOS,Packer,Michael_Skurka,1:397/2.1 +00F0,Bert,MS-DOS,Packer/mailer,Arnim_Wiezer,2:241/2104.9 +00F1,Techno,MS-DOS,Packer,Patrik_Holmsten,2:203/133 +00F2,AutoMail,MS-DOS,Packer,Mats_Wallin,2:201/239 +00F3,April,Amiga,Packer,Nick_de_Jong,2:282/309.3 +00F4,Amanda,MS-DOS,Packer,David_Douthitt,1:121/99.14 +00F5,NmFwd,MS-DOS,Packer,Alberto_Pasquale,2:332/504 +00F6,FileScan,MS-DOS,Packer,Matthias_Duesterhoeft,2:241/4512.2 +00F7,FredMail,MS-DOS,Packer,Michael_Butler,3:712/515 +00F8,TP_Kom,MS-DOS,Packer/mailer,Per_Sten,2:201/124 +00F9,FidoZerb,MS-DOS,Packer,Ulrich_Schlechte,2:241/3410.12 +00FA,!!MessageBase,MS-DOS,Packer/mailer,Holger_Lembke,2:240/500.20 +00FB,EMFido,Amiga,Packer,Gary_Glendown,2:249/3.999 +00FC,GS-Toss,MS-DOS,Packer,Marco_Bungalski,2:241/2021 +00FD,QWKDoor,Atari_ST,Packer,Christian_Limpach,2:270/20.1 +00FE,No_product_id_allocated,Any,Packer,No_Author,3:3/20 +00FF,16-bit_product_id,Any,Packer/Mailer,No_Author,3:3/20 +0100,Reserved,None,None,No_Author,3:3/20,19951209 +0101,The_Brake!,Mailer,John_Gladkih,2:5051/16,19951209 +0102,Zeus_BBS,Amiga,Mailer,Alex_May,2:441/58.0,19951209 +0103,XenoPhobe-Mailer,Msdos/Windows/OS2/Linux,Mailer,Peter_Kling,1:374/969.0,19951209 +0104,None,None,None,None,0:0/0, +0105,Terminate,Msdos/Os2/Windows,Mailer/Packer,SerWiz_Comm_&_Bo_Bendtsen,2:254/261,19951209 +0106,TeleMail,Msdos,Mailer/Packer,Juergen_Weigelt,2:2453/900,19951209 +0107,CMBBS,Msdos/Os2,Mailer/Packer,Christof_Engel,2:2490/5110,19951209 +0108,Shuttle,Windows,Mailer/Packer,MCH_Development_&_Marvin_Hart,1:106/500,19951209 +0109,Quater,Amiga,Mailer,Felice_Murolo,2:335/206,19951209 +010A,Windo,Windows,Mailer,Alan_Chavis,1:147/55,19951209 +010B,Xenia,Msdos/Os2,Mailer,Arjen_Lentz,2:283/512,19960601 +010C,GMS,AmigaOS,Mailer,Mirko_Viviani,2:331/213,19960601 +010D,HNET,Msdos,???,Pedro_Jaramillo,1:102/160,19960601 +010E,Shotgun_Professional,Msdos,???,Brent_Shellenberg,1:140/146,19960621 +010F,SLIPgate,Msdos,???,Kieran_Morrissey,3:634/376,19960723 +0110,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216 +0111,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216 +01FF,BBBS,MSDOS/OS2/NT/Amiga/Unix,Mailer/Packer,Kim_Heino,2:22/222,19980216 +02FF,NewsGate,Windows/NT,Packer/Gateway,Leilo_denna_Pietra,2:335/244,19980216 +03FF,Ravel,Macintosh,Mailer/Packer,Cyril_Moorzin,2:5030/700,19980310 +04FF,Beemail,Windows,Mailer/Packer,Andrius_Cepaitis,2:470/1,19980310 +05FF,QuickToss,DOS,Packer,Sandra_Godinez,1:387/601.3,19980310 +06FF,SpaceMail,???,Mailer,Andreas_Habicht,2:244/6121,19980710 +07FF,Argus,Windows/NT,Mailer,Max_Masyutin,2:469/84,19990216 +08FF,Hurricane,Windows/NT/Solaris,Packer,Paul_Walker,2:254/175.44,19990216 +09FF,Hub_Mailer,OS2,Mailer,Viatcheslav_Odintsov,2:5020/181,19990216 +0AFF,FDInt,MSDOS,Packer,Colin_Turner,2:443/13,19990216 +0BFF,GPMail,OS2,Mailer,Igor_Vanin,2:5030/448,19990216 +0CFF,FTrack,NT/OS2,Tracker,Fyodor_Ustinov,2:5020/79,19990313 +0DFF,Nice_Tosser,DOS/OS2/Win32,Tosser,Robert_Agababyan,2:5020/234.1,19990518 +0EFF,LuckyGate,DOS/OS2/Linux,Packer,Pavel_Gulchouck,2:463/68,19990709 +0FFF,McMail,DOS,Mailer,Simon_Slater,2:443/777,20000102 diff --git a/lib/ftscprod.c b/lib/ftscprod.c new file mode 100644 index 00000000..75d64792 --- /dev/null +++ b/lib/ftscprod.c @@ -0,0 +1,296 @@ +#include "libs.h" +#include "structs.h" +#include "common.h" + +struct _ftscprod ftscprod[] = { + {0x0000,(char *)"Fido"}, + {0x0001,(char *)"Rover"}, + {0x0002,(char *)"SEAdog"}, + {0x0003,(char *)"WinDog"}, + {0x0004,(char *)"Slick-150"}, + {0x0005,(char *)"Opus"}, + {0x0006,(char *)"Dutchie"}, + {0x0007,(char *)"WPL_Library"}, + {0x0008,(char *)"Tabby"}, + {0x0009,(char *)"SWMail"}, + {0x000A,(char *)"Wolf-68k"}, + {0x000B,(char *)"QMM"}, + {0x000C,(char *)"FrontDoor"}, + {0x000D,(char *)"GOmail"}, + {0x000E,(char *)"FFGate"}, + {0x000F,(char *)"FileMgr"}, + {0x0010,(char *)"FIDZERCP"}, + {0x0011,(char *)"MailMan"}, + {0x0012,(char *)"OOPS"}, + {0x0013,(char *)"GS-Point"}, + {0x0014,(char *)"BGMail"}, + {0x0015,(char *)"ComMotion/2"}, + {0x0016,(char *)"OurBBS_Fidomailer"}, + {0x0017,(char *)"FidoPcb"}, + {0x0018,(char *)"WimpLink"}, + {0x0019,(char *)"BinkScan"}, + {0x001A,(char *)"D'Bridge"}, + {0x001B,(char *)"BinkleyTerm"}, + {0x001C,(char *)"Yankee"}, + {0x001D,(char *)"uuGate"}, + {0x001E,(char *)"Daisy"}, + {0x001F,(char *)"Polar_Bear"}, + {0x0020,(char *)"The-Box"}, + {0x0021,(char *)"STARgate/2"}, + {0x0022,(char *)"TMail"}, + {0x0023,(char *)"TCOMMail"}, + {0x0024,(char *)"GIGO"}, + {0x0025,(char *)"RBBSMail"}, + {0x0026,(char *)"Apple-Netmail"}, + {0x0027,(char *)"Chameleon"}, + {0x0028,(char *)"Majik_Board"}, + {0x0029,(char *)"QM"}, + {0x002A,(char *)"Point_And_Click"}, + {0x002B,(char *)"Aurora_Three_Bundler"}, + {0x002C,(char *)"FourDog"}, + {0x002D,(char *)"MSG-PACK"}, + {0x002E,(char *)"AMAX"}, + {0x002F,(char *)"Domain_Communication_System"}, + {0x0030,(char *)"LesRobot"}, + {0x0031,(char *)"Rose"}, + {0x0032,(char *)"Paragon"}, + {0x0033,(char *)"BinkleyTerm/oMMM/ST"}, + {0x0034,(char *)"StarNet"}, + {0x0035,(char *)"ZzyZx"}, + {0x0036,(char *)"QEcho"}, + {0x0037,(char *)"BOOM"}, + {0x0038,(char *)"PBBS"}, + {0x0039,(char *)"TrapDoor"}, + {0x003A,(char *)"Welmat"}, + {0x003B,(char *)"NetGate"}, + {0x003C,(char *)"Odie"}, + {0x003D,(char *)"Quick_Gimme"}, + {0x003E,(char *)"dbLink"}, + {0x003F,(char *)"TosScan"}, + {0x0040,(char *)"Beagle"}, + {0x0041,(char *)"Igor"}, + {0x0042,(char *)"TIMS"}, + {0x0043,(char *)"Phoenix"}, + {0x0044,(char *)"FrontDoor_APX"}, + {0x0045,(char *)"XRS"}, + {0x0046,(char *)"Juliet_Mail_System"}, + {0x0047,(char *)"Jabberwocky"}, + {0x0048,(char *)"XST"}, + {0x0049,(char *)"MailStorm"}, + {0x004A,(char *)"BIX-Mail"}, + {0x004B,(char *)"IMAIL"}, + {0x004C,(char *)"FTNGate"}, + {0x004D,(char *)"RealMail"}, + {0x004E,(char *)"Lora-CBIS"}, + {0x004F,(char *)"TDCS"}, + {0x0050,(char *)"InterMail"}, + {0x0051,(char *)"RFD"}, + {0x0052,(char *)"Yuppie!"}, + {0x0053,(char *)"EMMA"}, + {0x0054,(char *)"QBoxMail"}, + {0x0055,(char *)"Number_4"}, + {0x0056,(char *)"Number_5"}, + {0x0057,(char *)"GSBBS"}, + {0x0058,(char *)"Merlin"}, + {0x0059,(char *)"TPCS"}, + {0x005A,(char *)"Raid"}, + {0x005B,(char *)"Outpost"}, + {0x005C,(char *)"Nizze"}, + {0x005D,(char *)"Armadillo"}, + {0x005E,(char *)"rfmail"}, + {0x005F,(char *)"Msgtoss"}, + {0x0060,(char *)"InfoTex"}, + {0x0061,(char *)"GEcho"}, + {0x0062,(char *)"CDEhost"}, + {0x0063,(char *)"Pktize"}, + {0x0064,(char *)"PC-RAIN"}, + {0x0065,(char *)"Truffle"}, + {0x0066,(char *)"Foozle"}, + {0x0067,(char *)"White_Pointer"}, + {0x0068,(char *)"GateWorks"}, + {0x0069,(char *)"Portal_of_Power"}, + {0x006A,(char *)"MacWoof"}, + {0x006B,(char *)"Mosaic"}, + {0x006C,(char *)"TPBEcho"}, + {0x006D,(char *)"HandyMail"}, + {0x006E,(char *)"EchoSmith"}, + {0x006F,(char *)"FileHost"}, + {0x0070,(char *)"SFTS"}, + {0x0071,(char *)"Benjamin"}, + {0x0072,(char *)"RiBBS"}, + {0x0073,(char *)"MP"}, + {0x0074,(char *)"Ping"}, + {0x0075,(char *)"Door2Europe"}, + {0x0076,(char *)"SWIFT"}, + {0x0077,(char *)"WMAIL"}, + {0x0078,(char *)"RATS"}, + {0x0079,(char *)"Harry_the_Dirty_Dog"}, + {0x007A,(char *)"Maximus-CBCS"}, + {0x007B,(char *)"SwifEcho"}, + {0x007C,(char *)"GCChost"}, + {0x007D,(char *)"RPX-Mail"}, + {0x007E,(char *)"Tosser"}, + {0x007F,(char *)"TCL"}, + {0x0080,(char *)"MsgTrack"}, + {0x0081,(char *)"FMail"}, + {0x0082,(char *)"Scantoss"}, + {0x0083,(char *)"Point_Manager"}, + {0x0084,(char *)"IMBINK"}, + {0x0085,(char *)"Simplex"}, + {0x0086,(char *)"UMTP"}, + {0x0087,(char *)"Indaba"}, + {0x0088,(char *)"Echomail_Engine"}, + {0x0089,(char *)"DragonMail"}, + {0x008A,(char *)"Prox"}, + {0x008B,(char *)"Tick"}, + {0x008C,(char *)"RA-Echo"}, + {0x008D,(char *)"TrapToss"}, + {0x008E,(char *)"Babel"}, + {0x008F,(char *)"UMS"}, + {0x0090,(char *)"RWMail"}, + {0x0091,(char *)"WildMail"}, + {0x0092,(char *)"AlMAIL"}, + {0x0093,(char *)"XCS"}, + {0x0094,(char *)"Fone-Link"}, + {0x0095,(char *)"Dogfight"}, + {0x0096,(char *)"Ascan"}, + {0x0097,(char *)"FastMail"}, + {0x0098,(char *)"DoorMan"}, + {0x0099,(char *)"PhaedoZap"}, + {0x009A,(char *)"SCREAM"}, + {0x009B,(char *)"MoonMail"}, + {0x009C,(char *)"Backdoor"}, + {0x009D,(char *)"MailLink"}, + {0x009E,(char *)"Mail_Manager"}, + {0x009F,(char *)"Black_Star"}, + {0x00A0,(char *)"Bermuda"}, + {0x00A1,(char *)"PT"}, + {0x00A2,(char *)"UltiMail"}, + {0x00A3,(char *)"GMD"}, + {0x00A4,(char *)"FreeMail"}, + {0x00A5,(char *)"Meliora"}, + {0x00A6,(char *)"Foodo"}, + {0x00A7,(char *)"MSBBS"}, + {0x00A8,(char *)"Boston_BBS"}, + {0x00A9,(char *)"XenoMail"}, + {0x00AA,(char *)"XenoLink"}, + {0x00AB,(char *)"ObjectMatrix"}, + {0x00AC,(char *)"Milquetoast"}, + {0x00AD,(char *)"PipBase"}, + {0x00AE,(char *)"EzyMail"}, + {0x00AF,(char *)"FastEcho"}, + {0x00B0,(char *)"IOS"}, + {0x00B1,(char *)"Communique"}, + {0x00B2,(char *)"PointMail"}, + {0x00B3,(char *)"Harvey's_Robot"}, + {0x00B4,(char *)"2daPoint"}, + {0x00B5,(char *)"CommLink"}, + {0x00B6,(char *)"fronttoss"}, + {0x00B7,(char *)"SysopPoint"}, + {0x00B8,(char *)"PTMAIL"}, + {0x00B9,(char *)"MHS"}, + {0x00BA,(char *)"DLGMail"}, + {0x00BB,(char *)"GatePrep"}, + {0x00BC,(char *)"Spoint"}, + {0x00BD,(char *)"TurboMail"}, + {0x00BE,(char *)"FXMAIL"}, + {0x00BF,(char *)"NextBBS"}, + {0x00C0,(char *)"EchoToss"}, + {0x00C1,(char *)"SilverBox"}, + {0x00C2,(char *)"MBMail"}, + {0x00C3,(char *)"SkyFreq"}, + {0x00C4,(char *)"ProMailer"}, + {0x00C5,(char *)"Mega_Mail"}, + {0x00C6,(char *)"YaBom"}, + {0x00C7,(char *)"TachEcho"}, + {0x00C8,(char *)"XAP"}, + {0x00C9,(char *)"EZMAIL"}, + {0x00CA,(char *)"Arc-Binkley"}, + {0x00CB,(char *)"Roser"}, + {0x00CC,(char *)"UU2"}, + {0x00CD,(char *)"NMS"}, + {0x00CE,(char *)"BBCSCAN"}, + {0x00CF,(char *)"XBBS"}, + {0x00D0,(char *)"LoTek_Vzrul"}, + {0x00D1,(char *)"Private_Point_Project"}, + {0x00D2,(char *)"NoSnail"}, + {0x00D3,(char *)"SmlNet"}, + {0x00D4,(char *)"STIR"}, + {0x00D5,(char *)"RiscBBS"}, + {0x00D6,(char *)"Hercules"}, + {0x00D7,(char *)"AMPRGATE"}, + {0x00D8,(char *)"BinkEMSI"}, + {0x00D9,(char *)"EditMsg"}, + {0x00DA,(char *)"Roof"}, + {0x00DB,(char *)"QwkPkt"}, + {0x00DC,(char *)"MARISCAN"}, + {0x00DD,(char *)"NewsFlash"}, + {0x00DE,(char *)"Paradise"}, + {0x00DF,(char *)"DogMatic-ACB"}, + {0x00E0,(char *)"T-Mail"}, + {0x00E1,(char *)"JetMail"}, + {0x00E2,(char *)"MainDoor"}, + {0x00E3,(char *)"Starnet_Products"}, + {0x00E4,(char *)"BMB"}, + {0x00E5,(char *)"BNP"}, + {0x00E6,(char *)"MailMaster"}, + {0x00E7,(char *)"Mail_Manager_+Plus+"}, + {0x00E8,(char *)"BloufGate"}, + {0x00E9,(char *)"CrossPoint"}, + {0x00EA,(char *)"DeltaEcho"}, + {0x00EB,(char *)"ALLFIX"}, + {0x00EC,(char *)"NetWay"}, + {0x00ED,(char *)"MARSmail"}, + {0x00EE,(char *)"ITRACK"}, + {0x00EF,(char *)"GateUtil"}, + {0x00F0,(char *)"Bert"}, + {0x00F1,(char *)"Techno"}, + {0x00F2,(char *)"AutoMail"}, + {0x00F3,(char *)"April"}, + {0x00F4,(char *)"Amanda"}, + {0x00F5,(char *)"NmFwd"}, + {0x00F6,(char *)"FileScan"}, + {0x00F7,(char *)"FredMail"}, + {0x00F8,(char *)"TP_Kom"}, + {0x00F9,(char *)"FidoZerb"}, + {0x00FA,(char *)"!!MessageBase"}, + {0x00FB,(char *)"EMFido"}, + {0x00FC,(char *)"GS-Toss"}, + {0x00FD,(char *)"QWKDoor"}, + {0x00FE,(char *)"No_product_id_allocated"}, + {0x00FF,(char *)"16-bit_product_id"}, + {0x0100,(char *)"Reserved"}, + {0x0101,(char *)"The_Brake!"}, + {0x0102,(char *)"Zeus_BBS"}, + {0x0103,(char *)"XenoPhobe-Mailer"}, + {0x0104,(char *)"None"}, + {0x0105,(char *)"Terminate"}, + {0x0106,(char *)"TeleMail"}, + {0x0107,(char *)"CMBBS"}, + {0x0108,(char *)"Shuttle"}, + {0x0109,(char *)"Quater"}, + {0x010A,(char *)"Windo"}, + {0x010B,(char *)"Xenia"}, + {0x010C,(char *)"GMS"}, + {0x010D,(char *)"HNET"}, + {0x010E,(char *)"Shotgun_Professional"}, + {0x010F,(char *)"SLIPgate"}, + {0x0110,(char *)"BBBS"}, + {0x0111,(char *)"NewsGate"}, + {0x01FF,(char *)"BBBS"}, + {0x02FF,(char *)"NewsGate"}, + {0x03FF,(char *)"Ravel"}, + {0x04FF,(char *)"Beemail"}, + {0x05FF,(char *)"QuickToss"}, + {0x06FF,(char *)"SpaceMail"}, + {0x07FF,(char *)"Argus"}, + {0x08FF,(char *)"Hurricane"}, + {0x09FF,(char *)"Hub_Mailer"}, + {0x0AFF,(char *)"FDInt"}, + {0x0BFF,(char *)"GPMail"}, + {0x0CFF,(char *)"FTrack"}, + {0x0DFF,(char *)"Nice_Tosser"}, + {0x0EFF,(char *)"LuckyGate"}, + {0x0FFF,(char *)"McMail"}, + {0xff,(char*)0L} +}; diff --git a/lib/getheader.c b/lib/getheader.c new file mode 100644 index 00000000..e8aa010d --- /dev/null +++ b/lib/getheader.c @@ -0,0 +1,188 @@ +/***************************************************************************** + * + * File ..................: getheader.c + * Purpose ...............: Read fidonet .pkt header + * Last modification date : 29-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_NODES + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +faddr pktfrom; +char pktpwd[9]; + + +/* + * Return codes: + * 0 - All Seems Well + * 1 - Invalid type (not 2 or 2+) + * 2 - Read header error + * 3 - Not for me + * 4 - Password error + */ +int getheader(faddr *f, faddr *t, FILE *pkt, char *pname) +{ + unsigned char buffer[0x3a]; + int i, pwdok; + int capword, prodx; + int major, minor = 0; + int tome = FALSE; + char *p, *prodn = NULL; + char buf[5]; + long year, month, day, hour, min, sec; + + f->domain = NULL; + f->name = NULL; + t->domain = NULL; + t->name = NULL; + + /* + * Read type 2+ packet header, see FSC-0039 version 4 + * and FTS-0001 + */ + if (fread(buffer, 1, 0x3a, pkt) != 0x3a) { + WriteError("$Could not read header (%s)", pname); + return 2; + } + if ((buffer[0x12] + (buffer[0x13] << 8)) != 2) { + WriteError("Not a type 2 packet (%s)", pname); + return 1; + } + + f->node = (buffer[0x01] << 8) + buffer[0x00]; + t->node = (buffer[0x03] << 8) + buffer[0x02]; + f->net = (buffer[0x15] << 8) + buffer[0x14]; + t->net = (buffer[0x17] << 8) + buffer[0x16]; + f->zone = (buffer[0x23] << 8) + buffer[0x22]; + t->zone = (buffer[0x25] << 8) + buffer[0x24]; + + year = (buffer[0x05] << 8) + buffer[0x04]; + month = (buffer[0x07] << 8) + buffer[0x06] + 1; + day = (buffer[0x09] << 8) + buffer[0x08]; + hour = (buffer[0x0b] << 8) + buffer[0x0a]; + min = (buffer[0x0d] << 8) + buffer[0x0c]; + sec = (buffer[0x0f] << 8) + buffer[0x0e]; + prodx = buffer[0x18]; + major = buffer[0x19]; + + capword = (buffer[0x2d] << 8) + buffer[0x2c]; + if (capword != ((buffer[0x28] << 8) + buffer[0x29])) + capword = 0; + + if (capword & 0x0001) { + /* + * FSC-0039 packet type 2+ + */ + prodx = prodx + (buffer[0x2a] << 8); + minor = buffer[0x2b]; + f->zone = buffer[0x2e] + (buffer[0x2f] << 8); + t->zone = buffer[0x30] + (buffer[0x31] << 8); + f->point = buffer[0x32] + (buffer[0x33] << 8); + t->point = buffer[0x34] + (buffer[0x35] << 8); + } + + for (i = 0; i < 8; i++) + pktpwd[i] = buffer[0x1a + i]; + pktpwd[8]='\0'; + for (p = pktpwd + 7; (p >= pktpwd) && (*p == ' '); p--) *p='\0'; + if (pktpwd[0]) + f->name = pktpwd; + + /* + * Fill in a default product code in case it doesn't exist + */ + sprintf(buf, "%04x", prodx); + prodn = xstrcpy((char *)"Unknown 0x"); + prodn = xstrcat(prodn, buf); + for (i = 0; ftscprod[i].name; i++) + if (ftscprod[i].code == prodx) { + free(prodn); + prodn = xstrcpy(ftscprod[i].name); + break; + } + + pktfrom.name = NULL; + pktfrom.domain = NULL; + pktfrom.zone = f->zone; + pktfrom.net = f->net; + pktfrom.node = f->node; + if (capword & 0x0001) + pktfrom.point = f->point; + else + pktfrom.point = 0; + + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && + ((t->zone == 0) || (t->zone == CFG.aka[i].zone)) && + (t->net == CFG.aka[i].net) && + (t->node == CFG.aka[i].node) && + ((!(capword & 0x0001)) || (t->point == CFG.aka[i].point))) + tome = TRUE; + } + + Syslog('+', "Packet : %s type %s", pname, (capword & 0x0001) ? "2+":"stone-age"); + Syslog('+', "From : %s to %s", xstrcpy(ascfnode(f, 0x1f)), xstrcpy(ascfnode(t,0x1f))); + Syslog('+', "Dated : %02u-%02u-%u %02u:%02u:%02u", day, month, year, hour, min, sec); + Syslog('+', "Program : %s %d.%d", prodn, major, minor); + + if (capword & 0x0001) { + buf[0] = buffer[0x36]; + buf[1] = buffer[0x37]; + buf[2] = buffer[0x38]; + buf[3] = buffer[0x39]; + buf[4] = '\0'; + } + + pwdok = TRUE; + if (noderecord(f)) { + if (strcasecmp(nodes.Epasswd, pktpwd) != 0) { + pwdok = FALSE; + if (strlen(pktpwd)) + Syslog('!', "Password : got \"%s\", expected \"%s\"", pktpwd, nodes.Epasswd); + } + } else { + Syslog('+', "Node not in setup"); + } + + if (prodn) + free(prodn); + + if (!tome) + return 3; + else if (!pwdok && nodes.MailPwdCheck) + return 4; + else + return 0; +} + + diff --git a/lib/gmtoffset.c b/lib/gmtoffset.c new file mode 100644 index 00000000..5d81fe55 --- /dev/null +++ b/lib/gmtoffset.c @@ -0,0 +1,169 @@ +/***************************************************************************** + * + * File ..................: gmtoffset.c + * Purpose ...............: Calculate UTC offset + * Last modification date : 18-Dec-1999 + * Source ................: Eugene G. Crosser's ifmail package. + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +/* + * Returns the offset from your location to UTC. So in the MET timezone + * this returns -60 (wintertime). People in the USA get positive results. + */ +long gmt_offset(time_t now) +{ + struct tm ptm; + struct tm gtm; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + return offset; +} + + + +/* + * Returns the TZUTC string, note that the sign is opposite from the + * function above. + */ +char *gmtoffset(time_t now) +{ + static char buf[6]="+0000"; + char sign; + int hr, min; + long offset; + + offset = gmt_offset(now); + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + + hr = offset / 60L; + min = offset % 60L; + + if (sign == '-') + sprintf(buf, "%c%02d%02d", sign, hr, min); + else + sprintf(buf, "%02d%02d", hr, min); + + return(buf); +} + + + +char *str_time(time_t total) +{ + static char buf[10]; + int h, m; + + memset(&buf, 0, sizeof(buf)); + + /* + * 0 .. 59 seconds + */ + if (total < (time_t)60) { + sprintf(buf, "%2d.00s", (int)total); + return buf; + } + + /* + * 1:00 .. 59:59 minutes:seconds + */ + if (total < (time_t)3600) { + h = total / 60; + m = total % 60; + sprintf(buf, "%2d:%02d ", h, m); + return buf; + } + + /* + * 1:00 .. 23:59 hours:minutes + */ + if (total < (time_t)86400) { + h = (total / 60) / 60; + m = (total / 60) % 60; + sprintf(buf, "%2d:%02dm", h, m); + return buf; + } + + /* + * 1/00 .. 30/23 days/hours + */ + if (total < (time_t)2592000) { + h = (total / 3600) / 24; + m = (total / 3600) % 24; + sprintf(buf, "%2d/%02dh", h, m); + return buf; + } + + sprintf(buf, "N/A "); + return buf; +} + + + +char *t_elapsed(time_t start, time_t end) +{ + return str_time(end - start); +} + + diff --git a/lib/hdr.c b/lib/hdr.c new file mode 100644 index 00000000..10093ba2 --- /dev/null +++ b/lib/hdr.c @@ -0,0 +1,47 @@ +/***************************************************************************** + * + * File ..................: hdr.c + * Purpose ...............: Header parser + * Last modification date : 22-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +char *hdr(char *key, rfcmsg *msg) +{ + for (; msg; msg = msg->next) + if (!strcasecmp(key, msg->key)) { + return(msg->val); + } + return(NULL); +} + + diff --git a/lib/jam.h b/lib/jam.h new file mode 100644 index 00000000..14892a18 --- /dev/null +++ b/lib/jam.h @@ -0,0 +1,196 @@ +/* +** JAM(mbp) - The Joaquim-Andrew-Mats Message Base Proposal +** +** C API +** +** Written by Joaquim Homrighausen. +** +** ---------------------------------------------------------------------- +** +** jam.h (JAMmb) +** +** Prototypes and definitions for the JAM message base format +** +** Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and +** Mats Wallin. ALL RIGHTS RESERVED. +** +** 93-06-28 JoHo +** Initial coding. +** +*/ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __JAM_H__ +#define __JAM_H__ + +#ifndef __JAMSYS_H__ +#include "jamsys.h" +#endif + +/* +** File extensions +*/ +#define EXT_HDRFILE ".jhr" +#define EXT_TXTFILE ".jdt" +#define EXT_IDXFILE ".jdx" +#define EXT_LRDFILE ".jlr" + +/* +** Revision level and header signature +*/ +#define CURRENTREVLEV 1 +#define HEADERSIGNATURE "JAM" + +/* +** Header file information block, stored first in all .JHR files +*/ +typedef struct + { + CHAR8 Signature[4]; /* followed by */ + UINT32 DateCreated; /* Creation date */ + UINT32 ModCounter; /* Last processed counter */ + UINT32 ActiveMsgs; /* Number of active (not deleted) msgs */ + UINT32 PasswordCRC; /* CRC-32 of password to access */ + UINT32 BaseMsgNum; /* Lowest message number in index file */ + CHAR8 RSRVD[1000]; /* Reserved space */ + } + JAMHDRINFO, _JAMDATA * JAMHDRINFOptr; + +/* +** Message status bits +*/ +#define MSG_LOCAL 0x00000001L /* Msg created locally */ +#define MSG_INTRANSIT 0x00000002L /* Msg is in-transit */ +#define MSG_PRIVATE 0x00000004L /* Private */ +#define MSG_READ 0x00000008L /* Read by addressee */ +#define MSG_SENT 0x00000010L /* Sent to remote */ +#define MSG_KILLSENT 0x00000020L /* Kill when sent */ +#define MSG_ARCHIVESENT 0x00000040L /* Archive when sent */ +#define MSG_HOLD 0x00000080L /* Hold for pick-up */ +#define MSG_CRASH 0x00000100L /* Crash */ +#define MSG_IMMEDIATE 0x00000200L /* Send Msg now, ignore restrictions */ +#define MSG_DIRECT 0x00000400L /* Send directly to destination */ +#define MSG_GATE 0x00000800L /* Send via gateway */ +#define MSG_FILEREQUEST 0x00001000L /* File request */ +#define MSG_FILEATTACH 0x00002000L /* File(s) attached to Msg */ +#define MSG_TRUNCFILE 0x00004000L /* Truncate file(s) when sent */ +#define MSG_KILLFILE 0x00008000L /* Delete file(s) when sent */ +#define MSG_RECEIPTREQ 0x00010000L /* Return receipt requested */ +#define MSG_CONFIRMREQ 0x00020000L /* Confirmation receipt requested */ +#define MSG_ORPHAN 0x00040000L /* Unknown destination */ +#define MSG_ENCRYPT 0x00080000L /* Msg text is encrypted */ +#define MSG_COMPRESS 0x00100000L /* Msg text is compressed */ +#define MSG_ESCAPED 0x00200000L /* Msg text is seven bit ASCII */ +#define MSG_FPU 0x00400000L /* Force pickup */ +#define MSG_TYPELOCAL 0x00800000L /* Msg is for local use only (not for export) */ +#define MSG_TYPEECHO 0x01000000L /* Msg is for conference distribution */ +#define MSG_TYPENET 0x02000000L /* Msg is direct network mail */ +#define MSG_NODISP 0x20000000L /* Msg may not be displayed to user */ +#define MSG_LOCKED 0x40000000L /* Msg is locked, no editing possible */ +#define MSG_DELETED 0x80000000L /* Msg is deleted */ + + +/* +** Message header +*/ +typedef struct + { + CHAR8 Signature[4]; /* followed by */ + UINT16 Revision; /* CURRENTREVLEV */ + UINT16 ReservedWord; /* Reserved */ + UINT32 SubfieldLen; /* Length of subfields */ + UINT32 TimesRead; /* Number of times message read */ + UINT32 MsgIdCRC; /* CRC-32 of MSGID line */ + UINT32 ReplyCRC; /* CRC-32 of REPLY line */ + UINT32 ReplyTo; /* This msg is a reply to.. */ + UINT32 Reply1st; /* First reply to this msg */ + UINT32 ReplyNext; /* Next msg in reply chain */ + UINT32 DateWritten; /* When msg was written */ + UINT32 DateReceived; /* When msg was received/read */ + UINT32 DateProcessed; /* When msg was processed by packer */ + UINT32 MsgNum; /* Message number (1-based) */ + UINT32 Attribute; /* Msg attribute, see "Status bits" */ + UINT32 Attribute2; /* Reserved for future use */ + UINT32 TxtOffset; /* Offset of text in text file */ + UINT32 TxtLen; /* Length of message text */ + UINT32 PasswordCRC; /* CRC-32 of password to access msg */ + UINT32 Cost; /* Cost of message */ + } + JAMHDR, _JAMDATA * JAMHDRptr; + +/* +** Message header subfield types +*/ +#define JAMSFLD_OADDRESS 0 +#define JAMSFLD_DADDRESS 1 +#define JAMSFLD_SENDERNAME 2 +#define JAMSFLD_RECVRNAME 3 +#define JAMSFLD_MSGID 4 +#define JAMSFLD_REPLYID 5 +#define JAMSFLD_SUBJECT 6 +#define JAMSFLD_PID 7 +#define JAMSFLD_TRACE 8 +#define JAMSFLD_ENCLFILE 9 +#define JAMSFLD_ENCLFWALIAS 10 +#define JAMSFLD_ENCLFREQ 11 +#define JAMSFLD_ENCLFILEWC 12 +#define JAMSFLD_ENCLINDFILE 13 +#define JAMSFLD_EMBINDAT 1000 +#define JAMSFLD_FTSKLUDGE 2000 +#define JAMSFLD_SEENBY2D 2001 +#define JAMSFLD_PATH2D 2002 +#define JAMSFLD_FLAGS 2003 +#define JAMSFLD_TZUTCINFO 2004 +#define JAMSFLD_UNKNOWN 0xffff + +/* +** Message header subfield +*/ +typedef struct + { + UINT16 LoID; /* Field ID, 0 - 0xffff */ + UINT16 HiID; /* Reserved for future use */ + UINT32 DatLen; /* Length of buffer that follows */ + CHAR8 Buffer[1]; /* DatLen bytes of data */ + } + JAMSUBFIELD, _JAMDATA * JAMSUBFIELDptr; + +typedef struct + { + UINT16 LoID; /* Field ID, 0 - 0xffff */ + UINT16 HiID; /* Reserved for future use */ + UINT32 DatLen; /* Length of buffer that follows */ + } + JAMBINSUBFIELD, _JAMDATA * JAMBINSUBFIELDptr; + +/* +** Message index record +*/ +typedef struct + { + UINT32 UserCRC; /* CRC-32 of destination username */ + UINT32 HdrOffset; /* Offset of header in .JHR file */ + } + JAMIDXREC, _JAMDATA * JAMIDXRECptr; + +/* +** Lastread structure, one per user +*/ +typedef struct + { + UINT32 UserCRC; /* CRC-32 of user name (lowercase) */ + UINT32 UserID; /* Unique UserID */ + UINT32 LastReadMsg; /* Last read message number */ + UINT32 HighReadMsg; /* Highest read message number */ + } + JAMLREAD, _JAMDATA * JAMLREADptr; + +#endif /* __JAM_H__ */ + +#ifdef __cplusplus +} +#endif + +/* end of file "jam.h" */ diff --git a/lib/jammsg.c b/lib/jammsg.c new file mode 100644 index 00000000..0e9a2038 --- /dev/null +++ b/lib/jammsg.c @@ -0,0 +1,1370 @@ +/***************************************************************************** + * + * File ..................: jammsg.c + * Purpose ...............: JAM message base functions + * Last modification date : 23-Jun-2001 + * + ***************************************************************************** + * + * Original written in C++ by Marco Maccaferri for LoraBBS and was + * distributed under GNU GPL. This version is modified for use with + * MBSE BBS and utilities. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" +#include "msgtext.h" +#include "msg.h" +#include "jam.h" +#include "jammsg.h" + +#define MAX_TEXT 2048 + +int fdHdr = -1; +int fdJdt = -1; +int fdJdx = -1; +int fdJlr = -1; +char *pSubfield; +char BaseName[PATH_MAX]; +char *pLine, *pBuff; +char szBuff[MAX_LINE_LENGTH + 1]; +char szLine[MAX_LINE_LENGTH + 1]; +JAMHDRINFO jamHdrInfo; +JAMHDR jamHdr; +unsigned long LastReadRec; + + + +unsigned long AddSubfield(unsigned int, char *); +unsigned long AddSubfield(unsigned int JamSFld, char *SubStr) +{ + JAMSUBFIELD jamSubfield; + unsigned long Len; + + jamSubfield.HiID = 0; + jamSubfield.LoID = JamSFld; + jamSubfield.DatLen = strlen(SubStr); /* + 1; */ + Len = jamSubfield.DatLen + sizeof(JAMBINSUBFIELD); + write(fdHdr, &jamSubfield, sizeof(JAMBINSUBFIELD)); + write(fdHdr, SubStr, strlen(SubStr)); /* + 1); */ + + return Len; +} + + + +void JAMset_flags(void); +void JAMset_flags() +{ + jamHdr.Attribute |= (Msg.Local) ? MSG_LOCAL : 0; + jamHdr.Attribute |= (Msg.Intransit) ? MSG_INTRANSIT : 0; + jamHdr.Attribute |= (Msg.Private) ? MSG_PRIVATE : 0; + jamHdr.Attribute |= (Msg.Received) ? MSG_READ : 0; + jamHdr.Attribute |= (Msg.Sent) ? MSG_SENT : 0; + jamHdr.Attribute |= (Msg.KillSent) ? MSG_KILLSENT : 0; + jamHdr.Attribute |= (Msg.ArchiveSent) ? MSG_ARCHIVESENT : 0; + jamHdr.Attribute |= (Msg.Hold) ? MSG_HOLD : 0; + jamHdr.Attribute |= (Msg.Crash) ? MSG_CRASH : 0; + jamHdr.Attribute |= (Msg.Immediate) ? MSG_IMMEDIATE : 0; + jamHdr.Attribute |= (Msg.Direct) ? MSG_DIRECT : 0; + jamHdr.Attribute |= (Msg.Gate) ? MSG_GATE : 0; + jamHdr.Attribute |= (Msg.FileRequest) ? MSG_FILEREQUEST : 0; + jamHdr.Attribute |= (Msg.FileAttach) ? MSG_FILEATTACH : 0; + jamHdr.Attribute |= (Msg.TruncFile) ? MSG_TRUNCFILE : 0; + jamHdr.Attribute |= (Msg.KillFile) ? MSG_KILLFILE : 0; + jamHdr.Attribute |= (Msg.ReceiptRequest) ? MSG_RECEIPTREQ : 0; + jamHdr.Attribute |= (Msg.ConfirmRequest) ? MSG_CONFIRMREQ : 0; + jamHdr.Attribute |= (Msg.Orphan) ? MSG_ORPHAN : 0; + jamHdr.Attribute |= (Msg.Encrypt) ? MSG_ENCRYPT : 0; + jamHdr.Attribute |= (Msg.Compressed) ? MSG_COMPRESS : 0; + jamHdr.Attribute |= (Msg.Escaped) ? MSG_ESCAPED : 0; + jamHdr.Attribute |= (Msg.ForcePU) ? MSG_FPU : 0; + jamHdr.Attribute |= (Msg.Localmail) ? MSG_TYPELOCAL : 0; + jamHdr.Attribute |= (Msg.Echomail) ? MSG_TYPEECHO : 0; + jamHdr.Attribute |= (Msg.Netmail) ? MSG_TYPENET : 0; + jamHdr.Attribute |= (Msg.Nodisplay) ? MSG_NODISP : 0; + jamHdr.Attribute |= (Msg.Locked) ? MSG_LOCKED : 0; + jamHdr.Attribute |= (Msg.Deleted) ? MSG_DELETED : 0; + + jamHdr.ReplyTo = Msg.Original; + jamHdr.ReplyNext = Msg.Reply; + jamHdr.DateReceived = Msg.Read; + jamHdr.MsgIdCRC = Msg.MsgIdCRC; + jamHdr.ReplyCRC = Msg.ReplyCRC; +} + + + + +/* + * Add a message, the structure msg must contain all needed + * information. + */ +int JAM_AddMsg() +{ + int i, RetVal = TRUE; + unsigned long ulMsg = JAM_Highest() + 1L; + char *pszText, *Sign= (char *)HEADERSIGNATURE; + JAMIDXREC jamIdx; + int Oke; + + memset(&jamHdr, 0, sizeof(JAMHDR)); + jamHdr.Signature[0] = Sign[0]; + jamHdr.Signature[1] = Sign[1]; + jamHdr.Signature[2] = Sign[2]; + jamHdr.Signature[3] = Sign[3]; + jamHdr.Revision = CURRENTREVLEV; + jamHdr.MsgNum = ulMsg; + + jamHdr.DateWritten = Msg.Written; + jamHdr.DateProcessed = Msg.Arrived; + + JAMset_flags(); + lseek(fdHdr, 0L, SEEK_END); + + jamIdx.UserCRC = 0; + jamIdx.HdrOffset = tell(fdHdr); + lseek(fdJdx, 0L, SEEK_END); + write(fdJdx, &jamIdx, sizeof(JAMIDXREC)); + + write(fdHdr, &jamHdr, sizeof(JAMHDR)); + + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SENDERNAME, Msg.From); + + if (Msg.To[0]) + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_RECVRNAME, Msg.To); + + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SUBJECT, Msg.Subject); + + if (Msg.FromAddress[0] != '\0') + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_OADDRESS, Msg.FromAddress); + + if (Msg.ToAddress[0] != '\0') + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_DADDRESS, Msg.ToAddress); + + Msg.Id = jamHdr.MsgNum; + + lseek(fdJdt, 0L, SEEK_END); + jamHdr.TxtOffset = tell(fdJdt); + jamHdr.TxtLen = 0; + + /* + * Read message text from memory, this also contains kludges. + * Extract those that are defined by the JAMmb specs, except + * the AREA: kludge. This one is only present in bad and dupe + * echomail areas and is present for tossbad and tossdupe. + */ + if ((pszText = (char *)MsgText_First ()) != NULL) + do { + if ((pszText[0] == '\001') || (!strncmp(pszText, "SEEN-BY:", 8))) { + Oke = FALSE; + + if (!strncmp(pszText, "\001PID: ", 6)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_PID, pszText + 6); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001MSGID: ", 8)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_MSGID, pszText + 8); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001REPLY: ", 8)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_REPLYID, pszText + 8); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001PATH: ", 7)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_PATH2D, pszText + 7); + Oke = TRUE; + } + + if (!strncmp(pszText, "\001Via", 4)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_TRACE, pszText + 5); + Oke = TRUE; + } + + if (!strncmp(pszText, "SEEN-BY: ", 9)) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_SEENBY2D, pszText + 9); + Oke = TRUE; + } + + /* + * Other non-JAM kludges + */ + if ((!Oke) && (pszText[0] == '\001')) { + jamHdr.SubfieldLen += AddSubfield(JAMSFLD_FTSKLUDGE, pszText + 1); + Oke = TRUE; + } + + if (!Oke) { + for (i = 0; i < strlen(pszText); i++) { + if (pszText[i] < 32) + printf("<%x>", pszText[i]); + else + printf("%c", pszText[i]); + } + } + } else { + write(fdJdt, pszText, strlen (pszText)); + jamHdr.TxtLen += strlen (pszText); + write(fdJdt, "\r", 1); + jamHdr.TxtLen += 1; + } + } while ((pszText = (char *)MsgText_Next ()) != NULL); + + /* + * Write final message header + */ + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + write(fdHdr, &jamHdr, sizeof (JAMHDR)); + + + /* + * Update area information + */ + lseek(fdHdr, 0L, SEEK_SET); + read(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + jamHdrInfo.ActiveMsgs++; + jamHdrInfo.ModCounter++; + lseek(fdHdr, 0L, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + + return RetVal; +} + + + +/* + * Close current message base + */ +void JAM_Close(void) +{ + if (fdJdx != -1) + close(fdJdx); + if (fdJdt != -1) + close(fdJdt); + if (fdHdr != -1) + close(fdHdr); + if (fdJlr != -1) + close(fdJlr); + + if (pSubfield != NULL) + free(pSubfield); + + fdHdr = fdJdt = fdJdx = fdJlr = -1; + pSubfield = NULL; + Msg.Id = 0L; +} + + + +/* + * Delete message number + */ +int JAM_Delete(unsigned long ulMsg) +{ + int RetVal = FALSE; + JAMIDXREC jamIdx; + + if (JAM_ReadHeader(ulMsg) == TRUE) { + jamHdr.Attribute |= MSG_DELETED; + + lseek(fdJdx, tell(fdJdx) - sizeof(jamIdx), SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + write(fdHdr, &jamHdr, sizeof(JAMHDR)); + + lseek(fdHdr, 0L, SEEK_SET); + read(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + jamHdrInfo.ActiveMsgs--; + lseek(fdHdr, 0L, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof (JAMHDRINFO)); + RetVal = TRUE; + } + } + + return RetVal; +} + + + +/* + * Search for requested LastRead record. + */ +int JAM_GetLastRead(lastread *LR) +{ + lastread lr; + + LastReadRec = 0L; + lseek(fdJlr, 0, SEEK_SET); + + while (read(fdJlr, &lr, sizeof(lastread)) == sizeof(lastread)) { + if (lr.UserID == LR->UserID) { + LR->LastReadMsg = lr.LastReadMsg; + LR->HighReadMsg = lr.HighReadMsg; + return TRUE; + } + LastReadRec++; + } + + return FALSE; +} + + + +/* + * Get highest message number + */ +unsigned long JAM_Highest(void) +{ + unsigned long RetVal = 0L; + JAMIDXREC jamIdx; + + if (jamHdrInfo.ActiveMsgs > 0L) { + lseek(fdJdx, filelength(fdJdx) - sizeof(jamIdx), SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + RetVal = jamHdr.MsgNum; + } + } + + Msg.Id = RetVal; + + return RetVal; +} + + + +int JAM_Lock(unsigned long ulTimeout) +{ +// char *File; +// int fd = -1, Tries = 0; + int Tries = 0; + struct flock fl; + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 1L; /* GoldED locks 1 byte as well */ + fl.l_pid = getpid(); + + while (fcntl(fdHdr, F_SETLK, &fl) && ((errno == EACCES) || (errno == EAGAIN))) { + if (++Tries >= (ulTimeout * 4)) { + fcntl(fdHdr, F_GETLK, &fl); + WriteError("JAM messagebase is locked by pid %d", fl.l_pid); + return FALSE; + } + usleep(250000); + Syslog('m', "JAM messagebase lock attempt %d", Tries); + } + +// File = calloc(PATH_MAX, sizeof(char)); +// sprintf(File, "%s%s", BaseName, ".LCK"); + +// while ((fd = creat(File, 0)) == -1 && errno == EACCES) { +// if (++Tries >= ulTimeout) { +// free(File); +// return FALSE; +// } +// sleep(1); +// } +// free(File); + +// if (fd == -1) +// return FALSE; + +// close(fd); + return TRUE; +} + + + +/* + * Get lowest message number + */ +unsigned long JAM_Lowest(void) +{ + unsigned long RetVal = 0L; + JAMIDXREC jamIdx; + + if (jamHdrInfo.ActiveMsgs > 0L) { + lseek(fdJdx, 0L, SEEK_SET); + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + RetVal = jamHdr.MsgNum; + } + } + + Msg.Id = RetVal; + + return RetVal; +} + + + +void JAM_New(void) +{ + memset(&Msg, 0, sizeof(Msg)); + MsgText_Clear(); +} + + + +int JAM_NewLastRead(lastread LR) +{ + lseek(fdJlr, 0, SEEK_END); + return (write(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)); +} + + + +int JAM_Next(unsigned long * ulMsg) +{ + int RetVal = FALSE, MayBeNext = FALSE; + JAMIDXREC jamIdx; + unsigned long _Msg; + + _Msg = *ulMsg; + + if (jamHdrInfo.ActiveMsgs > 0L) { + // -------------------------------------------------------------------- + // The first attempt to retrive the next message number suppose that + // the file pointers are located after the current message number. + // Usually this is the 99% of the situations because the messages are + // often readed sequentially. + // -------------------------------------------------------------------- + if (tell(fdJdx) >= sizeof (jamIdx)) + lseek(fdJdx, tell(fdJdx) - sizeof(jamIdx), SEEK_SET); + do { + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof (JAMHDR)); + if (MayBeNext == TRUE) { + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == _Msg) + MayBeNext = TRUE; + } + } while (RetVal == FALSE && tell(fdJdx) < filelength(fdJdx)); + + if (RetVal == FALSE && MayBeNext == FALSE) { + // -------------------------------------------------------------------- + // It seems that the file pointers are not located where they should be + // so our next attempt is to scan the database from the beginning to + // find the next message number. + // -------------------------------------------------------------------- + lseek(fdJdx, 0L, SEEK_SET); + do { + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum > _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + } while (RetVal == FALSE && tell(fdJdx) < filelength(fdJdx)); + } + + Msg.Id = 0L; + if (RetVal == TRUE) + Msg.Id = _Msg; + } + + memcpy(ulMsg, &_Msg, sizeof(unsigned long)); + return RetVal; +} + + + +/* + * Return number of messages + */ +unsigned long JAM_Number(void) +{ + return jamHdrInfo.ActiveMsgs; +} + + + +/* + * Open specified JAM message base + */ +int JAM_Open(char *Msgbase) +{ + int RetVal = FALSE; + char *File; + char *Signature = (char *)HEADERSIGNATURE; + + fdJdt = fdJdx = fdJlr = -1; + pSubfield = NULL; + File = calloc(PATH_MAX, sizeof(char)); + + sprintf(File, "%s%s", Msgbase, EXT_HDRFILE); + if ((fdHdr = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != -1) { + if (read(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) != sizeof(JAMHDRINFO)) { + memset(&jamHdrInfo, 0, sizeof(JAMHDRINFO)); + jamHdrInfo.Signature[0] = Signature[0]; + jamHdrInfo.Signature[1] = Signature[1]; + jamHdrInfo.Signature[2] = Signature[2]; + jamHdrInfo.Signature[3] = Signature[3]; + jamHdrInfo.DateCreated = time(NULL); + jamHdrInfo.BaseMsgNum = 1; + + lseek(fdHdr, 0, SEEK_SET); + write(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + } + + if (jamHdrInfo.Signature[0] == Signature[0] && + jamHdrInfo.Signature[1] == Signature[1] && + jamHdrInfo.Signature[2] == Signature[2] && + jamHdrInfo.Signature[3] == Signature[3]) { + sprintf(File, "%s%s", Msgbase, EXT_TXTFILE); + fdJdt = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", Msgbase, EXT_IDXFILE); + fdJdx = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", Msgbase, EXT_LRDFILE); + fdJlr = open(File, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + RetVal = TRUE; + + strcpy(BaseName, Msgbase); + } else { + close(fdHdr); + fdHdr = -1; + } + } else + memset(&jamHdrInfo, 0, sizeof(JAMHDRINFO)); + + Msg.Id = 0L; + free(File); + + return RetVal; +} + + + +/* + * Pack deleted messages from the message base. The messages are + * renumbered on the fly. LR update + */ +void JAM_Pack(void) +{ + int fdnHdr, fdnJdx, fdnJdt, fdnJlr; + int ToRead, Readed; + char *File, *New, *Subfield, *Temp; + JAMIDXREC jamIdx; + unsigned long NewNumber = 0, RefNumber = 0, Written = 0; + lastread LR; + + File = calloc(PATH_MAX, sizeof(char)); + New = calloc(PATH_MAX, sizeof(char)); + sprintf(File, "%s%s", BaseName, ".$dr"); + fdnHdr = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$dt"); + fdnJdt = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$dx"); + fdnJdx = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + sprintf(File, "%s%s", BaseName, ".$lr"); + fdnJlr = open(File, O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + + if (fdnHdr != -1 && fdnJdt != -1 && fdnJdx != -1 && fdnJlr != -1) { + lseek(fdHdr, 0L, SEEK_SET); + if (read(fdHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) == sizeof(JAMHDRINFO)) { + write(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + while (read(fdHdr, &jamHdr, sizeof(JAMHDR)) == sizeof(JAMHDR)) { + RefNumber++; + if (strncmp(jamHdr.Signature, "JAM", 3)) { + WriteError("jamPack: %s headerfile corrupt", BaseName); + lseek(fdJdx, (RefNumber -1) * sizeof(JAMIDXREC), SEEK_SET); + read(fdJdx, &jamIdx, sizeof(JAMIDXREC)); + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + if ((strncmp(jamHdr.Signature, "JAM", 3) == 0) && (jamHdr.MsgNum == RefNumber)) + WriteError("jamPack: corrected the problem"); + else { + WriteError("jamPack: PANIC, problem cannot be solved, skipping this area"); + Written = 0; + break; + } + } + if (jamHdr.Attribute & MSG_DELETED) { + if (jamHdr.SubfieldLen > 0L) + lseek (fdHdr, jamHdr.SubfieldLen, SEEK_CUR); + } else { + jamIdx.UserCRC = 0; + jamIdx.HdrOffset = tell(fdnHdr); + write(fdnJdx, &jamIdx, sizeof(JAMIDXREC)); + + lseek(fdJdt, jamHdr.TxtOffset, SEEK_SET); + jamHdr.TxtOffset = tell(fdnJdt); + NewNumber++; + Written++; + + lseek(fdJlr, 0, SEEK_SET); + while (read(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) { + /* + * Test if one of the lastread pointer is the current + * old message number. + */ + if ((LR.LastReadMsg == jamHdr.MsgNum) || (LR.HighReadMsg == jamHdr.MsgNum)) { + /* + * Adjust the matching numbers + */ + if (LR.LastReadMsg == jamHdr.MsgNum) + LR.LastReadMsg = NewNumber; + if (LR.HighReadMsg == jamHdr.MsgNum) + LR.HighReadMsg = NewNumber; + lseek(fdJlr, - sizeof(lastread), SEEK_CUR); + write(fdJlr, &LR, sizeof(lastread)); + } + } + jamHdr.MsgNum = NewNumber; + write(fdnHdr, &jamHdr, sizeof(JAMHDR)); + + if (jamHdr.SubfieldLen > 0L) { + if ((Subfield = (char *)malloc ((size_t)(jamHdr.SubfieldLen + 1))) != NULL) { + read (fdHdr, Subfield, (size_t)jamHdr.SubfieldLen); + write (fdnHdr, Subfield, (size_t)jamHdr.SubfieldLen); + free(Subfield); + } + } + + if ((Temp = (char *)malloc (MAX_TEXT)) != NULL) { + do { + if ((ToRead = MAX_TEXT) > jamHdr.TxtLen) + ToRead = (int)jamHdr.TxtLen; + Readed = (int)read (fdJdt, Temp, ToRead); + write (fdnJdt, Temp, Readed); + jamHdr.TxtLen -= Readed; + } while (jamHdr.TxtLen > 0); + free(Temp); + } + } + } + } + + /* + * Correct any errors in the header + */ + if (Written) { + lseek(fdnHdr, 0, SEEK_SET); + if (read(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)) == sizeof(JAMHDRINFO)) { + if (jamHdrInfo.ActiveMsgs != Written) { + WriteError("jamPack: repair msgs %lu to %lu area %s", + jamHdrInfo.ActiveMsgs, Written, BaseName); + jamHdrInfo.ActiveMsgs = Written; + lseek(fdnHdr, 0, SEEK_SET); + write(fdnHdr, &jamHdrInfo, sizeof(JAMHDRINFO)); + } + } + } + + /* + * Now copy the lastread file + */ + + lseek(fdJlr, 0, SEEK_SET); + while (read(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) + write(fdnJlr, &LR, sizeof(lastread)); + + close(fdnHdr); + close(fdnJdt); + close(fdnJdx); + close(fdnJlr); + fdnHdr = fdnJdt = fdnJdx = fdnJlr = -1; + + close(fdHdr); + close(fdJdt); + close(fdJdx); + close(fdJlr); + fdHdr = fdJdt = fdJdx = fdJlr = -1; + + sprintf(File, "%s%s", BaseName, ".$dr"); + sprintf(New, "%s%s", BaseName, EXT_HDRFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$dt"); + sprintf(New, "%s%s", BaseName, EXT_TXTFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$dx"); + sprintf(New, "%s%s", BaseName, EXT_IDXFILE); + unlink(New); + rename(File, New); + sprintf(File, "%s%s", BaseName, ".$lr"); + sprintf(New, "%s%s", BaseName, EXT_LRDFILE); + unlink(New); + rename(File, New); + + JAM_Open(BaseName); + } + + if (fdnHdr != -1) + close(fdnHdr); + sprintf(File, "%s%s", BaseName, ".$dr"); + unlink(File); + if (fdnJdt != -1) + close(fdnJdt); + sprintf(File, "%s%s", BaseName, ".$dt"); + unlink(File); + if (fdnJdx != -1) + close(fdnJdx); + sprintf(File, "%s%s", BaseName, ".$dx"); + unlink(File); + if (fdnJlr != -1) + close(fdnJlr); + sprintf(File, "%s%s", BaseName, ".$lr"); + unlink(File); + free(File); + free(New); +} + + + +int JAM_Previous (unsigned long *ulMsg) +{ + int RetVal = FALSE, MayBeNext = FALSE; + long Pos; + JAMIDXREC jamIdx; + unsigned long _Msg; + + _Msg = *ulMsg; + + if (jamHdrInfo.ActiveMsgs > 0L) { + // -------------------------------------------------------------------- + // The first attempt to retrive the next message number suppose that + // the file pointers are located after the current message number. + // Usually this is the 99% of the situations because the messages are + // often readed sequentially. + // -------------------------------------------------------------------- + if (tell (fdJdx) >= sizeof (jamIdx)) { + Pos = tell (fdJdx) - sizeof (jamIdx); + do { + lseek (fdJdx, Pos, SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (MayBeNext == TRUE) { + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == _Msg) + MayBeNext = TRUE; + } + Pos -= sizeof (jamIdx); + } while (RetVal == FALSE && Pos >= 0L); + } + + if (RetVal == FALSE && MayBeNext == FALSE) { + // -------------------------------------------------------------------- + // It seems that the file pointers are not located where they should be + // so our next attempt is to scan the database from the end to find + // the next message number. + // -------------------------------------------------------------------- + Pos = filelength (fdJdx) - sizeof (jamIdx); + do { + lseek (fdJdx, Pos, SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum < _Msg) { + _Msg = jamHdr.MsgNum; + RetVal = TRUE; + } + } + Pos -= sizeof (jamIdx); + } while (RetVal == FALSE && Pos >= 0L); + } + + Msg.Id = 0L; + if (RetVal == TRUE) + Msg.Id = _Msg; + } + + memcpy(ulMsg, &_Msg, sizeof(unsigned long)); + return (RetVal); +} + + + +int JAM_ReadHeader (unsigned long ulMsg) +{ + int i, RetVal = FALSE; + unsigned char *pPos; + unsigned long ulSubfieldLen, tmp; + JAMIDXREC jamIdx; + JAMBINSUBFIELD *jamSubField; + + tmp = Msg.Id; + JAM_New (); + Msg.Id = tmp; + + if (Msg.Id == ulMsg) { + // -------------------------------------------------------------------- + // The user is requesting the header of the last message retrived + // so our first attempt is to read the last index from the file and + // check if this is the correct one. + // -------------------------------------------------------------------- + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + if (((Msg.Id + 1) == ulMsg) && (RetVal == FALSE)) { + //--------------------------------------------------------------------- + // If the user is requesting the header of the next message we attempt + // to read the next header and check if this is the correct one. + // This is EXPERIMENTAL + //--------------------------------------------------------------------- + if (read(fdJdx, &jamIdx, sizeof(jamIdx)) == sizeof(jamIdx)) { + lseek(fdHdr, jamIdx.HdrOffset, SEEK_SET); + read(fdHdr, &jamHdr, sizeof(JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + + if (RetVal == FALSE) { + // -------------------------------------------------------------------- + // The message request is not the last retrived or the file pointers + // are not positioned where they should be, so now we attempt to + // retrive the message header scanning the database from the beginning. + // -------------------------------------------------------------------- + Msg.Id = 0L; + lseek (fdJdx, 0L, SEEK_SET); + do { + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx)); + } + + if (RetVal == TRUE) { + Msg.Current = Msg.Id = ulMsg; + + Msg.Local = (unsigned char)((jamHdr.Attribute & MSG_LOCAL) ? TRUE : FALSE); + Msg.Intransit = (unsigned char)((jamHdr.Attribute & MSG_INTRANSIT) ? TRUE : FALSE); + Msg.Private = (unsigned char)((jamHdr.Attribute & MSG_PRIVATE) ? TRUE : FALSE); + Msg.Received = (unsigned char)((jamHdr.Attribute & MSG_READ) ? TRUE : FALSE); + Msg.Sent = (unsigned char)((jamHdr.Attribute & MSG_SENT) ? TRUE : FALSE); + Msg.KillSent = (unsigned char)((jamHdr.Attribute & MSG_KILLSENT) ? TRUE : FALSE); + Msg.ArchiveSent = (unsigned char)((jamHdr.Attribute & MSG_ARCHIVESENT) ? TRUE : FALSE); + Msg.Hold = (unsigned char)((jamHdr.Attribute & MSG_HOLD) ? TRUE : FALSE); + Msg.Crash = (unsigned char)((jamHdr.Attribute & MSG_CRASH) ? TRUE : FALSE); + Msg.Immediate = (unsigned char)((jamHdr.Attribute & MSG_IMMEDIATE) ? TRUE : FALSE); + Msg.Direct = (unsigned char)((jamHdr.Attribute & MSG_DIRECT) ? TRUE : FALSE); + Msg.Gate = (unsigned char)((jamHdr.Attribute & MSG_GATE) ? TRUE : FALSE); + Msg.FileRequest = (unsigned char)((jamHdr.Attribute & MSG_FILEREQUEST) ? TRUE : FALSE); + Msg.FileAttach = (unsigned char)((jamHdr.Attribute & MSG_FILEATTACH) ? TRUE : FALSE); + Msg.TruncFile = (unsigned char)((jamHdr.Attribute & MSG_TRUNCFILE) ? TRUE : FALSE); + Msg.KillFile = (unsigned char)((jamHdr.Attribute & MSG_KILLFILE) ? TRUE : FALSE); + Msg.ReceiptRequest = (unsigned char)((jamHdr.Attribute & MSG_RECEIPTREQ) ? TRUE : FALSE); + Msg.ConfirmRequest = (unsigned char)((jamHdr.Attribute & MSG_CONFIRMREQ) ? TRUE : FALSE); + Msg.Orphan = (unsigned char)((jamHdr.Attribute & MSG_ORPHAN) ? TRUE : FALSE); + Msg.Encrypt = (unsigned char)((jamHdr.Attribute & MSG_ENCRYPT) ? TRUE : FALSE); + Msg.Compressed = (unsigned char)((jamHdr.Attribute & MSG_COMPRESS) ? TRUE : FALSE); + Msg.Escaped = (unsigned char)((jamHdr.Attribute & MSG_ESCAPED) ? TRUE : FALSE); + Msg.ForcePU = (unsigned char)((jamHdr.Attribute & MSG_FPU) ? TRUE : FALSE); + Msg.Localmail = (unsigned char)((jamHdr.Attribute & MSG_TYPELOCAL) ? TRUE : FALSE); + Msg.Echomail = (unsigned char)((jamHdr.Attribute & MSG_TYPEECHO) ? TRUE : FALSE); + Msg.Netmail = (unsigned char)((jamHdr.Attribute & MSG_TYPENET) ? TRUE : FALSE); + Msg.Nodisplay = (unsigned char)((jamHdr.Attribute & MSG_NODISP) ? TRUE : FALSE); + Msg.Locked = (unsigned char)((jamHdr.Attribute & MSG_LOCKED) ? TRUE : FALSE); + Msg.Deleted = (unsigned char)((jamHdr.Attribute & MSG_DELETED) ? TRUE : FALSE); + + Msg.Written = jamHdr.DateWritten; + Msg.Arrived = jamHdr.DateProcessed; + Msg.Read = jamHdr.DateReceived; + + Msg.Original = jamHdr.ReplyTo; + Msg.Reply = jamHdr.ReplyNext; + + if (pSubfield != NULL) + free (pSubfield); + pSubfield = NULL; + + if (jamHdr.SubfieldLen > 0L) { + ulSubfieldLen = jamHdr.SubfieldLen; + pPos = pSubfield = (unsigned char *)malloc ((size_t)(ulSubfieldLen + 1)); + if (pSubfield == NULL) + return (FALSE); + + read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen); + + while (ulSubfieldLen > 0L) { + jamSubField = (JAMBINSUBFIELD *)pPos; + pPos += sizeof (JAMBINSUBFIELD); + /* + * The next check is to prevent a segmentation + * fault by corrupted subfields. + */ + if ((jamSubField->DatLen < 0) || (jamSubField->DatLen > jamHdr.SubfieldLen)) + return FALSE; + + switch (jamSubField->LoID) { + case JAMSFLD_SENDERNAME: + if (jamSubField->DatLen > 100) { + memcpy (Msg.From, pPos, 100); + Msg.From[100] = '\0'; + } else { + memcpy (Msg.From, pPos, (int)jamSubField->DatLen); + Msg.From[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_RECVRNAME: + if (jamSubField->DatLen > 100) { + memcpy (Msg.To, pPos, 100); + Msg.To[100] = '\0'; + } else { + memcpy (Msg.To, pPos, (int)jamSubField->DatLen); + Msg.To[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_SUBJECT: + if (jamSubField->DatLen > 100) { + memcpy (Msg.Subject, pPos, 100); + Msg.Subject[100] = '\0'; + } else { + memcpy (Msg.Subject, pPos, (int)jamSubField->DatLen); + Msg.Subject[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_OADDRESS: + if (jamSubField->DatLen > 100) { + memcpy (Msg.FromAddress, pPos, 100); + Msg.FromAddress[100] = '\0'; + } else { + memcpy (Msg.FromAddress, pPos, (int)jamSubField->DatLen); + Msg.FromAddress[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_DADDRESS: + if (jamSubField->DatLen > 100) { + memcpy(Msg.ToAddress, pPos, 100); + Msg.ToAddress[100] = '\0'; + } else { + memcpy (Msg.ToAddress, pPos, (int)jamSubField->DatLen); + Msg.ToAddress[(int)jamSubField->DatLen] = '\0'; + } + break; + + case JAMSFLD_MSGID: + memcpy (Msg.Msgid, pPos, (int)jamSubField->DatLen); + Msg.Msgid[(int)jamSubField->DatLen] = '\0'; + break; + + default: + break; + } + ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen; + if (ulSubfieldLen > 0) + pPos += (int)jamSubField->DatLen; + } + } + /* + * In the original BBS we found that GEcho was not + * setting the FromAddress. We take it from the MSGID + * if there is one. + */ + if ((!strlen(Msg.FromAddress)) && (strlen(Msg.Msgid))) { + for (i = 0; i < strlen(Msg.Msgid); i++) { + if ((Msg.Msgid[i] == '@') || (Msg.Msgid[i] == ' ')) + break; + Msg.FromAddress[i] = Msg.Msgid[i]; + } + } + } + + return (RetVal); +} + + + +/* + * Read message + */ +int JAM_Read(unsigned long ulMsg, int nWidth) +{ + int RetVal = FALSE, SkipNext; + int i, nReaded, nCol, nRead; + unsigned char *pPos; + unsigned long ulTxtLen, ulSubfieldLen; + JAMIDXREC jamIdx; + JAMBINSUBFIELD *jamSubField; + LDATA *Bottom = NULL, *New; + + MsgText_Clear(); + + if ((RetVal = JAM_ReadHeader(ulMsg)) == TRUE) { + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + read (fdJdx, &jamIdx, sizeof (jamIdx)); + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + + if (pSubfield != NULL) + free (pSubfield); + pSubfield = NULL; + + if (jamHdr.SubfieldLen > 0L) { + ulSubfieldLen = jamHdr.SubfieldLen; + pPos = pSubfield = (unsigned char *)malloc ((size_t)(ulSubfieldLen + 1)); + if (pSubfield == NULL) + return (FALSE); + + read (fdHdr, pSubfield, (size_t)jamHdr.SubfieldLen); + + while (ulSubfieldLen > 0L) { + jamSubField = (JAMBINSUBFIELD *)pPos; + pPos += sizeof (JAMBINSUBFIELD); + + /* + * Check for corrupted subfields + */ + if ((jamSubField->DatLen < 0) || (jamSubField->DatLen > jamHdr.SubfieldLen)) + return FALSE; + + switch (jamSubField->LoID) { + case JAMSFLD_MSGID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + memset(&Msg.Msgid, 0, sizeof(Msg.Msgid)); + sprintf(Msg.Msgid, "%s", szBuff); + sprintf (szLine, "\001MSGID: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_REPLYID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001REPLY: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_PID: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001PID: %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_TRACE: + memcpy(szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001Via %s", szBuff); + MsgText_Add2(szLine); + break; + + case JAMSFLD_FTSKLUDGE: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + if (!strncmp(szBuff, "AREA:", 5)) + sprintf(szLine, "%s", szBuff); + else { + sprintf (szLine, "\001%s", szBuff); + if (strncmp(szLine, "\001REPLYADDR:", 11) == 0) { + sprintf(Msg.ReplyAddr, "%s", szLine+12); + } + if (strncmp(szLine, "\001REPLYTO:", 9) == 0) { + sprintf(Msg.ReplyTo, "%s", szLine+10); + } + if (strncmp(szLine, "\001REPLYADDR", 10) == 0) { + sprintf(Msg.ReplyAddr, "%s", szLine+11); + } + if (strncmp(szLine, "\001REPLYTO", 8) == 0) { + sprintf(Msg.ReplyTo, "%s", szLine+9); + } + } + MsgText_Add2(szLine); + break; + + case JAMSFLD_SEENBY2D: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "SEEN-BY: %s", szBuff); + if ((New = (LDATA *)malloc(sizeof(LDATA))) != NULL) { + memset(New, 0, sizeof(LDATA)); + New->Value = strdup(szLine); + if (Bottom != NULL) { + while (Bottom->Next != NULL) + Bottom = Bottom->Next; + New->Previous = Bottom; + New->Next = Bottom->Next; + if (New->Next != NULL) + New->Next->Previous = New; + Bottom->Next = New; + } + Bottom = New; + } + break; + + case JAMSFLD_PATH2D: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001PATH: %s", szBuff); + if ((New = (LDATA *)malloc(sizeof(LDATA))) != NULL) { + memset(New, 0, sizeof(LDATA)); + New->Value = strdup(szLine); + if (Bottom != NULL) { + while (Bottom->Next != NULL) + Bottom = Bottom->Next; + New->Previous = Bottom; + New->Next = Bottom->Next; + if (New->Next != NULL) + New->Next->Previous = New; + Bottom->Next = New; + } + Bottom = New; + } + break; + + case JAMSFLD_FLAGS: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szLine, "\001FLAGS %s", szLine); + MsgText_Add2(szLine); + break; + + case JAMSFLD_TZUTCINFO: + memcpy (szBuff, pPos, (int)jamSubField->DatLen); + szBuff[(int)jamSubField->DatLen] = '\0'; + sprintf (szBuff, "\001TZUTC %s", szLine); + MsgText_Add2(szLine); + break; + + default: + break; + } + + ulSubfieldLen -= sizeof (JAMBINSUBFIELD) + jamSubField->DatLen; + if (ulSubfieldLen > 0) + pPos += (int)jamSubField->DatLen; + } + } + + lseek (fdJdt, jamHdr.TxtOffset, SEEK_SET); + ulTxtLen = jamHdr.TxtLen; + pLine = szLine; + nCol = 0; + SkipNext = FALSE; + + do { + if ((unsigned long)(nRead = sizeof (szBuff)) > ulTxtLen) + nRead = (int)ulTxtLen; + + nReaded = (int)read (fdJdt, szBuff, nRead); + + for (i = 0, pBuff = szBuff; i < nReaded; i++, pBuff++) { + if (*pBuff == '\r') { + *pLine = '\0'; + if (pLine > szLine && SkipNext == TRUE) { + pLine--; + while (pLine > szLine && *pLine == ' ') + *pLine-- = '\0'; + if (pLine > szLine) + MsgText_Add3(szLine, (int)(strlen (szLine) + 1)); + } else + if (SkipNext == FALSE) + MsgText_Add2(szLine); + SkipNext = FALSE; + pLine = szLine; + nCol = 0; + } else + if (*pBuff != '\n') { + *pLine++ = *pBuff; + nCol++; + if (nCol >= nWidth) { + *pLine = '\0'; + if (strchr (szLine, ' ') != NULL) { + while (nCol > 1 && *pLine != ' ') { + nCol--; + pLine--; + } + if (nCol > 0) { + while (*pLine == ' ') + pLine++; + strcpy (szWrp, pLine); + } + *pLine = '\0'; + } else + szWrp[0] = '\0'; + MsgText_Add2(szLine); + strcpy (szLine, szWrp); + pLine = strchr (szLine, '\0'); + nCol = (int)strlen (szLine); + SkipNext = TRUE; + } + } + } + + ulTxtLen -= nRead; + } while (ulTxtLen > 0); + + if (Bottom != NULL) { + while (Bottom->Previous != NULL) + Bottom = Bottom->Previous; + MsgText_Add2(Bottom->Value); + + while (Bottom->Next != NULL) { + Bottom = Bottom->Next; + MsgText_Add2(Bottom->Value); + } + while (Bottom != NULL) { + if (Bottom->Previous != NULL) + Bottom->Previous->Next = Bottom->Next; + if (Bottom->Next != NULL) + Bottom->Next->Previous = Bottom->Previous; + New = Bottom; + if (Bottom->Next != NULL) + Bottom = Bottom->Next; + else if (Bottom->Previous != NULL) + Bottom = Bottom->Previous; + else + Bottom = NULL; + free(New->Value); + free(New); + } + } + } + + return (RetVal); +} + + + +int JAM_SetLastRead(lastread LR) +{ + if (lseek(fdJlr, LastReadRec * sizeof(lastread), SEEK_SET) != -1) + if (write(fdJlr, &LR, sizeof(lastread)) == sizeof(lastread)) + return TRUE; + return FALSE; +} + + + +/* + * Unlock the message base + */ +void JAM_UnLock(void) +{ + struct flock fl; + + fl.l_type = F_UNLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 1L; /* GoldED locks 1 byte as well */ + fl.l_pid = getpid(); + + if (fcntl(fdHdr, F_SETLK, &fl)) { + WriteError("$Can't unlock JAM message base"); + } + +// char *File; + +// File = calloc(PATH_MAX, sizeof(char)); +// sprintf(File, "%s%s", BaseName, ".LCK"); + +// if (unlink(File) == -1) +// WriteError("jammsg: unlock error"); +// free(File); +} + + + +/* + * Write message header + */ +int JAM_WriteHeader (unsigned long ulMsg) +{ + int RetVal = FALSE; + JAMIDXREC jamIdx; + + if (Msg.Id == ulMsg) { + // -------------------------------------------------------------------- + // The user is requesting to write the header of the last message + // retrived so our first attempt is to read the last index from the + // file and check if this is the correct one. + // -------------------------------------------------------------------- + lseek (fdJdx, tell (fdJdx) - sizeof (jamIdx), SEEK_SET); + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } + + if (RetVal == FALSE) { + // -------------------------------------------------------------------- + // The message requested is not the last retrived or the file pointers + // are not positioned where they should be, so now we attempt to + // retrive the message header scanning the database from the beginning. + // -------------------------------------------------------------------- + Msg.Id = 0L; + lseek (fdJdx, 0L, SEEK_SET); + do { + if (read (fdJdx, &jamIdx, sizeof (jamIdx)) == sizeof (jamIdx)) { + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + read (fdHdr, &jamHdr, sizeof (JAMHDR)); + if (!(jamHdr.Attribute & MSG_DELETED) && jamHdr.MsgNum == ulMsg) + RetVal = TRUE; + } + } while (RetVal == FALSE && tell (fdJdx) < filelength (fdJdx)); + } + + if (RetVal == TRUE) { + Msg.Id = jamHdr.MsgNum; + jamHdr.Attribute &= MSG_DELETED; + JAMset_flags(); + + lseek (fdHdr, jamIdx.HdrOffset, SEEK_SET); + write (fdHdr, &jamHdr, sizeof (JAMHDR)); + } + + return RetVal; +} + + diff --git a/lib/jammsg.h b/lib/jammsg.h new file mode 100644 index 00000000..a87e6493 --- /dev/null +++ b/lib/jammsg.h @@ -0,0 +1,27 @@ +#ifndef _JAMMSG_H +#define _JAMMSG_H + + +int JAM_AddMsg(void); +void JAM_Close(void); +int JAM_Delete(unsigned long); +int JAM_GetLastRead(lastread *); +unsigned long JAM_Highest(void); +int JAM_Lock(unsigned long); +unsigned long JAM_Lowest(void); +void JAM_New(void); +int JAM_NewLastRead(lastread); +int JAM_Next(unsigned long *); +unsigned long JAM_Number(void); +int JAM_Open(char *); +void JAM_Pack(void); +int JAM_Previous(unsigned long *); +int JAM_ReadHeader(unsigned long); +int JAM_Read(unsigned long, int); +int JAM_SetLastRead(lastread); +void JAM_UnLock(void); +int JAM_WriteHeader(unsigned long); + + +#endif + diff --git a/lib/jamsys.h b/lib/jamsys.h new file mode 100644 index 00000000..e8cb85c4 --- /dev/null +++ b/lib/jamsys.h @@ -0,0 +1,100 @@ +/* +** JAM(mbp) - The Joaquim-Andrew-Mats Message Base Proposal +** +** C API +** +** Written by Joaquim Homrighausen and Mats Wallin. +** +** ---------------------------------------------------------------------- +** +** jamsys.h (JAMmb) +** +** Compiler and platform dependant definitions +** +** Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and +** Mats Wallin. ALL RIGHTS RESERVED. +** +** 93-06-28 JoHo/MW +** Initial coding. +*/ + +#ifndef __JAMSYS_H__ +#define __JAMSYS_H__ + +/* +** The following assumptions are made about compilers and platforms: +** +** __MSDOS__ Defined if compiling for MS-DOS +** _WINDOWS Defined if compiling for Microsoft Windows +** __NT__ Defined if compiling for Windows NT +** __OS2__ Defined if compiling for OS/2 2.x +** __sparc__ Defined if compiling for Sun Sparcstation +** __50SERIES Defined if compiling for Prime with Primos +** +** __SMALL__ Defined if compiling under MS-DOS in small memory model +** __MEDIUM__ Defined if compiling under MS-DOS in medium memory model +** __COMPACT__ Defined if compiling under MS-DOS in compact memory model +** __LARGE__ Defined if compiling under MS-DOS in large memory model +** +** __ZTC__ Zortech C++ 3.x +** __BORLANDC__ Borland C++ 3.x +** __TURBOC__ Turbo C 2.0 +** __TSC__ JPI TopSpeed C 1.06 +** _MSC_VER Microsoft C 6.0 and later +** _QC Microsoft Quick C +*/ + +typedef long INT32; /* 32 bits signed integer */ +typedef unsigned long UINT32; /* 32 bits unsigned integer */ +typedef short int INT16; /* 16 bits signed integer */ +typedef unsigned short int UINT16; /* 16 bits unsigned integer */ +typedef char CHAR8; /* 8 bits signed integer */ +typedef unsigned char UCHAR8; /* 8 bits unsigned integer */ +typedef int FHANDLE; /* File handle */ + +#define _JAMFAR +#define _JAMPROC +#define _JAMDATA + + +typedef INT32 _JAMDATA * INT32ptr; +typedef UINT32 _JAMDATA * UINT32ptr; +typedef INT16 _JAMDATA * INT16ptr; +typedef UINT16 _JAMDATA * UINT16ptr; +typedef CHAR8 _JAMDATA * CHAR8ptr; +typedef UCHAR8 _JAMDATA * UCHAR8ptr; +typedef void _JAMDATA * VOIDptr; + +/* +** Values for "AccessMode" and "ShareMode" parameter to JAMsysSopen. +*/ + +#define JAMO_RDWR O_RDWR +#define JAMO_RDONLY O_RDONLY +#define JAMO_WRONLY O_WRONLY +#define JAMSH_DENYNO 0 +#define JAMSH_DENYRD 0 +#define JAMSH_DENYWR 0 +#define JAMSH_DENYRW 0 + + +/* +** Structure to contain date/time information +*/ +typedef struct JAMtm + { + int tm_sec, /* Seconds 0..59 */ + tm_min, /* Minutes 0..59 */ + tm_hour, /* Hour of day 0..23 */ + tm_mday, /* Day of month 1..31 */ + tm_mon, /* Month 0..11 */ + tm_year, /* Years since 1900 */ + tm_wday, /* Day of week 0..6 (Sun..Sat) */ + tm_yday, /* Day of year 0..365 */ + tm_isdst; /* Daylight savings time (not used) */ + } JAMTM, _JAMDATA * JAMTMptr; + +#endif /* __JAMSYS_H__ */ + + +/* end of file "jamsys.h" */ diff --git a/lib/libs.h b/lib/libs.h new file mode 100644 index 00000000..e3f2a744 --- /dev/null +++ b/lib/libs.h @@ -0,0 +1,89 @@ +/***************************************************************************** + * + * File ..................: libs.h + * Purpose ...............: Libraries include list + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _LIBS_H +#define _LIBS_H + +#include "../config.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#define _REGEX_RE_COMP + +#define TRUE 1 +#define FALSE 0 + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../lib/memwatch.h" + +#pragma pack(1) + +#endif + diff --git a/lib/mbfile.c b/lib/mbfile.c new file mode 100644 index 00000000..fefc4449 --- /dev/null +++ b/lib/mbfile.c @@ -0,0 +1,304 @@ +/***************************************************************************** + * + * File ..................: mbfile + * Purpose ...............: Basic File I/O + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This toolkit is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBTOOL; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +/* + * Buffered file copy, filetime is preserved. + */ +int file_cp(char *from, char *to) +{ + char *line; + FILE *stfrom, *stto; + int dummy, bread; + static int error; + struct stat sb; + struct utimbuf ut; + + stfrom = fopen(from, "r"); + if (stfrom == NULL) + return errno; + + stto = fopen(to, "w"); + if (stto == NULL) { + error = errno; + fclose(stfrom); + return error; + } + + line = malloc(16384); + + do { + bread = fread(line, 1, 16384, stfrom); + dummy = fwrite(line, 1, bread, stto); + if (bread != dummy) { + error = errno; + fclose(stfrom); + fclose(stto); + unlink(to); + free(line); + return error; + } + } while (bread != 0); + + free(line); + fclose(stfrom); + if (fclose(stto) != 0) { + error = errno; + unlink(to); + return error; + } + + /* + * copy successfull, now copy file- and modification-time + */ + if (stat(from, &sb) == 0) { + ut.actime = mktime(localtime(&sb.st_atime)); + ut.modtime = mktime(localtime(&sb.st_mtime)); + if (utime(to, &ut) != 0) { + error = errno; + unlink(to); + return error; + } + chmod(to, sb.st_mode); + } + + return 0; +} + + + +/* + * Remove a file + */ +int file_rm(char *path) +{ + if (unlink(path) != 0) + return errno; + return 0; +} + + + +/* + * Move or rename a file. Not fullproof if using NFS, see + * man 2 rename. If we are trying to move a file accross + * filesystems, which is not allowed, we fall back to simple + * copy the file and then delete the old file. + */ +int file_mv(char *oldpath, char *newpath) +{ + static int error; + + if (rename(oldpath, newpath) != 0) { + error = errno; + if (error != EXDEV) + return error; + /* + * We tried cross-device link, now the slow way :-) + */ + error = file_cp(oldpath, newpath); + if (error != 0) + return error; + error = file_rm(oldpath); + return 0; + } + + return 0; +} + + + +/* + * Test if the given file exists. The second option is: + * R_OK - test for Read rights + * W_OK - test for Write rights + * X_OK - test for eXecute rights + * F_OK - test file presence only + */ +int file_exist(char *path, int mode) +{ + if (access(path, mode) != 0) + return errno; + + return 0; +} + + + +/* + * Return size of file, or -1 if file doesn't exist + */ +long file_size(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_size; +} + + + +/* + * Claclulate the 32 bit CRC of a file. Return -1 if file not found. + */ +long file_crc(char *path, int slow) +{ + static long crc; + int bread; + FILE *fp; + char *line; + + if ((fp = fopen(path, "r")) == NULL) + return -1; + + line = malloc(32768); + crc = 0xffffffff; + + do { + bread = fread(line, 1, 32768, fp); + crc = upd_crc32(line, crc, bread); + if (slow) + usleep(1); + } while (bread > 0); + + free(line); + fclose(fp); + return crc ^ 0xffffffff; +} + + + +/* + * Return time of file, or -1 if file doen't exist, which is + * the same as 1 second before 1 jan 1970. You may test the + * result on -1 since time_t is actualy a long integer. + */ +time_t file_time(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_mtime; +} + + + +/* + * Make directory tree, the name must end with a / + */ +int mkdirs(char *name) +{ + char buf[PATH_MAX], *p, *q; + int rc, last = 0, oldmask; + + memset(&buf, 0, sizeof(buf)); + strncpy(buf, name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + p = buf+1; + + oldmask = umask(000); + while ((q = strchr(p, '/'))) { + *q = '\0'; + rc = mkdir(buf, 0775); + last = errno; + *q = '/'; + p = q+1; + } + + umask(oldmask); + + if ((last == 0) || (last == EEXIST)) { + return TRUE; + } else { + WriteError("$mkdirs(%s)", name); + return FALSE; + } +} + + + +int diskfree(int needed) +{ + char *mtab, *dev, *fs, *type; + FILE *fp; + struct statfs sfs; + int RetVal = TRUE; + unsigned long temp; + + if (! needed) + return TRUE; + + mtab = calloc(PATH_MAX, sizeof(char)); + if ((fp = fopen((char *)"/etc/mtab", "r")) == 0) { + WriteError("$Can't open /etc/mtab"); + return TRUE; + } + + while (fgets(mtab, PATH_MAX, fp)) { + dev = strtok(mtab, " "); + fs = strtok(NULL, " "); + type = strtok(NULL, " "); + if (strncmp((char *)"/dev/", dev, 5) == 0) { + /* + * Filter out unwanted filesystems, floppy. + * Also filter out the /boot file system. + */ + if (strncmp((char *)"/dev/fd", dev, 7) && strncmp((char *)"/boot", fs, 5) && + (!strncmp((char *)"ext2", type, 4) || !strncmp((char *)"reiserfs", type, 8) || + !strncmp((char *)"vfat", type, 4) || !strncmp((char *)"msdos", type, 5))) { + if (statfs(fs, &sfs) == 0) { + temp = (unsigned long)(sfs.f_bsize / 512L); + if (((unsigned long)(sfs.f_bavail * temp) / 2048L) < needed) { + RetVal = FALSE; + WriteError("On \"%s\" only %d kb left, need %d kb", fs, + (sfs.f_bavail * sfs.f_bsize) / 1024, needed * 1024); + } + } + } + } + } + fclose(fp); + free(mtab); + + return RetVal; +} + + diff --git a/lib/mbinet.h b/lib/mbinet.h new file mode 100644 index 00000000..93cbbc84 --- /dev/null +++ b/lib/mbinet.h @@ -0,0 +1,24 @@ +#ifndef _MBINET_H +#define _MBINET_H + + +int smtp_connect(void); +int smtp_send(char *); +char *smtp_receive(void); +int smtp_close(void); +int smtp_cmd(char *, int); + +int nntp_connect(void); +int nntp_send(char *); +char *nntp_receive(void); +int nntp_close(void); +int nntp_cmd(char *, int); + +int pop3_connect(void); +int pop3_send(char *); +char *pop3_receive(void); +int pop3_close(void); +int pop3_cmd(char *); + +#endif + diff --git a/lib/mbse.h b/lib/mbse.h new file mode 100644 index 00000000..4ffe6f05 --- /dev/null +++ b/lib/mbse.h @@ -0,0 +1,117 @@ +/***************************************************************************** + * + * File ..................: mbse.h + * Purpose ...............: Global variables for MBSE BBS + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _MBSE_H +#define _MBSE_H + +#define Max_passlen 14 /* Define maximum passwd length */ +#define LINES 24 /* Lines for MoreFile */ +#define LANG 500 /* Amount of Language Entries */ + + + +typedef struct _TagRec { + long Area; /* File Area number */ + int Active; /* Not deleted from taglist */ + int Cost; /* Free download */ + off_t Size; /* File Size */ + char File[81]; /* File Name */ +} _Tag; + + + +/* + * File Areas + */ +int iAreaNumber; /* Current File Area -1 */ +char sAreaDesc[PATH_MAX]; /* Current File Area Name */ +char sAreaPath[PATH_MAX]; /* Current File Area path */ +FILE *pTagList; /* Tagged files for download */ +_Tag Tag; /* Tag record */ + + + +/* + * Msg Areas + */ +int iMsgAreaNumber; /* Current Message Area number -1 */ +int iMsgAreaType; /* Current Message Area Type */ +char sMsgAreaDesc[PATH_MAX]; /* Current Message Area Name */ +char sMsgAreaBase[PATH_MAX]; /* Current Message Area Base */ +char sMailbox[21]; /* Current e-mail mailbox */ +char sMailpath[PATH_MAX]; /* Current e-mail path */ + + + +/* + * Protocols + */ +char sProtName[21]; /* Current Transfer Protocol name */ +char sProtUp[51]; /* Upload path & binary */ +char sProtDn[51]; /* Download path & binary */ +char sProtAdvice[31]; /* Advice for protocol */ +unsigned uProtBatch; /* Batching protocol */ +unsigned uProtBidir; /* Bi-directional protocol */ +int iProtEfficiency; /* Protocol efficiency */ + + + +/* + * Global variables + */ +char *mLanguage[LANG]; /* Define LANG=nnn Language Variables */ +char *mKeystroke[LANG]; /* Possible keystrokes */ +char *Date1, *Date2; /* Result from function SwapDate() */ +char *pTTY; /* Current tty name */ +char sUserTimeleft[7]; /* Global Time Left Variable */ +int iUserTimeLeft; /* Global Time Left Variable */ +char LastLoginDate[12]; /* Last login date */ +char LastLoginTime[9]; /* Last login time */ +char LastCaller[36]; /* Last caller on system */ +char FirstName[20]; /* Users First name */ +char LastName[30]; /* Users Last name */ +int LoginPrompt; /* Login prompt check - timeout */ +int UserAge; /* Users age */ +int grecno; /* User's Record Number in user file */ +int SYSOP; /* Int to see if user is Sysop */ +int iLineCount; /* Line Counter */ +int iExpired; /* Check if users time ran out */ +int iUnixMode; /* Using Unix Accounts */ +char sUnixName[9]; /* Unix login name */ +time_t Time2Go; /* Calculated time to force logout */ +struct tm *l_date; /* Structure for Date */ + +time_t ltime; +time_t Time_Now; + + + +#endif diff --git a/lib/memwatch.c b/lib/memwatch.c new file mode 100644 index 00000000..34221d11 --- /dev/null +++ b/lib/memwatch.c @@ -0,0 +1,2356 @@ +/* +** MEMWATCH.C +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +*/ + +#include "../config.h" + +#ifdef MEMWATCH + +#define __MEMWATCH_C 1 + +#ifdef MW_NOCPP +#define MEMWATCH_NOCPP +#endif +#ifdef MW_STDIO +#define MEMWATCH_STDIO +#endif + +/*********************************************************************** +** Include files +***********************************************************************/ + +#include "../config.h" +#include "libs.h" +#include "memwatch.h" + + +/*********************************************************************** +** Defines & other weird stuff +***********************************************************************/ + +/*lint -save -e767 */ +#define MW_VERSION "2.62" /* the current version number */ +#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line) +#define FLUSH() mwFlush() +#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1) +#define PRECHK 0x01234567L +#define POSTCHK 0x76543210L +/*lint -restore */ + +#define MW_NML 0x0001 + +#ifdef _MSC_VER +#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */ +#else +#define COMMIT "" /* Normal ANSI */ +#endif /* _MSC_VER */ + +#ifdef __cplusplus +#define CPPTEXT "++" +#else +#define CPPTEXT "" +#endif /* __cplusplus */ + +#ifdef MEMWATCH_STDIO +#define mwSTDERR stderr +#else +#define mwSTDERR mwLog +#endif + +/*********************************************************************** +** Defines to read/write 32 bit words in a portable way +** Note: Assumes that a 'long int' is 32 bits, and a 'char' is 8 bits. +***********************************************************************/ + +typedef unsigned char mwBYTE; +typedef unsigned long mwDWORD; + +#define GETDWORD(l, cp) { \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + (l) = ((mwDWORD)t_cp[0] << 24) \ + | ((mwDWORD)t_cp[1] << 16) \ + | ((mwDWORD)t_cp[2] << 8) \ + | ((mwDWORD)t_cp[3]) \ + ; \ +} + +#define PUTDWORD(l, cp) { \ + register mwDWORD t_l = (mwDWORD)(l); \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + *t_cp++ = (mwBYTE)(t_l >> 24); \ + *t_cp++ = (mwBYTE)(t_l >> 16); \ + *t_cp++ = (mwBYTE)(t_l >> 8); \ + *t_cp = (mwBYTE)t_l; \ +} + +/*********************************************************************** +** Typedefs & structures +***********************************************************************/ + +/* main data holding area, precedes actual allocation */ +typedef struct mwData_ mwData; +struct mwData_ { + mwData* prev; /* previous allocation in chain */ + mwData* next; /* next allocation in chain */ + const char* file; /* file name where allocated */ + long count; /* action count */ + long check; /* integrity check value */ +#if 0 + long crc; /* data crc value */ +#endif + size_t size; /* size of allocation */ + int line; /* line number where allocated */ + unsigned flag; /* flag word */ + }; + +/* statistics structure */ +typedef struct mwStat_ mwStat; +struct mwStat_ { + mwStat* next; /* next statistic buffer */ + const char* file; + long total; /* total bytes allocated */ + long num; /* total number of allocations */ + long max; /* max allocated at one time */ + long curr; /* current allocations */ + int line; + }; + +/* grabbing structure, 1K in size */ +typedef struct mwGrabData_ mwGrabData; +struct mwGrabData_ { + mwGrabData* next; + int type; + char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; + }; + +typedef struct mwMarker_ mwMarker; +struct mwMarker_ { + void *host; + char *text; + mwMarker *next; + int level; + }; + +/*********************************************************************** +** Static variables +***********************************************************************/ + +static int mwInited = 0; +static int mwInfoWritten = 0; +static int mwUseAtexit = 0; +static FILE* mwLog = NULL; +static int mwFlushing = 0; +static int mwStatLevel = MW_STAT_DEFAULT; +static int mwNML = MW_NML_DEFAULT; +static int mwFBI = 0; +static long mwAllocLimit = 0L; +static int mwUseLimit = 0; + +static long mwNumCurAlloc = 0L; +static mwData* mwHead = NULL; +static mwData* mwTail = NULL; + +static void (*mwOutFunction)(int) = NULL; +static int (*mwAriFunction)(const char*) = NULL; +static int mwAriAction = MW_ARI_ABORT; + +static char mwPrintBuf[MW_TRACE_BUFFER+8]; + +static unsigned long mwCounter = 0L; +static long mwErrors = 0L; + +static int mwTestFlags = 0; +static int mwTestAlways = 0; + +static FILE* mwLogB1 = NULL; +static int mwFlushingB1 = 0; + +static mwStat* mwStatList = NULL; +static long mwStatTotAlloc = 0L; +static long mwStatMaxAlloc = 0L; +static long mwStatNumAlloc = 0L; +static long mwStatCurAlloc = 0L; +static long mwNmlNumAlloc = 0L; +static long mwNmlCurAlloc = 0L; + +static mwGrabData* mwGrabList = NULL; +static long mwGrabSize = 0L; + +static void * mwLastFree[MW_FREE_LIST]; +static const char *mwLFfile[MW_FREE_LIST]; +static int mwLFline[MW_FREE_LIST]; +static int mwLFcur = 0; + +static mwMarker* mwFirstMark = NULL; + +static FILE* mwLogB2 = NULL; +static int mwFlushingB2 = 0; + +/*********************************************************************** +** Static function declarations +***********************************************************************/ + +static void mwAutoInit( void ); +static FILE* mwLogR( void ); +static void mwLogW( FILE* ); +static int mwFlushR( void ); +static void mwFlushW( int ); +static void mwFlush( void ); +static void mwIncErr( void ); +static void mwUnlink( mwData*, const char* file, int line ); +static int mwRelink( mwData*, const char* file, int line ); +static int mwIsHeapOK( mwData *mw ); +static int mwIsOwned( mwData* mw, const char* file, int line ); +static int mwTestBuf( mwData* mw, const char* file, int line ); +static void mwDefaultOutFunc( int ); +static void mwWrite( const char* format, ... ); +static void mwLogFile( const char* name ); +static size_t mwFreeUp( size_t, int ); +static const void *mwTestMem( const void *, unsigned, int ); +static int mwStrCmpI( const char *s1, const char *s2 ); +static int mwTestNow( const char *file, int line, int always_invoked ); +static void mwDropAll( void ); +static const char *mwGrabType( int type ); +static unsigned mwGrab_( unsigned kb, int type, int silent ); +static unsigned mwDrop_( unsigned kb, int type, int silent ); +static int mwARI( const char* text ); +static void mwStatReport( void ); +static mwStat* mwStatGet( const char*, int, int ); +static void mwStatAlloc( size_t, const char*, int ); +static void mwStatFree( size_t, const char*, int ); + +/*********************************************************************** +** System functions +***********************************************************************/ + +void mwInit( void ) { + time_t tid; + + if( mwInited++ > 0 ) return; + + /* start a log if none is running */ + if( mwLogR() == NULL ) mwLogFile( "/opt/mbse/log/memwatch.log" ); + if( mwLogR() == NULL ) { + int i; + char buf[32]; + /* oops, could not open it! */ + /* probably because it's already open */ + /* so we try some other names */ + for( i=1; i<100; i++ ) { + sprintf( buf, "memwat%02d.log", i ); + mwLogFile( buf ); + if( mwLogR() != NULL ) break; + } + } + + /* initialize the statistics */ + mwStatList = NULL; + mwStatTotAlloc = 0L; + mwStatCurAlloc = 0L; + mwStatMaxAlloc = 0L; + mwStatNumAlloc = 0L; + mwNmlCurAlloc = 0L; + mwNmlNumAlloc = 0L; + + /* write informational header if needed */ + if( !mwInfoWritten ) { + mwInfoWritten = 1; + (void) time( &tid ); + mwWrite( + "\n=============" + " MEMWATCH " MW_VERSION " Copyright (C) 1992-1999 Johan Lindh " + "=============\n"); + mwWrite( "\nStarted at %s\n", ctime( &tid ) ); + +/**************************************************************** Generic */ +#ifdef mwNew + mwWrite( "C++ new/delete tracking enabled\n" ); +#endif /* mwNew */ +#ifdef __STDC__ + mwWrite( "Compiled as standard ANSI C\n" ); +#endif /* __STDC__ */ +/**************************************************************** Generic */ + +/************************************************************ Microsoft C */ +#ifdef _MSC_VER + mwWrite( "Compiled using Microsoft C" CPPTEXT + " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 ); +#endif /* _MSC_VER */ +/************************************************************ Microsoft C */ + +/************************************************************** Borland C */ +#ifdef __BORLANDC__ + mwWrite( "Compiled using Borland C" +#ifdef __cplusplus + "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 ); +#else + " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 ); +#endif /* __cplusplus */ +#endif /* __BORLANDC__ */ +/************************************************************** Borland C */ + +/************************************************************** Watcom C */ +#ifdef __WATCOMC__ + mwWrite( "Compiled using Watcom C %d.%02d ", + __WATCOMC__/100, __WATCOMC__%100 ); +#ifdef __FLAT__ + mwWrite( "(32-bit flat model)" ); +#endif /* __FLAT__ */ + mwWrite( "\n" ); +#endif /* __WATCOMC__ */ +/************************************************************** Watcom C */ + + mwWrite( "\n" ); + FLUSH(); + } + + if( mwUseAtexit ) (void) atexit( mwAbort ); + return; + } + +void mwAbort( void ) { + mwData *mw; + mwMarker *mrk; + char *data; + time_t tid; + int c, i, j; + int errors; + long chk; + + tid = time( NULL ); + mwWrite( "\nStopped at %s\n", ctime( &tid) ); + + if( !mwInited ) + mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); + + /* release the grab list */ + mwDropAll(); + + /* report mwMarked items */ + while( mwFirstMark ) { + mrk = mwFirstMark->next; + mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); + free( mwFirstMark->text ); + free( mwFirstMark ); + mwFirstMark = mrk; + mwErrors ++; + } + + /* release all still allocated memory */ + errors = 0; + while( mwHead != NULL && errors < 3 ) { + if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { + if( errors < 3 ) + { + errors ++; + mwWrite( "internal: NML/unfreed scan restarting\n" ); + FLUSH(); + mwHead = mwHead; + continue; + } + mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); + FLUSH(); + break; + } + mwFlushW(0); + if( !(mwHead->flag & MW_NML) ) { + mwErrors++; + data = ((char*)(mwHead+1)); + mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", + mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+sizeof(long) ); + GETDWORD( chk, data ); + if( chk != PRECHK ) { + mwWrite( "[underflowed] "); + FLUSH(); + } + GETDWORD( chk, (data+sizeof(long)+mwHead->size) ); + if( chk != POSTCHK ) { + mwWrite( "[overflowed] "); + FLUSH(); + } + mwWrite( " \t{" ); + j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; + for( i=0;i<16;i++ ) { + if( i 126 ) c = '.'; + mwWrite( "%c", c ); + } + mwWrite( "}\n" ); + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + else { + data = ((char*)(mwHead+1)) + sizeof(long); + if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { + mwErrors++; + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mwHead->count, data + sizeof(long), mwHead->file, mwHead->line ); + FLUSH(); + } + mwNmlNumAlloc --; + mwNmlCurAlloc -= mwHead->size; + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + } + + if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); + if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); + + /* report statistics */ + mwStatReport(); + FLUSH(); + + mwInited = 0; + mwHead = mwTail = NULL; + if( mwErrors ) + fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); + mwLogFile( NULL ); + mwErrors = 0; + } + +void mwTerm( void ) { + if( mwInited == 1 ) + { + mwAbort(); + return; + } + if( !mwInited ) + mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); + else + mwInited --; + } + +void mwStatistics( int level ) +{ + mwAutoInit(); + if( level<0 ) level=0; + if( mwStatLevel != level ) + { + mwWrite( "statistics: now collecting on a %s basis\n", + level<1?"global":(level<2?"module":"line") ); + mwStatLevel = level; + } +} + +void mwAutoCheck( int onoff ) { + mwAutoInit(); + mwTestAlways = onoff; + if( onoff ) mwTestFlags = MW_TEST_ALL; + } + +void mwSetOutFunc( void (*func)(int) ) { + mwAutoInit(); + mwOutFunction = func; + } + +int mwTest( const char *file, int line, int items ) { + mwAutoInit(); + mwTestFlags = items; + return mwTestNow( file, line, 0 ); + } + +/* +** Returns zero if there are no errors. +** Returns nonzero if there are errors. +*/ +int mwTestBuffer( const char *file, int line, void *p ) { + mwData* mw; + + mwAutoInit(); + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + return mwTestBuf( mw, file, line ); + } + return 1; + } + +void mwBreakOut( const char* cause ) { + fprintf(mwSTDERR, "breakout: %s\n", cause); + mwWrite("breakout: %s\n", cause ); + return; + } + +/* +** 981217 JLI: is it possible that ->next is not always set? +*/ +void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { + mwMarker *mrk; + unsigned n, isnew; + char *buf; + int tot, oflow = 0; + char wherebuf[128]; + + mwAutoInit(); + TESTS(NULL,0); + + if( desc == NULL ) desc = "unknown"; + if( file == NULL ) file = "unknown"; + + tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); + if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } + + if( p == NULL ) { + mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); + return p; + } + + if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", + file, line, mwFirstMark, desc ); + return p; + } + + for( mrk=mwFirstMark; mrk; mrk=mrk->next ) + { + if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", + file, line, mrk, mrk->next, desc ); + return p; + } + if( mrk->host == p ) break; + } + + if( mrk == NULL ) { + isnew = 1; + mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); + if( mrk == NULL ) { + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + mrk->next = NULL; + n = 0; + } + else { + isnew = 0; + n = strlen( mrk->text ); + } + + n += strlen( wherebuf ); + buf = (char*) malloc( n+3 ); + if( buf == NULL ) { + if( isnew ) free( mrk ); + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + + if( isnew ) { + memcpy( buf, wherebuf, n+1 ); + mrk->next = mwFirstMark; + mrk->host = p; + mrk->text = buf; + mrk->level = 1; + mwFirstMark = mrk; + } + else { + strcpy( buf, mrk->text ); + strcat( buf, ", " ); + strcat( buf, wherebuf ); + free( mrk->text ); + mrk->text = buf; + mrk->level ++; + } + + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + return p; + } + +void* mwUnmark( void *p, const char *file, unsigned line ) { + mwMarker *mrk, *prv; + mrk = mwFirstMark; + prv = NULL; + while( mrk ) { + if( mrk->host == p ) { + if( mrk->level < 2 ) { + if( prv ) prv->next = mrk->next; + else mwFirstMark = mrk->next; + free( mrk->text ); + free( mrk ); + return p; + } + mrk->level --; + return p; + } + prv = mrk; + mrk = mrk->next; + } + mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); + return p; + } + +/*********************************************************************** +** Safe memory checkers +** +** Using ifdefs, implement the operating-system specific mechanism +** of identifying a piece of memory as legal to access with read +** and write priviliges. Default: return nonzero for non-NULL pointers. +***********************************************************************/ + +static char mwDummy( char c ) +{ + return c; +} + +#ifndef MW_SAFEADDR +#ifdef WIN32 +#define MW_SAFEADDR +#define WIN32_LEAN_AND_MEAN +#include +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) ) return 0; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + /* NOTE: For some reason, under Win95 the IsBad... */ + /* can return false for invalid pointers. */ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0; + return 1; +} +#endif /* WIN32 */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +#ifdef SIGSEGV +#define MW_SAFEADDR + +typedef void (*mwSignalHandlerPtr)( int ); +mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0; +jmp_buf mwSIGSEGVjump; +static void mwSIGSEGV( int n ); + +static void mwSIGSEGV( int n ) +{ + longjmp( mwSIGSEGVjump, 1 ); +} + +int mwIsReadAddr( const void *p, unsigned len ) +{ + const char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read all the bytes in the range */ + ptr = (const char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + if( *ptr == 0x7C ) (void) mwDummy( (char)0 ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read and write-back all the bytes in the range */ + ptr = (char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + *ptr = mwDummy( *ptr ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +#endif /* SIGSEGV */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +#endif + +/*********************************************************************** +** Abort/Retry/Ignore handlers +***********************************************************************/ + +static int mwARI( const char *estr ) { + char inbuf[81]; + int c; + fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); + (void) fgets(inbuf,sizeof(inbuf),stdin); + for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; + c = inbuf[c]; + if( c == 'R' || c == 'r' ) { + mwBreakOut( estr ); + return MW_ARI_RETRY; + } + if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; + return MW_ARI_ABORT; + } + +/* standard ARI handler (exported) */ +int mwAriHandler( const char *estr ) { + mwAutoInit(); + return mwARI( estr ); + } + +/* used to set the ARI function */ +void mwSetAriFunc( int (*func)(const char *) ) { + mwAutoInit(); + mwAriFunction = func; + } + +/*********************************************************************** +** Allocation handlers +***********************************************************************/ + +void* mwMalloc( size_t size, const char* file, int line) { + size_t needed; + mwData *mw; + char *ptr; + void *p; + + mwAutoInit(); + + TESTS(file,line); + + mwCounter ++; + needed = sizeof(mwData) + sizeof(long) + sizeof(long) + size; + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + mw = (mwData*) malloc( needed ); + if( mw == NULL ) { + if( mwFreeUp(needed,0) >= needed ) { + mw = (mwData*) malloc(needed); + if( mw == NULL ) { + mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); + mwIncErr(); + FLUSH(); + } + } + if( mw == NULL ) { + mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", + mwCounter, file, line, (long)size, mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + } + + mw->count = mwCounter; + mw->prev = NULL; + mw->next = mwHead; + mw->file = file; + mw->size = size; + mw->line = line; + mw->flag = 0; + mw->check = CHKVAL(mw); + + if( mwHead ) mwHead->prev = mw; + mwHead = mw; + if( mwTail == NULL ) mwTail = mw; + + ptr = (char*)(void*)(mw+1); + PUTDWORD( PRECHK, ptr ); /* '*(long*)ptr = PRECHK;' */ + ptr += sizeof(long); + p = ptr; + memset( ptr, MW_VAL_NEW, size ); + ptr += size; + PUTDWORD( POSTCHK, ptr ); /* '*(long*)ptr = POSTCHK;' */ + + mwNumCurAlloc ++; + mwStatCurAlloc += (long) size; + mwStatTotAlloc += (long) size; + if( mwStatCurAlloc > mwStatMaxAlloc ) + mwStatMaxAlloc = mwStatCurAlloc; + mwStatNumAlloc ++; + + if( mwStatLevel ) mwStatAlloc( size, file, line ); + + return p; + } + +void* mwRealloc( void *p, size_t size, const char* file, int line) { + int oldUseLimit, i; + mwData *mw; + char *ptr; + + mwAutoInit(); + + if( p == NULL ) return mwMalloc( size, file, line ); + if( size == 0 ) { mwFree( p, file, line ); return NULL; } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + if( mwIsOwned( mw, file, line ) ) { + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + mwIncErr(); + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { + TESTS(file,line); + mwCounter ++; + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + /* fake realloc operation */ + oldUseLimit = mwUseLimit; + mwUseLimit = 0; + ptr = (char*) mwMalloc( size, file, line ); + if( ptr != NULL ) { + if( size < mw->size ) + memcpy( ptr, p, size ); + else + memcpy( ptr, p, mw->size ); + mwFree( p, file, line ); + } + mwUseLimit = oldUseLimit; + return (void*) ptr; + } + + /* Unknown pointer! */ + + /* using free'd pointer? */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return NULL; + } + } + + /* some weird pointer */ + mwIncErr(); + mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return NULL; + } + +char *mwStrdup( char* str, const char* file, int line ) { + size_t len; + char *newstring; + if( str == NULL ) { + mwIncErr(); + mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", + mwCounter, file, line ); + FLUSH(); + return NULL; + } + len = strlen( str ) + 1; + newstring = (char*) mwMalloc( len, file, line ); + if( newstring != NULL ) memcpy( newstring, str, len ); + return newstring; + } + +void mwFree( void* p, const char* file, int line ) { + int i; + mwData* mw; + char buffer[ sizeof(mwData) + sizeof(long) + 64 ]; + + TESTS(file,line); + + /* this code is in support of C++ delete */ + if( file == NULL ) { + mwFree_( p ); + return; + } + + mwAutoInit(); + mwCounter ++; + + /* on NULL free, write a warning and return */ + if( p == NULL ) { + mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", + mwCounter, file, line ); + FLUSH(); + return; + } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + (void) mwTestBuf( mw, file, line ); + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* update the statistics */ + mwNumCurAlloc --; + mwStatCurAlloc -= (long) mw->size; + if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); + + /* we should either free the allocation or keep it as NML */ + if( mwNML ) { + mw->flag |= MW_NML; + mwNmlNumAlloc ++; + mwNmlCurAlloc += (long) mw->size; + memset( (char*)(mw+1)+sizeof(long), MW_VAL_NML, mw->size ); + } + else { + /* unlink the allocation, and enter the post-free data */ + mwUnlink( mw, file, line ); + memset( mw, MW_VAL_DEL, + mw->size + sizeof(mwData)+sizeof(long)+sizeof(long) ); + if( mwFBI ) { + memset( mw, '.', sizeof(mwData) + sizeof(long) ); + sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); + strncpy( (char*)(void*)mw, buffer, sizeof(mwData) + sizeof(long) ); + } + free( mw ); + } + + /* add the pointer to the last-free track */ + mwLFfile[ mwLFcur ] = file; + mwLFline[ mwLFcur ] = line; + mwLastFree[ mwLFcur++ ] = p; + if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; + + return; + } + + /* check for double-freeing */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return; + } + } + + /* some weird pointer... block the free */ + mwIncErr(); + mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return; + } + +void* mwCalloc( size_t a, size_t b, const char *file, int line ) { + void *p; + size_t size = a * b; + p = mwMalloc( size, file, line ); + if( p == NULL ) return NULL; + memset( p, 0, size ); + return p; + } + +void mwFree_( void *p ) { + TESTS(NULL,0); + free(p); + } + +void* mwMalloc_( size_t size ) { + TESTS(NULL,0); + return malloc( size ); + } + +void* mwRealloc_( void *p, size_t size ) { + TESTS(NULL,0); + return realloc( p, size ); + } + +void* mwCalloc_( size_t a, size_t b ) { + TESTS(NULL,0); + return calloc( a, b ); + } + +void mwFlushNow( void ) { + if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwDoFlush( int onoff ) { + mwFlushW( onoff<1?0:onoff ); + if( onoff ) if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwLimit( long lim ) { + TESTS(NULL,0); + mwWrite("limit: old limit = "); + if( !mwAllocLimit ) mwWrite( "none" ); + else mwWrite( "%ld bytes", mwAllocLimit ); + mwWrite( ", new limit = "); + if( !lim ) { + mwWrite( "none\n" ); + mwUseLimit = 0; + } + else { + mwWrite( "%ld bytes\n", lim ); + mwUseLimit = 1; + } + mwAllocLimit = lim; + FLUSH(); + } + +void mwSetAriAction( int action ) { + TESTS(NULL,0); + mwAriAction = action; + return; + } + +int mwAssert( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + switch( i ) { + case MW_ARI_IGNORE: + mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + case MW_ARI_RETRY: + mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); + } + + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +int mwVerify( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + if( i == 0 ) { + mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + } + if( i == 1 ) { + mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); + } + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +void mwTrace( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + + mwAutoInit(); + TESTS(NULL,0); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + + FLUSH(); + } + + +/*********************************************************************** +** Grab & Drop +***********************************************************************/ + +unsigned mwGrab( unsigned kb ) { + TESTS(NULL,0); + return mwGrab_( kb, MW_VAL_GRB, 0 ); + } + +unsigned mwDrop( unsigned kb ) { + TESTS(NULL,0); + return mwDrop_( kb, MW_VAL_GRB, 0 ); + } + +static void mwDropAll() { + TESTS(NULL,0); + (void) mwDrop_( 0, MW_VAL_GRB, 0 ); + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + if( mwGrabList != NULL ) + mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); + } + +static const char *mwGrabType( int type ) { + switch( type ) { + case MW_VAL_GRB: + return "grabbed"; + case MW_VAL_NML: + return "no-mans-land"; + default: + /* do nothing */ + ; + } + return ""; + } + +static unsigned mwGrab_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd; + if( !kb ) i = kb = 65000U; + + for(;kb;kb--) { + if( mwUseLimit && + (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { + if( !silent ) { + mwWrite("grabbed: all allowed memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); + if( gd == NULL ) { + if( !silent ) { + mwWrite("grabbed: all available memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + mwGrabSize += (long) sizeof(mwGrabData); + gd->next = mwGrabList; + memset( gd->blob, type, sizeof(gd->blob) ); + gd->type = type; + mwGrabList = gd; + } + if( !silent ) { + mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +static unsigned mwDrop_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd,*tmp,*pr; + const void *p; + + if( mwGrabList == NULL && kb == 0 ) return 0; + if( !kb ) i = kb = 60000U; + + pr = NULL; + gd = mwGrabList; + for(;kb;) { + if( gd == NULL ) { + if( i-kb > 0 && !silent ) { + mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + if( gd->type == type ) { + if( pr ) pr->next = gd->next; + kb --; + tmp = gd; + if( mwGrabList == gd ) mwGrabList = gd->next; + gd = gd->next; + p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); + if( p != NULL ) { + mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", + mwCounter, mwGrabType(type), p ); + FLUSH(); + } + mwGrabSize -= (long) sizeof(mwGrabData); + free( tmp ); + } + else { + pr = gd; + gd = gd->next; + } + } + if( !silent ) { + mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +/*********************************************************************** +** No-Mans-Land +***********************************************************************/ + +void mwNoMansLand( int level ) { + mwAutoInit(); + TESTS(NULL,0); + switch( level ) { + case MW_NML_NONE: + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + break; + case MW_NML_FREE: + break; + case MW_NML_ALL: + (void) mwGrab_( 0, MW_VAL_NML, 0 ); + break; + default: + return; + } + mwNML = level; + } + +/*********************************************************************** +** Static functions +***********************************************************************/ + +static void mwAutoInit( void ) +{ + if( mwInited ) return; + mwUseAtexit = 1; + mwInit(); + return; +} + +static FILE *mwLogR() { + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; + if( mwLog == mwLogB1 ) mwLogB2 = mwLog; + if( mwLog == mwLogB2 ) mwLogB1 = mwLog; + if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { + mwWrite("internal: log file handle damaged and recovered\n"); + FLUSH(); + return mwLog; + } + fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); + mwLog = mwLogB1 = mwLogB2 = mwSTDERR; + return mwSTDERR; + } + +static void mwLogW( FILE *p ) { + mwLog = mwLogB1 = mwLogB2 = p; + } + +static int mwFlushR() { + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; + if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; + if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; + if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { + mwWrite("internal: flushing flag damaged and recovered\n"); + FLUSH(); + return mwFlushing; + } + mwWrite("internal: flushing flag destroyed, so set to true\n"); + mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; + return 1; + } + +static void mwFlushW( int n ) { + mwFlushing = mwFlushingB1 = mwFlushingB2 = n; + } + +static void mwIncErr() { + mwErrors++; + mwFlushW( mwFlushR()+1 ); + FLUSH(); + } + +static void mwFlush() { + if( mwLogR() == NULL ) return; +#ifdef MW_FLUSH + fflush( mwLogR() ); +#else + if( mwFlushR() ) fflush( mwLogR() ); +#endif + return; + } + +static void mwUnlink( mwData* mw, const char* file, int line ) { + if( mw->prev == NULL ) { + if( mwHead != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", + mwCounter, file, line, mw ); + mwHead = mw->next; + } + else { + if( mw->prev->next != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", + mwCounter, file, line, mw ); + else mw->prev->next = mw->next; + } + if( mw->next == NULL ) { + if( mwTail != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", + mwCounter, file, line, mw ); + mwTail = mw->prev; + } + else { + if( mw->next->prev != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", + mwCounter, file, line, mw ); + else mw->next->prev = mw->prev; + } + } + +/* +** Relinking tries to repair a damaged mw block. +** Returns nonzero if it thinks it successfully +** repaired the heap chain. +*/ +static int mwRelink( mwData* mw, const char* file, int line ) { + int fails; + mwData *mw1, *mw2; + long count, size; + mwStat *ms; + + if( file == NULL ) file = "unknown"; + + if( mw == NULL ) { + mwWrite("relink: cannot repair MW at NULL\n"); + FLUSH(); + goto emergency; + } + + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + mwWrite("relink: MW-%p is a garbage pointer\n"); + FLUSH(); + goto emergency; + } + + mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); + FLUSH(); + fails = 0; + + /* Repair from head */ + if( mwHead != mw ) { + if( !mwIsSafeAddr( mwHead, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwHead; mw1; mw1=mw1->next ) { + if( mw1->next == mw ) { + mw->prev = mw1; + break; + } + if( mw1->next && + ( !mwIsSafeAddr(mw1->next, sizeof(mwData)) || mw1->next->prev != mw1) ) { + mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in forward chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); + if( mw->prev != NULL ) + { + mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); + mw->prev = NULL; + } + } + + /* Repair from tail */ + if( mwTail != mw ) { + if( !mwIsSafeAddr( mwTail, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwTail; mw1; mw1=mw1->prev ) { + if( mw1->prev == mw ) { + mw->next = mw1; + break; + } + if( mw1->prev && (!mwIsSafeAddr(mw1->prev, sizeof(mwData)) || mw1->prev->next != mw1) ) { + mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); + if( mw->next != NULL ) + { + mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); + mw->next = NULL; + } + } + + if( fails > 1 ) { + mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); + FLUSH(); + goto verifyok; + } + + /* restore MW info where possible */ + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + mw->check = CHKVAL(mw); + goto verifyok; + + /* Emergency repair */ + emergency: + + if( mwHead == NULL && mwTail == NULL ) + { + if( mwStatCurAlloc == 0 ) + mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); + else + mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); + FLUSH(); + return 0; + } + + mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); + FLUSH(); + + if( mwHead == NULL || mwTail == NULL ) + { + if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); + else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); + } + + mw1=NULL; + if( mwHead != NULL ) + { + if( !mwIsReadAddr(mwHead,sizeof(mwData)) || mwHead->check != CHKVAL(mwHead) ) + { + mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); + mwHead = NULL; + goto scan_reverse; + } + if( mwHead->prev != NULL ) + { + mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); + } + for( mw1=mwHead; mw1; mw1=mw1->next ) + { + if( mw1->next ) + { + if( !mwIsReadAddr(mw1->next,sizeof(mwData)) || + !mw1->next->check != CHKVAL(mw1) || + mw1->next->prev != mw1 ) + { + mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); + if( mwIsReadAddr(mw1->next,sizeof(mwData) ) ) + { + mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw1->file,16)?mw1->file:"", mw1->line ); + } + else + { + mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", + mw1->next ); + } + break; + } + } + } + } + + +scan_reverse: + mw2=NULL; + if( mwTail != NULL ) + { + if( !mwIsReadAddr(mwTail,sizeof(mwData)) || mwTail->check != CHKVAL(mwTail) ) + { + mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); + mwTail = NULL; + goto analyze; + } + if( mwTail->next != NULL ) + { + mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); + } + for( mw2=mwTail; mw2; mw2=mw2->prev ) + { + if( mw2->prev ) + { + if( !mwIsReadAddr(mw2->prev,sizeof(mwData)) || + !mw2->prev->check != CHKVAL(mw2) || + mw2->prev->next != mw2 ) + { + mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); + if( mwIsReadAddr(mw2->prev,sizeof(mwData) ) ) + { + mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw2->file,16)?mw2->file:"", mw2->line ); + } + else + { + mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", + mw2->prev ); + } + break; + } + } + } + } + +analyze: + if( mwHead == NULL && mwTail == NULL ) + { + mwWrite("relink: both head and tail pointers damaged, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + if( mwHead == NULL ) + { + mwHead = mw2; + mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); + mw2->prev = NULL; + mw1 = mw2 = NULL; + } + if( mwTail == NULL ) + { + mwTail = mw1; + mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); + mw1->next = NULL; + mw1 = mw2 = NULL; + } + if( mw1 == NULL && mw2 == NULL && + mwHead->prev == NULL && mwTail->next == NULL ) { + mwWrite("relink: verifying heap integrity...\n" ); + FLUSH(); + goto verifyok; + } + if( mw1 && mw2 && mw1 != mw2 ) { + mw1->next = mw2; + mw2->prev = mw1; + mwWrite("relink: emergency repairs successful, assessing damage...\n"); + FLUSH(); + } + else { + mwWrite("relink: heap totally destroyed, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + + /* Verify by checking that the number of active allocations */ + /* match the number of entries in the chain */ +verifyok: + if( !mwIsHeapOK( NULL ) ) { + mwWrite("relink: heap verification FAILS - aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { + count ++; + size += (long) mw1->size; + } + if( count == mwNumCurAlloc ) { + mwWrite("relink: successful, "); + if( size == mwStatCurAlloc ) { + mwWrite("no allocations lost\n"); + } + else { + if( mw != NULL ) { + mwWrite("size information lost for MW-%p\n", mw); + mw->size = 0; + } + } + } + else { + mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", + mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); + return 0; + } + + return 1; + } + +/* +** If mwData* is NULL: +** Returns 0 if heap chain is broken. +** Returns 1 if heap chain is intact. +** If mwData* is not NULL: +** Returns 0 if mwData* is missing or if chain is broken. +** Returns 1 if chain is intact and mwData* is found. +*/ +static int mwIsHeapOK( mwData *includes_mw ) { + int found = 0; + mwData *mw; + + for( mw = mwHead; mw; mw=mw->next ) { + if( includes_mw == mw ) found++; + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + if( mw->prev ) { + if( !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) return 0; + if( mw==mwHead || mw->prev->next != mw ) return 0; + } + if( mw->next ) { + if( !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) return 0; + if( mw==mwTail || mw->next->prev != mw ) return 0; + } + else if( mw!=mwTail ) return 0; + } + + if( includes_mw != NULL && !found ) return 0; + + return 1; + } + +static int mwIsOwned( mwData* mw, const char *file, int line ) { + int retv; + mwStat *ms; + + /* see if the address is legal according to OS */ + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + + /* make sure we have _anything_ allocated */ + if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) + return 0; + + /* calculate checksum */ + if( mw->check != CHKVAL(mw) ) { + /* may be damaged checksum, see if block is in heap */ + if( mwIsHeapOK( mw ) ) { + /* damaged checksum, repair it */ + mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", + mwCounter, file, line, mw ); + mwIncErr(); + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + else mw->file = ""; + mw->check = CHKVAL(mw); + return 1; + } + /* no, it's just some garbage data */ + return 0; + } + + /* check that the non-NULL pointers are safe */ + if( mw->prev && !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) mwRelink( mw, file, line ); + if( mw->next && !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) mwRelink( mw, file, line ); + + /* safe address, checksum OK, proceed with heap checks */ + + /* see if the block is in the heap */ + retv = 0; + if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } + else { if( mwHead == mw ) retv++; } + if( mw->next ) { if( mw->next->prev == mw ) retv ++; } + else { if( mwTail == mw ) retv++; } + if( mw->check == CHKVAL(mw) ) retv ++; + if( retv > 2 ) return 1; + + /* block not in heap, check heap for corruption */ + + if( !mwIsHeapOK( mw ) ) { + if( mwRelink( mw, file, line ) ) + return 1; + } + + /* unable to repair */ + mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", + mwCounter, file, line, mw ); + mwIncErr(); + + return 0; + } + +/* +** mwTestBuf: +** Checks a buffers links and pre/postfixes. +** Writes errors found to the log. +** Returns zero if no errors found. +*/ +static int mwTestBuf( mwData* mw, const char* file, int line ) { + int retv = 0; + char *p; + long chk; + + if( file == NULL ) file = "unknown"; + + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) { + mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", + mwCounter, file, line, mw ); + mwIncErr(); + return 2; + } + + if( mw->check != CHKVAL(mw) ) { + mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", + mwCounter, file, line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) return 2; + } + + if( mw->prev && mw->prev->next != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + if( mw->next && mw->next->prev != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + + p = (char*)(mw+1); + GETDWORD( chk, p ); + if( chk != PRECHK ) { + mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + p += mw->size + sizeof(long); + GETDWORD( chk, p ); + if( chk != POSTCHK ) { + mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + + return retv; + } + +static void mwDefaultOutFunc( int c ) { + if( mwLogR() ) fputc( c, mwLogR() ); + } + +static void mwWrite( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + mwAutoInit(); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); + FLUSH(); + } + return; + } + +static void mwLogFile( const char *name ) { + time_t tid; + (void) time( &tid ); + if( mwLogR() != NULL ) { + fclose( mwLogR() ); + mwLogW( NULL ); + } + if( name == NULL ) return; + mwLogW( fopen( name, "a" COMMIT ) ); + if( mwLogR() == NULL ) + mwWrite( "logfile: failed to open/create file '%s'\n", name ); + } + +/* +** Try to free NML memory until a contiguous allocation of +** 'needed' bytes can be satisfied. If this is not enough +** and the 'urgent' parameter is nonzero, grabbed memory is +** also freed. +*/ +static size_t mwFreeUp( size_t needed, int urgent ) { + void *p; + mwData *mw, *mw2; + char *data; + + /* free grabbed NML memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + /* free normal NML memory */ + mw = mwHead; + while( mw != NULL ) { + if( !(mw->flag & MW_NML) ) mw = mw->next; + else { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + mw2 = mw->next; + mwUnlink( mw, "mwFreeUp", 0 ); + free( mw ); + mw = mw2; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + } + + /* if not urgent (for internal purposes), fail */ + if( !urgent ) return 0; + + /* free grabbed memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + return 0; + } + +static const void * mwTestMem( const void *p, unsigned len, int c ) { + const unsigned char *ptr; + ptr = (const unsigned char *) p; + while( len-- ) { + if( *ptr != (unsigned char)c ) return (const void*)ptr; + ptr ++; + } + return NULL; + } + +static int mwStrCmpI( const char *s1, const char *s2 ) { + if( s1 == NULL || s2 == NULL ) return 0; + while( *s1 ) { + if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } + return 1; + } + return 0; + } + +#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; } + +static int mwTestNow( const char *file, int line, int always_invoked ) { + int retv = 0; + mwData *mw; + char *data; + + if( file && !always_invoked ) + mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", + mwCounter, file, line, + (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", + (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", + (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" + ); + + if( mwTestFlags & MW_TEST_CHAIN ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw->prev ) { + if( !mwIsSafeAddr(mw->prev, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwHead || mw->prev->next != mw ) { + AIPH(); + mwWrite("check: heap chain broken, prev link incorrect\n"); + mwIncErr(); + retv ++; + } + } + if( mw->next ) { + if( !mwIsSafeAddr(mw->next, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwTail || mw->next->prev != mw ) { + AIPH(); + mwWrite("check: heap chain broken, next link incorrect\n"); + mwIncErr(); + retv ++; + } + } + else if( mw!=mwTail ) { + AIPH(); + mwWrite("check: heap chain broken, tail incorrect\n"); + mwIncErr(); + retv ++; + } + } + } + if( mwTestFlags & MW_TEST_ALLOC ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( mwTestBuf( mw, file, line ) ) retv ++; + } + } + if( mwTestFlags & MW_TEST_NML ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( (mw->flag & MW_NML) ) { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + } + } + } + + + if( file && !always_invoked && !retv ) + mwWrite("check: <%ld> %s(%d), complete; no errors\n", + mwCounter, file, line ); + return retv; + } + +/********************************************************************** +** Statistics +**********************************************************************/ + +static void mwStatReport() +{ + mwStat* ms, *ms2; + const char *modname; + int modnamelen; + + /* global statistics report */ + mwWrite( "\nMemory usage statistics (global):\n" ); + mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc ); + mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc ); + mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc ); + mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc ); + FLUSH(); + + if( mwStatLevel < 1 ) return; + + /* on a per-module basis */ + mwWrite( "\nMemory usage statistics (detailed):\n"); + mwWrite( " Module/Line Number Largest Total Unfreed \n"); + for( ms=mwStatList; ms; ms=ms->next ) + { + if( ms->line == -1 ) + { + if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = ""; + else modname = ms->file; + modnamelen = strlen(modname); + if( modnamelen > 42 ) + { + modname = modname + modnamelen - 42; + } + + mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n", + modname, ms->num, ms->max, ms->total, ms->curr ); + if( ms->file && mwStatLevel > 1 ) + { + for( ms2=mwStatList; ms2; ms2=ms2->next ) + { + if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) ) + { + mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n", + ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr ); + } + } + } + } + } +} + +static mwStat* mwStatGet( const char *file, int line, int makenew ) { + mwStat* ms; + + if( mwStatLevel < 2 ) line = -1; + + for( ms=mwStatList; ms!=NULL; ms=ms->next ) { + if( line != ms->line ) continue; + if( file==NULL ) { + if( ms->file == NULL ) break; + continue; + } + if( ms->file == NULL ) continue; + if( !strcmp( ms->file, file ) ) break; + } + + if( ms != NULL ) return ms; + + if( !makenew ) return NULL; + + ms = (mwStat*) malloc( sizeof(mwStat) ); + if( ms == NULL ) { + if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) || + (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) { + mwWrite("internal: memory low, statistics incomplete for '%s'\n", file ); + return NULL; + } + } + ms->file = file; + ms->line = line; + ms->total = 0L; + ms->max = 0L; + ms->num = 0L; + ms->curr = 0L; + ms->next = mwStatList; + mwStatList = ms; + return ms; + } + +static void mwStatAlloc( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + } + + } + +static void mwStatFree( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + } + } + +#if 0 /* 980317: disabled C++ */ + +/********************************************************************** +** C++ new & delete +**********************************************************************/ + +#ifdef __cplusplus +#ifndef MEMWATCH_NOCPP + +int mwNCur = 0; +const char *mwNFile = NULL; +int mwNLine = 0; + +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; + +MemWatch::MemWatch() { + if( mwInited ) return; + mwUseAtexit = 0; + mwInit(); + } + +MemWatch::~MemWatch() { + if( mwUseAtexit ) return; + mwTerm(); + } + +/* +** This global new will catch all 'new' calls where MEMWATCH is +** not active. +*/ +void* operator new( unsigned size ) { + mwNCur = 0; + return mwMalloc( size, "", 0 ); + } + +/* +** This is the new operator that's called when a module uses mwNew. +*/ +void* operator new( unsigned size, const char *file, int line ) { + mwNCur = 0; + return mwMalloc( size, file, line ); + } + +/* +** Since this delete operator will recieve ALL delete's +** even those from within libraries, we must accept +** delete's before we've been initialized. Nor can we +** reliably check for wild free's if the mwNCur variable +** is not set. +*/ +void operator delete( void *p ) { + if( p == NULL ) return; + if( !mwInited ) { + free( p ); + return; + } + if( mwNCur ) { + mwFree( p, mwNFile, mwNLine ); + mwNCur = 0; + return; + } + mwFree_( p ); + } + +#endif /* MEMWATCH_NOCPP */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +#endif /* MEMWATCH.C */ diff --git a/lib/memwatch.c.org b/lib/memwatch.c.org new file mode 100644 index 00000000..4540127e --- /dev/null +++ b/lib/memwatch.c.org @@ -0,0 +1,2360 @@ +/* +** MEMWATCH.C +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +*/ + +#define __MEMWATCH_C 1 + +#ifdef MW_NOCPP +#define MEMWATCH_NOCPP +#endif +#ifdef MW_STDIO +#define MEMWATCH_STDIO +#endif + +/*********************************************************************** +** Include files +***********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "memwatch.h" + +#ifndef toupper +#include +#endif + +/*********************************************************************** +** Defines & other weird stuff +***********************************************************************/ + +/*lint -save -e767 */ +#define VERSION "2.62" /* the current version number */ +#define CHKVAL(mw) (0xFE0180L^(long)mw->count^(long)mw->size^(long)mw->line) +#define FLUSH() mwFlush() +#define TESTS(f,l) if(mwTestAlways) (void)mwTestNow(f,l,1) +#define PRECHK 0x01234567L +#define POSTCHK 0x76543210L +/*lint -restore */ + +#define MW_NML 0x0001 + +#ifdef _MSC_VER +#define COMMIT "c" /* Microsoft C requires the 'c' to perform as desired */ +#else +#define COMMIT "" /* Normal ANSI */ +#endif /* _MSC_VER */ + +#ifdef __cplusplus +#define CPPTEXT "++" +#else +#define CPPTEXT "" +#endif /* __cplusplus */ + +#ifdef MEMWATCH_STDIO +#define mwSTDERR stderr +#else +#define mwSTDERR mwLog +#endif + +/*********************************************************************** +** Defines to read/write 32 bit words in a portable way +** Note: Assumes that a 'long int' is 32 bits, and a 'char' is 8 bits. +***********************************************************************/ + +typedef unsigned char mwBYTE; +typedef unsigned long mwDWORD; + +#define GETDWORD(l, cp) { \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + (l) = ((mwDWORD)t_cp[0] << 24) \ + | ((mwDWORD)t_cp[1] << 16) \ + | ((mwDWORD)t_cp[2] << 8) \ + | ((mwDWORD)t_cp[3]) \ + ; \ +} + +#define PUTDWORD(l, cp) { \ + register mwDWORD t_l = (mwDWORD)(l); \ + register mwBYTE *t_cp = (mwBYTE *)(cp); \ + *t_cp++ = (mwBYTE)(t_l >> 24); \ + *t_cp++ = (mwBYTE)(t_l >> 16); \ + *t_cp++ = (mwBYTE)(t_l >> 8); \ + *t_cp = (mwBYTE)t_l; \ +} + +/*********************************************************************** +** Typedefs & structures +***********************************************************************/ + +/* main data holding area, precedes actual allocation */ +typedef struct mwData_ mwData; +struct mwData_ { + mwData* prev; /* previous allocation in chain */ + mwData* next; /* next allocation in chain */ + const char* file; /* file name where allocated */ + long count; /* action count */ + long check; /* integrity check value */ +#if 0 + long crc; /* data crc value */ +#endif + size_t size; /* size of allocation */ + int line; /* line number where allocated */ + unsigned flag; /* flag word */ + }; + +/* statistics structure */ +typedef struct mwStat_ mwStat; +struct mwStat_ { + mwStat* next; /* next statistic buffer */ + const char* file; + long total; /* total bytes allocated */ + long num; /* total number of allocations */ + long max; /* max allocated at one time */ + long curr; /* current allocations */ + int line; + }; + +/* grabbing structure, 1K in size */ +typedef struct mwGrabData_ mwGrabData; +struct mwGrabData_ { + mwGrabData* next; + int type; + char blob[ 1024 - sizeof(mwGrabData*) - sizeof(int) ]; + }; + +typedef struct mwMarker_ mwMarker; +struct mwMarker_ { + void *host; + char *text; + mwMarker *next; + int level; + }; + +/*********************************************************************** +** Static variables +***********************************************************************/ + +static int mwInited = 0; +static int mwInfoWritten = 0; +static int mwUseAtexit = 0; +static FILE* mwLog = NULL; +static int mwFlushing = 0; +static int mwStatLevel = MW_STAT_DEFAULT; +static int mwNML = MW_NML_DEFAULT; +static int mwFBI = 0; +static long mwAllocLimit = 0L; +static int mwUseLimit = 0; + +static long mwNumCurAlloc = 0L; +static mwData* mwHead = NULL; +static mwData* mwTail = NULL; + +static void (*mwOutFunction)(int) = NULL; +static int (*mwAriFunction)(const char*) = NULL; +static int mwAriAction = MW_ARI_ABORT; + +static char mwPrintBuf[MW_TRACE_BUFFER+8]; + +static unsigned long mwCounter = 0L; +static long mwErrors = 0L; + +static int mwTestFlags = 0; +static int mwTestAlways = 0; + +static FILE* mwLogB1 = NULL; +static int mwFlushingB1 = 0; + +static mwStat* mwStatList = NULL; +static long mwStatTotAlloc = 0L; +static long mwStatMaxAlloc = 0L; +static long mwStatNumAlloc = 0L; +static long mwStatCurAlloc = 0L; +static long mwNmlNumAlloc = 0L; +static long mwNmlCurAlloc = 0L; + +static mwGrabData* mwGrabList = NULL; +static long mwGrabSize = 0L; + +static void * mwLastFree[MW_FREE_LIST]; +static const char *mwLFfile[MW_FREE_LIST]; +static int mwLFline[MW_FREE_LIST]; +static int mwLFcur = 0; + +static mwMarker* mwFirstMark = NULL; + +static FILE* mwLogB2 = NULL; +static int mwFlushingB2 = 0; + +/*********************************************************************** +** Static function declarations +***********************************************************************/ + +static void mwAutoInit( void ); +static FILE* mwLogR( void ); +static void mwLogW( FILE* ); +static int mwFlushR( void ); +static void mwFlushW( int ); +static void mwFlush( void ); +static void mwIncErr( void ); +static void mwUnlink( mwData*, const char* file, int line ); +static int mwRelink( mwData*, const char* file, int line ); +static int mwIsHeapOK( mwData *mw ); +static int mwIsOwned( mwData* mw, const char* file, int line ); +static int mwTestBuf( mwData* mw, const char* file, int line ); +static void mwDefaultOutFunc( int ); +static void mwWrite( const char* format, ... ); +static void mwLogFile( const char* name ); +static size_t mwFreeUp( size_t, int ); +static const void *mwTestMem( const void *, unsigned, int ); +static int mwStrCmpI( const char *s1, const char *s2 ); +static int mwTestNow( const char *file, int line, int always_invoked ); +static void mwDropAll( void ); +static const char *mwGrabType( int type ); +static unsigned mwGrab_( unsigned kb, int type, int silent ); +static unsigned mwDrop_( unsigned kb, int type, int silent ); +static int mwARI( const char* text ); +static void mwStatReport( void ); +static mwStat* mwStatGet( const char*, int, int ); +static void mwStatAlloc( size_t, const char*, int ); +static void mwStatFree( size_t, const char*, int ); + +/*********************************************************************** +** System functions +***********************************************************************/ + +void mwInit( void ) { + time_t tid; + + if( mwInited++ > 0 ) return; + + /* start a log if none is running */ + if( mwLogR() == NULL ) mwLogFile( "memwatch.log" ); + if( mwLogR() == NULL ) { + int i; + char buf[32]; + /* oops, could not open it! */ + /* probably because it's already open */ + /* so we try some other names */ + for( i=1; i<100; i++ ) { + sprintf( buf, "memwat%02d.log", i ); + mwLogFile( buf ); + if( mwLogR() != NULL ) break; + } + } + + /* initialize the statistics */ + mwStatList = NULL; + mwStatTotAlloc = 0L; + mwStatCurAlloc = 0L; + mwStatMaxAlloc = 0L; + mwStatNumAlloc = 0L; + mwNmlCurAlloc = 0L; + mwNmlNumAlloc = 0L; + + /* write informational header if needed */ + if( !mwInfoWritten ) { + mwInfoWritten = 1; + (void) time( &tid ); + mwWrite( + "\n=============" + " MEMWATCH " VERSION " Copyright (C) 1992-1999 Johan Lindh " + "=============\n"); + mwWrite( "\nStarted at %s\n", ctime( &tid ) ); + +/**************************************************************** Generic */ +#ifdef mwNew + mwWrite( "C++ new/delete tracking enabled\n" ); +#endif /* mwNew */ +#ifdef __STDC__ + mwWrite( "Compiled as standard ANSI C\n" ); +#endif /* __STDC__ */ +/**************************************************************** Generic */ + +/************************************************************ Microsoft C */ +#ifdef _MSC_VER + mwWrite( "Compiled using Microsoft C" CPPTEXT + " %d.%02d\n", _MSC_VER / 100, _MSC_VER % 100 ); +#endif /* _MSC_VER */ +/************************************************************ Microsoft C */ + +/************************************************************** Borland C */ +#ifdef __BORLANDC__ + mwWrite( "Compiled using Borland C" +#ifdef __cplusplus + "++ %d.%01d\n", __BCPLUSPLUS__/0x100, (__BCPLUSPLUS__%0x100)/0x10 ); +#else + " %d.%01d\n", __BORLANDC__/0x100, (__BORLANDC__%0x100)/0x10 ); +#endif /* __cplusplus */ +#endif /* __BORLANDC__ */ +/************************************************************** Borland C */ + +/************************************************************** Watcom C */ +#ifdef __WATCOMC__ + mwWrite( "Compiled using Watcom C %d.%02d ", + __WATCOMC__/100, __WATCOMC__%100 ); +#ifdef __FLAT__ + mwWrite( "(32-bit flat model)" ); +#endif /* __FLAT__ */ + mwWrite( "\n" ); +#endif /* __WATCOMC__ */ +/************************************************************** Watcom C */ + + mwWrite( "\n" ); + FLUSH(); + } + + if( mwUseAtexit ) (void) atexit( mwAbort ); + return; + } + +void mwAbort( void ) { + mwData *mw; + mwMarker *mrk; + char *data; + time_t tid; + int c, i, j; + int errors; + long chk; + + tid = time( NULL ); + mwWrite( "\nStopped at %s\n", ctime( &tid) ); + + if( !mwInited ) + mwWrite( "internal: mwAbort(): MEMWATCH not initialized!\n" ); + + /* release the grab list */ + mwDropAll(); + + /* report mwMarked items */ + while( mwFirstMark ) { + mrk = mwFirstMark->next; + mwWrite( "mark: %p: %s\n", mwFirstMark->host, mwFirstMark->text ); + free( mwFirstMark->text ); + free( mwFirstMark ); + mwFirstMark = mrk; + mwErrors ++; + } + + /* release all still allocated memory */ + errors = 0; + while( mwHead != NULL && errors < 3 ) { + if( !mwIsOwned(mwHead, __FILE__, __LINE__ ) ) { + if( errors < 3 ) + { + errors ++; + mwWrite( "internal: NML/unfreed scan restarting\n" ); + FLUSH(); + mwHead = mwHead; + continue; + } + mwWrite( "internal: NML/unfreed scan aborted, heap too damaged\n" ); + FLUSH(); + break; + } + mwFlushW(0); + if( !(mwHead->flag & MW_NML) ) { + mwErrors++; + data = ((char*)(mwHead+1)); + mwWrite( "unfreed: <%ld> %s(%d), %ld bytes at %p ", + mwHead->count, mwHead->file, mwHead->line, (long)mwHead->size, data+sizeof(long) ); + GETDWORD( chk, data ); + if( chk != PRECHK ) { + mwWrite( "[underflowed] "); + FLUSH(); + } + GETDWORD( chk, (data+sizeof(long)+mwHead->size) ); + if( chk != POSTCHK ) { + mwWrite( "[overflowed] "); + FLUSH(); + } + mwWrite( " \t{" ); + j = 16; if( mwHead->size < 16 ) j = (int) mwHead->size; + for( i=0;i<16;i++ ) { + if( i 126 ) c = '.'; + mwWrite( "%c", c ); + } + mwWrite( "}\n" ); + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + else { + data = ((char*)(mwHead+1)) + sizeof(long); + if( mwTestMem( data, mwHead->size, MW_VAL_NML ) ) { + mwErrors++; + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mwHead->count, data + sizeof(long), mwHead->file, mwHead->line ); + FLUSH(); + } + mwNmlNumAlloc --; + mwNmlCurAlloc -= mwHead->size; + mw = mwHead; + mwUnlink( mw, __FILE__, __LINE__ ); + free( mw ); + } + } + + if( mwNmlNumAlloc ) mwWrite("internal: NoMansLand block counter %ld, not zero\n", mwNmlNumAlloc ); + if( mwNmlCurAlloc ) mwWrite("internal: NoMansLand byte counter %ld, not zero\n", mwNmlCurAlloc ); + + /* report statistics */ + mwStatReport(); + FLUSH(); + + mwInited = 0; + mwHead = mwTail = NULL; + if( mwErrors ) + fprintf(mwSTDERR,"MEMWATCH detected %ld anomalies\n",mwErrors); + mwLogFile( NULL ); + mwErrors = 0; + } + +void mwTerm( void ) { + if( mwInited == 1 ) + { + mwAbort(); + return; + } + if( !mwInited ) + mwWrite("internal: mwTerm(): MEMWATCH has not been started!\n"); + else + mwInited --; + } + +void mwStatistics( int level ) +{ + mwAutoInit(); + if( level<0 ) level=0; + if( mwStatLevel != level ) + { + mwWrite( "statistics: now collecting on a %s basis\n", + level<1?"global":(level<2?"module":"line") ); + mwStatLevel = level; + } +} + +void mwAutoCheck( int onoff ) { + mwAutoInit(); + mwTestAlways = onoff; + if( onoff ) mwTestFlags = MW_TEST_ALL; + } + +void mwSetOutFunc( void (*func)(int) ) { + mwAutoInit(); + mwOutFunction = func; + } + +int mwTest( const char *file, int line, int items ) { + mwAutoInit(); + mwTestFlags = items; + return mwTestNow( file, line, 0 ); + } + +/* +** Returns zero if there are no errors. +** Returns nonzero if there are errors. +*/ +int mwTestBuffer( const char *file, int line, void *p ) { + mwData* mw; + + mwAutoInit(); + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + return mwTestBuf( mw, file, line ); + } + return 1; + } + +void mwBreakOut( const char* cause ) { + fprintf(mwSTDERR, "breakout: %s\n", cause); + mwWrite("breakout: %s\n", cause ); + return; + } + +/* +** 981217 JLI: is it possible that ->next is not always set? +*/ +void * mwMark( void *p, const char *desc, const char *file, unsigned line ) { + mwMarker *mrk; + unsigned n, isnew; + char *buf; + int tot, oflow = 0; + char wherebuf[128]; + + mwAutoInit(); + TESTS(NULL,0); + + if( desc == NULL ) desc = "unknown"; + if( file == NULL ) file = "unknown"; + + tot = sprintf( wherebuf, "%.48s called from %s(%d)", desc, file, line ); + if( tot >= (int)sizeof(wherebuf) ) { wherebuf[sizeof(wherebuf)-1] = 0; oflow = 1; } + + if( p == NULL ) { + mwWrite("mark: %s(%d), no mark for NULL:'%s' may be set\n", file, line, desc ); + return p; + } + + if( mwFirstMark != NULL && !mwIsReadAddr( mwFirstMark, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mwFirstMark (%p) is trashed, can't mark for %s\n", + file, line, mwFirstMark, desc ); + return p; + } + + for( mrk=mwFirstMark; mrk; mrk=mrk->next ) + { + if( mrk->next != NULL && !mwIsReadAddr( mrk->next, sizeof( mwMarker ) ) ) + { + mwWrite("mark: %s(%d), mark(%p)->next(%p) is trashed, can't mark for %s\n", + file, line, mrk, mrk->next, desc ); + return p; + } + if( mrk->host == p ) break; + } + + if( mrk == NULL ) { + isnew = 1; + mrk = (mwMarker*) malloc( sizeof( mwMarker ) ); + if( mrk == NULL ) { + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + mrk->next = NULL; + n = 0; + } + else { + isnew = 0; + n = strlen( mrk->text ); + } + + n += strlen( wherebuf ); + buf = (char*) malloc( n+3 ); + if( buf == NULL ) { + if( isnew ) free( mrk ); + mwWrite("mark: %s(%d), no mark for %p:'%s', out of memory\n", file, line, p, desc ); + return p; + } + + if( isnew ) { + memcpy( buf, wherebuf, n+1 ); + mrk->next = mwFirstMark; + mrk->host = p; + mrk->text = buf; + mrk->level = 1; + mwFirstMark = mrk; + } + else { + strcpy( buf, mrk->text ); + strcat( buf, ", " ); + strcat( buf, wherebuf ); + free( mrk->text ); + mrk->text = buf; + mrk->level ++; + } + + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + return p; + } + +void* mwUnmark( void *p, const char *file, unsigned line ) { + mwMarker *mrk, *prv; + mrk = mwFirstMark; + prv = NULL; + while( mrk ) { + if( mrk->host == p ) { + if( mrk->level < 2 ) { + if( prv ) prv->next = mrk->next; + else mwFirstMark = mrk->next; + free( mrk->text ); + free( mrk ); + return p; + } + mrk->level --; + return p; + } + prv = mrk; + mrk = mrk->next; + } + mwWrite("mark: %s(%d), no mark found for %p\n", file, line, p ); + return p; + } + +/*********************************************************************** +** Safe memory checkers +** +** Using ifdefs, implement the operating-system specific mechanism +** of identifying a piece of memory as legal to access with read +** and write priviliges. Default: return nonzero for non-NULL pointers. +***********************************************************************/ + +static char mwDummy( char c ) +{ + return c; +} + +#ifndef MW_SAFEADDR +#ifdef WIN32 +#define MW_SAFEADDR +#define WIN32_LEAN_AND_MEAN +#include +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) ) return 0; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + /* NOTE: For some reason, under Win95 the IsBad... */ + /* can return false for invalid pointers. */ + if( p == NULL ) return 0; + if( IsBadReadPtr(p,len) || IsBadWritePtr(p,len) ) return 0; + return 1; +} +#endif /* WIN32 */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +#ifdef SIGSEGV +#define MW_SAFEADDR + +typedef void (*mwSignalHandlerPtr)( int ); +mwSignalHandlerPtr mwOldSIGSEGV = (mwSignalHandlerPtr) 0; +jmp_buf mwSIGSEGVjump; +static void mwSIGSEGV( int n ); + +static void mwSIGSEGV( int n ) +{ + longjmp( mwSIGSEGVjump, 1 ); +} + +int mwIsReadAddr( const void *p, unsigned len ) +{ + const char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read all the bytes in the range */ + ptr = (const char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + if( *ptr == 0x7C ) (void) mwDummy( (char)0 ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + char *ptr; + + if( p == NULL ) return 0; + if( !len ) return 1; + + /* set up to catch the SIGSEGV signal */ + mwOldSIGSEGV = signal( SIGSEGV, mwSIGSEGV ); + + if( setjmp( mwSIGSEGVjump ) ) + { + signal( SIGSEGV, mwOldSIGSEGV ); + return 0; + } + + /* read and write-back all the bytes in the range */ + ptr = (char *)p; + ptr += len; + + /* the reason for this rather strange construct is that */ + /* we want to keep the number of used parameters and locals */ + /* to a minimum. if we use len for a counter gcc will complain */ + /* it may get clobbered by longjmp() at high warning levels. */ + /* it's a harmless warning, but this way we don't have to see it. */ + do + { + ptr --; + *ptr = mwDummy( *ptr ); + } while( ptr != p ); + + /* remove the handler */ + signal( SIGSEGV, mwOldSIGSEGV ); + + return 1; +} +#endif /* SIGSEGV */ +#endif /* MW_SAFEADDR */ + +#ifndef MW_SAFEADDR +int mwIsReadAddr( const void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +int mwIsSafeAddr( void *p, unsigned len ) +{ + if( p == NULL ) return 0; + if( len == 0 ) return 1; + return 1; +} +#endif + +/*********************************************************************** +** Abort/Retry/Ignore handlers +***********************************************************************/ + +static int mwARI( const char *estr ) { + char inbuf[81]; + int c; + fprintf(mwSTDERR, "\n%s\nMEMWATCH: Abort, Retry or Ignore? ", estr); + (void) fgets(inbuf,sizeof(inbuf),stdin); + for( c=0; inbuf[c] && inbuf[c] <= ' '; c++ ) ; + c = inbuf[c]; + if( c == 'R' || c == 'r' ) { + mwBreakOut( estr ); + return MW_ARI_RETRY; + } + if( c == 'I' || c == 'i' ) return MW_ARI_IGNORE; + return MW_ARI_ABORT; + } + +/* standard ARI handler (exported) */ +int mwAriHandler( const char *estr ) { + mwAutoInit(); + return mwARI( estr ); + } + +/* used to set the ARI function */ +void mwSetAriFunc( int (*func)(const char *) ) { + mwAutoInit(); + mwAriFunction = func; + } + +/*********************************************************************** +** Allocation handlers +***********************************************************************/ + +void* mwMalloc( size_t size, const char* file, int line) { + size_t needed; + mwData *mw; + char *ptr; + void *p; + + mwAutoInit(); + + TESTS(file,line); + + mwCounter ++; + needed = sizeof(mwData) + sizeof(long) + sizeof(long) + size; + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc > mwAllocLimit) ) { + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (long)size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + mw = (mwData*) malloc( needed ); + if( mw == NULL ) { + if( mwFreeUp(needed,0) >= needed ) { + mw = (mwData*) malloc(needed); + if( mw == NULL ) { + mwWrite( "internal: mwFreeUp(%u) reported success, but malloc() fails\n", needed ); + mwIncErr(); + FLUSH(); + } + } + if( mw == NULL ) { + mwWrite( "fail: <%ld> %s(%d), %ld wanted %ld allocated\n", + mwCounter, file, line, (long)size, mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + } + + mw->count = mwCounter; + mw->prev = NULL; + mw->next = mwHead; + mw->file = file; + mw->size = size; + mw->line = line; + mw->flag = 0; + mw->check = CHKVAL(mw); + + if( mwHead ) mwHead->prev = mw; + mwHead = mw; + if( mwTail == NULL ) mwTail = mw; + + ptr = (char*)(void*)(mw+1); + PUTDWORD( PRECHK, ptr ); /* '*(long*)ptr = PRECHK;' */ + ptr += sizeof(long); + p = ptr; + memset( ptr, MW_VAL_NEW, size ); + ptr += size; + PUTDWORD( POSTCHK, ptr ); /* '*(long*)ptr = POSTCHK;' */ + + mwNumCurAlloc ++; + mwStatCurAlloc += (long) size; + mwStatTotAlloc += (long) size; + if( mwStatCurAlloc > mwStatMaxAlloc ) + mwStatMaxAlloc = mwStatCurAlloc; + mwStatNumAlloc ++; + + if( mwStatLevel ) mwStatAlloc( size, file, line ); + + return p; + } + +void* mwRealloc( void *p, size_t size, const char* file, int line) { + int oldUseLimit, i; + mwData *mw; + char *ptr; + + mwAutoInit(); + + if( p == NULL ) return mwMalloc( size, file, line ); + if( size == 0 ) { mwFree( p, file, line ); return NULL; } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + if( mwIsOwned( mw, file, line ) ) { + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + mwIncErr(); + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* if this allocation would violate the limit, fail it */ + if( mwUseLimit && ((long)size + mwStatCurAlloc - (long)mw->size > mwAllocLimit) ) { + TESTS(file,line); + mwCounter ++; + mwWrite( "limit fail: <%ld> %s(%d), %ld wanted %ld available\n", + mwCounter, file, line, (unsigned long)size - mw->size, mwAllocLimit - mwStatCurAlloc ); + mwIncErr(); + FLUSH(); + return NULL; + } + + /* fake realloc operation */ + oldUseLimit = mwUseLimit; + mwUseLimit = 0; + ptr = (char*) mwMalloc( size, file, line ); + if( ptr != NULL ) { + if( size < mw->size ) + memcpy( ptr, p, size ); + else + memcpy( ptr, p, mw->size ); + mwFree( p, file, line ); + } + mwUseLimit = oldUseLimit; + return (void*) ptr; + } + + /* Unknown pointer! */ + + /* using free'd pointer? */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return NULL; + } + } + + /* some weird pointer */ + mwIncErr(); + mwWrite( "realloc: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return NULL; + } + +char *mwStrdup( char* str, const char* file, int line ) { + size_t len; + char *newstring; + if( str == NULL ) { + mwIncErr(); + mwWrite( "strdup: <%ld> %s(%d), strdup(NULL) called\n", + mwCounter, file, line ); + FLUSH(); + return NULL; + } + len = strlen( str ) + 1; + newstring = (char*) mwMalloc( len, file, line ); + if( newstring != NULL ) memcpy( newstring, str, len ); + return newstring; + } + +void mwFree( void* p, const char* file, int line ) { + int i; + mwData* mw; + char buffer[ sizeof(mwData) + sizeof(long) + 64 ]; + + TESTS(file,line); + + /* this code is in support of C++ delete */ + if( file == NULL ) { + mwFree_( p ); + return; + } + + mwAutoInit(); + mwCounter ++; + + /* on NULL free, write a warning and return */ + if( p == NULL ) { + mwWrite( "NULL free: <%ld> %s(%d), NULL pointer free'd\n", + mwCounter, file, line ); + FLUSH(); + return; + } + + /* do the quick ownership test */ + mw = (mwData*) ( ((char*)p)-sizeof(long)-sizeof(mwData) ); + + if( mwIsOwned( mw, file, line ) ) { + (void) mwTestBuf( mw, file, line ); + + /* if the buffer is an NML, treat this as a double-free */ + if( mw->flag & MW_NML ) + { + if( *((unsigned char*)(mw+1)+sizeof(long)) != MW_VAL_NML ) + { + mwWrite( "internal: <%ld> %s(%d), no-mans-land MW-%p is corrupted\n", + mwCounter, file, line, mw ); + } + goto check_dbl_free; + } + + /* update the statistics */ + mwNumCurAlloc --; + mwStatCurAlloc -= (long) mw->size; + if( mwStatLevel ) mwStatFree( mw->size, mw->file, mw->line ); + + /* we should either free the allocation or keep it as NML */ + if( mwNML ) { + mw->flag |= MW_NML; + mwNmlNumAlloc ++; + mwNmlCurAlloc += (long) mw->size; + memset( (char*)(mw+1)+sizeof(long), MW_VAL_NML, mw->size ); + } + else { + /* unlink the allocation, and enter the post-free data */ + mwUnlink( mw, file, line ); + memset( mw, MW_VAL_DEL, + mw->size + sizeof(mwData)+sizeof(long)+sizeof(long) ); + if( mwFBI ) { + memset( mw, '.', sizeof(mwData) + sizeof(long) ); + sprintf( buffer, "FBI<%ld>%s(%d)", mwCounter, file, line ); + strncpy( (char*)(void*)mw, buffer, sizeof(mwData) + sizeof(long) ); + } + free( mw ); + } + + /* add the pointer to the last-free track */ + mwLFfile[ mwLFcur ] = file; + mwLFline[ mwLFcur ] = line; + mwLastFree[ mwLFcur++ ] = p; + if( mwLFcur == MW_FREE_LIST ) mwLFcur = 0; + + return; + } + + /* check for double-freeing */ +check_dbl_free: + for(i=0;i %s(%d), %p was" + " freed from %s(%d)\n", + mwCounter, file, line, p, + mwLFfile[i], mwLFline[i] ); + FLUSH(); + return; + } + } + + /* some weird pointer... block the free */ + mwIncErr(); + mwWrite( "WILD free: <%ld> %s(%d), unknown pointer %p\n", + mwCounter, file, line, p ); + FLUSH(); + return; + } + +void* mwCalloc( size_t a, size_t b, const char *file, int line ) { + void *p; + size_t size = a * b; + p = mwMalloc( size, file, line ); + if( p == NULL ) return NULL; + memset( p, 0, size ); + return p; + } + +void mwFree_( void *p ) { + TESTS(NULL,0); + free(p); + } + +void* mwMalloc_( size_t size ) { + TESTS(NULL,0); + return malloc( size ); + } + +void* mwRealloc_( void *p, size_t size ) { + TESTS(NULL,0); + return realloc( p, size ); + } + +void* mwCalloc_( size_t a, size_t b ) { + TESTS(NULL,0); + return calloc( a, b ); + } + +void mwFlushNow( void ) { + if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwDoFlush( int onoff ) { + mwFlushW( onoff<1?0:onoff ); + if( onoff ) if( mwLogR() ) fflush( mwLogR() ); + return; + } + +void mwLimit( long lim ) { + TESTS(NULL,0); + mwWrite("limit: old limit = "); + if( !mwAllocLimit ) mwWrite( "none" ); + else mwWrite( "%ld bytes", mwAllocLimit ); + mwWrite( ", new limit = "); + if( !lim ) { + mwWrite( "none\n" ); + mwUseLimit = 0; + } + else { + mwWrite( "%ld bytes\n", lim ); + mwUseLimit = 1; + } + mwAllocLimit = lim; + FLUSH(); + } + +void mwSetAriAction( int action ) { + TESTS(NULL,0); + mwAriAction = action; + return; + } + +int mwAssert( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "assert trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: assert trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + switch( i ) { + case MW_ARI_IGNORE: + mwWrite( "assert trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + case MW_ARI_RETRY: + mwWrite( "assert trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "assert trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: assert trap: %s(%d), %s\n", fn, ln, exps ); + } + + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +int mwVerify( int exp, const char *exps, const char *fn, int ln ) { + int i; + char buffer[MW_TRACE_BUFFER+8]; + TESTS(fn,ln); + if( exp ) return 0; + mwAutoInit(); + mwIncErr(); + mwCounter++; + mwWrite( "verify trap: <%ld> %s(%d), %s\n", mwCounter, fn, ln, exps ); + if( mwAriFunction != NULL ) { + sprintf( buffer, "MEMWATCH: verify trap: %s(%d), %s", fn, ln, exps ); + i = (*mwAriFunction)(buffer); + if( i == 0 ) { + mwWrite( "verify trap: <%ld> IGNORED - execution continues\n", mwCounter ); + return 0; + } + if( i == 1 ) { + mwWrite( "verify trap: <%ld> RETRY - executing again\n", mwCounter ); + return 1; + } + } + else { + if( mwAriAction & MW_ARI_NULLREAD ) { + /* This is made in an attempt to kick in */ + /* any debuggers or OS stack traces */ + FLUSH(); + /*lint -save -e413 */ + i = *((int*)NULL); + mwDummy( (char)i ); + /*lint -restore */ + } + if( mwAriAction & MW_ARI_IGNORE ) { + mwWrite( "verify trap: <%ld> AUTO IGNORED - execution continues\n", mwCounter ); + return 0; + } + fprintf(mwSTDERR,"\nMEMWATCH: verify trap: %s(%d), %s\n", fn, ln, exps ); + } + FLUSH(); + (void) mwTestNow( fn, ln, 1 ); + FLUSH(); + exit(255); + /* NOT REACHED - the return statement is in to keep */ + /* stupid compilers from squeaking about differing return modes. */ + /* Smart compilers instead say 'code unreachable...' */ + /*lint -save -e527 */ + return 0; + /*lint -restore */ + } + +void mwTrace( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + + mwAutoInit(); + TESTS(NULL,0); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwIncErr(); + mwTrace( " [WARNING: OUTPUT BUFFER OVERFLOW - SYSTEM UNSTABLE]\n" ); + } + + FLUSH(); + } + + +/*********************************************************************** +** Grab & Drop +***********************************************************************/ + +unsigned mwGrab( unsigned kb ) { + TESTS(NULL,0); + return mwGrab_( kb, MW_VAL_GRB, 0 ); + } + +unsigned mwDrop( unsigned kb ) { + TESTS(NULL,0); + return mwDrop_( kb, MW_VAL_GRB, 0 ); + } + +static void mwDropAll() { + TESTS(NULL,0); + (void) mwDrop_( 0, MW_VAL_GRB, 0 ); + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + if( mwGrabList != NULL ) + mwWrite( "internal: the grab list is not empty after mwDropAll()\n"); + } + +static const char *mwGrabType( int type ) { + switch( type ) { + case MW_VAL_GRB: + return "grabbed"; + case MW_VAL_NML: + return "no-mans-land"; + default: + /* do nothing */ + ; + } + return ""; + } + +static unsigned mwGrab_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd; + if( !kb ) i = kb = 65000U; + + for(;kb;kb--) { + if( mwUseLimit && + (mwStatCurAlloc + mwGrabSize + (long)sizeof(mwGrabData) > mwAllocLimit) ) { + if( !silent ) { + mwWrite("grabbed: all allowed memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + gd = (mwGrabData*) malloc( sizeof(mwGrabData) ); + if( gd == NULL ) { + if( !silent ) { + mwWrite("grabbed: all available memory to %s (%u kb)\n", + mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + mwGrabSize += (long) sizeof(mwGrabData); + gd->next = mwGrabList; + memset( gd->blob, type, sizeof(gd->blob) ); + gd->type = type; + mwGrabList = gd; + } + if( !silent ) { + mwWrite("grabbed: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +static unsigned mwDrop_( unsigned kb, int type, int silent ) { + unsigned i = kb; + mwGrabData *gd,*tmp,*pr; + const void *p; + + if( mwGrabList == NULL && kb == 0 ) return 0; + if( !kb ) i = kb = 60000U; + + pr = NULL; + gd = mwGrabList; + for(;kb;) { + if( gd == NULL ) { + if( i-kb > 0 && !silent ) { + mwWrite("dropped: all %s memory (%u kb)\n", mwGrabType(type), i-kb); + FLUSH(); + } + return i-kb; + } + if( gd->type == type ) { + if( pr ) pr->next = gd->next; + kb --; + tmp = gd; + if( mwGrabList == gd ) mwGrabList = gd->next; + gd = gd->next; + p = mwTestMem( tmp->blob, sizeof( tmp->blob ), type ); + if( p != NULL ) { + mwWrite( "wild pointer: <%ld> %s memory hit at %p\n", + mwCounter, mwGrabType(type), p ); + FLUSH(); + } + mwGrabSize -= (long) sizeof(mwGrabData); + free( tmp ); + } + else { + pr = gd; + gd = gd->next; + } + } + if( !silent ) { + mwWrite("dropped: %u kilobytes of %s memory\n", i, mwGrabType(type) ); + FLUSH(); + } + return i; + } + +/*********************************************************************** +** No-Mans-Land +***********************************************************************/ + +void mwNoMansLand( int level ) { + mwAutoInit(); + TESTS(NULL,0); + switch( level ) { + case MW_NML_NONE: + (void) mwDrop_( 0, MW_VAL_NML, 0 ); + break; + case MW_NML_FREE: + break; + case MW_NML_ALL: + (void) mwGrab_( 0, MW_VAL_NML, 0 ); + break; + default: + return; + } + mwNML = level; + } + +/*********************************************************************** +** Static functions +***********************************************************************/ + +static void mwAutoInit( void ) +{ + if( mwInited ) return; + mwUseAtexit = 1; + mwInit(); + return; +} + +static FILE *mwLogR() { + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) return mwLog; + if( mwLog == mwLogB1 ) mwLogB2 = mwLog; + if( mwLog == mwLogB2 ) mwLogB1 = mwLog; + if( mwLogB1 == mwLogB2 ) mwLog = mwLogB1; + if( (mwLog == mwLogB1) && (mwLog == mwLogB2) ) { + mwWrite("internal: log file handle damaged and recovered\n"); + FLUSH(); + return mwLog; + } + fprintf(mwSTDERR,"\nMEMWATCH: log file handle destroyed, using mwSTDERR\n" ); + mwLog = mwLogB1 = mwLogB2 = mwSTDERR; + return mwSTDERR; + } + +static void mwLogW( FILE *p ) { + mwLog = mwLogB1 = mwLogB2 = p; + } + +static int mwFlushR() { + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) return mwFlushing; + if( mwFlushing == mwFlushingB1 ) mwFlushingB2 = mwFlushing; + if( mwFlushing == mwFlushingB2 ) mwFlushingB1 = mwFlushing; + if( mwFlushingB1 == mwFlushingB2 ) mwFlushing = mwFlushingB1; + if( (mwFlushing == mwFlushingB1) && (mwFlushing == mwFlushingB2) ) { + mwWrite("internal: flushing flag damaged and recovered\n"); + FLUSH(); + return mwFlushing; + } + mwWrite("internal: flushing flag destroyed, so set to true\n"); + mwFlushing = mwFlushingB1 = mwFlushingB2 = 1; + return 1; + } + +static void mwFlushW( int n ) { + mwFlushing = mwFlushingB1 = mwFlushingB2 = n; + } + +static void mwIncErr() { + mwErrors++; + mwFlushW( mwFlushR()+1 ); + FLUSH(); + } + +static void mwFlush() { + if( mwLogR() == NULL ) return; +#ifdef MW_FLUSH + fflush( mwLogR() ); +#else + if( mwFlushR() ) fflush( mwLogR() ); +#endif + return; + } + +static void mwUnlink( mwData* mw, const char* file, int line ) { + if( mw->prev == NULL ) { + if( mwHead != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 NULL, but not head\n", + mwCounter, file, line, mw ); + mwHead = mw->next; + } + else { + if( mw->prev->next != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link1 failure\n", + mwCounter, file, line, mw ); + else mw->prev->next = mw->next; + } + if( mw->next == NULL ) { + if( mwTail != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 NULL, but not tail\n", + mwCounter, file, line, mw ); + mwTail = mw->prev; + } + else { + if( mw->next->prev != mw ) + mwWrite( "internal: <%ld> %s(%d), MW-%p: link2 failure\n", + mwCounter, file, line, mw ); + else mw->next->prev = mw->prev; + } + } + +/* +** Relinking tries to repair a damaged mw block. +** Returns nonzero if it thinks it successfully +** repaired the heap chain. +*/ +static int mwRelink( mwData* mw, const char* file, int line ) { + int fails; + mwData *mw1, *mw2; + long count, size; + mwStat *ms; + + if( file == NULL ) file = "unknown"; + + if( mw == NULL ) { + mwWrite("relink: cannot repair MW at NULL\n"); + FLUSH(); + goto emergency; + } + + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + mwWrite("relink: MW-%p is a garbage pointer\n"); + FLUSH(); + goto emergency; + } + + mwWrite("relink: <%ld> %s(%d) attempting to repair MW-%p...\n", mwCounter, file, line, mw ); + FLUSH(); + fails = 0; + + /* Repair from head */ + if( mwHead != mw ) { + if( !mwIsSafeAddr( mwHead, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; head pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwHead; mw1; mw1=mw1->next ) { + if( mw1->next == mw ) { + mw->prev = mw1; + break; + } + if( mw1->next && + ( !mwIsSafeAddr(mw1->next, sizeof(mwData)) || mw1->next->prev != mw1) ) { + mwWrite("relink: failed for MW-%p; forward chain fragmented at MW-%p: 'next' is %p\n", mw, mw1, mw1->next ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in forward chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the head (first) allocation\n", mw ); + if( mw->prev != NULL ) + { + mwWrite( "relink: MW-%p prev pointer is non-NULL, you have a wild pointer\n", mw ); + mw->prev = NULL; + } + } + + /* Repair from tail */ + if( mwTail != mw ) { + if( !mwIsSafeAddr( mwTail, sizeof(mwData) ) ) { + mwWrite("relink: failed for MW-%p; tail pointer destroyed\n", mw ); + FLUSH(); + goto emergency; + } + for( mw1=mwTail; mw1; mw1=mw1->prev ) { + if( mw1->prev == mw ) { + mw->next = mw1; + break; + } + if( mw1->prev && (!mwIsSafeAddr(mw1->prev, sizeof(mwData)) || mw1->prev->next != mw1) ) { + mwWrite("relink: failed for MW-%p; reverse chain fragmented at MW-%p, 'prev' is %p\n", mw, mw1, mw1->prev ); + FLUSH(); + goto emergency; + } + } + if( mw1 == NULL ) { + mwWrite("relink: MW-%p not found in reverse chain search\n", mw ); + FLUSH(); + fails ++; + } + } + else + { + mwWrite( "relink: MW-%p is the tail (last) allocation\n", mw ); + if( mw->next != NULL ) + { + mwWrite( "relink: MW-%p next pointer is non-NULL, you have a wild pointer\n", mw ); + mw->next = NULL; + } + } + + if( fails > 1 ) { + mwWrite("relink: heap appears intact, MW-%p probably garbage pointer\n", mw ); + FLUSH(); + goto verifyok; + } + + /* restore MW info where possible */ + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + mw->check = CHKVAL(mw); + goto verifyok; + + /* Emergency repair */ + emergency: + + if( mwHead == NULL && mwTail == NULL ) + { + if( mwStatCurAlloc == 0 ) + mwWrite("relink: <%ld> %s(%d) heap is empty, nothing to repair\n", mwCounter, file, line ); + else + mwWrite("relink: <%ld> %s(%d) heap damaged beyond repair\n", mwCounter, file, line ); + FLUSH(); + return 0; + } + + mwWrite("relink: <%ld> %s(%d) attempting emergency repairs...\n", mwCounter, file, line ); + FLUSH(); + + if( mwHead == NULL || mwTail == NULL ) + { + if( mwHead == NULL ) mwWrite("relink: mwHead is NULL, but mwTail is %p\n", mwTail ); + else mwWrite("relink: mwTail is NULL, but mwHead is %p\n", mwHead ); + } + + mw1=NULL; + if( mwHead != NULL ) + { + if( !mwIsReadAddr(mwHead,sizeof(mwData)) || mwHead->check != CHKVAL(mwHead) ) + { + mwWrite("relink: mwHead (MW-%p) is damaged, skipping forward scan\n", mwHead ); + mwHead = NULL; + goto scan_reverse; + } + if( mwHead->prev != NULL ) + { + mwWrite("relink: the mwHead pointer's 'prev' member is %p, not NULL\n", mwHead->prev ); + } + for( mw1=mwHead; mw1; mw1=mw1->next ) + { + if( mw1->next ) + { + if( !mwIsReadAddr(mw1->next,sizeof(mwData)) || + !mw1->next->check != CHKVAL(mw1) || + mw1->next->prev != mw1 ) + { + mwWrite("relink: forward chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw1->file, mw1->line ); + if( mwIsReadAddr(mw1->next,sizeof(mwData) ) ) + { + mwWrite("relink: forward chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw1->next, mw1->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw1->file,16)?mw1->file:"", mw1->line ); + } + else + { + mwWrite("relink: the 'next' pointer of this MW points to %p, which is out-of-legal-access\n", + mw1->next ); + } + break; + } + } + } + } + + +scan_reverse: + mw2=NULL; + if( mwTail != NULL ) + { + if( !mwIsReadAddr(mwTail,sizeof(mwData)) || mwTail->check != CHKVAL(mwTail) ) + { + mwWrite("relink: mwTail (%p) is damaged, skipping reverse scan\n", mwTail ); + mwTail = NULL; + goto analyze; + } + if( mwTail->next != NULL ) + { + mwWrite("relink: the mwTail pointer's 'next' member is %p, not NULL\n", mwTail->next ); + } + for( mw2=mwTail; mw2; mw2=mw2->prev ) + { + if( mw2->prev ) + { + if( !mwIsReadAddr(mw2->prev,sizeof(mwData)) || + !mw2->prev->check != CHKVAL(mw2) || + mw2->prev->next != mw2 ) + { + mwWrite("relink: reverse chain's last intact MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", mw2->file, mw2->line ); + if( mwIsReadAddr(mw2->prev,sizeof(mwData) ) ) + { + mwWrite("relink: reverse chain's first damaged MW is MW-%p, %ld %sbytes at %s(%d)\n", + mw2->prev, mw2->size, (mw->flag & MW_NML)?"NoMansLand ":"", + mwIsReadAddr(mw2->file,16)?mw2->file:"", mw2->line ); + } + else + { + mwWrite("relink: the 'prev' pointer of this MW points to %p, which is out-of-legal-access\n", + mw2->prev ); + } + break; + } + } + } + } + +analyze: + if( mwHead == NULL && mwTail == NULL ) + { + mwWrite("relink: both head and tail pointers damaged, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + if( mwHead == NULL ) + { + mwHead = mw2; + mwWrite("relink: heap truncated, MW-%p designated as new mwHead\n", mw2 ); + mw2->prev = NULL; + mw1 = mw2 = NULL; + } + if( mwTail == NULL ) + { + mwTail = mw1; + mwWrite("relink: heap truncated, MW-%p designated as new mwTail\n", mw1 ); + mw1->next = NULL; + mw1 = mw2 = NULL; + } + if( mw1 == NULL && mw2 == NULL && + mwHead->prev == NULL && mwTail->next == NULL ) { + mwWrite("relink: verifying heap integrity...\n" ); + FLUSH(); + goto verifyok; + } + if( mw1 && mw2 && mw1 != mw2 ) { + mw1->next = mw2; + mw2->prev = mw1; + mwWrite("relink: emergency repairs successful, assessing damage...\n"); + FLUSH(); + } + else { + mwWrite("relink: heap totally destroyed, aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + + /* Verify by checking that the number of active allocations */ + /* match the number of entries in the chain */ +verifyok: + if( !mwIsHeapOK( NULL ) ) { + mwWrite("relink: heap verification FAILS - aborting program\n"); + mwFlushW(1); + FLUSH(); + abort(); + } + for( size=count=0, mw1=mwHead; mw1; mw1=mw1->next ) { + count ++; + size += (long) mw1->size; + } + if( count == mwNumCurAlloc ) { + mwWrite("relink: successful, "); + if( size == mwStatCurAlloc ) { + mwWrite("no allocations lost\n"); + } + else { + if( mw != NULL ) { + mwWrite("size information lost for MW-%p\n", mw); + mw->size = 0; + } + } + } + else { + mwWrite("relink: partial, %ld MW-blocks of %ld bytes lost\n", + mwNmlNumAlloc+mwNumCurAlloc-count, mwNmlCurAlloc+mwStatCurAlloc-size ); + return 0; + } + + return 1; + } + +/* +** If mwData* is NULL: +** Returns 0 if heap chain is broken. +** Returns 1 if heap chain is intact. +** If mwData* is not NULL: +** Returns 0 if mwData* is missing or if chain is broken. +** Returns 1 if chain is intact and mwData* is found. +*/ +static int mwIsHeapOK( mwData *includes_mw ) { + int found = 0; + mwData *mw; + + for( mw = mwHead; mw; mw=mw->next ) { + if( includes_mw == mw ) found++; + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + if( mw->prev ) { + if( !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) return 0; + if( mw==mwHead || mw->prev->next != mw ) return 0; + } + if( mw->next ) { + if( !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) return 0; + if( mw==mwTail || mw->next->prev != mw ) return 0; + } + else if( mw!=mwTail ) return 0; + } + + if( includes_mw != NULL && !found ) return 0; + + return 1; + } + +static int mwIsOwned( mwData* mw, const char *file, int line ) { + int retv; + mwStat *ms; + + /* see if the address is legal according to OS */ + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) return 0; + + /* make sure we have _anything_ allocated */ + if( mwHead == NULL && mwTail == NULL && mwStatCurAlloc == 0 ) + return 0; + + /* calculate checksum */ + if( mw->check != CHKVAL(mw) ) { + /* may be damaged checksum, see if block is in heap */ + if( mwIsHeapOK( mw ) ) { + /* damaged checksum, repair it */ + mwWrite( "internal: <%ld> %s(%d), checksum for MW-%p is incorrect\n", + mwCounter, file, line, mw ); + mwIncErr(); + if( mwIsReadAddr( mw->file, 1 ) ) { + ms = mwStatGet( mw->file, -1, 0 ); + if( ms == NULL ) mw->file = ""; + } + else mw->file = ""; + mw->check = CHKVAL(mw); + return 1; + } + /* no, it's just some garbage data */ + return 0; + } + + /* check that the non-NULL pointers are safe */ + if( mw->prev && !mwIsSafeAddr( mw->prev, sizeof(mwData) ) ) mwRelink( mw, file, line ); + if( mw->next && !mwIsSafeAddr( mw->next, sizeof(mwData) ) ) mwRelink( mw, file, line ); + + /* safe address, checksum OK, proceed with heap checks */ + + /* see if the block is in the heap */ + retv = 0; + if( mw->prev ) { if( mw->prev->next == mw ) retv ++; } + else { if( mwHead == mw ) retv++; } + if( mw->next ) { if( mw->next->prev == mw ) retv ++; } + else { if( mwTail == mw ) retv++; } + if( mw->check == CHKVAL(mw) ) retv ++; + if( retv > 2 ) return 1; + + /* block not in heap, check heap for corruption */ + + if( !mwIsHeapOK( mw ) ) { + if( mwRelink( mw, file, line ) ) + return 1; + } + + /* unable to repair */ + mwWrite( "internal: <%ld> %s(%d), mwIsOwned fails for MW-%p\n", + mwCounter, file, line, mw ); + mwIncErr(); + + return 0; + } + +/* +** mwTestBuf: +** Checks a buffers links and pre/postfixes. +** Writes errors found to the log. +** Returns zero if no errors found. +*/ +static int mwTestBuf( mwData* mw, const char* file, int line ) { + int retv = 0; + char *p; + long chk; + + if( file == NULL ) file = "unknown"; + + if( !mwIsSafeAddr( mw, sizeof(mwData) ) ) { + mwWrite( "internal: <%ld> %s(%d): pointer MW-%p is invalid\n", + mwCounter, file, line, mw ); + mwIncErr(); + return 2; + } + + if( mw->check != CHKVAL(mw) ) { + mwWrite( "internal: <%ld> %s(%d), info trashed; relinking\n", + mwCounter, file, line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) return 2; + } + + if( mw->prev && mw->prev->next != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link1 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + if( mw->next && mw->next->prev != mw ) { + mwWrite( "internal: <%ld> %s(%d), buffer <%ld> %s(%d) link2 broken\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + if( !mwRelink( mw, file, line ) ) retv = 2; + } + + p = (char*)(mw+1); + GETDWORD( chk, p ); + if( chk != PRECHK ) { + mwWrite( "underflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + p += mw->size + sizeof(long); + GETDWORD( chk, p ); + if( chk != POSTCHK ) { + mwWrite( "overflow: <%ld> %s(%d), %ld bytes alloc'd at <%ld> %s(%d)\n", + mwCounter,file,line, (long)mw->size, mw->count, mw->file, mw->line ); + mwIncErr(); + retv = 1; + } + + return retv; + } + +static void mwDefaultOutFunc( int c ) { + if( mwLogR() ) fputc( c, mwLogR() ); + } + +static void mwWrite( const char *format, ... ) { + int tot, oflow = 0; + va_list mark; + mwAutoInit(); + if( mwOutFunction == NULL ) mwOutFunction = mwDefaultOutFunc; + va_start( mark, format ); + tot = vsprintf( mwPrintBuf, format, mark ); + va_end( mark ); + if( tot >= MW_TRACE_BUFFER ) { mwPrintBuf[MW_TRACE_BUFFER] = 0; oflow = 1; } + for(tot=0;mwPrintBuf[tot];tot++) + (*mwOutFunction)( mwPrintBuf[tot] ); + if( oflow ) { + mwWrite( "\ninternal: mwWrite(): WARNING! OUTPUT EXCEEDED %u CHARS: SYSTEM UNSTABLE\n", MW_TRACE_BUFFER-1 ); + FLUSH(); + } + return; + } + +static void mwLogFile( const char *name ) { + time_t tid; + (void) time( &tid ); + if( mwLogR() != NULL ) { + fclose( mwLogR() ); + mwLogW( NULL ); + } + if( name == NULL ) return; + mwLogW( fopen( name, "a" COMMIT ) ); + if( mwLogR() == NULL ) + mwWrite( "logfile: failed to open/create file '%s'\n", name ); + } + +/* +** Try to free NML memory until a contiguous allocation of +** 'needed' bytes can be satisfied. If this is not enough +** and the 'urgent' parameter is nonzero, grabbed memory is +** also freed. +*/ +static size_t mwFreeUp( size_t needed, int urgent ) { + void *p; + mwData *mw, *mw2; + char *data; + + /* free grabbed NML memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_NML, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + /* free normal NML memory */ + mw = mwHead; + while( mw != NULL ) { + if( !(mw->flag & MW_NML) ) mw = mw->next; + else { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + mw2 = mw->next; + mwUnlink( mw, "mwFreeUp", 0 ); + free( mw ); + mw = mw2; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + } + + /* if not urgent (for internal purposes), fail */ + if( !urgent ) return 0; + + /* free grabbed memory */ + for(;;) { + if( mwDrop_( 1, MW_VAL_GRB, 1 ) == 0 ) break; + p = malloc( needed ); + if( p == NULL ) continue; + free( p ); + return needed; + } + + return 0; + } + +static const void * mwTestMem( const void *p, unsigned len, int c ) { + const unsigned char *ptr; + ptr = (const unsigned char *) p; + while( len-- ) { + if( *ptr != (unsigned char)c ) return (const void*)ptr; + ptr ++; + } + return NULL; + } + +static int mwStrCmpI( const char *s1, const char *s2 ) { + if( s1 == NULL || s2 == NULL ) return 0; + while( *s1 ) { + if( toupper(*s2) == toupper(*s1) ) { s1++; s2++; continue; } + return 1; + } + return 0; + } + +#define AIPH() if( always_invoked ) { mwWrite("autocheck: <%ld> %s(%d) ", mwCounter, file, line ); always_invoked = 0; } + +static int mwTestNow( const char *file, int line, int always_invoked ) { + int retv = 0; + mwData *mw; + char *data; + + if( file && !always_invoked ) + mwWrite("check: <%ld> %s(%d), checking %s%s%s\n", + mwCounter, file, line, + (mwTestFlags & MW_TEST_CHAIN) ? "chain ": "", + (mwTestFlags & MW_TEST_ALLOC) ? "alloc ": "", + (mwTestFlags & MW_TEST_NML) ? "nomansland ": "" + ); + + if( mwTestFlags & MW_TEST_CHAIN ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( !mwIsSafeAddr(mw, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw->prev ) { + if( !mwIsSafeAddr(mw->prev, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwHead || mw->prev->next != mw ) { + AIPH(); + mwWrite("check: heap chain broken, prev link incorrect\n"); + mwIncErr(); + retv ++; + } + } + if( mw->next ) { + if( !mwIsSafeAddr(mw->next, sizeof(mwData)) ) { + AIPH(); + mwWrite("check: heap corruption detected\n"); + mwIncErr(); + return retv + 1; + } + if( mw==mwTail || mw->next->prev != mw ) { + AIPH(); + mwWrite("check: heap chain broken, next link incorrect\n"); + mwIncErr(); + retv ++; + } + } + else if( mw!=mwTail ) { + AIPH(); + mwWrite("check: heap chain broken, tail incorrect\n"); + mwIncErr(); + retv ++; + } + } + } + if( mwTestFlags & MW_TEST_ALLOC ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( mwTestBuf( mw, file, line ) ) retv ++; + } + } + if( mwTestFlags & MW_TEST_NML ) { + for( mw = mwHead; mw; mw=mw->next ) { + if( (mw->flag & MW_NML) ) { + data = ((char*)(mw+1)) + sizeof(long); + if( mwTestMem( data, mw->size, MW_VAL_NML ) ) { + mwIncErr(); + mwWrite( "wild pointer: <%ld> NoMansLand %p alloc'd at %s(%d)\n", + mw->count, data + sizeof(long), mw->file, mw->line ); + } + } + } + } + + + if( file && !always_invoked && !retv ) + mwWrite("check: <%ld> %s(%d), complete; no errors\n", + mwCounter, file, line ); + return retv; + } + +/********************************************************************** +** Statistics +**********************************************************************/ + +static void mwStatReport() +{ + mwStat* ms, *ms2; + const char *modname; + int modnamelen; + + /* global statistics report */ + mwWrite( "\nMemory usage statistics (global):\n" ); + mwWrite( " N)umber of allocations made: %ld\n", mwStatNumAlloc ); + mwWrite( " L)argest memory usage : %ld\n", mwStatMaxAlloc ); + mwWrite( " T)otal of all alloc() calls: %ld\n", mwStatTotAlloc ); + mwWrite( " U)nfreed bytes totals : %ld\n", mwStatCurAlloc ); + FLUSH(); + + if( mwStatLevel < 1 ) return; + + /* on a per-module basis */ + mwWrite( "\nMemory usage statistics (detailed):\n"); + mwWrite( " Module/Line Number Largest Total Unfreed \n"); + for( ms=mwStatList; ms; ms=ms->next ) + { + if( ms->line == -1 ) + { + if( ms->file == NULL || !mwIsReadAddr(ms->file,22) ) modname = ""; + else modname = ms->file; + modnamelen = strlen(modname); + if( modnamelen > 42 ) + { + modname = modname + modnamelen - 42; + } + + mwWrite(" %-42s %-8ld %-8ld %-8ld %-8ld\n", + modname, ms->num, ms->max, ms->total, ms->curr ); + if( ms->file && mwStatLevel > 1 ) + { + for( ms2=mwStatList; ms2; ms2=ms2->next ) + { + if( ms2->line!=-1 && ms2->file!=NULL && !mwStrCmpI( ms2->file, ms->file ) ) + { + mwWrite( " %-8d %-8ld %-8ld %-8ld %-8ld\n", + ms2->line, ms2->num, ms2->max, ms2->total, ms2->curr ); + } + } + } + } + } +} + +static mwStat* mwStatGet( const char *file, int line, int makenew ) { + mwStat* ms; + + if( mwStatLevel < 2 ) line = -1; + + for( ms=mwStatList; ms!=NULL; ms=ms->next ) { + if( line != ms->line ) continue; + if( file==NULL ) { + if( ms->file == NULL ) break; + continue; + } + if( ms->file == NULL ) continue; + if( !strcmp( ms->file, file ) ) break; + } + + if( ms != NULL ) return ms; + + if( !makenew ) return NULL; + + ms = (mwStat*) malloc( sizeof(mwStat) ); + if( ms == NULL ) { + if( mwFreeUp( sizeof(mwStat), 0 ) < sizeof(mwStat) || + (ms=(mwStat*)malloc(sizeof(mwStat))) == NULL ) { + mwWrite("internal: memory low, statistics incomplete for '%s'\n", file ); + return NULL; + } + } + ms->file = file; + ms->line = line; + ms->total = 0L; + ms->max = 0L; + ms->num = 0L; + ms->curr = 0L; + ms->next = mwStatList; + mwStatList = ms; + return ms; + } + +static void mwStatAlloc( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) { + ms->total += (long) size; + ms->curr += (long) size; + ms->num ++; + if( ms->curr > ms->max ) ms->max = ms->curr; + } + } + + } + +static void mwStatFree( size_t size, const char* file, int line ) { + mwStat* ms; + + /* update the module statistics */ + ms = mwStatGet( file, -1, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + + /* update the line statistics */ + if( mwStatLevel > 1 && line != -1 && file ) { + ms = mwStatGet( file, line, 1 ); + if( ms != NULL ) ms->curr -= (long) size; + } + } + +#if 0 /* 980317: disabled C++ */ + +/********************************************************************** +** C++ new & delete +**********************************************************************/ + +#ifdef __cplusplus +#ifndef MEMWATCH_NOCPP + +int mwNCur = 0; +const char *mwNFile = NULL; +int mwNLine = 0; + +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; + +MemWatch::MemWatch() { + if( mwInited ) return; + mwUseAtexit = 0; + mwInit(); + } + +MemWatch::~MemWatch() { + if( mwUseAtexit ) return; + mwTerm(); + } + +/* +** This global new will catch all 'new' calls where MEMWATCH is +** not active. +*/ +void* operator new( unsigned size ) { + mwNCur = 0; + return mwMalloc( size, "", 0 ); + } + +/* +** This is the new operator that's called when a module uses mwNew. +*/ +void* operator new( unsigned size, const char *file, int line ) { + mwNCur = 0; + return mwMalloc( size, file, line ); + } + +/* +** Since this delete operator will recieve ALL delete's +** even those from within libraries, we must accept +** delete's before we've been initialized. Nor can we +** reliably check for wild free's if the mwNCur variable +** is not set. +*/ +void operator delete( void *p ) { + if( p == NULL ) return; + if( !mwInited ) { + free( p ); + return; + } + if( mwNCur ) { + mwFree( p, mwNFile, mwNLine ); + mwNCur = 0; + return; + } + mwFree_( p ); + } + +#endif /* MEMWATCH_NOCPP */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +/* MEMWATCH.C */ \ No newline at end of file diff --git a/lib/memwatch.h b/lib/memwatch.h new file mode 100644 index 00000000..4ef003fa --- /dev/null +++ b/lib/memwatch.h @@ -0,0 +1,701 @@ +/* +** MEMWATCH.H +** Nonintrusive ANSI C memory leak / overwrite detection +** Copyright (C) 1992-99 Johan Lindh +** All rights reserved. +** Version 2.62 +** +************************************************************************ +** +** PURPOSE: +** +** MEMWATCH has been written to allow guys and gals that like to +** program in C a public-domain memory error control product. +** I hope you'll find it's as advanced as most commercial packages. +** The idea is that you use it during the development phase and +** then remove the MEMWATCH define to produce your final product. +** MEMWATCH is distributed in source code form in order to allow +** you to compile it for your platform with your own compiler. +** It's aim is to be 100% ANSI C, but some compilers are more stingy +** than others. If it doesn't compile without warnings, please mail +** me the configuration of operating system and compiler you are using +** along with a description of how to modify the source, and the version +** number of MEMWATCH that you are using. +** +************************************************************************ +** +** And now for some legalese... +** +** LICENSE: +** +** You are granted a non-exclusive right to use MEMWATCH in your +** programs, provided that you agree to the following terms: +** +** 1. Johan Lindh retains the full copyright of MEMWATCH, and owns +** all rights to it. This means you can't sell it yourself, or +** ship it as part of another product, or as part of a package. +** 2. If you modify any of the files, you must not give them to +** anyone else. But please send me a copy of the changes, +** along with a text as to why they should be implemented. +** 3. You read and agree to the DISCLAIMER, below. +** +** DISCLAIMER: +** +** THIS SOFTWARE IS PROVIDED FREE OF CHARGE 'AS IS' AND JOHAN LINDH MAKES +** NO EXPRESS OR IMPLIED WARRANTIES WITH RESPECT TO IT. JOHAN LINDH WILL +** NOT BE LIABLE FOR ANY DAMAGES, DIRECT OR INDIRECT, ARISING FROM THE +** USAGE OR HANDLING OF THIS SOFTWARE. +** +************************************************************************ +** +** REVISION HISTORY: +** +** 920810 JLI [1.00] +** 920830 JLI [1.10 double-free detection] +** 920912 JLI [1.15 mwPuts, mwGrab/Drop, mwLimit] +** 921022 JLI [1.20 ASSERT and VERIFY] +** 921105 JLI [1.30 C++ support and TRACE] +** 921116 JLI [1.40 mwSetOutFunc] +** 930215 JLI [1.50 modified ASSERT/VERIFY] +** 930327 JLI [1.51 better auto-init & PC-lint support] +** 930506 JLI [1.55 MemWatch class, improved C++ support] +** 930507 JLI [1.60 mwTest & CHECK()] +** 930809 JLI [1.65 Abort/Retry/Ignore] +** 930820 JLI [1.70 data dump when unfreed] +** 931016 JLI [1.72 modified C++ new/delete handling] +** 931108 JLI [1.77 mwSetAssertAction() & some small changes] +** 940110 JLI [1.80 no-mans-land alloc/checking] +** 940328 JLI [2.00 version 2.0 rewrite] +** Improved NML (no-mans-land) support. +** Improved performance (especially for free()ing!). +** Support for 'read-only' buffers (checksums) +** ^^ NOTE: I never did this... maybe I should? +** FBI (free'd block info) tagged before freed blocks +** Exporting of the mwCounter variable +** mwBreakOut() localizes debugger support +** Allocation statistics (global, per-module, per-line) +** Self-repair ability with relinking +** 950913 JLI [2.10 improved garbage handling] +** 951201 JLI [2.11 improved auto-free in emergencies] +** 960125 JLI [X.01 implemented auto-checking using mwAutoCheck()] +** 960514 JLI [2.12 undefining of existing macros] +** 960515 JLI [2.13 possibility to use default new() & delete()] +** 960516 JLI [2.20 suppression of file flushing on unfreed msgs] +** 960516 JLI [2.21 better support for using MEMWATCH with DLL's] +** 960710 JLI [X.02 multiple logs and mwFlushNow()] +** 960801 JLI [2.22 merged X.01 version with current] +** 960805 JLI [2.30 mwIsXXXXAddr() to avoid unneeded GP's] +** 960805 JLI [2.31 merged X.02 version with current] +** 961002 JLI [2.32 support for realloc() + fixed STDERR bug] +** 961222 JLI [2.40 added mwMark() & mwUnmark()] +** 970101 JLI [2.41 added over/underflow checking after failed ASSERT/VERIFY] +** 970113 JLI [2.42 added support for PC-Lint 7.00g] +** 970207 JLI [2.43 added support for strdup()] +** 970209 JLI [2.44 changed default filename to lowercase] +** 970405 JLI [2.45 fixed bug related with atexit() and some C++ compilers] +** 970723 JLI [2.46 added MW_ARI_NULLREAD flag] +** 970813 JLI [2.47 stabilized marker handling] +** 980317 JLI [2.48 ripped out C++ support; wasn't working good anyway] +** 980318 JLI [2.50 improved self-repair facilities & SIGSEGV support] +** 980417 JLI [2.51 more checks for invalid addresses] +** 980512 JLI [2.52 moved MW_ARI_NULLREAD to occur before aborting] +** 990112 JLI [2.53 added check for empty heap to mwIsOwned] +** 990217 JLI [2.55 improved the emergency repairs diagnostics and NML] +** 990224 JLI [2.56 changed ordering of members in structures] +** 990303 JLI [2.57 first maybe-fixit-for-hpux test] +** 990516 JLI [2.58 added 'static' to the definition of mwAutoInit] +** 990517 JLI [2.59 fixed some high-sensitivity warnings] +** 990610 JLI [2.60 fixed some more high-sensitivity warnings] +** 990715 JLI [2.61 changed TRACE/ASSERT/VERIFY macro names] +** 991001 JLI [2.62 added CHECK_BUFFER() and mwTestBuffer()] +** +** To use, simply include 'MEMWATCH.H' as a header file, +** and add MEMWATCH.C to your list of files, and define the macro +** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself. +** +** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(), +** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly +** free both malloc()'d memory as well as mwMalloc()'d. +** +** 980317: C++ support has been disabled. +** The code remains, but is not compiled. +** +** For use with C++, which allows use of inlining in header files +** and class specific new/delete, you must also define 'new' as +** 'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include +** C++ header files from libraries, otherwise you can mess up their +** class definitions. If you don't define these, the C++ allocations +** will not have source file and line number information. Also note, +** most C++ class libraries implement their own C++ memory management, +** and don't allow anyone to override them. MFC belongs to this crew. +** In these cases, the only thing to do is to use MEMWATCH_NOCPP. +** +** You can capture output from MEMWATCH using mwSetOutFunc(). +** Just give it the adress of a "void myOutFunc(int c)" function, +** and all characters to be output will be redirected there. +** +** A failing ASSERT() or VERIFY() will normally always abort your +** program. This can be changed using mwSetAriFunc(). Give it a +** pointer to a "int myAriFunc(const char *)" function. Your function +** must ask the user whether to Abort, Retry or Ignore the trap. +** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it +** causes the expression to be evaluated again! MEMWATCH has a +** default ARI handler. It's disabled by default, but you can enable +** it by calling 'mwDefaultAri()'. Note that this will STILL abort +** your program unless you define MEMWATCH_STDIO to allow MEMWATCH +** to use the standard C I/O streams. Also, setting the ARI function +** will cause MEMWATCH *NOT* to write the ARI error to stderr. The +** error string is passed to the ARI function instead, as the +** 'const char *' parameter. +** +** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations. +** This can be useful if you're using a debug terminal or smart debugger. +** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE. +** +** MEMWATCH fills all allocated memory with the byte 0xFE, so if +** you're looking at erroneous data which are all 0xFE:s, the +** data probably was not initialized by you. The exception is +** calloc(), which will fill with zero's. All freed buffers are +** zapped with 0xFD. If this is what you look at, you're using +** data that has been freed. If this is the case, be aware that +** MEMWATCH places a 'free'd block info' structure immediately +** before the freed data. This block contains info about where +** the block was freed. The information is in readable text, +** in the format "FBIfilename(line)", for example: +** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's +** disabled by default. Use mwFreeBufferInfo(1) to enable it. +** +** To aid in tracking down wild pointer writes, MEMWATCH can perform +** no-mans-land allocations. No-mans-land will contain the byte 0xFC. +** MEMWATCH will, when this is enabled, convert recently free'd memory +** into NML allocations. +** +** MEMWATCH protects it's own data buffers with checksums. If you +** get an internal error, it means you're overwriting wildly, +** or using an uninitialized pointer. +** +************************************************************************ +** +** Note when compiling with Microsoft C: +** - MSC ignores fflush() by default. This is overridden, so that +** the disk log will always be current. +** +** This utility has been tested with: +** PC-lint 7.0k, passed as 100% ANSI C compatible +** Microsoft Visual C++ on Win16 and Win32 +** Microsoft C on DOS +** SAS C on an Amiga 500 +** Gnu C on a PC running Red Hat Linux +** ...and using an (to me) unknown compiler on an Atari machine. +** +************************************************************************ +** +** Format of error messages in MEMWATCH.LOG: +** message: filename(linenumber), information +** +** Errors caught by MemWatch, when they are detected, and any +** actions taken besides writing to the log file MEMWATCH.LOG: +** +** Double-freeing: +** A pointer that was recently freed and has not since been +** reused was freed again. The place where the previous free() +** was executed is displayed. +** Detect: delete or free() using the offending pointer. +** Action: The delete or free() is cancelled, execution continues. +** Underflow: +** You have written just ahead of the allocated memory. +** The size and place of the allocation is displayed. +** Detect: delete or free() of the damaged buffer. +** Action: The buffer is freed, but there may be secondary damage. +** Overflow: +** Like underflow, but you've written after the end of the buffer. +** Detect: see Underflow. +** Action: see Underflow. +** WILD free: +** An unrecognized pointer was passed to delete or free(). +** The pointer may have been returned from a library function; +** in that case, use mwFree_() to force free() of it. +** Also, this may be a double-free, but the previous free was +** too long ago, causing MEMWATCH to 'forget' it. +** Detect: delete or free() of the offending pointer. +** Action: The delete or free() is cancelled, execution continues. +** NULL free: +** It's unclear to me whether or not freeing of NULL pointers +** is legal in ANSI C, therefore a warning is written to the log file, +** but the error counter remains the same. This is legal using C++, +** so the warning does not appear with delete. +** Detect: When you free(NULL). +** Action: The free() is cancelled. +** Failed: +** A request to allocate memory failed. If the allocation is +** small, this may be due to memory depletion, but is more likely +** to be memory fragmentation problems. The amount of memory +** allocated so far is displayed also. +** Detect: When you new, malloc(), realloc() or calloc() memory. +** Action: NULL is returned. +** Realloc: +** A request to re-allocate a memory buffer failed for reasons +** other than out-of-memory. The specific reason is shown. +** Detect: When you realloc() +** Action: realloc() is cancelled, NULL is returned +** Limit fail: +** A request to allocate memory failed since it would violate +** the limit set using mwLimit(). mwLimit() is used to stress-test +** your code under simulated low memory conditions. +** Detect: At new, malloc(), realloc() or calloc(). +** Action: NULL is returned. +** Assert trap: +** An ASSERT() failed. The ASSERT() macro works like C's assert() +** macro/function, except that it's interactive. See your C manual. +** Detect: On the ASSERT(). +** Action: Program ends with an advisory message to stderr, OR +** Program writes the ASSERT to the log and continues, OR +** Program asks Abort/Retry/Ignore? and takes that action. +** Verify trap: +** A VERIFY() failed. The VERIFY() macro works like ASSERT(), +** but if MEMWATCH is not defined, it still evaluates the +** expression, but it does not act upon the result. +** Detect: On the VERIFY(). +** Action: Program ends with an advisory message to stderr, OR +** Program writes the VERIFY to the log and continues, OR +** Program asks Abort/Retry/Ignore? and takes that action. +** Wild pointer: +** A no-mans-land buffer has been written into. MEMWATCH can +** allocate and distribute chunks of memory solely for the +** purpose of trying to catch random writes into memory. +** Detect: Always on CHECK(), but can be detected in several places. +** Action: The error is logged, and if an ARI handler is installed, +** it is executed, otherwise, execution continues. +** Unfreed: +** A memory buffer you allocated has not been freed. +** You are informed where it was allocated, and whether any +** over or underflow has occured. MemWatch also displays up to +** 16 bytes of the data, as much as it can, in hex and text. +** Detect: When MemWatch terminates. +** Action: The buffer is freed. +** Check: +** An error was detected during a CHECK() operation. +** The associated pointer is displayed along with +** the file and line where the CHECK() was executed. +** Followed immediately by a normal error message. +** Detect: When you CHECK() +** Action: Depends on the error +** Relink: +** After a MEMWATCH internal control block has been trashed, +** MEMWATCH tries to repair the damage. If successful, program +** execution will continue instead of aborting. Some information +** about the block may be gone permanently, though. +** Detect: N/A +** Action: Relink successful: program continues. +** Relink fails: program aborts. +** Internal: +** An internal error is flagged by MEMWATCH when it's control +** structures have been damaged. You are likely using an uninitialized +** pointer somewhere in your program, or are zapping memory all over. +** The message may give you additional diagnostic information. +** If possible, MEMWATCH will recover and continue execution. +** Detect: Various actions. +** Action: Whatever is needed +** Mark: +** The program terminated without umarking all marked pointers. Marking +** can be used to track resources other than memory. mwMark(pointer,text,...) +** when the resource is allocated, and mwUnmark(pointer) when it's freed. +** The 'text' is displayed for still marked pointers when the program +** ends. +** Detect: When MemWatch terminates. +** Action: The error is logged. +** +** +************************************************************************ +** +** The author may be reached by e-mail at the address below. If you +** mail me about source code changes in MEMWATCH, remember to include +** MW's version number. +** +** Johan Lindh +** johan@link-data.com +** +** The latest version of MEMWATCH may be downloaded from +** http://www.link-data.com/ +*/ + +#ifdef MEMWATCH + +#ifndef __MEMWATCH_H +#define __MEMWATCH_H + +/* Make sure that malloc(), realloc(), calloc() and free() are declared. */ +/*lint -save -e537 */ +#include +/*lint -restore */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* +** Constants used +** All MEMWATCH constants start with the prefix MW_, followed by +** a short mnemonic which indicates where the constant is used, +** followed by a descriptive text about it. +*/ + +#define MW_ARI_NULLREAD 0x10 /* Null read (to start debugger) */ +#define MW_ARI_ABORT 0x04 /* ARI handler says: abort program! */ +#define MW_ARI_RETRY 0x02 /* ARI handler says: retry action! */ +#define MW_ARI_IGNORE 0x01 /* ARI handler says: ignore error! */ + +#define MW_VAL_NEW 0xFE /* value in newly allocated memory */ +#define MW_VAL_DEL 0xFD /* value in newly deleted memory */ +#define MW_VAL_NML 0xFC /* value in no-mans-land */ +#define MW_VAL_GRB 0xFB /* value in grabbed memory */ + +#define MW_TEST_ALL 0xFFFF /* perform all tests */ +#define MW_TEST_CHAIN 0x0001 /* walk the heap chain */ +#define MW_TEST_ALLOC 0x0002 /* test allocations & NML guards */ +#define MW_TEST_NML 0x0004 /* test all-NML areas for modifications */ + +#define MW_NML_NONE 0 /* no NML */ +#define MW_NML_FREE 1 /* turn FREE'd memory into NML */ +#define MW_NML_ALL 2 /* all unused memory is NML */ +#define MW_NML_DEFAULT 0 /* the default NML setting */ + +#define MW_STAT_GLOBAL 0 /* only global statistics collected */ +#define MW_STAT_MODULE 1 /* collect statistics on a module basis */ +#define MW_STAT_LINE 2 /* collect statistics on a line basis */ +#define MW_STAT_DEFAULT 0 /* the default statistics setting */ + +/* +** MemWatch internal constants +** You may change these and recompile MemWatch to change the limits +** of some parameters. Respect the recommended minimums! +*/ +#define MW_TRACE_BUFFER 256 /* (min 160) size of TRACE()'s output buffer */ +#define MW_FREE_LIST 64 /* (min 4) number of free()'s to track */ + +/* +** Exported variables +** In case you have to remove the 'const' keyword because your compiler +** doesn't support it, be aware that changing the values may cause +** unpredictable behaviour. +** - mwCounter contains the current action count. You can use this to +** place breakpoints using a debugger, if you want. +*/ +#ifndef __MEMWATCH_C +extern const unsigned long mwCounter; +#endif + +/* +** System functions +** Normally, it is not nessecary to call any of these. MEMWATCH will +** automatically initialize itself on the first MEMWATCH function call, +** and set up a call to mwAbort() using atexit(). Some C++ implementations +** run the atexit() chain before the program has terminated, so you +** may have to use mwInit() or the MemWatch C++ class to get good +** behaviour. +** - mwInit() can be called to disable the atexit() usage. If mwInit() +** is called directly, you must call mwTerm() to end MemWatch, or +** mwAbort(). +** - mwTerm() is usually not nessecary to call; but if called, it will +** call mwAbort() if it finds that it is cancelling the 'topmost' +** mwInit() call. +** - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc. +*/ +void mwInit( void ); +void mwTerm( void ); +void mwAbort( void ); + +/* +** Setup functions +** These functions control the operation of MEMWATCH's protective features. +** - mwFlushNow() causes MEMWATCH to flush it's buffers. +** - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after +** writes. The default is smart flushing: MEMWATCH will not flush buffers +** explicitly until memory errors are detected. Then, all writes are +** flushed until program end or mwDoFlush(0) is called. +** - mwLimit() sets the allocation limit, an arbitrary limit on how much +** memory your program may allocate in bytes. Used to stress-test app. +** Also, in virtual-memory or multitasking environs, puts a limit on +** how much MW_NML_ALL can eat up. +** - mwGrab() grabs up X kilobytes of memory. Allocates actual memory, +** can be used to stress test app & OS both. +** - mwDrop() drops X kilobytes of grabbed memory. +** - mwNoMansLand() sets the behaviour of the NML logic. See the +** MW_NML_xxx for more information. The default is MW_NML_DEFAULT. +** - mwStatistics() sets the behaviour of the statistics collector. See +** the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT. +** - mwFreeBufferInfo() enables or disables the tagging of free'd buffers +** with freeing information. This information is written in text form, +** using sprintf(), so it's pretty slow. Disabled by default. +** - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function +** is used. Slows down performance, of course. +** - mwCalcCheck() calculates checksums for all data buffers. Slow! +** - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!! +** - mwMark() sets a generic marker. Returns the pointer given. +** - mwUnmark() removes a generic marker. If, at the end of execution, some +** markers are still in existence, these will be reported as leakage. +** returns the pointer given. +*/ +void mwFlushNow( void ); +void mwDoFlush( int onoff ); +void mwLimit( long bytes ); +unsigned mwGrab( unsigned kilobytes ); +unsigned mwDrop( unsigned kilobytes ); +void mwNoMansLand( int mw_nml_level ); +void mwStatistics( int level ); +void mwFreeBufferInfo( int onoff ); +void mwAutoCheck( int onoff ); +void mwCalcCheck( void ); +void mwDumpCheck( void ); +void * mwMark( void *p, const char *description, const char *file, unsigned line ); +void * mwUnmark( void *p, const char *file, unsigned line ); + +/* +** Testing/verification/tracing +** All of these macros except VERIFY() evaluates to a null statement +** if MEMWATCH is not defined during compilation. +** - mwIsReadAddr() checks a memory area for read privilige. +** - mwIsSafeAddr() checks a memory area for both read & write privilige. +** This function and mwIsReadAddr() is highly system-specific and +** may not be implemented. If this is the case, they will default +** to returning nonzero for any non-NULL pointer. +** - CHECK() does a complete memory integrity test. Slow! +** - CHECK_THIS() checks only selected components. +** - CHECK_BUFFER() checks the indicated buffer for errors. +** - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues. +** Otherwise, the ARI handler is called, if present. If not present, +** the default ARI action is taken (set with mwSetAriAction()). +** ASSERT() can be disabled by defining MW_NOASSERT. +** - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without +** MEMWATCH the macro evaluates to the expression. +** VERIFY() can be disabled by defining MW_NOVERIFY. +** - mwTRACE() or TRACE() writes some text and data to the log. Use like printf(). +** Note: there is a limit to the maximum resulting string length that +** can be written. This defaults to MW_TRACE_BUFFER characters. +** TRACE() can be disabled by defining MW_NOTRACE. +*/ +int mwIsReadAddr( const void *p, unsigned len ); +int mwIsSafeAddr( void *p, unsigned len ); +int mwTest( const char *file, int line, int mw_test_flags ); +int mwTestBuffer( const char *file, int line, void *p ); +int mwAssert( int, const char*, const char*, int ); +int mwVerify( int, const char*, const char*, int ); + +/* +** User I/O functions +** - mwTrace() works like printf(), but dumps output either to the +** function specified with mwSetOutFunc(), or the log file. +** - mwPuts() works like puts(), dumps output like mwTrace(). +** - mwSetOutFunc() allows you to give the adress of a function +** where all user output will go. (exeption: see mwSetAriFunc) +** Specifying NULL will direct output to the log file. +** - mwSetAriFunc() gives MEMWATCH the adress of a function to call +** when an 'Abort, Retry, Ignore' question is called for. The +** actual error message is NOT printed when you've set this adress, +** but instead it is passed as an argument. If you call with NULL +** for an argument, the ARI handler is disabled again. When the +** handler is disabled, MEMWATCH will automatically take the +** action specified by mwSetAriAction(). +** - mwSetAriAction() sets the default ARI return value MEMWATCH should +** use if no ARI handler is specified. Defaults to MW_ARI_ABORT. +** - mwAriHandler() is an ANSI ARI handler you can use if you like. It +** dumps output to stderr, and expects input from stdin. +** - mwBreakOut() is called in certain cases when MEMWATCH feels it would +** be nice to break into a debugger. If you feel like MEMWATCH, place +** an execution breakpoint on this function. +*/ +void mwTrace( const char* format_string, ... ); +void mwPuts( const char* text ); +void mwSetOutFunc( void (*func)(int) ); +void mwSetAriFunc( int (*func)(const char*) ); +void mwSetAriAction( int mw_ari_value ); +int mwAriHandler( const char* cause ); +void mwBreakOut( const char* cause ); + +/* +** Allocation/deallocation functions +** These functions are the ones actually to perform allocations +** when running MEMWATCH, for both C and C++ calls. +** - mwMalloc() debugging allocator +** - mwMalloc_() always resolves to a clean call of malloc() +** - mwRealloc() debugging re-allocator +** - mwRealloc_() always resolves to a clean call of realloc() +** - mwCalloc() debugging allocator, fills with zeros +** - mwCalloc_() always resolves to a clean call of calloc() +** - mwFree() debugging free. Can only free memory which has +** been allocated by MEMWATCH. +** - mwFree_() resolves to a) normal free() or b) debugging free. +** Can free memory allocated by MEMWATCH and malloc() both. +** Does not generate any runtime errors. +*/ +void* mwMalloc( size_t, const char*, int ); +void* mwMalloc_( size_t ); +void* mwRealloc( void *, size_t, const char*, int ); +void* mwRealloc_( void *, size_t ); +void* mwCalloc( size_t, size_t, const char*, int ); +void* mwCalloc_( size_t, size_t ); +void mwFree( void*, const char*, int ); +void mwFree_( void* ); +char* mwStrdup( char *, const char*, int ); + +/* +** Enable/disable precompiler block +** This block of defines and if(n)defs make sure that references +** to MEMWATCH is completely removed from the code if the MEMWATCH +** manifest constant is not defined. +*/ +#ifndef __MEMWATCH_C +#ifdef MEMWATCH + +#define mwASSERT(exp) while(mwAssert((int)(exp),#exp,__FILE__,__LINE__)) +#ifndef MW_NOASSERT +#ifndef ASSERT +#define ASSERT mwASSERT +#endif /* !ASSERT */ +#endif /* !MW_NOASSERT */ +#define mwVERIFY(exp) while(mwVerify((int)(exp),#exp,__FILE__,__LINE__)) +#ifndef MW_NOVERIFY +#ifndef VERIFY +#define VERIFY mwVERIFY +#endif /* !VERIFY */ +#endif /* !MW_NOVERIFY */ +#define mwTRACE mwTrace +#ifndef MW_NOTRACE +#ifndef TRACE +#define TRACE mwTRACE +#endif /* !TRACE */ +#endif /* !MW_NOTRACE */ + +#define malloc(n) mwMalloc(n,__FILE__,__LINE__) +#ifdef strdup +#undef strdup +#endif +#define strdup(p) mwStrdup(p,__FILE__,__LINE__) +#define realloc(p,n) mwRealloc(p,n,__FILE__,__LINE__) +#define calloc(n,m) mwCalloc(n,m,__FILE__,__LINE__) +#define free(p) mwFree(p,__FILE__,__LINE__) +#define CHECK() mwTest(__FILE__,__LINE__,MW_TEST_ALL) +#define CHECK_THIS(n) mwTest(__FILE__,__LINE__,n) +#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b) +#define MARK(p) mwMark(p,#p,__FILE__,__LINE__) +#define UNMARK(p) mwUnmark(p,__FILE__,__LINE__) + +#else /* MEMWATCH */ + +#define mwASSERT(exp) +#ifndef MW_NOASSERT +#ifndef ASSERT +#define ASSERT mwASSERT +#endif /* !ASSERT */ +#endif /* !MW_NOASSERT */ + +#define mwVERIFY(exp) exp +#ifndef MW_NOVERIFY +#ifndef VERIFY +#define VERIFY mwVERIFY +#endif /* !VERIFY */ +#endif /* !MW_NOVERIFY */ + +/*lint -esym(773,mwTRACE) */ +#define mwTRACE /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */ +#ifndef MW_NOTRACE +#ifndef TRACE +/*lint -esym(773,TRACE) */ +#define TRACE mwTRACE +#endif /* !TRACE */ +#endif /* !MW_NOTRACE */ + +extern void mwDummyTraceFunction(const char *,...); +/*lint -save -e652 */ +#define mwDoFlush(n) +#define mwPuts(s) +#define mwInit() +#define mwGrab(n) +#define mwDrop(n) +#define mwLimit(n) +#define mwTest(f,l) +#define mwSetOutFunc(f) +#define mwSetAriFunc(f) +#define mwDefaultAri() +#define mwNomansland() +#define mwStatistics(f) +#define mwMark(p,t,f,n) (p) +#define mwUnmark(p,f,n) (p) +#define mwMalloc(n,f,l) malloc(n) +#define mwStrdup(p,f,l) strdup(p) +#define mwRealloc(p,n,f,l) realloc(p,n) +#define mwCalloc(n,m,f,l) calloc(n,m) +#define mwFree(p) free(p) +#define mwMalloc_(n) malloc(n) +#define mwRealloc_(p,n) realloc(p,n) +#define mwCalloc_(n,m) calloc(n,m) +#define mwFree_(p) free(p) +#define mwAssert(e,es,f,l) +#define mwVerify(e,es,f,l) (e) +#define mwTrace mwDummyTrace +#define mwTestBuffer(f,l,b) (0) +#define CHECK() +#define CHECK_THIS(n) +#define CHECK_BUFFER(b) +#define MARK(p) (p) +#define UNMARK(p) (p) +/*lint -restore */ + +#endif /* MEMWATCH */ +#endif /* !__MEMWATCH_C */ + +#ifdef __cplusplus + } +#endif + +#if 0 /* 980317: disabled C++ */ + +/* +** C++ support section +** Implements the C++ support. Please note that in order to avoid +** messing up library classes, C++ support is disabled by default. +** You must NOT enable it until AFTER the inclusion of all header +** files belonging to code that are not compiled with MEMWATCH, and +** possibly for some that are! The reason for this is that a C++ +** class may implement it's own new() function, and the preprocessor +** would substitute this crucial declaration for MEMWATCH new(). +** You can forcibly deny C++ support by defining MEMWATCH_NOCPP. +** To enble C++ support, you must be compiling C++, MEMWATCH must +** be defined, MEMWATCH_NOCPP must not be defined, and finally, +** you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'. +** Unlike C, C++ code can begin executing *way* before main(), for +** example if a global variable is created. For this reason, you can +** declare a global variable of the class 'MemWatch'. If this is +** is the first variable created, it will then check ALL C++ allocations +** and deallocations. Unfortunately, this evaluation order is not +** guaranteed by C++, though the compilers I've tried evaluates them +** in the order encountered. +*/ +#ifdef __cplusplus +#ifndef __MEMWATCH_C +#ifdef MEMWATCH +#ifndef MEMWATCH_NOCPP +extern int mwNCur; +extern const char *mwNFile; +extern int mwNLine; +class MemWatch { +public: + MemWatch(); + ~MemWatch(); + }; +void * operator new(size_t); +void * operator new(size_t,const char *,int); +void operator delete(void *); +#define mwNew new(__FILE__,__LINE__) +#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete +#endif /* MEMWATCH_NOCPP */ +#endif /* MEMWATCH */ +#endif /* !__MEMWATCH_C */ +#endif /* __cplusplus */ + +#endif /* 980317: disabled C++ */ + +#endif /* __MEMWATCH_H */ + +#endif /* EOF MEMWATCH.H */ diff --git a/lib/mime.c b/lib/mime.c new file mode 100644 index 00000000..462e4fe2 --- /dev/null +++ b/lib/mime.c @@ -0,0 +1,266 @@ +/***************************************************************************** + * + * File ..................: mime.c + * Purpose ...............: Common library + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +/* QP-Decode code by T.Tanaka */ +/* QP-Encode inspired from sendmail code of Berkley */ + +/* XD() converts hexadecimal digit to decimal */ +#define XD(c) ( (((c) >= '0') && ((c) <= '9')) ? (c) - '0' : \ + (((c) >= 'A') && ((c) <= 'F')) ? (c) - 'A' + 10 : \ + (((c) >= 'a') && ((c) <= 'f')) ? (c) - 'a' + 10 : 0) + +/* chars to be converted in qp_encode() */ +char badchars[] = "\001\002\003\004\005\006\007" \ + "\010\011\012\013\014\015\016\017" \ + "\020\021\022\023\024\025\026\027" \ + "\030\031\032\033\034\035\036\037" \ + "\177" \ + "\200\201\202\203\204\205\206\207" \ + "\210\211\212\213\214\215\216\217" \ + "\220\221\222\223\224\225\226\227" \ + "\230\231\232\233\234\235\236\237" \ + "\240\241\242\243\244\245\246\247" \ + "\250\251\252\253\254\255\256\257" \ + "\260\261\262\263\264\265\266\267" \ + "\270\271\272\273\274\275\276\277" \ + "\300\301\302\303\304\305\306\307" \ + "\310\311\312\313\314\315\316\317" \ + "\320\321\322\323\324\325\326\327" \ + "\330\331\332\333\334\335\336\337" \ + "\340\341\342\343\344\345\346\347" \ + "\350\351\352\353\354\355\356\357" \ + "\360\361\362\363\364\365\366\367" \ + "\370\371\372\373\374\375\376\377"; +char badchars2[] = "!\"#$@[\\]^`{|}~()<>,;:/_"; + +char Base16Code[] = "0123456789ABCDEF"; +char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* returns numeric value from a Base64Code[] digit */ +static int index_hex[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1,0x3e, -1, -1, -1,0x3f, + 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b, + 0x3c,0x3d, -1, -1, -1, -1, -1, -1, + -1,0x00,0x01,0x02,0x03,0x04,0x05,0x06, + 0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, + 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16, + 0x17,0x18,0x19, -1, -1, -1, -1, -1, + -1,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20, + 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, + 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30, + 0x31,0x32,0x33, -1, -1, -1, -1, -1 +}; + + + +char *qp_decode(char *s) +{ + static char *buf; + char *p, *q; + + if (buf) + free(buf); + if ((buf = malloc(strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("qp_decode: out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + if (*p == '=') { + ++p; + if (*p == '\0') { /* ends with "=(null)" */ + *q++ = '='; + break; + } else if (*p == '\n') + break; + else if (isxdigit(*p) && isxdigit(*(p + 1))) { + *q++ = 16 * XD(*p) + XD(*(p + 1)); + ++p; + ++p; + } else { /* "=1x" "=5(null)" "=G\n" "=0=" etc. */ + *q++ = '='; + *q++ = *p++; + } + } else + *q++ = *p++; + } + *q = '\0'; + + return buf; +} + + + +char *qp_encode(char *s, int mode) +{ + static char *buf; + char *p, *q; + int linelen = 0; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("qp_encode: out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + if (*p == '\n') { + *q++ = *p++; + linelen = 0; + } else if ((mode == 1) && (*p == ' ')) { + *q++ = '_'; + p++; + linelen += 1; + } else if (*p == ' ' || *p == '\t') { + if ((linelen > 72) && (*(p+1) != '\n')) { + *q++ = *p++; + *q++ = '='; + *q++ = '\n'; + linelen = 0; + } else if (*(p+1) == '\n') { + *q++ = *p++; + *q++ = '='; + *q++ = *p++; + linelen = 0; + } else { + *q++ = *p++; + linelen += 1; + } + } else if ((strchr(badchars,*p)) || (*p == '=') || ((mode==1) && (strchr(badchars2,*p)))) { + if (linelen > 72) { + *q++ = '\n'; + linelen = 0; + } + *q++ = '='; + *q++ = Base16Code[(*p >> 4) & 0x0f]; + *q++ = Base16Code[*p & 0x0f]; + linelen += 3; + p++; + } else { + *q++ = *p++; + linelen++; + } + } + *q = '\0'; + + return buf; +} + + + +/* + * Base64 stores 3 bytes of 8bits into 4 bytes of six bits (the 2 remaining + * bits are left to 0). + * + * AAAAAAAA BBBBBBBB CCCCCCCC --> 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC + * + */ + +char *b64_decode(char *s) +{ + static char *buf; + static char buf2[4]; + char *p, *q; + int i,t; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("b64_decode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + for (i = 0; i < 4; i++) + buf2[i]=0x40; + for (i = 0;((i < 4) && (*p != '\0'));) { + t = (index_hex[(unsigned int)*p]); + if (*p == '=') + buf2[i++]=0x40; + else if (t != -1) + buf2[i++]=(char)t; + p++; + } + if ((buf2[0] < 0x40) && (buf2[1] < 0x40)) + *q++=(((buf2[0] & 0x3f) << 2) | ((buf2[1] >> 4) & 0x03)); + if ((buf2[1] < 0x40) && (buf2[2] < 0x40)) + *q++=(((buf2[1] & 0x0f) << 4) | ((buf2[2] >> 2) & 0x0f)); + if ((buf2[2] < 0x40) && (buf2[3] < 0x40)) + *q++=(((buf2[2] & 0x03) << 6) | (buf2[3] & 0x3f)); + } + *q = '\0'; + + return buf; +} + + + +char *b64_encode(char *s) +{ + static char *buf; + static char buf2[3]; + char *p, *q; + int i; + + if (buf) + free(buf); + if ((buf = malloc(3 * strlen(s) + 1 * sizeof(char))) == NULL) { + WriteError("b64_encode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + for (i = 0; ((i < 3) && (*p != '\0')); ) + buf2[i++] = *p++; + *q++=Base64Code[((buf2[0] >> 2) & 0x3f)]; + *q++=Base64Code[(((buf2[0] & 0x03) << 4) | ((buf2[1] >> 4) & 0x0f))]; + if (i<2) + *q++='='; + else + *q++=Base64Code[(((buf2[1] & 0x0f) << 2) | ((buf2[2] >> 6) & 0x03))]; + if (i<3) + *q++='='; + else + *q++=Base64Code[(buf2[2] & 0x3f)]; + } + *q = '\0'; + + return buf; +} + diff --git a/lib/mkprod.awk b/lib/mkprod.awk new file mode 100644 index 00000000..0ec556c4 --- /dev/null +++ b/lib/mkprod.awk @@ -0,0 +1,15 @@ +BEGIN { + print "#include \"libs.h\"" + print "#include \"structs.h\"" + print "#include \"common.h\"" + print "" + print "struct _ftscprod ftscprod[] = {" + } +/^[^;]/ { + if ($2 != "DROPPED") + print " {0x" $1 ",\(char \*\)\"" $2 "\"}," + } +END { + print " {0xff,(char*)0L}" + print "};" + } diff --git a/lib/msg.c b/lib/msg.c new file mode 100644 index 00000000..eb68ade5 --- /dev/null +++ b/lib/msg.c @@ -0,0 +1,321 @@ +/***************************************************************************** + * + * File ..................: msg.c + * Purpose ...............: Global message base functions + * Last modification date : 20-Dec-1998 + * + ***************************************************************************** + * Copyright (C) 1997-1998 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "msgtext.h" +#include "msg.h" +#include "jammsg.h" + + + +char *strlwr (char *s) +{ + char *p = s; + + while (*p != '\0') { + *p = (char)tolower (*p); + p++; + } + + return (s); +} + + + +char *strupr (char *s) +{ + char *p = s; + + while (*p != '\0') { + *p = (char)toupper (*p); + p++; + } + + return (s); +} + + + +long filelength(int fd) +{ + long retval = -1L; + struct stat buf; + + if (fd != -1) { + fstat(fd, &buf); + retval = buf.st_size; + } + + return (retval); +} + + + +long tell(int fd) +{ + long retval = -1L; + + if (fd != -1) + retval = lseek(fd, 0L, SEEK_CUR); + + return retval; +} + + + +/* + * Add a message + */ +int Msg_AddMsg() +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_AddMsg(); +} + + + +/* + * Close current message base + */ +void Msg_Close(void) +{ + if (MsgBase.Locked) + Msg_UnLock(); + + JAM_Close(); + MsgText_Clear(); + MsgBase.Open = FALSE; +} + + + +/* + * Delete message number + */ +int Msg_Delete(unsigned long ulMsg) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_Delete(ulMsg); +} + + + +int Msg_GetLastRead(lastread *LR) +{ + return JAM_GetLastRead(LR); +} + + + +/* + * Get highest message number + */ +unsigned long Msg_Highest(void) +{ + return MsgBase.Highest = JAM_Highest(); +} + + + +int Msg_Lock(unsigned long ulTimeout) +{ + return MsgBase.Locked = JAM_Lock(ulTimeout); +} + + + +/* + * Get lowest message number + */ +unsigned long Msg_Lowest(void) +{ + return MsgBase.Lowest = JAM_Lowest(); +} + + + +void Msg_New(void) +{ + JAM_New(); +} + + + +int Msg_NewLastRead(lastread LR) +{ + return JAM_NewLastRead(LR); +} + + + +int Msg_Next(unsigned long * ulMsg) +{ + return JAM_Next(ulMsg); +} + + + +/* + * Return number of messages + */ +unsigned long Msg_Number(void) +{ + return MsgBase.Total = JAM_Number(); +} + + + +/* + * Open specified message base + */ +int Msg_Open(char *Base) +{ + int RetVal = FALSE; + + if (MsgBase.Open) { + if (strcmp(MsgBase.Path, Base) != 0) + Msg_Close(); + else + return TRUE; + } + + RetVal = JAM_Open(Base); + + MsgBase.Open = RetVal; + + strcpy(MsgBase.Path, Base); + return RetVal; +} + + + +/* + * Pack deleted messages from the message base. + */ +void Msg_Pack(void) +{ + if (!MsgBase.Locked) + return; + + JAM_Pack(); +} + + + +int Msg_Previous (unsigned long * ulMsg) +{ + return JAM_Previous(ulMsg); +} + + + +int Msg_ReadHeader (unsigned long ulMsg) +{ + return JAM_ReadHeader(ulMsg); +} + + + +/* + * Read message + */ +int Msg_Read(unsigned long ulMsg, int nWidth) +{ + return JAM_Read(ulMsg, nWidth); +} + + + +int Msg_SetLastRead(lastread LR) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_SetLastRead(LR); +} + + + +/* + * Unlock the message base + */ +void Msg_UnLock(void) +{ + JAM_UnLock(); + MsgBase.Locked = FALSE; +} + + + +/* + * Write message header + */ +int Msg_WriteHeader (unsigned long ulMsg) +{ + if (!MsgBase.Locked) + return FALSE; + + return JAM_WriteHeader(ulMsg); +} + + + +/* + * Write messagetext from file, strip linefeeds. + */ +void Msg_Write(FILE *fp) +{ + char *Buf; + int i; + + Buf = calloc(2049, sizeof(char)); + while ((fgets(Buf, 2048, fp)) != NULL) { + + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + MsgText_Add2(Buf); + } + + free(Buf); +} + + diff --git a/lib/msg.h b/lib/msg.h new file mode 100644 index 00000000..f5c4a0bb --- /dev/null +++ b/lib/msg.h @@ -0,0 +1,140 @@ +#ifndef _MSG_H +#define _MSG_H + +#define MAX_LINE_LENGTH 512 + + +/* + * Global message buffer + */ +typedef struct _msgbuf { + unsigned long Id; + unsigned long Current; + char From[101]; /* From name */ + char To[101]; /* To name */ + char Subject[101]; /* Message subject */ + unsigned Local : 1; /* Message is local */ + unsigned Intransit : 1; /* Message is in transit */ + unsigned Private : 1; /* Message is private */ + unsigned Received : 1; /* Message is received */ + unsigned Sent : 1; /* Message is sent */ + unsigned KillSent : 1; /* Kill after sent */ + unsigned ArchiveSent : 1; /* Archive after sent */ + unsigned Hold : 1; /* Hold message */ + unsigned Crash : 1; /* Crash flag */ + unsigned Immediate : 1; /* Immediate mail */ + unsigned Direct : 1; /* Direct flag */ + unsigned Gate : 1; /* Send via gateway */ + unsigned FileRequest : 1; /* File request */ + unsigned FileAttach : 1; /* File attached */ + unsigned TruncFile : 1; /* Trunc file after sent */ + unsigned KillFile : 1; /* Kill file after sent */ + unsigned ReceiptRequest : 1; /* Return receipt request */ + unsigned ConfirmRequest : 1; /* Confirm receipt request */ + unsigned Orphan : 1; /* Orphaned message */ + unsigned Encrypt : 1; /* Encrypted message */ + unsigned Compressed : 1; /* Compressed message */ + unsigned Escaped : 1; /* Msg is 7bit ASCII */ + unsigned ForcePU : 1; /* Force PickUp */ + unsigned Localmail : 1; /* Local use only */ + unsigned Echomail : 1; /* Echomail flag */ + unsigned Netmail : 1; /* Netmail flag */ + unsigned News : 1; /* News article */ + unsigned Email : 1; /* e-mail message */ + unsigned Nntp : 1; /* Offer to NNTP server */ + unsigned Nodisplay : 1; /* No display to user */ + unsigned Locked : 1; /* Locked, no edit allowed */ + unsigned Deleted : 1; /* Msg is deleted */ + time_t Written; /* Date message is written */ + time_t Arrived; /* Date message arrived */ + time_t Read; /* Date message is received */ + char FromAddress[101]; /* From address */ + char ToAddress[101]; /* To address */ + unsigned long Reply; /* Message is reply to */ + unsigned long Original; /* Original message */ + unsigned long MsgIdCRC; /* Message Id CRC */ + unsigned long ReplyCRC; /* Reply CRC */ + char Msgid[81]; /* Msgid string */ + char Replyid[81]; /* Replyid string */ + char ReplyAddr[81]; /* Gated Reply Address */ + char ReplyTo[81]; /* Gated Reply To */ + long Size; /* Message size during write*/ +} msgbuf; + + + +/* + * Globale message area buffer + */ +typedef struct _msgbase { + char Path[PATH_MAX]; /* Path to message base */ + unsigned Open : 1; /* If base is open */ + unsigned Locked : 1; /* If base is locked */ + unsigned long LastNum; /* Lastread message number */ + unsigned long Lowest; /* Lowest message number */ + unsigned long Highest; /* Highest message number */ + unsigned long Total; /* Total number of msgs */ +} msgbase; + + + +/* + * LastRead structure + */ +typedef struct _lastread { + unsigned long UserCRC; /* CRC32 lowercase username */ + unsigned long UserID; /* Unique user-id */ + unsigned long LastReadMsg; /* Last Read message number */ + unsigned long HighReadMsg; /* Highes read message */ +} lastread; + + + +/* + * Global variables + */ +msgbuf Msg; /* Message buffer */ +msgbase MsgBase; /* Message Base buffer */ +msgbase EmailBase; /* Email Base buffer */ +lastread LastRead; /* LastRead pointer record */ +char szWrp[MAX_LINE_LENGTH + 1]; + + + +/* + * Common function prototypes. + */ +char *strlwr(char *); +char *strupr(char *); +long filelength(int); +long tell(int); + + + +/* + * Message Base Prototypes + */ +int Msg_AddMsg(void); +void Msg_Close(void); +int Msg_Delete(unsigned long); +int Msg_GetLastRead(lastread *); +unsigned long Msg_Highest(void); +int Msg_Lock(unsigned long); +unsigned long Msg_Lowest(void); +void Msg_New(void); +int Msg_NewLastRead(lastread); +int Msg_Next(unsigned long *); +unsigned long Msg_Number(void); +int Msg_Open(char *); +void Msg_Pack(void); +int Msg_Previous(unsigned long *); +int Msg_ReadHeader(unsigned long); +int Msg_Read(unsigned long, int); +int Msg_SetLastRead(lastread); +void Msg_UnLock(void); +int Msg_WriteHeader(unsigned long); +void Msg_Write(FILE *); + + +#endif + diff --git a/lib/msgflags.c b/lib/msgflags.c new file mode 100644 index 00000000..01b047fb --- /dev/null +++ b/lib/msgflags.c @@ -0,0 +1,144 @@ +/***************************************************************************** + * + * File ..................: msgflags.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 06-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +static char *flnm[] = { + (char *)"PVT",(char *)"CRS",(char *)"RCV",(char *)"SNT", + (char *)"ATT",(char *)"TRN",(char *)"ORP",(char *)"K/S", + (char *)"LOC",(char *)"HLD",(char *)"RSV",(char *)"FRQ", + (char *)"RRQ",(char *)"RRC",(char *)"ARQ",(char *)"FUP" +}; + + + +int flagset(char *s) +{ + char *buf,*p; + int i; + int fl=0; + + Syslog('M', "setting flags from string \"%s\"",MBSE_SS(s)); + buf=xstrcpy(s); + for (p=strtok(buf," ,\t\n"); p; p=strtok(NULL," ,\t\n")) { + for (i=0;i<16;i++) + if (!strcasecmp(p,flnm[i])) { + Syslog('M', "setting flag bit %d for \"%s\"", i,MBSE_SS(p)); + fl |= (1 << i); + } + } + free(buf); + Syslog('M', "set flags 0x%04x",fl); + return fl; +} + + + +char *compose_flags(int flags, char *fkludge) +{ + int i; + char *buf = NULL, *p; + + if ((fkludge == NULL) && (!flags)) + return buf; + + Syslog('M', "composing flag string from binary 0x%04x and string \"%s\"", flags,MBSE_SS(fkludge)); + if (fkludge) { + if (!isspace(fkludge[0])) + buf=xstrcpy((char *)" "); + buf=xstrcat(buf,fkludge); + p=buf+strlen(buf)-1; + while (isspace(*p)) + *p--='\0'; + } + + for (i = 0; i < 16; i++) + if ((flags & (1 << i)) && (!flag_on(flnm[i],buf))) { + buf=xstrcat(buf,(char *)" "); + buf=xstrcat(buf,flnm[i]); + Syslog('m', "adding \"%s\"",flnm[i]); + } + Syslog('M', "resulting string is \"%s\"",buf); + return buf; +} + + + +char *strip_flags(char *flags) +{ + char *p,*q=NULL,*tok; + int canonic,i; + + if (flags == NULL) + return NULL; + + Syslog('M', "stripping official flags from \"%s\"",MBSE_SS(flags)); + p=xstrcpy(flags); + for (tok=strtok(flags,", \t\n");tok;tok=strtok(NULL,", \t\n")) { + canonic=0; + for (i=0;i<16;i++) + if (strcasecmp(tok,flnm[i]) == 0) + canonic=1; + if (!canonic) { + q=xstrcat(q,(char *)" "); + q=xstrcat(q,tok); + } + } + free(p); + Syslog('M', "stripped string is \"%s\"",q); + return q; +} + + + +int flag_on(char *flag, char *flags) +{ + char *p,*tok; + int up=0; + + Syslog('M', "checking flag \"%s\" in string \"%s\"",MBSE_SS(flag),MBSE_SS(flags)); + if (flags == NULL) + return 0; + p=xstrcpy(flags); + for (tok = strtok(p, ", \t\n"); tok; tok = strtok(NULL, ", \t\n")) { + if (strcasecmp(flag, tok) == 0) + up = 1; + } + free(p); + Syslog('M', "flag%s present",up?"":" not"); + return up; +} + + diff --git a/lib/msgtext.c b/lib/msgtext.c new file mode 100644 index 00000000..67f68024 --- /dev/null +++ b/lib/msgtext.c @@ -0,0 +1,335 @@ +/***************************************************************************** + * + * File ..................: msgtext.c + * Purpose ...............: Message text memory storage. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "msgtext.h" +#include "msg.h" + + +LDATA *List; + + + + +unsigned short MsgText_Add1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + Msg.Size += sizeof((void *)lpData); + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +unsigned short MsgText_Add2(char * lpData) +{ + return (MsgText_Add3((void *)lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Add3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc(sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + Msg.Size += usSize; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +void MsgText_Clear (void) +{ + while (List != NULL) + MsgText_Remove(); + Elements = 0; +} + + + +void *MsgText_First (void) +{ + void *RetVal = NULL; + + if (List != NULL) { + while (List->Previous != NULL) + List = List->Previous; + RetVal = List->Value; + } + + return RetVal; +} + + + +unsigned short MsgText_Insert1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + + if (List != NULL) { + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +unsigned short MsgText_Insert2(char * lpData) +{ + return (MsgText_Insert3(lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Insert3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if ((New = (LDATA *)malloc (sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + + if (List != NULL) { + New->Previous = List; + New->Next = List->Next; + if (New->Next != NULL) + New->Next->Previous = New; + List->Next = New; + } + + Elements++; + List = New; + RetVal = 1; + } + + return (RetVal); +} + + + +void * MsgText_Last(void) +{ + void * RetVal = NULL; + + if (List != NULL) { + while (List->Next != NULL) + List = List->Next; + RetVal = List->Value; + } + + return (RetVal); +} + + + +void * MsgText_Next (void) +{ + void * RetVal = NULL; + + if (List != NULL) { + if (List->Next != NULL) { + List = List->Next; + RetVal = List->Value; + } + } + + return (RetVal); +} + + + +void * MsgText_Previous (void) +{ + void * RetVal = NULL; + + if (List != NULL) { + if (List->Previous != NULL) { + List = List->Previous; + RetVal = List->Value; + } + } + + return (RetVal); +} + + + +void MsgText_Remove(void) +{ + LDATA *Temp; + + if (List != NULL) { + if (List->Previous != NULL) + List->Previous->Next = List->Next; + if (List->Next != NULL) + List->Next->Previous = List->Previous; + Temp = List; + if (List->Next != NULL) + List = List->Next; + else if (List->Previous != NULL) + List = List->Previous; + else + List = NULL; + free (Temp); + Elements--; + } +} + + + +unsigned short MsgText_Replace1(void * lpData) +{ + unsigned short RetVal = 0; + LDATA *New; + + if (List != NULL) { + if ((New = (LDATA *)malloc (sizeof (LDATA))) != NULL) { + memset (New, 0, sizeof (LDATA)); + New->Value = (void *)lpData; + New->Next = List->Next; + New->Previous = List->Previous; + + if (New->Next != NULL) + New->Next->Previous = New; + if (New->Previous != NULL) + New->Previous->Next = New; + + free (List); + List = New; + RetVal = 1; + } + } + + return (RetVal); +} + + + +unsigned short MsgText_Replace2(char * lpData) +{ + return (MsgText_Replace3(lpData, (unsigned short)(strlen (lpData) + 1))); +} + + + +unsigned short MsgText_Replace3(void * lpData, unsigned short usSize) +{ + unsigned short RetVal = 0; + LDATA *New; + + if (List != NULL) { + if ((New = (LDATA *)malloc (sizeof (LDATA) + usSize)) != NULL) { + memset (New, 0, sizeof (LDATA) + usSize); + memcpy (New->Data, lpData, usSize); + New->Value = (void *)New->Data; + New->Next = List->Next; + New->Previous = List->Previous; + + if (New->Next != NULL) + New->Next->Previous = New; + if (New->Previous != NULL) + New->Previous->Next = New; + free (List); + List = New; + RetVal = 1; + } + } + + return (RetVal); +} + + + +void * MsgText_Value(void) +{ + return ((List == NULL) ? NULL : List->Value); +} + diff --git a/lib/msgtext.h b/lib/msgtext.h new file mode 100644 index 00000000..d82adc93 --- /dev/null +++ b/lib/msgtext.h @@ -0,0 +1,34 @@ +#ifndef _MSGTEXT_H +#define _MSGTEXT_H + +typedef struct _lData { + struct _lData *Previous; + struct _lData *Next; + void * Value; + char Data[1]; +} LDATA; + + + +unsigned short Elements; + +unsigned short MsgText_Add1(void * lpData); +unsigned short MsgText_Add2(char * lpData); +unsigned short MsgText_Add3(void * lpData, unsigned short usSize); +void MsgText_Clear(void); +void * MsgText_First(void); +unsigned short MsgText_Insert1(void * lpData); +unsigned short MsgText_Insert2(char * lpData); +unsigned short MsgText_Insert3(void * lpData, unsigned short usSize); +void * MsgText_Last(void); +void * MsgText_Next(void); +void * MsgText_Previous(void); +void MsgText_Remove(void); +unsigned short MsgText_Replace1(void * lpData); +unsigned short MsgText_Replace2(char * lpData); +unsigned short MsgText_Replace3(void * lpData, unsigned short usSize); +void * MsgText_Value(void); + + +#endif + diff --git a/lib/nntp.c b/lib/nntp.c new file mode 100644 index 00000000..334f6e21 --- /dev/null +++ b/lib/nntp.c @@ -0,0 +1,294 @@ +/***************************************************************************** + * + * File ..................: nntp.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int nntpsock = -1; /* TCP/IP socket */ +struct hostent *nhp; /* Host info remote */ +struct servent *nsp; /* Service information */ +struct sockaddr_in nntp_loc; /* For local socket address */ +struct sockaddr_in nntp_rem; /* For remote socket address */ + + +int nntp_auth(void); + + +int nntp_connect(void) +{ + int addrlen; + char *p; + + if (nntpsock != -1) + return nntpsock; + + if (!strlen(CFG.nntpnode)) { + WriteError("NNTP: host not configured"); + return -1; + } + + Syslog('+', "NNTP: connecting host: %s", CFG.nntpnode); + memset(&nntp_loc, 0, sizeof(struct sockaddr_in)); + memset(&nntp_rem, 0, sizeof(struct sockaddr_in)); + + nntp_rem.sin_family = AF_INET; + + if ((nhp = gethostbyname(CFG.nntpnode)) == NULL) { + WriteError("$NNTP: can't find host %s", CFG.nntpnode); + return -1; + } + + nntp_rem.sin_addr.s_addr = ((struct in_addr *)(nhp->h_addr))->s_addr; + + if ((nsp = getservbyname("nntp", "tcp")) == NULL) { + WriteError("$NNTP: can't find service port for nntp/tcp"); + return -1; + } + nntp_rem.sin_port = nsp->s_port; + + if ((nntpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$NNTP: unable to create tcp socket"); + return -1; + } + + if (connect(nntpsock, (struct sockaddr *)&nntp_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$NNTP: cannot connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(nntpsock, (struct sockaddr *)&nntp_loc, &addrlen) == -1) { + WriteError("$NNTP: unable to read socket address"); + return -1; + } + + p = nntp_receive(); + if (strlen(p) == 0) { + WriteError("NNTP: no response"); + nntp_close(); + return -1; + } + Syslog('+', "NNTP: %s", p); + + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + if (nntp_auth() == FALSE) { + WriteError("Authorisation failure"); + nntp_close(); + return -1; + } + } else if (strncmp(p, "200", 3)) { + WriteError("NNTP: bad response: %s", p); + nntp_close(); + return -1; + } + + if (CFG.modereader) { + Syslog('+', "NNTP: setting mode reader"); + nntp_send((char *)"MODE READER\r\n"); + p = nntp_receive(); + Syslog('+', "NNTP: %s", p); + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + Syslog('+', "NNTP: %s", p); + if (nntp_auth() == FALSE) { + WriteError("NNTP: authorisation failure"); + nntp_close(); + return -1; + } + } else if (strncmp(p, "200", 3)) { + WriteError("NNTP: bad response: %s", p); + nntp_close(); + return -1; + } + } + return nntpsock; +} + + + +int nntp_send(char *buf) +{ + if (nntpsock == -1) + return -1; + + if (send(nntpsock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$NNTP: socket send failed"); + if (errno == ENOTCONN || errno == EPIPE) { + WriteError("NNTP: closing local side"); + nntpsock = -1; + } + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *nntp_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i = 0, j; + + if (nntpsock == -1) + return NULL; + + memset((char *)&buf, 0, SS_BUFSIZE); + while (TRUE) { + j = recv(nntpsock, &buf[i], 1, 0); + if (j == -1) { + WriteError("$NNTP: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + if (errno == ENOTCONN || errno == EPIPE) { + WriteError("NNTP: closing local side"); + nntpsock = -1; + } + return buf; + } + if (buf[i] == '\n') + break; + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int nntp_close(void) +{ + if (nntpsock == -1) + return 0; + + nntp_cmd((char *)"QUIT\r\n", 205); + + if (shutdown(nntpsock, 1) == -1) { + WriteError("$NNTP: can't close socket"); + return -1; + } + + nntpsock = -1; + Syslog('+', "NNTP: closed"); + return 0; +} + + + +/* + * Send NNTP command, check response code. + * If the code not matches, the value is returned, else zer. + */ +int nntp_cmd(char *cmd, int resp) +{ + char *p, rsp[6]; + + if (nntp_send(cmd) == -1) + return -1; + + sprintf(rsp, "%d", resp); + p = nntp_receive(); + + if (strncmp(p, "480", 3) == 0) { + /* + * Must login with username and password + */ + Syslog('+', "NNTP: %s", p); + if (nntp_auth() == FALSE) { + WriteError("Authorisation failure"); + nntp_close(); + return -1; + } + /* + * Now send command again, we are now authorized. + */ + if (nntp_send(cmd) == -1) + return -1; + p = nntp_receive(); + } + + if (strncmp(p, rsp, strlen(rsp))) { + WriteError("NNTP> %s", cmd); + WriteError("NNTP< %s", p); + memset(&resp, 0, sizeof(rsp)); + strncpy(rsp, p, 3); + return atoi(rsp); + } + return 0; +} + + + +int nntp_auth(void) +{ + char *cmd; + + if (!(strlen(CFG.nntpuser) && strlen(CFG.nntppass))) { + WriteError("NNTP: password required but not configured"); + return FALSE; + } + cmd = calloc(128, sizeof(char)); + + sprintf(cmd, "AUTHINFO USER %s\r\n", CFG.nntpuser); + if (nntp_cmd(cmd, 381)) + return FALSE; + + sprintf(cmd, "AUTHINFO PASS %s\r\n", CFG.nntppass); + if (nntp_cmd(cmd, 281) == 0) { + free(cmd); + Syslog('+', "NNTP: logged in"); + return TRUE; + } else { + free(cmd); + return FALSE; + } +} + + diff --git a/lib/nodelist.c b/lib/nodelist.c new file mode 100644 index 00000000..4aa5b9e3 --- /dev/null +++ b/lib/nodelist.c @@ -0,0 +1,607 @@ +/***************************************************************************** + * + * File ..................: nodelist.c + * Purpose ...............: Read nodelists information + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +#define NULLDOMAIN "nulldomain" + + +struct _pkey pkey[] = { + {(char *)"Down", NL_NODE, NL_DOWN}, + {(char *)"Hold", NL_NODE, NL_HOLD}, + {(char *)"Region", NL_REGION, NL_REGION}, + {(char *)"Host", NL_HOST, NL_HOST}, + {(char *)"Hub", NL_HUB, NL_HUB}, + {(char *)"Point", NL_POINT, NL_POINT}, + {(char *)"Pvt", NL_NODE, NL_NODE}, + {NULL, 0, 0} +}; + + + +struct _okey okey[] = { + {(char *)"CM", OL_CM}, + {(char *)"MO", OL_MO}, + {(char *)"LO", OL_LO}, + {(char *)"MN", OL_MN}, + {NULL, 0} +}; + +struct _fkey fkey[] = { + {(char *)"V22", NL_V22}, + {(char *)"V29", NL_V29}, + {(char *)"V32", NL_V32}, + {(char *)"V32B",NL_V32B | NL_V32}, + {(char *)"V34", NL_V34}, + {(char *)"V42", NL_V42 | NL_MNP}, + {(char *)"V42B",NL_V42B | NL_V42 | NL_MNP}, + {(char *)"MNP", NL_MNP}, + {(char *)"H96", NL_H96}, + {(char *)"HST", NL_HST | NL_MNP}, + {(char *)"H14", NL_H14 | NL_HST | NL_MNP}, + {(char *)"H16", NL_H16 | NL_H14 | NL_HST | NL_MNP | NL_V42 | NL_V42B}, + {(char *)"MAX", NL_MAX}, + {(char *)"PEP", NL_PEP}, + {(char *)"CSP", NL_CSP}, + {(char *)"V32T",NL_V32T | NL_V32B | NL_V32}, + {(char *)"VFC", NL_VFC}, + {(char *)"ZYX", NL_ZYX | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP}, + {(char *)"X2C", NL_X2C | NL_X2S | NL_V34}, + {(char *)"X2S", NL_X2S | NL_V34}, + {(char *)"V90C",NL_V90C | NL_V90S | NL_V34}, + {(char *)"V90S",NL_V90S | NL_V34}, + {(char *)"Z19", NL_Z19 | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP | NL_ZYX}, + {NULL, 0} +}; + +struct _xkey xkey [] = { + {(char *)"XA", RQ_XA}, + {(char *)"XB", RQ_XB}, + {(char *)"XC", RQ_XC}, + {(char *)"XP", RQ_XP}, + {(char *)"XR", RQ_XR}, + {(char *)"XW", RQ_XW}, + {(char *)"XX", RQ_XX}, + {NULL, 0} +}; + +struct _dkey dkey [] = { + {(char *)"V110L", ND_V110L}, + {(char *)"V110H", ND_V110H}, + {(char *)"V120L", ND_V120L}, + {(char *)"V120H", ND_V120H}, + {(char *)"X75", ND_X75}, + {NULL, 0} +}; + +struct _ikey ikey [] = { + {(char *)"IBN", IP_IBN}, + {(char *)"IFC", IP_IFC}, + {(char *)"ITN", IP_ITN}, + {(char *)"IVM", IP_IVM}, + {(char *)"IP", IP_IP}, + {(char *)"IFT", IP_IFT}, + {NULL, 0} +}; + + + +int initnl(void) +{ + int rc = 0; + FILE *dbf, *fp; + char *filexnm, *path; + struct _nlfil fdx; + + filexnm = xstrcpy(CFG.nodelists); + filexnm = xstrcat(filexnm,(char *)"/node.files"); + + if ((dbf = fopen(filexnm, "r")) == NULL) { + WriteError("$Can't open %s", filexnm); + rc = 101; + } else { + path = calloc(128, sizeof(char)); + + while (fread(&fdx, sizeof(fdx), 1, dbf) == 1) { + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + rc = 101; + } else { + fclose(fp); + } + } + + fclose(dbf); + free(path); + } + + free(filexnm); + return rc; +} + + + +int comp_node(struct _nlidx, struct _ixentry); +int comp_node(struct _nlidx fap1, struct _ixentry fap2) +{ + if (fap1.zone != fap2.zone) + return (fap1.zone - fap2.zone); + else if (fap1.net != fap2.net) + return (fap1.net - fap2.net); + else if (fap1.node != fap2.node) + return (fap1.node - fap2.node); + else + return (fap1.point - fap2.point); +} + + + +node *getnlent(faddr *addr) +{ + FILE *fp; + static node nodebuf; + static char buf[256], *p, *q; + struct _ixentry xaddr; + int i, j, Found = FALSE; + int ixflag, stdflag; + char *mydomain, *path; + struct _nlfil fdx; + struct _nlidx ndx; + long lowest, highest, current; + + Syslog('s', "getnlent: %s", ascfnode(addr,0xff)); + + mydomain = xstrcpy(CFG.aka[0].domain); + if (mydomain == NULL) + mydomain = (char *)NULLDOMAIN; + + nodebuf.addr.domain = NULL; + nodebuf.addr.zone = 0; + nodebuf.addr.net = 0; + nodebuf.addr.node = 0; + nodebuf.addr.point = 0; + nodebuf.addr.name = NULL; + nodebuf.upnet = 0; + nodebuf.upnode = 0; + nodebuf.region = 0; + nodebuf.type = 0; + nodebuf.pflag = 0; + nodebuf.name = NULL; + nodebuf.location = NULL; + nodebuf.sysop = NULL; + nodebuf.phone = NULL; + nodebuf.speed = 0; + nodebuf.mflags = 0L; + nodebuf.oflags = 0L; + nodebuf.xflags = 0L; + nodebuf.iflags = 0L; + nodebuf.dflags = 0L; + nodebuf.uflags[0] = NULL; + + if (addr == NULL) + goto retdummy; + + if (addr->zone == 0) + addr->zone = CFG.aka[0].zone; + xaddr.zone = addr->zone; + nodebuf.addr.zone = addr->zone; + xaddr.net = addr->net; + nodebuf.addr.net = addr->net; + xaddr.node = addr->node; + nodebuf.addr.node = addr->node; + xaddr.point = addr->point; + nodebuf.addr.point = addr->point; + + if (initnl()) + goto retdummy; + + /* + * First, lookup node in index. NOTE -- NOT 5D YET + */ + path = calloc(128, sizeof(char)); + sprintf(path, "%s/%s", CFG.nodelists, "node.index"); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + + fseek(fp, 0, SEEK_END); + highest = ftell(fp) / sizeof(ndx); + lowest = 0; + + while (TRUE) { + current = ((highest - lowest) / 2) + lowest; + fseek(fp, current * sizeof(ndx), SEEK_SET); + if (fread(&ndx, sizeof(ndx), 1, fp) != 1) + break; + + if (comp_node(ndx, xaddr) == 0) { + Found = TRUE; + break; + } + if (comp_node(ndx, xaddr) < 0) + lowest = current; + else + highest = current; + if ((highest - lowest) <= 1) + break; + } + + fclose(fp); + + if (!Found) { + free(path); + goto retdummy; + } + + sprintf(path, "%s/%s", CFG.nodelists, "node.files"); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + + /* + * Get filename from node.files + */ + for (i = 0; i < (ndx.fileno +1); i++) + fread(&fdx, sizeof(fdx), 1, fp); + fclose(fp); + + /* CHECK DOMAIN HERE */ + + /* + * Open and read in real nodelist + */ + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + WriteError("$Can't open %s", path); + free(path); + goto retdummy; + } + free(path); + + if (fseek(fp, ndx.offset, SEEK_SET) != 0) { + WriteError("$Seek failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + + if (fgets(buf, sizeof(buf)-1, fp) == NULL) { + WriteError("$fgets failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + fclose(fp); + + nodebuf.type = ndx.type; + nodebuf.pflag = ndx.pflag; + + if (*(p = buf + strlen(buf) -1) == '\n') + *p = '\0'; + if (*(p = buf + strlen(buf) -1) == '\r') + *p = '\0'; + for (p = buf; *p; p++) + if (*p == '_') + *p = ' '; + + p = buf; + + if ((q = strchr(p,','))) + *q++ = '\0'; + + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.name = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.location = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.sysop = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + if (strcasecmp(p, "-Unpublished-") == 0) + nodebuf.phone = NULL; + else + nodebuf.phone = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.speed = atoi(p); + + /* + * Process the nodelist flags. + */ + ixflag = 0; + stdflag = TRUE; + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + /* + * Experimental: process authorized flags and + * User flags both as authorized. + */ + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + nodebuf.mflags |= fkey[j].flag; + for (j = 0; okey[j].key; j++) + if (strcasecmp(p, okey[j].key) == 0) + nodebuf.oflags |= okey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + nodebuf.dflags |= dkey[j].flag; + for (j = 0; ikey[j].key; j++) + if (strncasecmp(p, ikey[j].key, strlen(ikey[j].key)) == 0) + nodebuf.iflags |= ikey[j].flag; + for (j = 0; xkey[j].key; j++) + if (strcasecmp(p, xkey[j].key) == 0) + nodebuf.xflags |= xkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + nodebuf.uflags[ixflag++] = p; + if (ixflag < MAXUFLAGS) + nodebuf.uflags[ixflag] = NULL; + } + } + } + } + + nodebuf.addr.name = nodebuf.sysop; + nodebuf.addr.domain = xstrcpy(fdx.domain); + nodebuf.upnet = ndx.upnet; + nodebuf.upnode = ndx.upnode; + nodebuf.region = ndx.region; + if (addr->domain == NULL) + addr->domain = xstrcpy(nodebuf.addr.domain); + + Syslog('s', "getnlent: system %s, %s", nodebuf.name, nodebuf.location); + Syslog('s', "getnlent: sysop %s, %s", nodebuf.sysop, nodebuf.phone); + if (nodebuf.mflags) + Syslog('S', "getnlent: mflags 0x%08lx", nodebuf.mflags); + if (nodebuf.oflags) + Syslog('S', "getnlent: oflags 0x%08lx", nodebuf.oflags); + if (nodebuf.dflags) + Syslog('S', "getnlent: dflags 0x%08lx", nodebuf.dflags); + if (nodebuf.iflags) + Syslog('S', "getnlent: iflags 0x%08lx", nodebuf.iflags); + if (nodebuf.xflags) + Syslog('S', "getnlent: xflags 0x%08lx", nodebuf.xflags); + for (j = 0; nodebuf.uflags[j]; j++) + Syslog('S', "getnlent: uflag %s", nodebuf.uflags[j]); + + moflags(nodebuf.mflags); + diflags(nodebuf.dflags); + ipflags(nodebuf.iflags); + olflags(nodebuf.oflags); + rqflags(nodebuf.xflags); + free(mydomain); + + return &nodebuf; + +badsyntax: + WriteError("nodelist %d offset +%lu: bad syntax in line \"%s\"", + ndx.fileno, (unsigned long)ndx.offset, buf); + /* fallthrough */ + +retdummy: + memset(&nodebuf, 0, sizeof(nodebuf)); + nodebuf.pflag = NL_DUMMY; + nodebuf.name = (char *)"Unknown"; + nodebuf.location = (char *)"Nowhere"; + nodebuf.sysop = (char *)"Sysop"; + nodebuf.phone = NULL; + nodebuf.speed = 2400; + free(mydomain); + + return &nodebuf; +} + + + +void olflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Mailer flags :"); + if (flags & OL_CM) + t = xstrcat(t, (char *)" CM"); + if (flags & OL_MO) + t = xstrcat(t, (char *)" MO"); + if (flags & OL_LO) + t = xstrcat(t, (char *)" LO"); + if (flags & OL_MN) + t = xstrcat(t, (char *)" MN"); + Syslog('s', "%s", t); + free(t); +} + + + +void rqflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Request flags:"); + if (flags & RQ_RQ_BR) + t = xstrcat(t, (char *)" RQ_BR"); + if (flags & RQ_RQ_BU) + t = xstrcat(t, (char *)" RQ_BU"); + if (flags & RQ_RQ_WR) + t = xstrcat(t, (char *)" RQ_WR"); + if (flags & RQ_RQ_WU) + t = xstrcat(t, (char *)" RQ_WU"); + Syslog('s', "%s", t); + free(t); +} + + + +void moflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + t = xstrcpy((char *)"Modem flags :"); + if (flags & NL_V22) + t = xstrcat(t, (char *)" V22"); + if (flags & NL_V29) + t = xstrcat(t, (char *)" V29"); + if (flags & NL_V32) + t = xstrcat(t, (char *)" V32"); + if (flags & NL_V32B) + t = xstrcat(t, (char *)" V32B"); + if (flags & NL_V34) + t = xstrcat(t, (char *)" V34"); + if (flags & NL_V42) + t = xstrcat(t, (char *)" V42"); + if (flags & NL_V42B) + t = xstrcat(t, (char *)" V42B"); + if (flags & NL_MNP) + t = xstrcat(t, (char *)" MNP"); + if (flags & NL_H96) + t = xstrcat(t, (char *)" H96"); + if (flags & NL_HST) + t = xstrcat(t, (char *)" HST"); + if (flags & NL_H14) + t = xstrcat(t, (char *)" H14"); + if (flags & NL_H16) + t = xstrcat(t, (char *)" H16"); + if (flags & NL_MAX) + t = xstrcat(t, (char *)" MAX"); + if (flags & NL_PEP) + t = xstrcat(t, (char *)" PEP"); + if (flags & NL_CSP) + t = xstrcat(t, (char *)" CSP"); + if (flags & NL_V32T) + t = xstrcat(t, (char *)" V32T"); + if (flags & NL_VFC) + t = xstrcat(t, (char *)" VFC"); + if (flags & NL_ZYX) + t = xstrcat(t, (char *)" ZYX"); + if (flags & NL_X2C) + t = xstrcat(t, (char *)" X2C"); + if (flags & NL_X2S) + t = xstrcat(t, (char *)" X2S"); + if (flags & NL_V90C) + t = xstrcat(t, (char *)" V90C"); + if (flags & NL_V90S) + t = xstrcat(t, (char *)" V90S"); + Syslog('s', "%s", t); + free(t); +} + + + +void diflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"ISDN flags :"); + if (flags & ND_V110L) + t = xstrcat(t, (char *)" V110L"); + if (flags & ND_V110H) + t = xstrcat(t, (char *)" V110H"); + if (flags & ND_V120L) + t = xstrcat(t, (char *)" V120L"); + if (flags & ND_V120H) + t = xstrcat(t, (char *)" V120H"); + if (flags & ND_X75) + t = xstrcat(t, (char *)" X75"); + Syslog('s', "%s", t); + free(t); +} + + + +void ipflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"TCP/IP flags :"); + if (flags & IP_IBN) + t = xstrcat(t, (char *)" IBN"); + if (flags & IP_IFC) + t = xstrcat(t, (char *)" IFC"); + if (flags & IP_ITN) + t = xstrcat(t, (char *)" ITN"); + if (flags & IP_IVM) + t = xstrcat(t, (char *)" IVM"); + if (flags & IP_IP) + t = xstrcat(t, (char *)" IP"); + Syslog('s', "%s", t); + free(t); +} + + + diff --git a/lib/nodelock.c b/lib/nodelock.c new file mode 100644 index 00000000..cc6014b1 --- /dev/null +++ b/lib/nodelock.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * + * File ..................: nodelock.c + * Purpose ...............: Node locking + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + + +int nodelock(faddr *addr) +{ + char *fn,*tfn,*p; + char tmp[16]; + FILE *fp; + pid_t pid,mypid; + int tmppid,sverr; + + fn = bsyname(addr); + tfn = xstrcpy(fn); + if ((p=strrchr(tfn,'/'))) + *++p='\0'; + mypid = getpid(); + sprintf(tmp, "aa%d", mypid); + tfn = xstrcat(tfn, tmp); + mkdirs(tfn); + + if ((fp = fopen(tfn,"w")) == NULL) { + WriteError("$Can't open tmp file for bsy lock (%s) \"%s\"",ascfnode(addr, 0x1f), tfn); + free(tfn); + return 1; + } + + fprintf(fp,"%10d\n", mypid); + fclose(fp); + chmod(tfn, 0444); + if (link(tfn, fn) == 0) { + unlink(tfn); + free(tfn); + return 0; + } else { + sverr=errno; + } + + if (sverr != EEXIST) { + WriteError("$Could not link \"%s\" to \"%s\"",tfn,fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } + + if ((fp=fopen(fn,"r")) == NULL) { + WriteError("$Could not open existing lock file \"%s\"",fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } + + /* + * Lock exists, check owner + */ + fscanf(fp, "%d", &tmppid); + pid = tmppid; + fclose(fp); + + /* + * If lock is our own lock, then it's ok and we are ready. + */ + if (getpid() == pid) { + unlink(tfn); + free(tfn); + return 0; + } + + if (kill(pid, 0) && (errno == ESRCH)) { + Syslog('+', "Found stale bsy file for %s, unlink", ascfnode(addr,0x1f)); + unlink(fn); + } else { + Syslog('+', "Node %s is locked by pid %d", ascfnode(addr, 0x1f), pid); + unlink(tfn); + free(tfn); + return 1; + } + + if (link(tfn,fn) == 0) { + unlink(tfn); + free(tfn); + return 0; + } else { + WriteError("$Could not link \"%s\" to \"%s\"",tfn,fn); + WriteError("Locking %s failed", ascfnode(addr, 0x1f)); + unlink(tfn); + free(tfn); + return 1; + } +} + + + +int nodeulock(faddr *addr) +{ + char *fn; + FILE *fp; + pid_t pid,mypid; + int tmppid; + + fn = bsyname(addr); + if ((fp = fopen(fn, "r")) == NULL) { + WriteError("$Can't open lock file (%s) \"%s\"", ascfnode(addr, 0x1f), fn); + return 1; + } + + fscanf(fp, "%d", &tmppid); + pid = tmppid; + fclose(fp); + mypid = getpid(); + + if (pid == mypid) { + unlink(fn); + return 0; + } else { + WriteError("Unlock (%s) file failed for process %u, we are %u", ascfnode(addr, 0x1f), pid,mypid); + return 1; + } +} + + diff --git a/lib/noderecord.c b/lib/noderecord.c new file mode 100644 index 00000000..1ad29705 --- /dev/null +++ b/lib/noderecord.c @@ -0,0 +1,58 @@ +/***************************************************************************** + * + * File ..................: noderecord.c + * Purpose ...............: Load noderecord + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "dbnode.h" +#include "common.h" + + + +int noderecord(faddr *addr) +{ + fidoaddr fa; + + memset(&fa, 0, sizeof(fa)); + fa.zone = addr->zone; + fa.net = addr->net; + fa.node = addr->node; + fa.point = addr->point; + + if (!(TestNode(fa))) + if (!SearchNode(fa)) { + return FALSE; + } + + return TRUE; +} + + diff --git a/lib/packet.c b/lib/packet.c new file mode 100644 index 00000000..3b79307c --- /dev/null +++ b/lib/packet.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: packet.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" +#include "dbnode.h" + + + +static FILE *pktfp=NULL; +static faddr pktroute = +{ + NULL,0,0,0,0,NULL +}; + + + +FILE *openpkt(FILE *pkt, faddr *addr, char flavor) +{ + off_t pos; + struct flock fl; + struct stat st; + char *Name; + struct tm *ptm; + time_t t; + int i; + faddr *bestaka; + unsigned char buffer[0x3a]; + char str[9]; + + if (pkt == NULL) { + if (pktfp) { + Syslog('P', "packet opened, check address"); + if (metric(addr,&pktroute) == 0) { + if ((CFG.maxpktsize == 0L) || + ((fstat(fileno(pktfp),&st) == 0) && + (st.st_size < CFG.maxpktsize))) { + Syslog('P', "return existing fp"); + return pktfp; + } + Syslog('P', "packet too big, open new"); + closepkt(); + } else { + Syslog('P', "address changed, closing fp"); + closepkt(); + } + } + + Syslog('P', "open new packet file"); + pktroute.zone = addr->zone; + pktroute.net = addr->net; + pktroute.node = addr->node; + pktroute.point = addr->point; + pktroute.domain = xstrcpy(addr->domain); + pktroute.name = NULL; + Name = pktname(addr,flavor); + mkdirs(Name); + + if ((pktfp = fopen(Name, "r+")) == NULL) + pktfp = fopen(Name,"w"); + if (pktfp == NULL) { + WriteError("$Unable to open packet %s",MBSE_SS(Name)); + return NULL; + } + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (fcntl(fileno(pktfp), F_SETLKW, &fl) < 0) { + WriteError("$Unable to lock packet %s", MBSE_SS(Name)); + fclose(pktfp); + return NULL; + } + + pkt = pktfp; + pos = fseek(pkt, -2L, SEEK_END); + } + + pos = ftell(pkt); + if (pos <= 0L) { + Syslog('P', "creating new .pkt"); + + memset(&buffer, 0, sizeof(buffer)); + time(&t); + ptm = localtime(&t); + if (ptm->tm_sec > 59) + ptm->tm_sec = 59; + + bestaka = bestaka_s(addr); + buffer[0x00] = (bestaka->node & 0x00ff); + buffer[0x01] = (bestaka->node & 0xff00) >> 8; + buffer[0x02] = (addr->node & 0x00ff); + buffer[0x03] = (addr->node & 0xff00) >> 8; + buffer[0x04] = ((ptm->tm_year + 1900) & 0x00ff); + buffer[0x05] = ((ptm->tm_year + 1900) & 0xff00) >> 8; + buffer[0x06] = ptm->tm_mon; + buffer[0x08] = ptm->tm_mday; + buffer[0x0a] = ptm->tm_hour; + buffer[0x0c] = ptm->tm_min; + buffer[0x0e] = ptm->tm_sec; + buffer[0x12] = 2; + buffer[0x14] = (bestaka->net & 0x00ff); + buffer[0x15] = (bestaka->net & 0xff00) >> 8; + buffer[0x16] = (addr->net & 0x00ff); + buffer[0x17] = (addr->net & 0xff00) >> 8; + buffer[0x18] = 0xfe; + + memset(&str, 0, 8); + if (noderecord(addr) && strlen(nodes.Epasswd)) + sprintf(str, "%s", nodes.Epasswd); + for (i = 0; i < 8; i++) + buffer[0x1a + i] = str[i]; + + buffer[0x22] = (bestaka->zone & 0x00ff); + buffer[0x23] = (bestaka->zone & 0xff00) >> 8; + buffer[0x24] = (addr->zone & 0x00ff); + buffer[0x25] = (addr->zone & 0xff00) >> 8; + buffer[0x29] = 1; + buffer[0x2c] = 1; + buffer[0x2e] = buffer[0x22]; + buffer[0x2f] = buffer[0x23]; + buffer[0x30] = buffer[0x24]; + buffer[0x31] = buffer[0x25]; + buffer[0x32] = (bestaka->point & 0x00ff); + buffer[0x33] = (bestaka->point & 0xff00) >> 8; + buffer[0x34] = (addr->point & 0x00ff); + buffer[0x35] = (addr->point & 0xff00) >> 8; + buffer[0x36] = 'm'; + buffer[0x37] = 'b'; + buffer[0x38] = 's'; + buffer[0x39] = 'e'; + + fseek(pkt, 0L, SEEK_SET); + fwrite(buffer, 1, 0x3a, pkt); + } + + return pkt; +} + + + +void closepkt(void) +{ + unsigned char buffer[2]; + + Syslog('P', "closepkt entered"); + memset(&buffer, 0, sizeof(buffer)); + + if (pktfp) { + fwrite(buffer, 1, 2, pktfp); + fclose(pktfp); /* close also discards lock */ + } + pktfp = NULL; + if (pktroute.domain) + free(pktroute.domain); +} + + diff --git a/lib/parsedate.c b/lib/parsedate.c new file mode 100644 index 00000000..ce58b0c3 --- /dev/null +++ b/lib/parsedate.c @@ -0,0 +1,1780 @@ +/* $Revision$ +** +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990. +** Further revised (removed obsolete constructs and cleaned up timezone +** names) in August, 1991, by Rich. Paul Eggert +** helped in September, 1992. +** +** This grammar has six shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 530 *//* Empty body for statement */ +/* SUPPRESS 593 on yyerrlab *//* Label was not used */ +/* SUPPRESS 593 on yynewstate *//* Label was not used */ +/* SUPPRESS 595 on yypvt *//* Automatic variable may be used before set */ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + +#if !defined(HAVE_TM_ZONE) && !defined(_TIMEZONE) && !defined(HAVE_DECLARED_TIMEZONE) +extern time_t timezone; +#endif + +#define yylhs date_yylhs +#define yylen date_yylen +#define yydefred date_yydefred +#define yydgoto date_yydgoto +#define yysindex date_yysindex +#define yyrindex date_yyrindex +#define yygindex date_yygindex +#define yytable date_yytable +#define yycheck date_yycheck +#define yyparse date_parse +#define yylex date_lex +#define yyerror date_error + +static int date_lex(void); + + /* See the LeapYears table in Convert. */ +#define EPOCH 1970 +#define END_OF_TIME 2038 + /* Constants for general time calculations. */ +#define DST_OFFSET 1 +#define SECSPERDAY (24L * 60L * 60L) + /* Readability for TABLE stuff. */ +#define HOUR(x) (x * 60) + +#define LPAREN '(' +#define RPAREN ')' +#define IS7BIT(x) ((unsigned int)(x) < 0200) + +/* +** Get the number of elements in a fixed-size array, or a pointer just +** past the end of it. +*/ +#define SIZEOF(array) ((int)(sizeof array / sizeof array[0])) +#define ENDOF(array) (&array[SIZEOF(array)]) +#define CTYPE(isXXXXX, c) ((isascii((c)) && isXXXXX((c)))) + + +typedef char const *STRING; +typedef char * const CSTRING; + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + STRING name; + int type; + time_t value; +} TABLE; + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + + +/* +** Global variables. We could get rid of most of them by using a yacc +** union, but this is more efficient. (This routine predates the +** yacc %union construct.) +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static int yyHaveDate; +static int yyHaveRel; +static int yyHaveTime; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + + + +static void date_error(char *); + + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 44 +#define YYFLAG -32768 +#define YYNTBASE 15 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 265 ? yytranslate[x] : 23) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 14, 2, 2, 13, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 12, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 3, 4, 5, 6, + 7, 8, 9, 10, 11 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 6, 9, 11, 13, 16, 21, 26, + 33, 40, 42, 44, 47, 49, 51, 55, 61, 64, + 69, 72, 76, 82, 85, 88, 91, 94, 95 +}; + +static const short yyrhs[] = { -1, + 15, 16, 0, 17, 0, 17, 18, 0, 20, 0, + 21, 0, 10, 22, 0, 10, 12, 10, 22, 0, + 10, 12, 10, 19, 0, 10, 12, 10, 12, 10, + 22, 0, 10, 12, 10, 12, 10, 19, 0, 11, + 0, 4, 0, 11, 19, 0, 19, 0, 9, 0, + 10, 13, 10, 0, 10, 13, 10, 13, 10, 0, + 6, 10, 0, 6, 10, 14, 10, 0, 10, 6, + 0, 10, 6, 10, 0, 3, 14, 10, 6, 10, + 0, 9, 8, 0, 10, 8, 0, 9, 7, 0, + 10, 7, 0, 0, 5, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 160, 161, 164, 173, 177, 180, 185, 197, 203, 210, + 216, 226, 230, 234, 242, 248, 269, 273, 293, 297, + 308, 312, 323, 336, 339, 342, 345, 350, 353 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","tDAY","tDAYZONE", +"tMERIDIAN","tMONTH","tMONTH_UNIT","tSEC_UNIT","tSNUMBER","tUNUMBER","tZONE", +"':'","'/'","','","spec","item","time","zone","numzone","date","rel","o_merid", NULL +}; +#endif + +static const short yyr1[] = { 0, + 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, + 17, 18, 18, 18, 18, 19, 20, 20, 20, 20, + 20, 20, 20, 21, 21, 21, 21, 22, 22 +}; + +static const short yyr2[] = { 0, + 0, 2, 1, 2, 1, 1, 2, 4, 4, 6, + 6, 1, 1, 2, 1, 1, 3, 5, 2, 4, + 2, 3, 5, 2, 2, 2, 2, 0, 1 +}; + +static const short yydefact[] = { 1, + 0, 0, 0, 0, 28, 2, 3, 5, 6, 0, + 19, 26, 24, 29, 21, 27, 25, 0, 0, 7, + 13, 16, 12, 4, 15, 0, 0, 22, 28, 17, + 14, 0, 20, 0, 9, 8, 0, 23, 28, 18, + 11, 10, 0, 0 +}; + +static const short yydefgoto[] = { 1, + 6, 7, 24, 25, 8, 9, 20 +}; + +static const short yypact[] = {-32768, + 1, -11, 11, 20, 12,-32768, 4,-32768,-32768, 13, + 16,-32768,-32768,-32768, 21,-32768,-32768, 22, 23,-32768, +-32768,-32768, 5,-32768,-32768, 28, 25,-32768, 17, 24, +-32768, 26,-32768, 29,-32768,-32768, 30,-32768, 0,-32768, +-32768,-32768, 38,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768,-32768,-32768, -23,-32768,-32768, -27 +}; + + +#define YYLAST 40 + + +static const short yytable[] = { 31, + 43, 36, 10, 2, 14, 35, 3, 21, 22, 4, + 5, 42, 22, 22, 23, 41, 14, 15, 16, 17, + 11, 14, 26, 18, 19, 22, 12, 13, 34, 27, + 28, 29, 30, 32, 33, 38, 37, 44, 39, 40 +}; + +static const short yycheck[] = { 23, + 0, 29, 14, 3, 5, 29, 6, 4, 9, 9, + 10, 39, 9, 9, 11, 39, 5, 6, 7, 8, + 10, 5, 10, 12, 13, 9, 7, 8, 12, 14, + 10, 10, 10, 6, 10, 10, 13, 0, 10, 10 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +// #line 3 "/usr/local/share/bison.simple" +/* This file comes from bison-1.28. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +#ifndef YYSTACK_USE_ALLOCA +#ifdef alloca +#define YYSTACK_USE_ALLOCA +#else /* alloca not defined */ +#ifdef __GNUC__ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) || (defined (__sun) && defined (__i386)) +#define YYSTACK_USE_ALLOCA +#include +#else /* not sparc */ +/* We think this test detects Watcom and Microsoft C. */ +/* This used to test MSDOS, but that is a bad idea + since that symbol is in the user namespace. */ +#if (defined (_MSDOS) || defined (_MSDOS_)) && !defined (__TURBOC__) +#if 0 /* No need for malloc.h, which pollutes the namespace; + instead, just don't use alloca. */ +#include +#endif +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +/* I don't know what this was needed for, but it pollutes the namespace. + So I turned it off. rms, 2 May 1997. */ +/* #include */ + #pragma alloca +#define YYSTACK_USE_ALLOCA +#else /* not MSDOS, or __TURBOC__, or _AIX */ +#if 0 +#ifdef __hpux /* haible@ilog.fr says this works for HPUX 9.05 and up, + and on HPUX 10. Eventually we can turn this on. */ +#define YYSTACK_USE_ALLOCA +#define alloca __builtin_alloca +#endif /* __hpux */ +#endif +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc */ +#endif /* not GNU C */ +#endif /* alloca not defined */ +#endif /* YYSTACK_USE_ALLOCA not defined */ + +#ifdef YYSTACK_USE_ALLOCA +#define YYSTACK_ALLOC alloca +#else +#define YYSTACK_ALLOC malloc +#endif + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), cyylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&cyylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&cyylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&cyylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&cyylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +CYYSTYPE cyylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Define __yy_memcpy. Note that the size argument + should be passed with type unsigned int, because that is what the non-GCC + definitions require. With GCC, __builtin_memcpy takes an arg + of type size_t, but it can handle unsigned int. */ + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + unsigned int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, unsigned int count) +{ + register char *t = to; + register char *f = from; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +#ifdef YYPARSE_PARAM +int yyparse (void *); +#else +int yyparse (void); +#endif +#endif + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register CYYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + CYYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + CYYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + int yyfree_stacks = 0; + +#ifdef YYPURE + int yychar; + CYYSTYPE cyylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + CYYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + CYYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror((char *)"parser stack overflow"); + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; +#ifndef YYSTACK_USE_ALLOCA + yyfree_stacks = 1; +#endif + yyss = (short *) YYSTACK_ALLOC (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, + size * (unsigned int) sizeof (*yyssp)); + yyvs = (CYYSTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, + size * (unsigned int) sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) YYSTACK_ALLOC (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, + size * (unsigned int) sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, cyylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = cyylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 3: +{ + yyHaveTime++; +#if defined(lint) + /* I am compulsive about lint natterings... */ + if (yyHaveTime == -1) { + YYERROR; + } +#endif /* defined(lint) */ + ; + break;} +case 4: +{ + yyHaveTime++; + yyTimezone = yyvsp[0].Number; + ; + break;} +case 5: +{ + yyHaveDate++; + ; + break;} +case 6: +{ + yyHaveRel = 1; + ; + break;} +case 7: +{ + if (yyvsp[-1].Number < 100) { + yyHour = yyvsp[-1].Number; + yyMinutes = 0; + } + else { + yyHour = yyvsp[-1].Number / 100; + yyMinutes = yyvsp[-1].Number % 100; + } + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 8: +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 9: +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + ; + break;} +case 10: +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = yyvsp[0].Meridian; + ; + break;} +case 11: +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyTimezone = yyvsp[0].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + ; + break;} +case 12: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 13: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSTon; + ; + break;} +case 14: +{ + /* Only allow "GMT+300" and "GMT-0800" */ + if (yyvsp[-1].Number != 0) { + YYABORT; + } + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 15: +{ + yyval.Number = yyvsp[0].Number; + yyDSTmode = DSToff; + ; + break;} +case 16: +{ + int i; + + /* Unix and GMT and numeric timezones -- a little confusing. */ + if (yyvsp[0].Number < 0) { + /* Don't work with negative modulus. */ + yyvsp[0].Number = -yyvsp[0].Number; + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = (yyvsp[0].Number / 100) * 60 + i; + } + else { + if (yyvsp[0].Number > 9999 || (i = yyvsp[0].Number % 100) >= 60) { + YYABORT; + } + yyval.Number = -((yyvsp[0].Number / 100) * 60 + i); + } + ; + break;} +case 17: +{ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 18: +{ + if (yyvsp[-4].Number > 100) { + /* assume YYYY/MM/DD format, so need not to add 1900 */ + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } + else { + /* assume MM/DD/YY* format */ + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + } + ; + break;} +case 19: +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + ; + break;} +case 20: +{ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 21: +{ + yyDay = yyvsp[-1].Number; + yyMonth = yyvsp[0].Number; + ; + break;} +case 22: +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 23: +{ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + if (yyvsp[0].Number > 100) { + /* assume year is YYYY format, so need not to add 1900 */ + yyYear = yyvsp[0].Number; + } else { + /* assume year is YY format, so need to add 1900 */ + yyYear = yyvsp[0].Number + 1900; + } + ; + break;} +case 24: +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 25: +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 26: +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 27: +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + ; + break;} +case 28: +{ + yyval.Meridian = MER24; + ; + break;} +case 29: +{ + yyval.Meridian = yyvsp[0].Meridian; + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror((char *)"parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = cyylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + yyacceptlab: + /* YYACCEPT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 0; + + yyabortlab: + /* YYABORT comes here. */ + if (yyfree_stacks) + { + free (yyss); + free (yyvs); +#ifdef YYLSP_NEEDED + free (yyls); +#endif + } + return 1; +} + + +/* Month and day table. */ +static TABLE MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + /* The value of the day isn't used... */ + { "sunday", tDAY, 0 }, + { "monday", tDAY, 0 }, + { "tuesday", tDAY, 0 }, + { "wednesday", tDAY, 0 }, + { "thursday", tDAY, 0 }, + { "friday", tDAY, 0 }, + { "saturday", tDAY, 0 }, +}; + +/* Time units table. */ +static TABLE UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "week", tSEC_UNIT, 7 * 24 * 60 * 60 }, + { "day", tSEC_UNIT, 1 * 24 * 60 * 60 }, + { "hour", tSEC_UNIT, 60 * 60 }, + { "minute", tSEC_UNIT, 60 }, + { "min", tSEC_UNIT, 60 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, +}; + +/* Timezone table. */ +static TABLE TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal */ + { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */ + { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */ + { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */ + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */ + { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */ + { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */ + { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */ + { "mez", tZONE, -HOUR(1) }, /* Middle European */ + { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */ + { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */ + { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */ + { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */ + { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */ + { "cct", tZONE, -HOUR(8) }, /* China Coast */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard */ + { "kst", tZONE, -HOUR(9) }, /* Korean Standard */ + { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */ + { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */ + { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */ + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + + /* For completeness we include the following entries. */ +#if 0 + + /* Duplicate names. Either they conflict with a zone listed above + * (which is either more likely to be seen or just been in circulation + * longer), or they conflict with another zone in this section and + * we could not reasonably choose one over the other. */ + { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */ + { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */ + { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */ + { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */ + { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */ + { "cst", tZONE, HOUR( 5) }, /* Chile Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */ + { "ast", tZONE, HOUR( 5) }, /* Acre Standard */ + { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */ + { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */ + { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */ + { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */ + { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */ + { "sst", tZONE, HOUR(11) }, /* Samoa Standard */ + { "ist", tZONE, -HOUR(2) }, /* Israel Standard */ + { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */ + { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */ + { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */ + { "cst", tZONE, -HOUR(8) }, /* China Standard */ + { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */ + { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */ + + /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ + { "wat", tZONE, -HOUR(1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard */ + { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad */ + { "it", tZONE, -(HOUR(3)+30) }, /* Iran */ + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ + { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */ + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ + { "nst", tZONE, -HOUR(7) }, /* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra */ + { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */ + { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */ + { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */ + { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */ +#endif /* 0 */ +}; + + + +/* ARGSUSED */ +static void +date_error(s) + char *s; +{ + /* NOTREACHED */ +} + +int GetTimeInfo(TIMEINFO *Now) +{ + static time_t NextHour; + static long LastTzone; + struct tm *tm; + int secondsUntilNextHour; +#if defined(HAVE_GETTIMEOFDAY) + struct timeval tv; +#endif /* defined(HAVE_GETTIMEOFDAY) */ +#if !defined(HAVE_TM_GMTOFF) + struct tm local; + struct tm gmt; +#endif /* !defined(HAVE_TM_GMTOFF) */ + + /* Get the basic time. */ +#if defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(&tv, (struct timezone *)NULL) == -1) + return -1; + Now->time = tv.tv_sec; + Now->usec = tv.tv_usec; +#else + /* Can't check for -1 since that might be a time, I guess. */ + (void)time(&Now->time); + Now->usec = 0; +#endif /* defined(HAVE_GETTIMEOFDAY) */ + + /* Now get the timezone if the last time < HH:00:00 <= now for some HH. */ + if (NextHour <= Now->time) { + if ((tm = localtime(&Now->time)) == NULL) + return -1; + secondsUntilNextHour = 60 * (60 - tm->tm_min) - tm->tm_sec; +#if !defined(HAVE_TM_GMTOFF) + /* To get the timezone, compare localtime with GMT. */ + local = *tm; + if ((tm = gmtime(&Now->time)) == NULL) + return -1; + gmt = *tm; + + /* Assume we are never more than 24 hours away. */ + LastTzone = gmt.tm_yday - local.tm_yday; + if (LastTzone > 1) + LastTzone = -24; + else if (LastTzone < -1) + LastTzone = 24; + else + LastTzone *= 24; + + /* Scale in the hours and minutes; ignore seconds. */ + LastTzone += gmt.tm_hour - local.tm_hour; + LastTzone *= 60; + LastTzone += gmt.tm_min - local.tm_min; +#else + LastTzone = (0 - tm->tm_gmtoff) / 60; +#endif /* defined(HAVE_TM_GMTOFF) */ + NextHour = Now->time + secondsUntilNextHour; + } + Now->tzone = LastTzone; + return 0; +} + + + +static time_t ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian) +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61) + return -1; + if (Meridian == MER24) { + if (Hours < 0 || Hours > 23) + return -1; + } + else { + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + if (Meridian == MERpm) + Hours += 12; + } + return (Hours * 60L + Minutes) * 60L + Seconds; +} + + +static time_t +Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian, DSTMODE dst) +{ + static int DaysNormal[13] = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int DaysLeap[13] = { + 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + static int LeapYears[] = { + 1972, 1976, 1980, 1984, 1988, 1992, 1996, + 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036 + }; + int *yp; + int *mp; + time_t Julian; + int i; + time_t tod; + + /* Year should not be passed as a relative value, but absolute one. + so this should not happen, but just ensure it */ + if (Year < 0) + Year = -Year; + if (Year < 100) + Year += 1900; + if (Year < EPOCH) + Year += 100; + for (mp = DaysNormal, yp = LeapYears; yp < ENDOF(LeapYears); yp++) + if (Year == *yp) { + mp = DaysLeap; + break; + } + if (Year < EPOCH || Year > END_OF_TIME + || Month < 1 || Month > 12 + /* NOSTRICT *//* conversion from long may lose accuracy */ + || Day < 1 || Day > mp[(int)Month]) + return -1; + + Julian = Day - 1 + (Year - EPOCH) * 365; + for (yp = LeapYears; yp < ENDOF(LeapYears); yp++, Julian++) + if (Year <= *yp) + break; + for (i = 1; i < Month; i++) + Julian += *++mp; + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + tod = Julian; + if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst)) + Julian -= DST_OFFSET * 60 * 60; + return Julian; +} + + +static time_t DSTcorrect(time_t Start, time_t Future) +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60; +} + + +static time_t RelativeMonth(time_t Start, time_t RelMonth) +{ + struct tm *tm; + time_t Month; + time_t Year; + + tm = localtime(&Start); + Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; + Year = Month / 12; + Year += 1900; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int LookupWord(char *buff, int length) +{ + char *p; + STRING q; + TABLE *tp; + int c; + + p = buff; + c = p[0]; + + /* See if we have an abbreviation for a month. */ + if (length == 3 || (length == 4 && p[3] == '.')) + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) { + q = tp->name; + if (c == q[0] && p[1] == q[1] && p[2] == q[2]) { + cyylval.Number = tp->value; + return tp->type; + } + } + else + for (tp = MonthDayTable; tp < ENDOF(MonthDayTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Try for a timezone. */ + for (tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Try the units table. */ + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + if (--length > 0 && p[length] == 's') { + p[length] = '\0'; + for (tp = UnitsTable; tp < ENDOF(UnitsTable); tp++) + if (c == tp->name[0] && strcmp(p, tp->name) == 0) { + p[length] = 's'; + cyylval.Number = tp->value; + return tp->type; + } + p[length] = 's'; + } + length++; + + /* Drop out any periods. */ + for (p = buff, q = (STRING)buff; *q; q++) + if (*q != '.') + *p++ = *q; + *p = '\0'; + + /* Try the meridians. */ + if (buff[1] == 'm' && buff[2] == '\0') { + if (buff[0] == 'a') { + cyylval.Meridian = MERam; + return tMERIDIAN; + } + if (buff[0] == 'p') { + cyylval.Meridian = MERpm; + return tMERIDIAN; + } + } + + /* If we saw any periods, try the timezones again. */ + if (p - buff != length) { + c = buff[0]; + for (p = buff, tp = TimezoneTable; tp < ENDOF(TimezoneTable); tp++) + if (c == tp->name[0] && p[1] == tp->name[1] + && strcmp(p, tp->name) == 0) { + cyylval.Number = tp->value; + return tp->type; + } + } + + /* Unknown word -- assume GMT timezone. */ + cyylval.Number = 0; + return tZONE; +} + + +static int date_lex(void) +{ + char c; + char *p; + char buff[20]; + int sign; + int i; + int nesting; + + for ( ; ; ) { + /* Get first character after the whitespace. */ + for ( ; ; ) { + while (CTYPE(isspace, (int)*yyInput)) + yyInput++; + c = *yyInput; + + /* Ignore RFC 822 comments, typically time zone names. */ + if (c != LPAREN) + break; + for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; ) + if (c == LPAREN) + nesting++; + else if (!IS7BIT(c) || c == '\0' || c == '\r' + || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c)))) + /* Lexical error: bad comment. */ + return '?'; + yyInput++; + } + + /* A number? */ + if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + yyInput++; + if (!CTYPE(isdigit, (int)*yyInput)) + /* Skip the plus or minus sign. */ + continue; + } + else + sign = 0; + for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); ) + i = 10 * i + c - '0'; + yyInput--; + cyylval.Number = sign < 0 ? -i : i; + return sign ? tSNUMBER : tUNUMBER; + } + + /* A word? */ + if (CTYPE(isalpha, (int)c)) { + for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); ) + if (p < &buff[sizeof buff - 1]) + *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c; + *p = '\0'; + yyInput--; + return LookupWord(buff, p - buff); + } + + return *yyInput++; + } +} + + +time_t parsedate(char *p, TIMEINFO *now) +{ + struct tm *tm; + TIMEINFO ti; + time_t Start; + + yyInput = p; + if (now == NULL) { + now = &ti; + (void)GetTimeInfo(&ti); + } + + tm = localtime(&now->time); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; +#ifdef HAVE_TM_GMTOFF + yyTimezone = tm->tm_gmtoff/60; +#else + yyTimezone = timezone/60; +#endif + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveRel = 0; + yyHaveTime = 0; + + if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1) + return -1; + + if (yyHaveDate || yyHaveTime) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now->time; + if (!yyHaveRel) + Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec; + } + + Start += yyRelSeconds; + if (yyRelMonth) + Start += RelativeMonth(Start, yyRelMonth); + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} diff --git a/lib/pktname.c b/lib/pktname.c new file mode 100644 index 00000000..5cadc666 --- /dev/null +++ b/lib/pktname.c @@ -0,0 +1,286 @@ +/***************************************************************************** + * + * File ..................: pktname.c + * Purpose ...............: BinkleyTerm outbound naming + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +#define ptyp "ut" +#define ftyp "lo" +#define ttyp "pk" +#define rtyp "req" +#define styp "spl" +#define btyp "bsy" +#define qtyp "sts" +#define ltyp "pol" + + +static char buf[PATH_MAX]; + + +char *prepbuf(faddr *addr) +{ + char *p, *domain=NULL; + char zpref[8]; + int i; + + sprintf(buf, "%s", CFG.outbound); + + if (CFG.addr4d) { + Syslog('o', "Use 4d addressing, zone is %d", addr->zone); + + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * If we got a 5d address we use the given domain, if + * we got a 4d address, we look for a matching domain name. + */ + if (addr->domain) + domain = xstrcpy(addr->domain); + else + for (i = 0; i < 40; i++) + if (CFG.aka[i].zone == addr->zone) { + domain = xstrcpy(CFG.aka[i].domain); + break; + } + + if ((domain != NULL) && (strlen(CFG.aka[0].domain) != 0) && + (strcasecmp(domain,CFG.aka[0].domain) != 0)) { + if ((p = strrchr(buf,'/'))) + p++; + else + p = buf; + strcpy(p, domain); + for (; *p; p++) + *p = tolower(*p); + for (i = 0; i < 40; i++) + if ((strlen(CFG.aka[i].domain)) && + (strcasecmp(CFG.aka[i].domain, domain) == 0)) + break; + + /* + * The default zone must be the first one in the + * setup, other zones get the hexadecimal zone + * number appended. + */ + if (CFG.aka[i].zone == addr->zone) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * this is our primary domain + */ + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0]='\0'; + else + sprintf(zpref,".%03x",addr->zone); + } + } + + p = buf + strlen(buf); + + if (addr->point) + sprintf(p,"%s/%04x%04x.pnt/%08x.", zpref,addr->net,addr->node,addr->point); + else + sprintf(p,"%s/%04x%04x.",zpref,addr->net,addr->node); + + p = buf + strlen(buf); + if (domain) + free(domain); + return p; +} + + + +char *pktname(faddr *addr, char flavor) +{ + char *p; + + p = prepbuf(addr); + if (flavor == 'f') + flavor = 'o'; + + sprintf(p, "%c%s", flavor, ptyp); + Syslog('O', "packet name is \"%s\"",buf); + return buf; +} + + + +char *floname(faddr *addr, char flavor) +{ + char *p; + + p = prepbuf(addr); + if (flavor == 'o') + flavor = 'f'; + sprintf(p, "%c%s", flavor, ftyp); + Syslog('O', "flo file name is \"%s\"",buf); + return buf; +} + + + +char *reqname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", rtyp); + Syslog('O', "req file name is \"%s\"",buf); + return buf; +} + + + +char *splname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", styp); + Syslog('O', "spl file name is \"%s\"",buf); + return buf; +} + + + +char *bsyname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", btyp); + Syslog('O', "bsy file name is \"%s\"",buf); + return buf; +} + + + +char *stsname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", qtyp); + Syslog('O', "sts file name is \"%s\"",buf); + return buf; +} + + + +char *polname(faddr *addr) +{ + char *p; + + p = prepbuf(addr); + sprintf(p, "%s", ltyp); + Syslog('O', "pol file name is \"%s\"", buf); + return buf; +} + + + +static char *dow[] = {(char *)"su", (char *)"mo", (char *)"tu", (char *)"we", + (char *)"th", (char *)"fr", (char *)"sa"}; + +char *dayname(void) +{ + time_t tt; + struct tm *ptm; + + (void)time(&tt); + ptm = localtime(&tt); + sprintf(buf, "%s", dow[ptm->tm_wday]); + + return buf; +} + + + +char *arcname(faddr *addr, unsigned short Zone, int ARCmailCompat) +{ + char *p; + char *ext; + time_t tt; + struct tm *ptm; + faddr *bestaka; + + (void)time(&tt); + ptm = localtime(&tt); + ext = dow[ptm->tm_wday]; + + bestaka = bestaka_s(addr); + + (void)prepbuf(addr); + p = strrchr(buf, '/'); + + if (!ARCmailCompat && (Zone != addr->zone)) { + /* + * Generate ARCfile name from the CRC of the ASCII string + * of the node address. + */ + sprintf(p, "/%08lx.%s0", StringCRC32(ascfnode(addr, 0x1f)), ext); + } else { + if (addr->point) { + sprintf(p, "/%04x%04x.%s0", + ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node) + (addr->point)) & 0xffff, + ext); + } else if (bestaka->point) { + /* + * Inserted the next code for if we are a point, + * I hope this is ARCmail 0.60 compliant. 21-May-1999 + */ + sprintf(p, "/%04x%04x.%s0", ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node) - (bestaka->point)) & 0xffff, ext); + } else { + sprintf(p, "/%04x%04x.%s0", ((bestaka->net) - (addr->net)) & 0xffff, + ((bestaka->node) - (addr->node)) &0xffff, ext); + } + } + + Syslog('O', "Arc file name is \"%s\"", buf); + return buf; +} + + diff --git a/lib/pop3.c b/lib/pop3.c new file mode 100644 index 00000000..de904259 --- /dev/null +++ b/lib/pop3.c @@ -0,0 +1,202 @@ +/***************************************************************************** + * + * File ..................: pop3.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 12-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int pop3sock = -1; /* TCP/IP socket */ +struct hostent *php; /* Host info remote */ +struct servent *psp; /* Service information */ +struct sockaddr_in pop3_loc; /* For local socket address */ +struct sockaddr_in pop3_rem; /* For remote socket address */ + + + +int pop3_connect(void) +{ + int addrlen; + char *p; + + if (!strlen(CFG.popnode)) { + WriteError("POP3: host not configured"); + return -1; + } + + Syslog('+', "POP3: connecting host: %s", CFG.popnode); + memset(&pop3_loc, 0, sizeof(struct sockaddr_in)); + memset(&pop3_rem, 0, sizeof(struct sockaddr_in)); + + pop3_rem.sin_family = AF_INET; + + if ((php = gethostbyname(CFG.popnode)) == NULL) { + WriteError("$POP3: can't find host %s", CFG.popnode); + return -1; + } + + pop3_rem.sin_addr.s_addr = ((struct in_addr *)(php->h_addr))->s_addr; + + if ((psp = getservbyname("pop3", "tcp")) == NULL) { + /* + * RedHat doesn't follow IANA specs and uses pop-3 in /etc/services + */ + if ((psp = getservbyname("pop-3", "tcp")) == NULL) { + WriteError("$POP3: can't find service port for pop3/tcp"); + return -1; + } + } + pop3_rem.sin_port = psp->s_port; + + if ((pop3sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$POP3: unable to create tcp socket"); + return -1; + } + + if (connect(pop3sock, (struct sockaddr *)&pop3_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$POP3: cannot connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(pop3sock, (struct sockaddr *)&pop3_loc, &addrlen) == -1) { + WriteError("$POP3: unable to read socket address"); + return -1; + } + + p = pop3_receive(); + if (strlen(p) == 0) { + WriteError("POP3: no response from server"); + pop3_close(); + return -1; + } + + if (strncmp(p, "+OK", 3)) { + WriteError("POP3: bad response: %s", p); + pop3_close(); + return -1; + } + + Syslog('+', "POP3: %s", p); + + return pop3sock; +} + + + +int pop3_send(char *buf) +{ + if (pop3sock == -1) + return -1; + + if (send(pop3sock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$POP3: socket send failed"); + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *pop3_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i, j; + + memset((char *)&buf, 0, SS_BUFSIZE); + i = 0; + while (TRUE) { + j = recv(pop3sock, &buf[i], 1, 0); + if (j == -1) { + WriteError("$POP3: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + if (buf[i] == '\n') + break; + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int pop3_close(void) +{ + if (pop3sock == -1) + return 0; + + if (shutdown(pop3sock, 1) == -1) { + WriteError("$POP3: can't close socket"); + return -1; + } + + pop3sock = -1; + Syslog('+', "POP3: closed"); + return 0; +} + + + +int pop3_cmd(char *cmd) +{ + char *p; + + if (pop3_send(cmd) == -1) + return -1; + + p = pop3_receive(); + + if (strncmp(p, "+OK", 3)) { + WriteError("POP3> %s", cmd); + WriteError("POP3< %s", p); + return -1; + } + return 0; +} + + + diff --git a/lib/rawio.c b/lib/rawio.c new file mode 100644 index 00000000..96f750eb --- /dev/null +++ b/lib/rawio.c @@ -0,0 +1,238 @@ +/***************************************************************************** + * + * File ..................: rawio.c + * Purpose ...............: Raw I/O routines. + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + +int rawset = FALSE; + + +/* + * Sets raw mode and saves the terminal setup + */ +void Setraw() +{ + if (ioctl(ttyfd, TCGETA, &tbuf) == -1) { + perror("TCGETA Failed"); + exit(1); /* ERROR - could not set get tty ioctl */ + } + + tbufsav = tbuf; + tbuf.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP | IXON ); + /* + * Map CRNL modes strip control characters and flow control + */ + tbuf.c_oflag &= ~OPOST; /* Don't do ouput character translation */ + tbuf.c_lflag &= ~(ICANON | ECHO); /* No canonical input and no echo */ + tbuf.c_cc[VMIN] = 1; /* Receive 1 character at a time */ + tbuf.c_cc[VTIME] = 0; /* No time limit per character */ + + if (ioctl(ttyfd, TCSETAF, &tbuf) == -1) { + perror("TCSETAF failed"); + exit(1); /* ERROR - could not set tty ioctl */ + } + + rawset = TRUE; +} + + + +/* + * Unsets raw mode and returns state of terminal + */ +void Unsetraw() +{ + /* + * Only unset the mode if it is set to raw mode + */ + if (rawset == TRUE) { + if (ioctl(ttyfd, TCSETAF, &tbufsav) == -1) { + perror("TCSETAF Normal Failed"); + exit(1); /* ERROR - could not save original tty ioctl */ + } + } + rawset = FALSE; +} + + + +/* + * This function is used to get a single character from a user ie for a + * menu option + */ +unsigned char Getone() +{ + unsigned char c = 0; + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 8"); + exit(1); + } + Setraw(); + + c = Readkey(); + + Unsetraw(); + close(ttyfd); + return(c); +} + + + +/* + * Read the (locked) speed from the tty + */ +int Speed(void) +{ + int mspeed; + struct termio ttyhold; + + static int baud[16] = {0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400}; + + ioctl(0, TCGETA, &ttyhold); + mspeed = baud[ttyhold.c_cflag & 017]; + ioctl(0, TCSETAF, &ttyhold); + + return(mspeed); +} + + + +/* + * Wait for a character for a maximum of wtime * 10 mSec. + */ +int Waitchar(unsigned char *ch, int wtime) +{ + int i, rc = -1; + + for (i = 0; i < wtime; i++) { + rc = read(ttyfd, ch, 1); + if (rc == 1) + return rc; + usleep(10000); + } + return rc; +} + + + +int Escapechar(unsigned char *ch) +{ + int rc; + unsigned char c; + + /* + * Escape character, if nothing follows within + * 50 mSec, the user really pressed . + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + if (*ch == '[') { + /* + * Start of CSI sequence. If nothing follows, + * return immediatly. + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + /* + * Test for the most important keys. Note + * that only the cursor movement keys are + * guaranteed to work with PC-clients. + */ + c = *ch; + if (c == 'A') + c = KEY_UP; + if (c == 'B') + c = KEY_DOWN; + if (c == 'C') + c = KEY_RIGHT; + if (c == 'D') + c = KEY_LEFT; + if ((c == '1') || (c == 'H') || (c == 0)) + c = KEY_HOME; + if ((c == '4') || (c == 'K') || (c == 101) || (c == 144)) + c = KEY_END; + if (c == '2') + c = KEY_INS; + if (c == '3') + c = KEY_DEL; + if (c == '5') + c = KEY_PGUP; + if (c == '6') + c = KEY_PGDN; + memcpy(ch, &c, sizeof(unsigned char)); + return rc; + } + return -1; +} + + + +/* + * This next function will detect the grey keys on the keyboard for + * VT100, VT220, Xterm, PC-ANSI, and Linux console. Works with + * several terminals on serial lines (tested 1200 bps). + * If for example cursur keys are detected, this function returns + * a translated value. + */ +unsigned char Readkey(void) +{ + unsigned char ch = 0; + int rc = -1; + + while (rc == -1) { + rc = Waitchar(&ch, 5); + + /* + * If the character is not an Escape character, + * then this function is finished. + */ + if ((rc == 1) && (ch != KEY_ESCAPE)) + return ch; + + if ((rc == 1) && (ch == KEY_ESCAPE)) { + rc = Escapechar(&ch); + if (rc == 1) + return ch; + else + return KEY_ESCAPE; + } + } + + return(ch); +} + + + diff --git a/lib/records.h b/lib/records.h new file mode 100644 index 00000000..7ccc3642 --- /dev/null +++ b/lib/records.h @@ -0,0 +1,123 @@ +/***************************************************************************** + * + * File ..................: records.h + * Purpose ...............: MBSE BBS Global structure + * Last modification date : 25-Sep-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _RECORDS_H +#define _RECORDS_H + +struct userhdr usrconfighdr; /* Users database */ +struct userrec usrconfig; +struct userrec exitinfo; /* Users online data */ + +struct servicehdr servhdr; /* Services database */ +struct servicerec servrec; + +struct sysrec SYSINFO; /* System info statistics */ + +struct prothdr PROThdr; /* Transfer protocols */ +struct prot PROT; + +struct onelinehdr olhdr; /* Oneliner database */ +struct oneline ol; + +struct fileareashdr areahdr; /* File areas */ +struct fileareas area; +struct FILERecord file; +struct _fgrouphdr fgrouphdr; /* File groups */ +struct _fgroup fgroup; + +struct _ngrouphdr ngrouphdr; /* Newfiles groups */ +struct _ngroup ngroup; + +struct bbslisthdr bbshdr; /* BBS list */ +struct bbslist bbs; + +struct lastcallershdr LCALLhdr; /* Lastcallers info */ +struct lastcallers LCALL; + +struct sysconfig CFG; /* System configuration */ + +struct limitshdr LIMIThdr; /* User limits */ +struct limits LIMIT; + +struct menufile menus; + +struct msgareashdr msgshdr; /* Messages configuration */ +struct msgareas msgs; +struct _mgrouphdr mgrouphdr; /* Message groups */ +struct _mgroup mgroup; + +struct timebankhdr bankhdr; /* Timebank structure */ +struct timebank bank; + +struct languagehdr langhdr; /* Language data */ +struct language lang; +struct langdata ldata; + +struct crackerhdr safehdr; /* Safe cracker structure */ +struct cracker safe; + +struct _fidonethdr fidonethdr; /* Fidonet structure */ +struct _fidonet fidonet; +struct domhdr domainhdr; +struct domrec domtrans; + +struct _archiverhdr archiverhdr; /* Archivers */ +struct _archiver archiver; + +struct _virscanhdr virscanhdr; /* Virus scanners */ +struct _virscan virscan; + +struct _ttyinfohdr ttyinfohdr; /* TTY lines */ +struct _ttyinfo ttyinfo; +struct _modemhdr modemhdr; /* Modem models */ +struct _modem modem; + +struct _tichdr tichdr; /* TIC areas */ +struct _tic tic; +struct _hatchhdr hatchhdr; /* Hatch areas */ +struct _hatch hatch; +struct _magichdr magichdr; /* Magic areas */ +struct _magic magic; + +struct _nodeshdr nodeshdr; /* Fidonet nodes */ +struct _nodes nodes; + +struct _bill bill; /* Unsent bills */ + +struct _newfileshdr newfileshdr; /* New file reports */ +struct _newfiles newfiles; + +struct _scanmgrhdr scanmgrhdr; /* Filefind areas */ +struct _scanmgr scanmgr; + +#endif + diff --git a/lib/rfcaddr.c b/lib/rfcaddr.c new file mode 100644 index 00000000..538c8fba --- /dev/null +++ b/lib/rfcaddr.c @@ -0,0 +1,328 @@ +/***************************************************************************** + * + * File ..................: rfcaddr.c + * Purpose ...............: MBSE BBS Common Library + * Last modification date : 23-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +extern int addrerror; + +static char *errname[] = { + (char *)"nested <>", + (char *)"multiple <>", + (char *)"unmatched <>""()", + (char *)"badtoken", + (char *)"badstructure", +}; + + + +char *addrerrstr(int err) +{ + int i; + static char buf[128]; + + buf[0] = '\0'; + for (i = 0; i < ADDR_ERRMAX; i++) + if (err & (1 << i)) { + if (buf[0]) + strcat(buf,","); + strcat(buf, errname[i]); + } + if (buf[0] == '\0') + strcpy(buf,"none"); + return buf; +} + + + +void tidyrfcaddr(parsedaddr addr) +{ + if (addr.target) + free(addr.target); + if (addr.remainder) + free(addr.remainder); + if (addr.comment) + free(addr.comment); +} + + + +parsedaddr parserfcaddr(char *s) +{ + parsedaddr result; + char *inbrackets = NULL, *outbrackets = NULL, *cleanbuf = NULL, *combuf = NULL; + char *t, *r, *c, *p, *q, **x; + int quotes, brackets, escaped, anglecomplete; + char *firstat, *lastat, *percent, *colon, *comma, *exclam; + +// Syslog('M', "parserfcaddr() 1"); + + result.target = NULL; + result.remainder = NULL; + result.comment = NULL; + addrerror = 0; + + if ((s == NULL) || (*s == '\0')) + return result; + + /* First check if there is an "angled" portion */ + +// Syslog('M', "parserfcaddr() 1b strlen=%d", strlen(s)); + inbrackets = calloc(strlen(s)+1, sizeof(char)); + outbrackets = calloc(strlen(s)+1, sizeof(char)); + brackets = quotes = escaped = anglecomplete = 0; +// Syslog('M', "parserfcaddr() 2"); + for (p = s,q = inbrackets, r = outbrackets, x = &r; *p; p++) { + if (escaped) + escaped = FALSE; + else /* process all special chars */ + switch (*p) { + case '\\': escaped = TRUE; break; + case '\"': quotes = !quotes; break; + case '<': if (quotes) + break; + if (brackets) + addrerror |= ADDR_NESTED; + if (anglecomplete) + addrerror |= ADDR_MULTIPLE; + brackets++; + x = &q; + break; + case '>': if (quotes) + break; + if (brackets) + brackets--; + else + addrerror |= ADDR_UNMATCHED; + if (!brackets) + anglecomplete = 1; + break; + } + *((*x)++) = *p; + if (!brackets) + x = &r; + } +// Syslog('M', "parserfcaddr() 3"); + *q = '\0'; + *r = '\0'; + if (brackets || quotes) + addrerror |= ADDR_UNMATCHED; + +// Syslog('N', " inbrackets: \"%s\"",inbrackets); +// Syslog('N', "outbrackets: \"%s\"",outbrackets); +// Syslog('N', " addrerror: 0x%04x",addrerror); + + if (addrerror) + goto leave1; + + cleanbuf = calloc(strlen(s)+1, sizeof(char)); + combuf = calloc(strlen(s)+1, sizeof(char)); +// Syslog('M', "parserfcaddr() 4"); + if (*inbrackets) { /* there actually is an angled portion */ + strcpy(combuf, outbrackets); + c = combuf + strlen(combuf); + p = inbrackets + 1; + *(p+strlen(p)-1) = '\0'; + } else { + c = combuf; + p = outbrackets; + } + +// Syslog('N', " now parsing: \"%s\"",p); +// Syslog('N', "current comment: \"%s\"",result.comment); + + + /* OK, now we have result.comment filled with wat was outside + angle brackets, c pointing past the end of it, + p pointing to what is supposed to be address, with angle + brackets already removed */ +// Syslog('M', "parserfcaddr() 5"); + quotes = brackets = escaped = 0; + for (r = cleanbuf, x = &r; *p; p++) { + if (escaped) { + escaped=0; + *((*x)++)=*p; + } else /* process all special chars */ + if (isspace(*p)) { + if ((quotes) || (brackets)) + *((*x)++) = *p; + } else + switch (*p) { + case '\\': escaped=1; + /* pass backslash itself only inside quotes + and comments, or for the special cases + \" and \\ otherwise eat it away */ + if ((quotes) || (brackets)) + *((*x)++) = *p; + else if ((*(p+1)=='"') || (*(p+1)=='\\')) + *((*x)++) = *p; + break; + case '\"': quotes = !quotes; + *((*x)++) = *p; + break; + case '(': + brackets++; + x = &c; + break; + case ')': + if (brackets) + brackets--; + else + addrerror |= ADDR_UNMATCHED; + if (!brackets) + x = &r; + break; + default: + *((*x)++) = *p; + break; + } + } + *r = '\0'; + *c = '\0'; + if (brackets || quotes) + addrerror |= ADDR_UNMATCHED; + +// Syslog('N', " now parsing: \"%s\"",inbrackets); +// Syslog('N', "complete comment: \"%s\"",result.comment); +// Syslog('N', " addrerror: 0x%04x",addrerror); + +// Syslog('M', "parserfcaddr() 6"); + if (addrerror) + goto leave2; + + /* OK, now we have inangles buffer filled with the 'clean' address, + all comments removed, and result.comment is ready filled */ + + /* seach for special chars that are outside quotes */ + + firstat = lastat = percent = colon = comma = exclam = NULL; + quotes = 0; escaped = 0; + for (p = cleanbuf; *p; p++) + if (*p == '\\') + p++; + else if (*p == '\"') + quotes = !quotes; + else if (!quotes) + switch (*p) { + case '@': + if (!firstat) + firstat = p; + lastat = p; + break; + case '%': + percent = p; + break; + case ':': + colon = p; + break; + case ',': + comma = p; + break; + case '!': + if (!exclam) + exclam = p; + break; + } +// Syslog('M', "parserfcaddr() 7"); + if ((firstat == cleanbuf) && colon) { +// Syslog('N', "@aaa,@bbb:xxx@yyy construct"); + if (comma && (comma < colon)) { + *comma = '\0'; + r = comma + 1; +// Syslog('M', "parserfcaddr() 9"); + } else { + *colon = '\0'; + r = colon + 1; +// Syslog('M', "parserfcaddr() 10"); + } + t = firstat + 1; +// Syslog('M', "parserfcaddr() 11"); + } else if (lastat) { +// Syslog('N', "anything@somewhere construct"); + *lastat = '\0'; + r = cleanbuf; + t = lastat + 1; +// Syslog('M', "parserfcaddr() 12"); + } else if (exclam) { +// Syslog('N', "domain!something construct (without @'s)"); + *exclam = '\0'; + r = exclam + 1; + t = cleanbuf; +// Syslog('M', "parserfcaddr() 13"); + } else if (percent) { +// Syslog('N', "anything%%somewhere construct (without !'s and @'s)"); + *percent = '\0'; + r = cleanbuf; + t = percent + 1; +// Syslog('M', "parserfcaddr() 14"); + } else { +// Syslog('N', "remainder only present"); + /* unquote it if necessary */ + if ((*cleanbuf == '\"') && (*(p = (cleanbuf+strlen(cleanbuf)-1)) == '\"')) { + *p = '\0'; + r = cleanbuf + 1; + } else + r = cleanbuf; + t = NULL; +// Syslog('M', "parserfcaddr() 15"); + } +// Syslog('M', "parserfcaddr() 16"); + if (t && (*t != '\0')) + result.target = xstrcpy(t); +// Syslog('M', "parserfcaddr() 17"); + if (r && (*r != '\0')) + result.remainder = xstrcpy(r); +// Syslog('M', "parserfcaddr() 18"); + if (*combuf != '\0') + result.comment = xstrcpy(combuf); +// Syslog('M', "parserfcaddr() 19"); + +leave1: /* this is also normal exit */ +// Syslog('M', "parserfcaddr() leave1"); + free(cleanbuf); + free(combuf); + free(inbrackets); + free(outbrackets); +// Syslog('M', "going"); + return result; + +leave2: /* if error found on second stage, free */ +// Syslog('M', "parserfcaddr() leave2"); + free(cleanbuf); + free(combuf); +// Syslog('M', "going"); + return result; +} + diff --git a/lib/rfcdate.c b/lib/rfcdate.c new file mode 100644 index 00000000..c12eabdf --- /dev/null +++ b/lib/rfcdate.c @@ -0,0 +1,192 @@ +/***************************************************************************** + * + * File ..................: rfcdate.c + * Purpose ...............: Date utilities + * Last modification date : 30-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" +#include "clcomm.h" + + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +time_t parsefdate(char *str, void *now) +{ + struct tm tm, *pnow; + int i, rc; + time_t Now; + char *dummy, *pday, *pmon, *pyear, *phour, *pminute, *psecond; + char *buf; + + Now = time(NULL); + pnow = localtime(&Now); + dummy = pday = pmon = pyear = phour = pminute = psecond = NULL; + + if (str == NULL) { + WriteError("parsefdate entered NULL"); + return (time_t)0; + } + + buf = xstrcpy(str); + rc = 1; + memset(&tm, 0, sizeof(tm)); + + if ((strncasecmp(str,"Sun ",4) == 0) || + (strncasecmp(str,"Mon ",4) == 0) || + (strncasecmp(str,"Tue ",4) == 0) || + (strncasecmp(str,"Wed ",4) == 0) || + (strncasecmp(str,"Thu ",4) == 0) || + (strncasecmp(str,"Fri ",4) == 0) || + (strncasecmp(str,"Sat ",4) == 0)) { + /* + * SEAdog mode + */ + if ((dummy = strtok(str, " ")) != NULL) + if ((pday = strtok(NULL, " ")) != NULL) + if ((pmon = strtok(NULL, " ")) != NULL) + if ((pyear = strtok(NULL, " ")) != NULL) + if ((phour = strtok(NULL, ": ")) != NULL) + if ((pminute = strtok(NULL, ": ")) != NULL) + rc = 0; + psecond = xstrcpy((char *)"00"); + } else { + /* + * FTS-0001 Standard mode + */ + if ((pday = strtok(str, " ")) != NULL) + if ((pmon = strtok(NULL, " ")) != NULL) + if ((pyear = strtok(NULL, " ")) != NULL) + if ((phour = strtok(NULL, ": ")) != NULL) + if ((pminute = strtok(NULL, ": ")) != NULL) + if ((psecond = strtok(NULL, ": ")) != NULL) + rc = 0; + } + if (rc == 1) { + WriteError("Could not parse date \"%s\"", str); + return (time_t)0; + } + + tm.tm_sec = atoi(psecond); + tm.tm_min = atoi(pminute); + tm.tm_hour = atoi(phour); + tm.tm_mday = atoi(pday); + tm.tm_isdst = pnow->tm_isdst; + + for (i = 0; i < 12; i++) + if (strncasecmp(months[i], pmon, 3) == 0) + break; + tm.tm_mon = i; + + tm.tm_year = atoi(pyear); + if (tm.tm_year < 0) { + rc = 1; + } else if (tm.tm_year < 100) { /* Correct date field */ + while (pnow->tm_year - tm.tm_year > 50) { + tm.tm_year +=100; /* Sliding window adaption */ + } + } else if (tm.tm_year < 1900) { /* Field contains year like */ + rc = 2; /* Timed/Netmgr bug */ + } else { + tm.tm_year -= 1900; /* 4 Digit year field */ + rc = 2; + } + + /* + * Log if something isn't right + */ + if (rc) + Syslog('+', "fdate \"%s\" to %02d-%02d-%d %02d:%02d:%02d rc=%d", buf, + tm.tm_mday, tm.tm_mon+1, tm.tm_year+1900, + tm.tm_hour, tm.tm_min, tm.tm_sec, rc); + + free(buf); + return mktime(&tm) - (gmt_offset((time_t)0) * 60); +} + + + +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm, gtm; + char sign; + int hr, min; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + hr = offset / 60L; + min = offset % 60L; + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d", wdays[ptm.tm_wday], ptm.tm_mday, months[ptm.tm_mon], + ptm.tm_year + 1900, ptm.tm_hour, ptm.tm_min, ptm.tm_sec, sign, hr, min); + return(buf); +} + + + diff --git a/lib/rfcmsg.c b/lib/rfcmsg.c new file mode 100644 index 00000000..c5afd82d --- /dev/null +++ b/lib/rfcmsg.c @@ -0,0 +1,168 @@ +/***************************************************************************** + * + * File ..................: rfcmsg.c + * Purpose ...............: RFC msg + * Last modification date : 14-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "common.h" +#include "clcomm.h" + + + +#ifndef BUFSIZ +#define BUFSIZ 512 +#endif + +#define KWDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_." + + + +rfcmsg *parsrfc(FILE *fp) +{ + int linecont=FALSE,newcont,firstline; + rfcmsg *start=NULL, *cur=NULL; + char buffer[BUFSIZ]; + char *p; + + while (bgets(buffer, BUFSIZ-1, fp) && strcmp(buffer,"\n")) { + newcont = (buffer[strlen(buffer)-1] != '\n'); + Syslog('M', "Line read: \"%s\" - %s continued", buffer,newcont?"to be":"not to be"); + if (linecont) { + Syslog('M', "this is a continuation of a long line"); + cur->val=xstrcat(cur->val,buffer); + } else { + if (isspace(buffer[0])) { + if (strspn(buffer," \t\n") == strlen(buffer)) { + Syslog('M', "breaking with blank-only line"); + break; + } + Syslog('M', "this is a continuation line"); + if (!cur) { + Syslog('M', "Wrong first line: \"%s\"",buffer); + cur = (rfcmsg *)malloc(sizeof(rfcmsg)); + start = cur; + cur->next = NULL; + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } else + cur->val = xstrcat(cur->val,buffer); + } else { +// Syslog('M', "this is a header line"); + if (cur) { + firstline=FALSE; + (cur->next) = (rfcmsg *)malloc(sizeof(rfcmsg)); + cur = cur->next; + } else { + firstline = TRUE; + cur = (rfcmsg *)malloc(sizeof(rfcmsg)); + start = cur; + } + cur->next = NULL; + cur->key = NULL; + cur->val = NULL; + if (firstline && !strncmp(buffer,"From ",5)) { + Syslog('M', "This is a uucpfrom line"); + cur->key=xstrcpy((char *)"X-UUCP-From"); + cur->val=xstrcpy(buffer+4); + } else if ( !strncasecmp(buffer,"Cc:",3)) { + Syslog('M', "Cc: line"); + if (strchr(buffer+3,'@')) { + cur->key = xstrcpy((char *)"Cc"); + cur->val = xstrcpy(buffer+3); + } else { + Syslog('M', "FTN Cc: line: \"%s\"", buffer); + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } + } else if ((p=strchr(buffer,':')) && (p > buffer) && /* ':' isn't 1st chr */ + isspace(*(p+1)) && /* space past ':' */ + /* at least one non blank char */ + (strspn(p+2, " \t\n") < strlen(p+2)) && (strspn(buffer,KWDCHARS) == (p-buffer))) { + *p='\0'; +// Syslog('M', "This is a regular header"); + cur->key = xstrcpy(buffer); + cur->val = xstrcpy(p+1); + } else { + Syslog('M', "Non-header line: \"%s\"",buffer); + cur->key = xstrcpy((char *)"X-Body-Start"); + cur->val = xstrcpy(buffer); + break; + } + } + } + linecont = newcont; + } + return(start); +} + + + +void tidyrfc(rfcmsg *msg) +{ + rfcmsg *nxt; + + for (; msg; msg=nxt) { + nxt = msg->next; + if (msg->key) + free(msg->key); + if (msg->val) + free(msg->val); + free(msg); + } + return; +} + + + +void dumpmsg(rfcmsg *msg, FILE *fp) +{ + char *p; + + p = hdr((char *)"X-Body-Start",msg); + for (; msg; msg=msg->next) + if (strcasecmp(msg->key, "X-Body-Start")) { + if (!strcasecmp(msg->key, "X-UUCP-From")) + fputs("From", fp); + else { + fputs(msg->key,fp); + fputs(":",fp); + } + fputs(msg->val,fp); + } + fputs("\n",fp); + if (p) + fputs(p,fp); + return; +} + + diff --git a/lib/semafore.c b/lib/semafore.c new file mode 100644 index 00000000..5cae6a19 --- /dev/null +++ b/lib/semafore.c @@ -0,0 +1,73 @@ +/***************************************************************************** + * + * File ..................: semafore.c + * Purpose ...............: Create, test and remove semafore's + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "clcomm.h" +#include "common.h" + + +void CreateSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SECR:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) + WriteError("Can't create semafore %s", sem); +} + + + +void RemoveSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SERM:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) + WriteError("Can't remove semafore %s", sem); +} + + + +int IsSema(char *sem) +{ + char temp[40]; + + sprintf(temp, "%s", SockR("SEST:1,%s;", sem)); + if (strncmp(temp, "200", 3) == 0) { + WriteError("Can't read semafore %s", sem); + return FALSE; + } + strtok(temp, ","); + return atoi(strtok(NULL, ";")); +} + + diff --git a/lib/signame.c b/lib/signame.c new file mode 100644 index 00000000..8f63d4c7 --- /dev/null +++ b/lib/signame.c @@ -0,0 +1,95 @@ +/***************************************************************************** + * + * File ..................: signame.c + * Purpose ...............: Signal names + * Last modification date : 19-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "clcomm.h" + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/lib/smtp.c b/lib/smtp.c new file mode 100644 index 00000000..6bdc7619 --- /dev/null +++ b/lib/smtp.c @@ -0,0 +1,213 @@ +/***************************************************************************** + * + * File ..................: smtp.c + * Purpose ...............: MBSE BBS Internet Library + * Last modification date : 23-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "mbinet.h" + + +static int smtpsock = -1; /* TCP/IP socket */ +struct hostent *shp; /* Host info remote */ +struct servent *ssp; /* Service information */ +struct sockaddr_in smtp_loc; /* For local socket address */ +struct sockaddr_in smtp_rem; /* For remote socket address */ + + + +int smtp_connect(void) +{ + int addrlen; + char *p, temp[40]; + + if (smtpsock != -1) + return smtpsock; + + if (!strlen(CFG.smtpnode)) { + WriteError("SMTP: host not configured"); + return -1; + } + + Syslog('+', "SMTP: connecting host: %s", CFG.smtpnode); + memset(&smtp_loc, 0, sizeof(struct sockaddr_in)); + memset(&smtp_rem, 0, sizeof(struct sockaddr_in)); + + smtp_rem.sin_family = AF_INET; + + if ((shp = gethostbyname(CFG.smtpnode)) == NULL) { + WriteError("$SMTP: can't find host %s", CFG.smtpnode); + return -1; + } + + smtp_rem.sin_addr.s_addr = ((struct in_addr *)(shp->h_addr))->s_addr; + + if ((ssp = getservbyname("smtp", "tcp")) == NULL) { + WriteError("$SMTP: can't find service port for smtp/tcp"); + return -1; + } + smtp_rem.sin_port = ssp->s_port; + + if ((smtpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + WriteError("$SMTP: unable to create tcp socket"); + return -1; + } + + if (connect(smtpsock, (struct sockaddr *)&smtp_rem, sizeof(struct sockaddr_in)) == -1) { + WriteError("$SMTP: can't connect tcp socket"); + return -1; + } + + addrlen = sizeof(struct sockaddr_in); + + if (getsockname(smtpsock, (struct sockaddr *)&smtp_loc, &addrlen) == -1) { + WriteError("$SMTP: unable to read socket address"); + return -1; + } + + p = smtp_receive(); + if (strlen(p) == 0) { + WriteError("SMTP: no response"); + smtp_close(); + return -1; + } + + if (strncmp(p, "220", 3)) { + WriteError("SMTP: bad response: %s", p); + smtp_close(); + return -1; + } + + Syslog('+', "SMTP: %s", p); + + sprintf(temp, "HELO %s\r\n", CFG.sysdomain); + if (smtp_cmd(temp, 250)) { + smtp_close(); + return -1; + } + + return smtpsock; +} + + + +int smtp_send(char *buf) +{ + if (smtpsock == -1) + return -1; + + if (send(smtpsock, buf, strlen(buf), 0) != strlen(buf)) { + WriteError("$SMTP: socket send failed"); + return -1; + } + return 0; +} + + + +/* + * Return empty buffer if something went wrong, else the complete + * dataline is returned + */ +char *smtp_receive(void) +{ + static char buf[SS_BUFSIZE]; + int i, j; + + memset((char *)&buf, 0, SS_BUFSIZE); + i = 0; + while ((strchr(buf, '\n')) == NULL) { + j = recv(smtpsock, &buf[i], SS_BUFSIZE-i, 0); + if (j == -1) { + WriteError("$SMTP: error reading socket"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + i += j; + } + + for (i = 0; i < strlen(buf); i++) { + if (buf[i] == '\n') + buf[i] = '\0'; + if (buf[i] == '\r') + buf[i] = '\0'; + } + + return buf; +} + + + +int smtp_close(void) +{ + if (smtpsock == -1) + return 0; + + smtp_cmd((char *)"QUIT\r\n", 221); + + if (shutdown(smtpsock, 1) == -1) { + WriteError("$SMTP: can't close socket"); + return -1; + } + + smtpsock = -1; + Syslog('+', "SMTP: closed"); + return 0; +} + + + +/* + * Send command to the SMTP service. On error return the + * received error number, else return zero. + */ +int smtp_cmd(char *cmd, int resp) +{ + char *p, rsp[6]; + + if (smtp_send(cmd) == -1) + return -1; + + sprintf(rsp, "%d", resp); + p = smtp_receive(); + + if (strncmp(p, rsp, strlen(rsp))) { + WriteError("SMTP> %s", cmd); + WriteError("SMTP< %s", p); + memset(&resp, 0, sizeof(rsp)); + strncpy(rsp, p, 3); + return atoi(rsp); + } + return 0; +} + + + diff --git a/lib/strcasestr.c b/lib/strcasestr.c new file mode 100644 index 00000000..35bc82db --- /dev/null +++ b/lib/strcasestr.c @@ -0,0 +1,25 @@ + +#include "libs.h" + +#ifndef HAVE_STRCASESTR + +char *strcasestr(char *a, char *b) +{ + char *p,*max; + int l; + + if (a && b) { + + l=strlen(b); + max=a+strlen(a)-l; + for (p=a;p<=max;p++) + if (!strncasecmp(p,b,l)) return(p); + return((char *)0); + } + else { + return ((char *) 0); + } +} + +#endif + diff --git a/lib/structs.h b/lib/structs.h new file mode 100644 index 00000000..a80083bd --- /dev/null +++ b/lib/structs.h @@ -0,0 +1,1546 @@ +/***************************************************************************** + * + * File ..................: structs.h + * Purpose ...............: MBSE BBS Global structure + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#ifndef _STRUCTS_H +#define _STRUCTS_H + + + +/***************************************************************************** + * + * Global definitions and structures. + * + */ + +#define Copyright "Copyright (C) 1997-2001 Michiel Broek, All Rights Reserved" +#define ShortRight "Copyright (C) 1997-2001 M. Broek" + + +typedef enum {YES, NO, ASK, ONLY} ASKTYPE; +typedef enum {LOCALMAIL, NETMAIL, ECHOMAIL, NEWS} MSGTYPE; +typedef enum {BOTH, PRIVATE, PUBLIC, RONLY, FTNMOD, USEMOD} MSGKINDSTYPE; +typedef enum {IGNORE, CREATE, KILL} ORPHANTYPE; +typedef enum {SEND, RECV, BOTHDIR} NODETYPE; +typedef enum {POTS, ISDN, NETWORK, LOCAL} LINETYPE; +typedef enum {BROWSING, DOWNLOAD, UPLOAD, READ_POST, DOOR, SYSOPCHAT, + FILELIST, TIMEBANK, SAFE, WHOSON, OLR} DOESTYPE; +typedef enum {I_AVT0, I_ANSI, I_VT52, I_VT100, I_TTY} ITERM; +typedef enum {I_DZA, I_ZAP, I_ZMO, I_SLK, I_KER} IPROT; +typedef enum {E_NOISP, E_TMPISP, E_PRMISP} EMODE; +typedef enum {AREAMGR, FILEMGR, EMAIL} SERVICE; +typedef enum {FEEDINN, FEEDRNEWS, FEEDUUCP} NEWSFEED; + + + +/*********************************************************************** + * + * Nodelist definitions. + * + */ + +#define MAXUFLAGS 16 + + +/* + * Nodelist index file to nodelists. (node.files) + */ +typedef struct _nlfil { + char filename[13]; /* Nodelist filename */ + char domain[13]; /* Domain name */ + unsigned short number; /* File number */ +} nlfil; + + + +/* + * Nodelist index file for node lookup. (node.index) + */ +typedef struct _nlidx { + unsigned short zone; /* Zone number */ + unsigned short net; /* Net number */ + unsigned short node; /* Node number */ + unsigned short point; /* Point number */ + unsigned short region; /* Region of node */ + unsigned short upnet; /* Uplink net */ + unsigned short upnode; /* Uplink node */ + unsigned char type; /* Node type */ + unsigned char pflag; /* Node status */ + unsigned short fileno; /* Nodelist number */ + long offset; /* Offset in nodelist */ +} nlidx; + + + +/* + * Nodelist usernames index file. (node.users) + */ +typedef struct _nlusr { + char user[36]; /* User name */ + long record; /* Record in index */ +} nlusr; + + + +/* + * type values + */ +#define NL_NONE 0 +#define NL_ZONE 1 +#define NL_REGION 2 +#define NL_HOST 3 +#define NL_HUB 4 +#define NL_NODE 5 +#define NL_POINT 6 + + + +/* + * pflag values, all bits zero, node may be dialed analogue FTS-0001. + * the rest are special cases. + */ +#define NL_DOWN 0x01 /* Node is Down */ +#define NL_HOLD 0x02 /* Node is Hold */ +#define NL_PVT 0x04 /* Private node */ +#define NL_DUMMY 0x08 /* Dummy entry */ +#define NL_ISDN 0x10 /* ISDN Only node */ +#define NL_TCPIP 0x20 /* TCP/IP Only node */ + + +/************************************************************************ + * + * Other BBS structures + * + */ + + +/* + * Security structure + */ +typedef struct _security { + unsigned int level; /* Security level */ + unsigned long flags; /* Access flags */ + unsigned long notflags; /* No Access flags */ +} securityrec; + + + +/* + * Fidonet 5d address structure + */ +typedef struct _fidoaddr { + unsigned short zone; /* Zone number */ + unsigned short net; /* Net number */ + unsigned short node; /* Node number */ + unsigned short point; /* Point number */ + char domain[13]; /* Domain name (no dots) */ +} fidoaddr; + + + +/* + * Connected system structure + */ +typedef struct _sysconnect { + fidoaddr aka; /* Address of system */ + unsigned short sendto; /* If we send to system */ + unsigned short receivefrom; /* If we receive from */ + unsigned pause : 1; /* If system is paused */ + unsigned cutoff : 1; /* Cutoff by moderator */ + unsigned spare3 : 1; + unsigned spare4 : 1; + unsigned spare5 : 1; + unsigned spare6 : 1; + unsigned spare7 : 1; + unsigned spare8 : 1; + unsigned spare9 : 1; /* Forces enough space */ +} sysconnect; + + + int Diw; /* Day in week index */ + int Miy; /* Month in year index */ + + +/* + * Statistic counters structure + */ +typedef struct _statcnt { + unsigned long tdow[7]; /* Days of current week */ + unsigned long ldow[7]; /* Days of previous week */ + unsigned long tweek; /* Week total counters */ + unsigned long lweek; /* Last week counters */ + unsigned long month[12]; /* Monthly total counters */ + unsigned long total; /* The ever growing total */ +} statcnt; + + + +/* + * Find replace match structure (phone translation etc). + */ +typedef struct _dual { + char match[21]; /* String to match */ + char repl[21]; /* To replace with */ +} dual; + + + +/* + * Downloaded FTP files (~/var/download.ftp) + */ +typedef struct _downftp { + unsigned long Areanr; + char Name[13]; +} downftp; + + +/**************************************************************************** + * + * Datafile records structure in $MBSE_ROOT/etc + * + */ + + +/* + * Task Manager configuration (task.data) + */ +struct taskrec { + float maxload; /* Maximum system load */ + + char isp_connect[81]; /* ISP connect command */ + char isp_hangup[81]; /* ISP hangup command */ + char isp_ping1[41]; /* ISP ping host 1 */ + char isp_ping2[41]; /* ISP ping host 2 */ + + char zmh_start[6]; /* Zone Mail Hour start */ + char zmh_end[6]; /* Zone Mail Hour end */ + + char cmd_mailout[81]; /* mailout command */ + char cmd_mailin[81]; /* mailin command */ + char cmd_newnews[81]; /* newnews command */ + char cmd_mbindex1[81]; /* mbindex command 1 */ + char cmd_mbindex2[81]; /* mbindex command 2 */ + char cmd_mbindex3[81]; /* mbindex command 3 */ + char cmd_msglink[81]; /* msglink command */ + char cmd_reqindex[81]; /* reqindex command */ + + int max_pots; /* maximum pots calls */ + int max_isdn; /* maximum ISDN calls */ + int max_tcp; /* maximum TCP/IP calls */ + + unsigned ipblocks : 1; /* internet blocks dial */ + unsigned debug : 1; /* debugging on/off */ +}; + + + +/* + * Special mail services (service.data) + */ +struct servicehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last updated at */ +}; + +struct servicerec { + char Service[16]; /* Service name */ + int Action; /* Service action */ + unsigned Active : 1; /* Service is active */ + unsigned Deleted : 1; /* Service is deleted */ +}; + + + +/* + * Domain translation (domain.data) + */ +struct domhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last updated at */ +}; + +struct domrec { + char ftndom[61]; /* Fidonet domain */ + char intdom[61]; /* Internet domain */ + unsigned Active : 1; /* Domain is active */ + unsigned Deleted : 1; /* Domain is deleted */ +}; + + + +/* + * Users Control Structures (users.data) + */ +struct userhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct userrec { + char sUserName[36]; /* User First and Last Name */ + char Name[9]; /* Unix name */ + unsigned long iPassword; /* Users Password (CRC) */ + char sVoicePhone[20]; /* Voice Number */ + char sDataPhone[20]; /* Data/Business Number */ + char sLocation[28]; /* Users Location */ + char address[3][41]; /* Users address */ + char sDateOfBirth[12]; /* Date of Birth */ + time_t tFirstLoginDate; /* Date of First Login */ + time_t tLastLoginDate; /* Date of Last Login */ + securityrec Security; /* User Security Level */ + char sComment[81]; /* User Comment */ + char sExpiryDate[12]; /* User Expiry Date */ + securityrec ExpirySec; /* Expiry Security Level */ + char sSex[8]; /* Users Sex */ + + unsigned Hidden : 1; /* Hide User from Lists */ + unsigned HotKeys : 1; /* Hot-Keys ON/OFF */ + unsigned GraphMode : 1; /* ANSI Mode ON/OFF */ + unsigned Deleted : 1; /* Deleted Status */ + unsigned NeverDelete : 1; /* Never Delete User */ + unsigned Chat : 1; /* Has IEMSI Chatmode */ + unsigned LockedOut : 1; /* User is locked out */ + unsigned DoNotDisturb : 1; /* DoNot disturb */ + unsigned Cls : 1; /* CLS on/off */ + unsigned More : 1; /* More prompt */ + unsigned FsMsged : 1; /* Fullscreen editor */ + unsigned MailScan : 1; /* New Mail scan */ + unsigned Guest : 1; /* Is guest account */ + unsigned OL_ExtInfo : 1; /* OLR extended msg info */ + int iTotalCalls; /* Total number of calls */ + int iTimeLeft; /* Time left today */ + int iConnectTime; /* Connect time this call */ + int iTimeUsed; /* Time used today */ + int iScreenLen; /* User Screen Length */ + time_t tLastPwdChange; /* Date last password chg */ + unsigned iHangUps; /* Total improper hangups */ + long Credit; /* Users credit */ + int Paged; /* Times paged today */ + int OfflineFmt; /* Offline Reader format */ + int LastPktNum; /* Todays Last packet number*/ + char Archiver[6]; /* Archiver to use */ + + int iLastFileArea; /* Number of last file area */ + int iLastFileGroup; /* Number of last file group*/ + char sProtocol[21]; /* Users default protocol */ + unsigned long Downloads; /* Total number of d/l's */ + unsigned long Uploads; /* Total number of uploads */ + unsigned long UploadK; /* Upload KiloBytes */ + unsigned long DownloadK; /* Download KiloBytes */ + long DownloadKToday; /* KB Downloaded today */ + long UploadKToday; /* KB Uploaded today */ + int iTransferTime; /* Last file transfer time */ + int iLastMsgArea; /* Number of last msg area */ + int iLastMsgGroup; /* Number of last msg group */ + int iPosted; /* Number of msgs posted */ + int iLanguage; /* Current Language */ + char sHandle[36]; /* Users Handle */ + int iStatus; /* WhosDoingWhat status */ + int DownloadsToday; /* Downloads today */ + int CrtDef; /* IEMSI Terminal emulation */ + int Protocol; /* IEMSI protocol */ + unsigned IEMSI : 1; /* Is this a IEMSI session */ + unsigned ieMNU : 1; /* Can do ASCII download */ + unsigned ieTAB : 1; /* Can handle TAB character */ + unsigned ieASCII8 : 1; /* Can handle 8-bit IBM-PC */ + unsigned ieNEWS : 1; /* Show bulletins */ + unsigned ieFILE : 1; /* Check for new files */ + unsigned Email : 1; /* Has private email box */ + char Password[15]; /* Plain password */ +}; + + + +/* + * System Control Structures (sysinfo.data) + */ +struct sysrec { + unsigned long SystemCalls; /* Total # of system calls */ + unsigned long Pots; /* POTS calls */ + unsigned long ISDN; /* ISDN calls */ + unsigned long Network; /* Network (internet) calls*/ + unsigned long Local; /* Local calls */ + unsigned long ADSL; /* ADSL calls */ + time_t StartDate; /* Start Date of BBS */ + char LastCaller[36]; /* Last Caller to BBS */ +}; + + + +/* + * Protocol Control Structure (protocol.data) + */ +struct prothdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct prot { + char ProtKey[2]; /* Protocol Key */ + char ProtName[21]; /* Protocol Name */ + char ProtUp[51]; /* Upload Path & Binary */ + char ProtDn[51]; /* Download Path & Bianry */ + unsigned Available : 1; /* Available/Not Available */ + unsigned Batch : 1; /* Batching protocol */ + unsigned Bidir : 1; /* Bi Directional */ + unsigned Deleted : 1; /* Protocol is deleted */ + unsigned Internal : 1; /* Internal protocol */ + char Advice[31]; /* Small advice to user */ + int Efficiency; /* Protocol efficiency in % */ + securityrec Level; /* Sec. level to select */ +}; + + + +/* + * Oneliners Control Structure (oneline.data) + */ +struct onelinehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of record */ +}; + +struct oneline { + char Oneline[81]; /* Oneliner text */ + char UserName[36]; /* User who wrote oneliner */ + char DateOfEntry[12]; /* Date of oneliner entry */ + unsigned Available : 1; /* Deleted Status */ +}; + + + +/* + * File Areas Control Structure (fareas.data) + */ +struct fileareashdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct fileareas { + char Name[45]; /* Filearea Name */ + char Path[81]; /* Filearea Path */ + securityrec DLSec; /* Download Security */ + securityrec UPSec; /* Upload Security */ + securityrec LTSec; /* List Security */ + int Age; /* Age to access area */ + unsigned New : 1; /* New Files Check */ + unsigned Dupes : 1; /* Check for Duplicates */ + unsigned Free : 1; /* All files are Free */ + unsigned DirectDL : 1; /* Direct Download */ + unsigned PwdUP : 1; /* Password Uploads */ + unsigned FileFind : 1; /* FileFind Scan */ + unsigned AddAlpha : 1; /* Add New files sorted */ + unsigned Available : 1; /* Area is available */ + unsigned CDrom : 1; /* Area is on CDrom */ + unsigned FileReq : 1; /* Allow File Requests */ + char BbsGroup[13]; /* BBS Group */ + char Password[21]; /* Area Password */ + unsigned DLdays; /* Move not DL for days */ + unsigned FDdays; /* Move if FD older than */ + unsigned MoveArea; /* Move to Area */ + int Cost; /* File Cost */ + char FilesBbs[65]; /* Path to files.bbs if CD */ + char NewGroup[13]; /* Newfiles scan group */ + char Archiver[6]; /* Archiver for area */ + unsigned Upload; /* Upload area */ +}; + + + +/* + * Index file for fast search of file requests (request.index) + */ +struct FILEIndex { + char Name[13]; /* Short DOS name */ + char LName[81]; /* Long filename */ + long AreaNum; /* File area number */ + long Record; /* Record in database */ +}; + + + +/* + * File Record Control Structure (fdb#.data) + */ +struct FILERecord { + char Name[13]; /* DOS style filename */ + char LName[81]; /* Long filename */ + char xTicArea[13]; /* Tic area file came in */ + off_t Size; /* File Size */ + unsigned long Crc32; /* File CRC-32 */ + char Uploader[36]; /* Uploader name */ + time_t UploadDate; /* Date/Time uploaded */ + time_t FileDate; /* Real file date */ + time_t LastDL; /* Last Download date */ + unsigned long TimesDL; /* Times file was dl'ed */ + unsigned long TimesFTP; /* Times file was FTP'ed */ + unsigned long TimesReq; /* Times file was frequed */ + char Password[16]; /* File password */ + char Desc[25][49]; /* file description */ + int Cost; /* File cost */ + unsigned Free : 1; /* Free File */ + unsigned Deleted : 1; /* Deleted */ + unsigned Missing : 1; /* Missing */ + unsigned NoKill : 1; /* Cannot be deleted */ + unsigned Announced : 1; /* File is announced */ +}; + + + +/* + * BBS List Control Structure (bbslist.data) + */ +struct bbslisthdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct bbslist { + char UserName[36]; /* User Name */ + char DateOfEntry[12]; /* Entry date */ + char Verified[12]; /* Last Verify date */ + unsigned Available : 1; /* Available Status */ + char BBSName[41]; /* BBS Name */ + int Lines; /* Nr of phone lines */ + char Phone[5][21]; /* BBS phone number */ + char Speeds[5][41]; /* Speeds for each line */ + fidoaddr FidoAka[5]; /* Fidonet Aka's */ + char Software[20]; /* BBS Software */ + char Sysop[36]; /* Name of Sysop */ + int Storage; /* Storage amount in megs */ + char Desc[2][81]; /* Description */ + char IPaddress[51]; /* IP or domain name */ + char Open[21]; /* Online time */ +}; + + + +/* + * Last Callers Control Structure (lastcall.data) + */ +struct lastcallershdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct lastcallers { + char UserName[36]; /* User Name */ + char Handle[36]; /* User Handle */ + char TimeOn[6]; /* Time user called bbs */ + int CallTime; /* Time this call */ + char Device[10]; /* Device user used */ + int Calls; /* Total calls to bbs */ + unsigned int SecLevel; /* Users security level */ + char Speed[21]; /* Caller speed */ + unsigned Hidden : 1; /* Hidden or Not at time */ + unsigned Download : 1; /* If downloaded */ + unsigned Upload : 1; /* If uploaded */ + unsigned Read : 1; /* If read messages */ + unsigned Wrote : 1; /* If wrote a message */ + unsigned Chat : 1; /* If did chat */ + unsigned Olr : 1; /* If used Offline Reader */ + char Location[28]; /* User Location */ +}; + + + +/* + * System Control Structure (config.data) + */ +struct sysconfig { + /* Registration Info */ + char sysop_name[36]; /* Sysop Name */ + char bbs_name[36]; /* BBS Name */ + char sysop[9]; /* Unix Sysop name */ + char location[36]; /* System location */ + char bbsid[9]; /* QWK/Bluewave BBS ID */ + char bbsid2[3]; /* Omen filename */ + char sysdomain[36]; /* System Domain name */ + char comment[56]; /* Do what you like here */ + char origin[51]; /* Default origin line */ + + /* FileNames */ + char error_log[15]; /* Name of Error Log */ + char default_menu[15]; /* Default Menu */ + char current_language[15]; /* Default Language */ + char chat_log[15]; /* Chat Logfile */ + char welcome_logo[15]; /* Welcome Logofile */ + + /* Paths */ + char rnewspath[65]; /* Path to rnews */ + char bbs_menus[65]; /* Default Menus */ + char bbs_txtfiles[65]; /* Default Textfiles */ + char nntpnode[65]; /* NNTP server */ + char xbbs_filebase[65]; + char xbbs_language[65]; + char req_magic[65]; /* Request magic directory */ + char bbs_usersdir[65]; /* Users Home Dir Base */ + char nodelists[65]; /* Nodelists */ + char inbound[65]; /* Inbound directory */ + char pinbound[65]; /* Protected inbound */ + char outbound[65]; /* Outbound */ + char xsequencer[65]; + char dospath[65]; /* DOS path */ + char uxpath[65]; /* Unix path */ + + /* Allfiles/Newfiles */ + char ftp_base[65]; /* FTP root */ + int newdays; /* New files since */ + securityrec security; /* Max level list */ + + unsigned addr4d : 1; /* Use 4d addressing */ + unsigned leavecase : 1; /* Leave outbound case */ + + /* BBS Globals */ + int max_login; /* Maximum login attempts */ + unsigned NewAreas : 1; /* Notify if new msg areas */ + unsigned elite_mode : 1; /* Allow new users/Private? */ + unsigned slow_util : 1; /* Run utils slowly */ + unsigned exclude_sysop : 1; /* Exclude Sysop from lists */ + unsigned xUseSysDomain : 1; + unsigned xChkMail : 1; + unsigned iConnectString : 1; /* Display Connect String */ + unsigned iAskFileProtocols : 1; /* Ask user FileProtocols */ + /* before every d/l or u/l */ + unsigned sysop_access; /* Sysop Access Security */ + int password_length; /* Minimum Password Length */ + long bbs_loglevel; /* Logging level for BBS */ + int iPasswd_Char; /* Password Character */ + int iQuota; /* User homedir quota in MB */ + int idleout; /* Idleout Value */ + int CityLen; /* Minimum city length */ + short OLR_NewFileLimit; /* Limit Newfilesscan days */ + unsigned iCRLoginCount; /* Count login Enters */ + + /* New Users */ + securityrec newuser_access; /* New Users Access level */ + int OLR_MaxMsgs; /* OLR Max nr Msgs download */ + unsigned iCapUserName : 1; /* Capitalize Username */ + unsigned iAnsi : 1; /* Ask Ansi */ + unsigned iSex : 1; /* Ask Sex */ + unsigned iDataPhone : 1; /* Ask Data Phone */ + unsigned iVoicePhone : 1; /* Ask Voice Phone */ + unsigned iHandle : 1; /* Ask Alias/Handle */ + unsigned iDOB : 1; /* Ask Date of Birth */ + unsigned iTelephoneScan : 1; /* Telephone Scan */ + unsigned iLocation : 1; /* Ask Location */ + unsigned iCapLocation : 1; /* Capitalize Location */ + unsigned iHotkeys : 1; /* Ask Hot-Keys */ + unsigned GiveEmail : 1; /* Give user email */ + unsigned AskAddress : 1; /* Ask Home Address */ + unsigned iOneName : 1; /* Allow one user name */ + unsigned iCrashLevel; /* User level for crash mail*/ + unsigned iAttachLevel; /* User level for fileattach*/ + + /* Colors */ + int TextColourF; /* Text Colour Foreground */ + int TextColourB; /* Text Colour Background */ + int UnderlineColourF; /* Underline Text Colour */ + int UnderlineColourB; /* Underline Colour */ + int InputColourF; /* Input Text Colour */ + int InputColourB; /* Input Text Colour */ + int CRColourF; /* CR Text Colour */ + int CRColourB; /* CR Text Colour */ + int MoreF; /* More Prompt Text Colour */ + int MoreB; /* More Prompt Text Colour */ + int HiliteF; /* Hilite Text Colour */ + int HiliteB; /* Hilite Text Colour */ + int FilenameF; /* Filename Colour */ + int FilenameB; /* Filename Colour */ + int FilesizeF; /* Filesize Colour */ + int FilesizeB; /* Filesize Colour */ + int FiledateF; /* Filedate Colour */ + int FiledateB; /* Filedate Colour */ + int FiledescF; /* Filedesc Colour */ + int FiledescB; /* Filedesc Colour */ + int MsgInputColourF; /* MsgInput Filename Colour */ + int MsgInputColourB; /* MsgInput Filename Colour */ + + /* Next User Door */ + char sNuScreen[50]; /* Next user txtfile */ + char sNuQuote[81]; /* next user quote */ + + /* Safe Cracker Door */ + int iSafeFirstDigit; /* Safe Door First Digit */ + int iSafeSecondDigit; /* Safe Door Second Digit */ + int iSafeThirdDigit; /* Safe Door Third Digit */ + int iSafeMaxTrys; /* Max trys per day */ + int iSafeMaxNumber; /* Maximum Safe Number */ + unsigned iSafeNumGen : 1; /* Use number generator */ + char sSafePrize[81]; /* Safe Prize */ + char sSafeWelcome[81]; /* Safe welcome file */ + char sSafeOpened[81]; /* Opended safe file */ + + /* Sysop Paging */ + int iPageLength; /* Page Length in Seconds */ + int iMaxPageTimes; /* Max Pages per call */ + unsigned iAskReason : 1; /* Ask Reason */ + int iSysopArea; /* Msg Area if Sysop not in */ + unsigned iExternalChat : 1; /* Use External Chat */ + char sExternalChat[50]; /* External Chat Program */ + unsigned iAutoLog : 1; /* Log Chats ? */ + char sChatDevice[20]; /* Chat Device */ + unsigned iChatPromptChk; /* Check for chat at prompt */ + unsigned iStopChatTime; /* Stop time during chat */ + char cStartTime[7][6]; /* Starting Times */ + char cStopTime[7][6]; /* Stop Times */ + char sCallScript[51]; /* Sysop External Call scr. */ + + /* Mail Options */ + char xquotestr[11]; /* Quote String */ + + /* Time Bank Door */ + int iMaxTimeBalance; /* Users Time Balance */ + int iMaxTimeWithdraw; /* Max Time WithDrawel */ + int iMaxTimeDeposit; /* Max Time Deposit Per day */ + int iMaxByteBalance; /* Users Time Balance */ + int iMaxByteWithdraw; /* Max Time WithDrawel */ + int iMaxByteDeposit; /* Max Time Deposit Per dat */ + unsigned xNewBytes : 1; + char sTimeRatio[7]; /* User Time Ratio,Returned */ + char sByteRatio[7]; /* User Time Ratio,Returned */ + + long new_groups; /* Maximum newfiles groups */ + int new_split; /* Split reports at KB. */ + int new_force; /* Force split at KB. */ + char startname[9]; /* BBS startup name */ + char extra4[239]; + + /* TIC Processing */ + unsigned ct_KeepDate : 1; /* Keep Filedate */ + unsigned ct_KeepMgr : 1; /* Keep Mgr netmails */ + unsigned ct_ResFuture : 1; /* Reset Future filedates */ + unsigned ct_LocalRep : 1; /* Respond to local requests*/ + unsigned ct_ReplExt : 1; /* Replace Extension */ + unsigned ct_PlusAll : 1; /* Areamgr: allow +%* */ + unsigned ct_Notify : 1; /* Areamgr: Notify on/off */ + unsigned ct_Passwd : 1; /* Areamgr: Passwd change */ + unsigned ct_Message : 1; /* Areamgr: Msg file on/off */ + unsigned ct_TIC : 1; /* Areamgr: TIC files on/off*/ + unsigned ct_Pause : 1; /* Areamgr: Allow Pause */ + char logfile[15]; /* System Logfile */ + int OLR_MaxReq; /* Max nr of Freq's */ + int tic_days; /* Keep on hold for n days */ + char hatchpasswd[21]; /* Internal Hatch Passwd */ + unsigned long drspace; /* Minimum free drivespace */ + char xmgrname[5][21]; /* Areamgr names */ + long tic_systems; /* Systems in database */ + long tic_groups; /* Groups in database */ + long tic_dupes; /* TIC dupes dabase size */ + char badtic[65]; /* Bad TIC's path */ + char ticout[65]; /* TIC queue */ + + /* Mail Tosser */ + char pktdate[65]; /* pktdate by Tobias Ernst */ + int maxpktsize; /* Maximum packet size */ + int maxarcsize; /* Maximum archive size */ + int toss_old; /* Reject older then days */ + char xtoss_log[11]; + long util_loglevel; /* Logging level for utils */ + char badboard[65]; /* Bad Mail board */ + char dupboard[65]; /* Dupe Mail board */ + char popnode[65]; /* Node with pop3 boxes */ + char smtpnode[65]; /* SMTP node */ + int toss_days; /* Keep on hold */ + int toss_dupes; /* Dupes in database */ + int defmsgs; /* Default purge messages */ + int defdays; /* Default purge days */ + int freespace; /* Free diskspace in MBytes */ + long toss_systems; /* Systems in database */ + long toss_groups; /* Groups in database */ + char xareamgr[5][21]; /* Areamgr names */ + + /* Flags */ + char fname[32][17]; /* Name of the access flags */ + fidoaddr aka[40]; /* Fidonet AKA's */ + unsigned short akavalid[40]; /* Fidonet AKA valid/not */ + + long cico_loglevel; /* Mailer loglevel */ + long timeoutreset; /* Reset timeout */ + long timeoutconnect; /* Connect timeout */ + long dialdelay; /* Delay between calls */ + unsigned NoFreqs : 1; /* Don't allow requests */ + unsigned NoCall : 1; /* Don't call */ + unsigned NoHold : 1; /* Don't send hold mail */ + unsigned NoPUA : 1; /* Don't Pickup All */ + unsigned NoEMSI : 1; /* Don't do EMSI */ + unsigned NoWazoo : 1; /* Don't do Yooho/2U2 */ + unsigned NoZmodem : 1; /* Don't do Zmodem */ + unsigned NoZedzap : 1; /* Don't do Zedzap */ + unsigned xNoJanus : 1; + unsigned NoHydra : 1; /* Don't do Hydra */ + unsigned NoTCP : 1; /* Don't do TCP/IP */ + char Phone[21]; /* Default phonenumber */ + unsigned long Speed; /* Default linespeed */ + char Flags[31]; /* Default EMSI flags */ + int Req_Files; /* Maximum files request */ + int Req_MBytes; /* Maximum MBytes request */ + char extra5[96]; + dual phonetrans[40]; /* Phone translation table */ + + /* FTP Daemon */ + int ftp_limit; /* Connections limit */ + int ftp_loginfails; /* Maximum login fails */ + unsigned ftp_compress : 1; /* Allow compress */ + unsigned ftp_tar : 1; /* Allow tar */ + unsigned ftp_upl_mkdir : 1; /* Allow mkdir */ + unsigned ftp_log_cmds : 1; /* Log user commands */ + unsigned ftp_anonymousok : 1; /* Allow anonymous logins */ + unsigned ftp_mbseok : 1; /* Allow mbse user login */ + unsigned ftp_x7 : 1; + unsigned ftp_x8 : 1; + unsigned ftp_x9 : 1; + char ftp_readme_login[21]; /* Readme file for login */ + char ftp_readme_cwd[21]; /* Readme file for cwd */ + char ftp_msg_login[21]; /* Message file for login */ + char ftp_msg_cwd[21]; /* Message file for cwd */ + char ftp_msg_shutmsg[41]; /* Shutdown message */ + char ftp_upl_path[81]; /* Upload path */ + char ftp_banner[81]; /* Banner file */ + char ftp_email[41]; /* Email address */ + char ftp_pth_filter[41]; /* Path filter expression */ + char ftp_pth_message[81]; /* Message to display */ + + /* HTML creation */ + char www_root[81]; /* HTML doc root */ + char www_link2ftp[21]; /* Link name to ftp_base */ + char www_url[41]; /* Webserver URL */ + char www_charset[21]; /* Default characher set */ + char www_tbgcolor[21]; /* Table bgcolor */ + char www_hbgcolor[21]; /* Header bgcolor */ + char www_author[41]; /* Author name in pages */ + char www_convert[81]; /* Graphic Convert command */ + char www_icon_home[21]; /* Icon for Home */ + char www_name_home[21]; /* String for Home */ + char www_icon_back[21]; /* Icon for Back */ + char www_name_back[21]; /* String for Back */ + char www_icon_prev[21]; /* Icon for previous page */ + char www_name_prev[21]; /* String for previous page */ + char www_icon_next[21]; /* Icon for next page */ + char www_name_next[21]; /* String for next page */ + int www_files_page; /* Files per webpage */ + + fidoaddr EmailFidoAka; /* Email aka in fidomode */ + fidoaddr UUCPgate; /* UUCP gateway in fidomode */ + int EmailMode; /* Email mode to use */ + unsigned modereader : 1; /* NNTP Mode Reader */ + unsigned allowcontrol : 1; /* Allow control messages */ + unsigned dontregate : 1; /* Don't regate gated msgs */ + char nntpuser[16]; /* NNTP username */ + char nntppass[16]; /* NNTP password */ + long nntpdupes; /* NNTP dupes database size */ + int newsfeed; /* Newsfeed mode */ +}; + + + +/* + * Limits Control Structure (limits.data) + */ +struct limitshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct limits { + unsigned long Security; /* Security Level */ + long Time; /* Amount of time per call */ + unsigned long DownK; /* Download KB per call */ + unsigned int DownF; /* Download files per call */ + char Description[41]; /* Description for level */ + unsigned Available : 1; /* Is this limit available */ + unsigned Deleted : 1; /* Is this limit deleted */ +}; + + + +/* + * Menu File Control Structure (*.mnu) + */ +struct menufile { + char MenuKey[2]; /* Menu Key */ + int MenuType; /* Menu Type */ + char OptionalData[81]; /* Optional Date */ + char Display[81]; /* Menu display line */ + securityrec MenuSecurity; /* Menu Security Level */ + int Age; /* Minimum Age to use menu */ + unsigned int MaxSecurity; /* Maximum security level */ + char Password[15]; /* Menu Password */ + char TypeDesc[30]; /* Menu Type Description */ + unsigned AutoExec : 1; /* Auto Exec Menu Type */ + unsigned NoDoorsys : 1; /* Suppress door.sys */ + unsigned Y2Kdoorsys : 1; /* Write Y2K style door.sys */ + unsigned Comport : 1; /* Vmodem compart mode */ + long Credit; /* Credit needed */ + int OpenFrom; /* Open From */ + int OpenTo; /* Open To */ + int ForeGnd; /* ForeGround color */ + int BackGnd; /* BackGround color */ +}; + + + +/* + * News dupes database. Stores newsgroupname and CRC32 of article msgid. + */ +struct newsdupes { + char NewsGroup[65]; /* Name of the group */ + unsigned long Crc; /* CRC32 of msgid */ +}; + + + +/* + * Message Areas Structure (mareas.data) + * This is also used for echomail, netmail and news + */ +struct msgareashdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long syssize; /* Size for systems */ + time_t lastupd; /* Last date stats updated */ +}; + +struct msgareas { + char Name[41]; /* Message area Name */ + char Tag[51]; /* Area tag */ + char Base[65]; /* JAM base */ + char QWKname[21]; /* QWK area name */ + int Type; /* Msg Area Types */ + /* Local, Net, Echo, New, E */ + int MsgKinds; /* Type of Messages */ + /* Public,Private,ReadOnly */ + int DaysOld; /* Days to keep messages */ + int MaxMsgs; /* Maximum number of msgs */ + int UsrDelete; /* Allow users to delete */ + securityrec RDSec; /* Read Security */ + securityrec WRSec; /* Write Security */ + securityrec SYSec; /* Sysop Security */ + int Age; /* Age to access this area */ + char Password[20]; /* Area Password */ + char Group[13]; /* Group Area */ + fidoaddr Aka; /* Fidonet address */ + char Origin[65]; /* Origin Line */ + unsigned Aliases : 1; /* Allow aliases */ + unsigned NetReply; /* Area for Netmail reply */ + unsigned Active : 1; /* Area is active */ + unsigned OLR_Forced : 1; /* OLR Area always on */ + unsigned xFileAtt : 1; /* Allow file attach */ + unsigned xModerated : 1; /* Moderated newsgroup */ + unsigned Quotes : 1; /* Add random quotes */ + unsigned Mandatory : 1; /* Mandatory for nodes */ + unsigned UnSecure : 1; /* UnSecure tossing */ + unsigned xUseFidoDomain : 1; + unsigned OLR_Default : 1; /* OLR Deafault turned on */ + unsigned xPrivate : 1; /* Pvt bits allowed */ + unsigned xCheckSB : 1; + unsigned xPassThru : 1; + unsigned xNotiFied : 1; + unsigned xUplDisc : 1; + statcnt Received; /* Received messages */ + statcnt Posted; /* Posted messages */ + time_t LastRcvd; /* Last time msg received */ + time_t LastPosted; /* Last time msg posted */ + char Newsgroup[81]; /* Newsgroup name */ + char Distribution[17]; /* Ng distribution */ + char Moderator[65]; /* Moderator */ + int Rfccode; /* RFC characterset */ + int Ftncode; /* FTN characterset */ +}; + + + +/* + * System Bank Control Structure (bank.data) + */ +struct timebankhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct timebank { + char Name[36]; /* Account Name */ + char Date[12]; /* Current Date */ + int TimeDeposit; /* Time deposited today */ + int KByteDeposit; /* Bytes deposited today */ + int TimeWithdraw; /* Time withdrawn today */ + int KByteWithdraw; /* Bytes withdrawn today */ + int TimeBalance; /* Current Time Balance */ + int KByteBalance; /* Current Byte Balance */ +}; + + + +/* + * Structure for Language file (language.data) + */ +struct languagehdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct language { + char Name[30]; /* Name of Language */ + char LangKey[2]; /* Language Key */ + char MenuPath[81]; /* Path of menu directory */ + char TextPath[81]; /* Path of text files */ + unsigned Available : 1; /* Availability of Language*/ + unsigned Deleted : 1; /* Language is deleted */ + char Filename[81]; /* Path of language file */ + securityrec Security; /* Security level */ + char MacroPath[81]; /* Path to the macro files */ +}; + + + +/* + * Structure for Language Data File (english.lang) + */ +struct langdata { + char sString[85]; /* Language text */ + char sKey[30]; /* Keystroke characters */ +}; + + + +/* + * Structure for Safe Cracker Door Data File (safe.data) + */ +struct crackerhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct cracker { + char Date[12]; /* Date used */ + char Name[36]; /* User name */ + int Trys; /* Trys today */ + unsigned Opened : 1; /* If user succeeded */ +}; + + + +/* + * Fidonet Networks (fidonet.data) + */ +struct _fidonethdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +typedef struct _seclist { + char nodelist[9]; /* Secondary nodelist name */ + unsigned short zone; /* Adress for this list */ + unsigned short net; + unsigned short node; +} seclistrec; + +struct _fidonet { + char domain[13]; /* Network domain name */ + char nodelist[9]; /* Nodelist name */ + seclistrec seclist[6]; /* 6 secondary nodelists */ + unsigned short zone[6]; /* Maximum 6 zones */ + char comment[41]; /* Record comment */ + unsigned available : 1; /* Network available */ + unsigned deleted : 1; /* Network is deleted */ +}; + + + +/* + * Archiver programs (archiver.data) + */ +struct _archiverhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _archiver { + char comment[41]; /* Archiver comment */ + char name[6]; /* Archiver name */ + unsigned available : 1; /* Archiver available */ + unsigned deleted : 1; /* Archiver is deleted */ + char farc[65]; /* Archiver for files */ + char marc[65]; /* Archiver for mail */ + char barc[65]; /* Archiver for banners */ + char tarc[65]; /* Archiver test */ + char funarc[65]; /* Unarc files */ + char munarc[65]; /* Unarc mail */ + char iunarc[65]; /* Unarc FILE_ID.DIZ */ +}; + + + +/* + * Virus scanners (virscan.data) + */ +struct _virscanhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _virscan { + char comment[41]; /* Comment */ + char scanner[65]; /* Scanner command */ + unsigned available : 1; /* Scanner available */ + unsigned deleted : 1; /* Scanner is deleted */ + char options[65]; /* Scanner options */ + int error; /* Error level for OK */ +}; + + + +/* + * TTY information + */ +struct _ttyinfohdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _ttyinfo { + char comment[41]; /* Comment for tty */ + char tty[7]; /* TTY device name */ + char phone[26]; /* Phone or dns name */ + char speed[21]; /* Max speed for this tty */ + char flags[31]; /* Fidonet capabilty flags */ + int type; /* Pots/ISDN/Netw/Local */ + unsigned available : 1; /* Available flag */ + unsigned authlog : 1; /* Is speed logged */ + unsigned honor_zmh : 1; /* Honor ZMH on this line */ + unsigned deleted : 1; /* Is deleted */ + unsigned callout : 1; /* Callout allowed */ + char modem[31]; /* Modem type */ + char name[36]; /* EMSI line name */ + long portspeed; /* Locked portspeed */ +}; + + + +/* + * Modem definitions. + */ +struct _modemhdr { + long hdrsize; /* Size of header record */ + long recsize; /* Size of records */ +}; + +struct _modem { + char modem[31]; /* Modem type */ + char init[3][61]; /* Init strings */ + char ok[11]; /* OK string */ + char hangup[41]; /* Hangup command */ + char info[41]; /* After hangup get info */ + char dial[41]; /* Dial command */ + char connect[20][31]; /* Connect strings */ + char error[10][21]; /* Error strings */ + char reset[61]; /* Reset string */ + int costoffset; /* Offset add to connect */ + char speed[16]; /* EMSI speed string */ + unsigned available : 1; /* Is modem available */ + unsigned deleted : 1; /* Is modem deleted */ + unsigned stripdash : 1; /* Strip dashes from dial */ +}; + + + +/* + * Structure for TIC areas (tic.data) + */ +struct _tichdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long syssize; /* Size for systems */ + time_t lastupd; /* Last statistic update */ +}; + +struct _tic { + char Name[21]; /* Area name */ + char Comment[56]; /* Area comment */ + long FileArea; /* The BBS filearea */ + char Message[15]; /* Message file */ + char Group[13]; /* FDN group */ + int KeepLatest; /* Keep latest n files */ + long xOld[6]; + time_t AreaStart; /* Startdate */ + fidoaddr Aka; /* Fidonet address */ + char Convert[6]; /* Archiver to convert */ + time_t LastAction; /* Last Action in this area*/ + char Banner[15]; /* Banner file */ + long xUnitCost; + long xUnitSize; + long xAddPerc; + unsigned Replace : 1; /* Allow Replace */ + unsigned DupCheck : 1; /* Dupe Check */ + unsigned Secure : 1; /* Check for secure system */ + unsigned NoTouch : 1; /* Don't touch filedate */ + unsigned VirScan : 1; /* Run Virus scanners */ + unsigned Announce : 1; /* Announce files */ + unsigned UpdMagic : 1; /* Update Magic database */ + unsigned FileId : 1; /* Check FILE_ID.DIZ */ + unsigned ConvertAll : 1; /* Convert allways */ + unsigned SendOrg : 1; /* Send Original to downl's*/ + unsigned Mandat : 1; /* Mandatory area */ + unsigned Notified : 1; /* Notified if disconn. */ + unsigned UplDiscon : 1; /* Uplink disconnected */ + unsigned Active : 1; /* If this area is active */ + unsigned Deleted : 1; /* If this area is deleted */ + statcnt Files; /* Total processed files */ + statcnt KBytes; /* Total processed KBytes */ +}; + + + +/* + * Nodes, up- and downlinks. (nodes.data) + */ +struct _nodeshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long filegrp; /* Size for file groups */ + long mailgrp; /* Size for mail groups */ + time_t lastupd; /* Last statistic update */ +}; + +struct _nodes { + char Sysop[36]; /* Sysop name */ + fidoaddr Aka[20]; /* Aka's for this system */ + char Fpasswd[16]; /* Files password */ + char Epasswd[16]; /* Session/Mail password */ + char Apasswd[16]; /* Areamgr password */ + char UplFmgrPgm[9]; /* Uplink FileMgr program */ + char UplFmgrPass[16]; /* Uplink FileMgr password */ + char UplAmgrPgm[9]; /* Uplink AreaMgr program */ + char UplAmgrPass[16]; /* Uplink AreaMgr password */ + + unsigned Direct : 1; /* Netmail Direct */ + unsigned Message : 1; /* Send Message w. files */ + unsigned Tic : 1; /* Send TIC files */ + unsigned Notify : 1; /* Send Notify messages */ + unsigned FileFwd : 1; /* Accept File Forward */ + unsigned MailFwd : 1; /* Accept Mail Forward */ + unsigned AdvTic : 1; /* Advanced Tic files */ + unsigned Billing : 1; /* Cost sharing on/off */ + + unsigned BillDirect : 1; /* Send bill direct */ + unsigned Crash : 1; /* Netmail crash */ + unsigned Hold : 1; /* Netmail hold */ + unsigned AddPlus : 1; /* Add + for uplink msgs */ + unsigned MailPwdCheck : 1; /* Mail password check */ + unsigned Deleted : 1; /* Node is deleted */ + unsigned NoEMSI : 1; /* No EMSI handshake */ + unsigned NoWaZOO : 1; /* No YooHoo/2U2 handshake */ + + unsigned NoFreqs : 1; /* Don't allow requests */ + unsigned NoCall : 1; /* Don't call this node */ + unsigned NoHold : 1; /* Don't send hold mail */ + unsigned NoPUA : 1; /* Don't pickup all */ + unsigned NoZmodem : 1; /* Don't use Zmodem */ + unsigned NoZedzap : 1; /* Don't use Zedzap */ + unsigned xNoJanus : 1; /* Don't use Janus */ + unsigned NoHydra : 1; /* Don't use Hydra */ + + unsigned NoTCP : 1; /* Don't use TCP/IP */ + unsigned PackNetmail : 1; /* Pack netmail */ + unsigned ARCmailCompat : 1; /* ARCmail Compatibility */ + unsigned ARCmailAlpha : 1; /* Allow a..z ARCmail name */ + unsigned FNC : 1; /* FileName Conversion */ + + char xExtra[94]; + time_t StartDate; /* Node start date */ + time_t LastDate; /* Last action date */ + long Credit; /* Node's credit */ + long Debet; /* Node's debet */ + long AddPerc; /* Add Percentage */ + long WarnLevel; /* Warning level */ + long StopLevel; /* Stop level */ + fidoaddr RouteVia; /* Routing address */ + int Language; /* Language for netmail */ + statcnt FilesSent; /* Files sent to node */ + statcnt FilesRcvd; /* Files received from node*/ + statcnt F_KbSent; /* File KB. sent */ + statcnt F_KbRcvd; /* File KB. received */ + statcnt MailSent; /* Messages sent to node */ + statcnt MailRcvd; /* Messages received */ + char dial[41]; /* Dial command override */ + char phone[2][21]; /* Phone numbers override */ +}; + + + +/* + * Groups for file areas. (fgroups.data) + */ +struct _fgrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last statistics update */ +}; + +struct _fgroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Is group deleted */ + unsigned DivideCost : 1; /* Divide cost over links */ + fidoaddr UseAka; /* Aka to use */ + fidoaddr UpLink; /* Uplink address */ + long UnitCost; /* Cost per unit */ + long UnitSize; /* Size per unit */ + long AddProm; /* Promillage to add */ + time_t StartDate; /* Start Date */ + time_t LastDate; /* Last active date */ + char AreaFile[13]; /* Areas filename */ + statcnt Files; /* Files processed */ + statcnt KBytes; /* KBytes msgs or files */ +}; + + + +/* + * Groups for message areas. (mgroups.data) + */ +struct _mgrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last statistics update */ +}; + +struct _mgroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Group is deleted */ + fidoaddr UseAka; /* Aka to use */ + fidoaddr UpLink; /* Uplink address */ + long xOld[6]; + time_t StartDate; /* Start Date */ + time_t LastDate; /* Last active date */ + char AreaFile[13]; /* Areas filename */ + statcnt MsgsRcvd; /* Received messages */ + statcnt MsgsSent; /* Sent messages */ +}; + + + +/* + * Groups for newfiles announce. (ngroups.data) + */ +struct _ngrouphdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _ngroup { + char Name[13]; /* Group Name */ + char Comment[56]; /* Group Comment */ + unsigned Active : 1; /* Group Active */ + unsigned Deleted : 1; /* Group is deleted */ +}; + + + +/* + * Hatch manager (hatch.data) + */ +struct _hatchhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + time_t lastupd; /* Last stats update */ +}; + +struct _hatch { + char Spec[79]; /* File spec to hatch */ + char Name[21]; /* File Echo name */ + char Replace[15]; /* File to replace */ + char Magic[15]; /* Magic to update */ + char Desc[256]; /* Description for file */ + unsigned DupeCheck : 1; /* Check for dupes */ + unsigned Active : 1; /* Record active */ + unsigned Deleted : 1; /* Record is deleted */ + unsigned short Days[7]; /* Days in the week */ + unsigned short Month[32]; /* Days in the month */ + statcnt Hatched; /* Hatched statistics */ +}; + + + +/* + * Magic manager (magic.data) + */ +typedef enum { + MG_EXEC, /* Execute command */ + MG_COPY, /* Copy file */ + MG_UNPACK, /* Unpack file */ + MG_KEEPNUM, /* Keep nr of files */ + MG_MOVE, /* Move to other area */ + MG_UPDALIAS, /* Update alias */ + MG_ADOPT, /* Adopt file */ + MG_OTHER, /* Store in other path */ + MG_DELETE /* Delete file */ +} MAGICTYPE; + +struct _magichdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _magic { + char Mask[15]; /* Filemask for magic */ + unsigned int Attrib; /* Record type */ + unsigned Active : 1; /* Record active */ + unsigned Compile : 1; /* Compile Flag */ + unsigned Deleted : 1; /* Deleted record */ + char From[21]; /* From area */ + char Path[65]; /* Destination path */ + char Cmd[65]; /* Command to execute */ + int KeepNum; /* Keep number of files */ + char ToArea[21]; /* Destination area */ +}; + + + +/* + * Billing database + */ +struct _bill { + fidoaddr Node; /* Fido address */ + char FileName[15]; /* File Name */ + char FileEcho[21]; /* File Echo */ + char Group[13]; /* Group */ + off_t Size; /* File Size */ + long Cost; /* File Cost */ +}; + + + +/* + * Newfile reports (newfiles.data) + */ +struct _newfileshdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ + long grpsize; /* Size of groups */ +}; + +struct _newfiles { + char Comment[56]; /* Comment */ + char Area[51]; /* Message area */ + char Origin[51]; /* Origin line, or random */ + char From[36]; /* From field */ + char Too[36]; /* To field */ + char Subject[61]; /* Subject field */ + int Language; /* Language */ + char Template[15]; /* Template filename */ + fidoaddr UseAka; /* Aka to use */ + unsigned Active : 1; /* Active */ + unsigned HiAscii : 1; /* Hi-Ascii allowed */ + unsigned Deleted : 1; /* Report is deleted */ +}; + + + +/* + * Scanmanager (scanmgr.data) + */ +struct _scanmgrhdr { + long hdrsize; /* Size of header */ + long recsize; /* Size of records */ +}; + +struct _scanmgr { + char Comment[56]; /* Comment */ + char Origin[51]; /* Origin line */ + fidoaddr Aka; /* Fido address */ + char ScanBoard[51]; /* Board to scan */ + char ReplBoard[51]; /* Reply board */ + int Language; /* Language to use */ + char template[15]; /* Template filename */ + unsigned Active : 1; /* Record active */ + unsigned NetReply : 1; /* Netmail reply */ + unsigned Deleted : 1; /* Area is deleted */ + unsigned HiAscii : 1; /* High Ascii allowed */ +}; + + + +/* + * Record structure for file handling + */ +struct _filerecord { + char Echo[21]; /* File echo */ + char Comment[56]; /* Comment */ + char Group[13]; /* Group */ + char Name[13]; /* File Name */ + char LName[81]; /* Long FileName */ + off_t Size; /* File Size */ + unsigned long SizeKb; /* File Size in Kb */ + time_t Fdate; /* File Date */ + char Origin[24]; /* Origin system */ + char From[24]; /* From system */ + char Crc[9]; /* CRC 32 */ + char Replace[13]; /* Replace file */ + char Magic[21]; /* Magic name */ + char Desc[256]; /* Short description */ + char LDesc[25][49]; /* Long description */ + int TotLdesc; /* Total long desc lines */ + long Cost; /* File cost */ + unsigned Announce : 1; /* Announce this file */ +}; + + + +/* + * Mailer history file (mailhist.data) + * The first record conatains only the date (online) from which date this + * file is valid. The offline date is teh date this file is created or + * packed. From the second record and on the records are valid data records. + */ +struct _history { + fidoaddr aka; /* Node number */ + char system_name[36]; /* System name */ + char sysop[36]; /* Sysop name */ + char location[36]; /* System location */ + char tty[7]; /* Tty of connection */ + time_t online; /* Starttime of session */ + time_t offline; /* Endtime of session */ + unsigned long sent_bytes; /* Bytes sent */ + unsigned long rcvd_bytes; /* Bytes received */ + int cost; /* Session cost */ + unsigned inbound : 1; /* Inbound session */ +}; + + +#endif + diff --git a/lib/strutil.c b/lib/strutil.c new file mode 100644 index 00000000..9d85aba4 --- /dev/null +++ b/lib/strutil.c @@ -0,0 +1,357 @@ +/***************************************************************************** + * + * File ..................: strutil.c + * Purpose ...............: Common string functions + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "structs.h" +#include "common.h" + + + + +char *padleft(char *str, int size, char pad) +{ + static char stri[256]; + static char temp[256]; + + strcpy(stri, str); + memset(temp, pad, (long)size); + temp[size] = '\0'; + if (strlen(stri) <= size) + memmove(temp, stri, (long)strlen(stri)); + else + memmove(temp, stri, (long)size); + return temp; +} + + + +/* + * Small function to convert String to LowerCase + */ +char *tl(char *str) +{ + char *p = str; + + while (*p != '\0') { + *p = (char)tolower(*p); + p++; + } + + return str; +} + + + + +void Striplf(char *String) +{ + int i; + + for(i = 0; i < strlen(String); i++) { + if(*(String + i) == '\0') + break; + if(*(String + i) == '\n') + *(String + i) = '\0'; + } +} + + + +/* + * Converts first letter to UpperCase + */ +void tlf(char *str) +{ + *(str) = toupper(*(str)); +} + + + +/* + * Small function to convert String to UpperCase + */ +char *tu(char *str) +{ + char *p = str; + + while (*p != '\0') { + *p = (char)toupper(*p); + p++; + } + + return str; +} + + + +/* + * Converts the first letter in every word in a string to uppercase, + * all other character will be lowercase. Will handle the notation + * Bob Ten.Dolle as well + */ +char *tlcap(char *String) +{ + static char stri[256]; + int Loop, Strlen; + + strcpy(stri, String); + Strlen = strlen(stri); + + /* + * Automatic do the first character + */ + stri[0] = toupper(stri[0]); + + for(Loop = 1; Loop < Strlen; Loop++) { + stri[Loop] = tolower(stri[Loop]); + if (( stri[Loop] == ' ') || (stri[Loop] == '.')) { + /* + * This is a space charracter, increase the counter + * and convert the next character to uppercase. + */ + Loop++; + stri[Loop] = toupper(stri[Loop]); + } + } + return stri; +} + + + +/* + * Hilite "Word" in string, this is done by inserting ANSI + * Hilite characters in the string. + */ +char *Hilite(char *str, char *Word) +{ + char *pos; + char *new; + char *old; + int t; + + new = strdup(str); + old = strdup(str); + tl(new); + + if ((pos = strstr(new,Word)) == NULL) + return(str); + + str = realloc(str,strlen(new)+200); + strcpy(str,"\0"); + + while (( pos = strstr(new,Word)) != NULL) { + *pos = '\0'; + t = strlen(new); + strncat(str,old,t); + strcat(str,""); + old+=t; + strncat(str,old,strlen(Word)); + strcat(str,""); + old+=strlen(Word); + new = new+t+strlen(Word); + } + strcat(str,old); + return(str); +} + + + +/* + * Replace spaces is a string with underscore characters. + */ +void Addunderscore(char *temp) +{ + int i; + + for(i = 0; i < strlen(temp); i++) { + if (*(temp + i) == '\0') + break; + if (*(temp + i) == ' ') + *(temp + i) = '_'; + } +} + + + +/* + * Find & Replace string in a string + */ +void strreplace(char *sStr, char *sFind, char *sReplace) +{ + char sNewstr[81]=""; + char *posStr, *posFind; + int iPos, iLen, iCounter; + + posStr=sStr; + if(( posFind = strstr(sStr, sFind)) != NULL) { + iPos = (int)(posFind - posStr); + strncpy(sNewstr, sStr, iPos); + strcat(sNewstr, sReplace); + iPos+= strlen(sFind); + iLen = strlen(sNewstr); + for (iCounter=0; iCounter < (strlen(sStr) - iPos); iCounter++) + sNewstr[iCounter + iLen] = sStr[iCounter + iPos]; + sNewstr[iCounter+1+iLen] = '\0'; + strcpy(sStr, sNewstr); + } +} + + + +/* + * Converts to HH:MM + */ +char *StrTimeHM(time_t date) +{ + static char ttime[6]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(ttime, "%02d:%02d", l_d->tm_hour, l_d->tm_min); + return ttime; +} + + + +/* + * Returns HH:MM:SS + */ +char *StrTimeHMS(time_t date) +{ + static char ttime[9]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(ttime, "%02d:%02d:%02d", l_d->tm_hour, l_d->tm_min, l_d->tm_sec); + return ttime; +} + + + +/* + * Get the current local time, returns HH:MM + */ +char *GetLocalHM() +{ + static char gettime[15]; + time_t T_Now; + + time(&T_Now); + sprintf(gettime,"%s", StrTimeHM(T_Now)); + return(gettime); +} + + + + +/* + * Get the current local time, returns HH:MM:SS + */ +char *GetLocalHMS() +{ + static char gettime[15]; + time_t T_Now; + + time(&T_Now); + sprintf(gettime,"%s", StrTimeHMS(T_Now)); + return(gettime); +} + + + +/* + * Returns date as MM-DD-YYYY + */ +char *StrDateMDY(time_t *Clock) +{ + struct tm *tm; + static char cdate[12]; + + tm = localtime(Clock); + sprintf(cdate,"%02d-%02d-%04d", tm->tm_mon+1, tm->tm_mday, tm->tm_year+1900); + return(cdate); +} + + + +/* + * Returns DD-MM-YYYY + */ +char *StrDateDMY(time_t date) +{ + static char tdate[15]; + struct tm *l_d; + + l_d = localtime(&date); + sprintf(tdate, "%02d-%02d-%04d", l_d->tm_mday, l_d->tm_mon+1, l_d->tm_year+1900); + return tdate; +} + + + + +/* + * This function returns the date for today, to test against other functions + * DD-MM-YYYY (DAY-MONTH-YEAR) + */ +char *GetDateDMY() +{ + static char tdate[15]; + struct tm *l_d; + time_t T_Now; + + time(&T_Now); + l_d = localtime(&T_Now); + sprintf(tdate, "%02d-%02d-%04d", l_d->tm_mday,l_d->tm_mon+1,l_d->tm_year+1900); + return(tdate); +} + + + +/* + * Returns current date in DDMMYYY + */ +/* +char *tDate1() +{ + static char tdate1[15]; + struct tm *l_d; + time_t T_Now; + + time(&T_Now); + l_d = localtime(&T_Now); + sprintf(tdate1, "%02d%02d%02d", + l_d->tm_mday,l_d->tm_mon+1,l_d->tm_year+1900); + + return(tdate1); +} + +*/ diff --git a/lib/term.c b/lib/term.c new file mode 100644 index 00000000..772c0e01 --- /dev/null +++ b/lib/term.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * + * File ..................: term.c + * Purpose ...............: Terminal output routines. + * Last modification date : 03-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_USERS + +#include "libs.h" +#include "structs.h" +#include "ansi.h" +#include "records.h" +#include "common.h" + + +int termmode; /* 0 = tty, 1 = ANSI */ + + + +void TermInit(int mode) +{ + termmode = mode; +} + + + +/* + * Function will print about of enters specified + */ +void Enter(int num) +{ + int i; + + for(i = 0; i < num; i++) + printf("\n"); +} + + + + +void pout(int fg, int bg, char *Str) +{ + colour(fg, bg); + printf(Str); +} + + + +void poutCenter(int fg, int bg, char *Str) +{ + colour(fg, bg); + Center(Str); +} + + + +void poutCR(int fg, int bg, char *Str) +{ + colour(fg, bg); + puts(Str); +} + + + +/* + * Changes ansi background and foreground color + */ +void colour(int fg, int bg) +{ + if (termmode == 1) { + + int att=0, fore=37, back=40; + + if (fg<0 || fg>31 || bg<0 || bg>7) { + printf("ANSI: Illegal colour specified: %i, %i\n", fg, bg); + return; + } + + printf("["); + if ( fg > 15) { + printf("5;"); + fg-=16; + } + if (fg > 7) { + att=1; + fg=fg-8; + } + + if (fg==0) fore=30; + else if (fg==1) fore=34; + else if (fg==2) fore=32; + else if (fg==3) fore=36; + else if (fg==4) fore=31; + else if (fg==5) fore=35; + else if (fg==6) fore=33; + else fore=37; + + if (bg==1) back=44; + else if (bg==2) back=42; + else if (bg==3) back=46; + else if (bg==4) back=41; + else if (bg==5) back=45; + else if (bg==6) back=43; + else if (bg==7) back=47; + else back=40; + + printf("%d;%d;%dm", att, fore, back); + } +} + + + +void Center(char *string) +{ + int Strlen; + int Maxlen = 70; + int i, x, z; + char *Str; + + Str = calloc(81, sizeof(char)); + Strlen = strlen(string); + + if(Strlen == Maxlen) + printf("%s\n", string); + else { + x = Maxlen - Strlen; + z = x / 2; + for(i = 0; i < z; i++) + strcat(Str, " "); + strcat(Str, string); + printf("%s\n", Str); + } + + free(Str); +} + + + +void clear() +{ + if (termmode == 1) { + colour(LIGHTGRAY, BLACK); + printf(ANSI_HOME); + printf(ANSI_CLEAR); + } else + Enter(1); +} + + + +/* + * Moves cursor to specified position + */ +void locate(int y, int x) +{ + if (termmode > 0) { + if (exitinfo.iScreenLen != 0) { + if (y > exitinfo.iScreenLen || x > 80) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + printf("ANSI: exitinfo.iScreenLen: %i\n", exitinfo.iScreenLen); + return; + } + } else { + if (y > 25 || x > 80) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + return; + } + } + printf("\x1B[%i;%iH", y, x); + } +} + + + +void fLine(int Len) +{ + int x; + + if (termmode == 0) + for (x = 0; x < Len; x++) + printf("-"); + + if (termmode == 1) + for (x = 0; x < Len; x++) + printf("%c", 196); + + printf(" \n"); +} + + + + +void sLine() +{ + fLine(79); +} + + + +/* + * curses compatible functions + */ +void mvprintw(int y, int x, const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + locate(y, x); + printf(outputstr); + free(outputstr); +} + + + diff --git a/lib/test.c b/lib/test.c new file mode 100644 index 00000000..1734e725 --- /dev/null +++ b/lib/test.c @@ -0,0 +1,106 @@ + +/* +** NOTE: Running this program in a Win32 or Unix environment +** will probably result in a segmentation fault or protection +** error. These errors may be caused by MEMWATCH when it's +** looking at memory to see if it owns it, or may be caused by +** the test program writing to memory it does not own. +** +** MEMWATCH has two functions called 'mwIsReadAddr()' and +** 'mwIsSafeAddr()', which are system-specific. +** If they are implemented for your system, and works +** correctly, MEMWATCH will identify garbage pointers and +** avoid causing segmentation faults, GP's etc. +** +** If they are NOT implemented, count on getting the core +** dumped when running this test program! As of this writing, +** the safe-address checking has been implemented for Win32 +** and ANSI-C compliant systems. The ANSI-C checking traps +** SIGSEGV and uses setjmp/longjmp to resume processing, +** but I've only tested this under Linux (where it works). +** +** Note for Win95 users: The Win32 IsBadReadPtr() and it's +** similar functions can return incorrect values. This has +** not happened under WinNT, though, just Win95. +** +** 980318 Johan Lindh +** +*/ + +#include "libs.h" + +#error "Hey! Don't just compile this program, read the comments first!" +#ifndef SIGSEGV +#error SIGNAL.H does not define SIGSEGV; running this program WILL cause a core dump/crash! +#endif + +main() +{ + char *p; + + /* Collect stats on a line number basis */ + mwStatistics( 2 ); + + /* Slows things down, but OK for this test prg */ + /* mwAutoCheck( 1 ); */ + + TRACE("Hello world!\n"); + + p = malloc(210); + free(p); + p = malloc(20); + p = malloc(200); /* causes unfreed error */ + p[-1] = 0; /* causes underflow error */ + free(p); + + p = malloc(100); + p[ -(int)(sizeof(long)*8) ] = -1; /* try to damage MW's heap chain */ + free( p ); /* should cause relink */ + + mwSetAriFunc( mwAriHandler ); + ASSERT(1==2); + + mwLimit(1000000); + mwNoMansLand( MW_NML_ALL ); + + /* These may cause a general protection fault (segmentation fault) */ + /* They're here to help test the no-mans-land protection */ + if( mwIsSafeAddr(p+50000,1) ) { + TRACE("Killing byte at %p\n", p+50000); + *(p+50000) = 0; + } + if( mwIsSafeAddr(p+30000,1) ) { + TRACE("Killing byte at %p\n", p+30000); + *(p+30000) = 0; + } + if( mwIsSafeAddr(p+1000,1) ) { + TRACE("Killing byte at %p\n", p+1000); + *(p+1000) = 0; + } + if( mwIsSafeAddr(p-100,1) ) { + TRACE("Killing byte at %p\n", p-100); + *(p-100) = 0; + } + + /* This may cause a GP fault as well, since MW data buffers */ + /* have been damaged in the above killing spree */ + CHECK(); + + p = malloc(12000); + p[-5] = 1; + p[-10] = 2; + p[-15] = 3; + p[-20] = 4; + + /* This may cause a GP fault since MW's buffer list may have */ + /* been damaged by above killing, and it will try to repair it. */ + free(p); + + p = realloc(p,10); /* causes realloc: free'd from error */ + + /* May cause GP since MW will inspect the memory to see if it owns it. */ + free( (void*)main ); + + return 0; +} + diff --git a/lib/unpacker.c b/lib/unpacker.c new file mode 100644 index 00000000..1723b3c9 --- /dev/null +++ b/lib/unpacker.c @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * File ..................: unpacker.c + * Purpose ...............: Archive unpacker + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#define DB_ARCHIVE + +#include "libs.h" +#include "structs.h" +#include "records.h" +#include "clcomm.h" +#include "common.h" + + +char *unpacker(char *fn) +{ + FILE *fp; + unsigned char buf[8]; + + if ((fp = fopen(fn,"r")) == NULL) { + WriteError("$Could not open file %s", fn); + return NULL; + } + + if (fread(buf,1,sizeof(buf),fp) != sizeof(buf)) { + WriteError("$Could not read head of the file %s", fn); + fclose(fp); + return NULL; + } + + fclose(fp); + + if (memcmp(buf,"PK",2) == 0) return (char *)"ZIP"; + if (*buf == 0x1a) return (char *)"ARC"; + if (memcmp(buf+2,"-l",2) == 0) return (char *)"LZH"; + if (memcmp(buf,"ZOO",3) == 0) return (char *)"ZOO"; + if (memcmp(buf,"`\352",2) == 0) return (char *)"ARJ"; + if (memcmp(buf,"Rar",3) == 0) return (char *)"RAR"; + if (memcmp(buf, ";A ",3) == 0) return (char *)"ASC"; + + Syslog('p', "Unknown compress scheme in file %s", fn); + return NULL; +} + + + +int getarchiver(char *unarc) +{ + FILE *fp; + char *filename; + + memset(&archiver, 0, sizeof(archiver)); + filename = calloc(PATH_MAX, sizeof(char)); + sprintf(filename, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(filename, "r")) == NULL) { + WriteError("$Can't open %s", filename); + free(filename); + return FALSE; + } + free(filename); + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((archiver.available) && (strcmp(archiver.name, unarc) == 0)) { + fclose(fp); + return TRUE; + } + } + + fclose(fp); + return FALSE; +} + + + diff --git a/mbcico/Makefile.am b/mbcico/Makefile.am new file mode 100644 index 00000000..4779f331 --- /dev/null +++ b/mbcico/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = README +SUBDIRS = . + +noinst_PROGRAMS = mbcico mbout + +mbcico_SOURCES = zmmisc.c zmrle.c zmrecv.c zmsend.c binkp.c \ +xmsend.c xmrecv.c m7recv.c m7send.c hydra.c \ +answer.c chat.c dial.c dietifna.c emsidat.c filelist.c \ +openfile.c openport.c opentcp.c rdoptions.c yoohoo.c \ +recvbark.c respfreq.c sendbark.c tcp.c tcpproto.c wazoo.c \ +filetime.c ftsc.c atoul.c portsel.c \ +ttyio.c lutil.c scanout.c emsi.c ulock.c \ +callstat.c session.c call.c callall.c mbcico.c \ +zmodem.h binkp.h config.h statetbl.h \ +xmsend.h xmrecv.h m7recv.h m7send.h hydra.h \ +answer.h chat.h dial.h dietifna.h emsidat.h filelist.h \ +openfile.h openport.h opentcp.h rdoptions.h yoohoo.h \ +recvbark.h respfreq.h sendbark.h tcp.h tcpproto.h wazoo.h \ +filetime.h ftsc.h atoul.h portsel.h \ +ttyio.h lutil.h scanout.h emsi.h ulock.h \ +callstat.h session.h call.h callall.h mbcico.h + +mbout_SOURCES = outstat.c nlinfo.c mbout.c scanout.c callstat.c \ +outstat.h nlinfo.h scanout.h callstat.h + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a \ +../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(mkinstalldirs) $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbcico $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbout $(bindir) + + diff --git a/mbcico/Makefile.in b/mbcico/Makefile.in new file mode 100644 index 00000000..a5699638 --- /dev/null +++ b/mbcico/Makefile.in @@ -0,0 +1,536 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +EXTRA_DIST = README +SUBDIRS = . + +noinst_PROGRAMS = mbcico mbout + +mbcico_SOURCES = zmmisc.c zmrle.c zmrecv.c zmsend.c binkp.c xmsend.c xmrecv.c m7recv.c m7send.c hydra.c answer.c chat.c dial.c dietifna.c emsidat.c filelist.c openfile.c openport.c opentcp.c rdoptions.c yoohoo.c recvbark.c respfreq.c sendbark.c tcp.c tcpproto.c wazoo.c filetime.c ftsc.c atoul.c portsel.c ttyio.c lutil.c scanout.c emsi.c ulock.c callstat.c session.c call.c callall.c mbcico.c zmodem.h binkp.h config.h statetbl.h xmsend.h xmrecv.h m7recv.h m7send.h hydra.h answer.h chat.h dial.h dietifna.h emsidat.h filelist.h openfile.h openport.h opentcp.h rdoptions.h yoohoo.h recvbark.h respfreq.h sendbark.h tcp.h tcpproto.h wazoo.h filetime.h ftsc.h atoul.h portsel.h ttyio.h lutil.h scanout.h emsi.h ulock.h callstat.h session.h call.h callall.h mbcico.h + + +mbout_SOURCES = outstat.c nlinfo.c mbout.c scanout.c callstat.c outstat.h nlinfo.h scanout.h callstat.h + + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbcico_OBJECTS = zmmisc.o zmrle.o zmrecv.o zmsend.o binkp.o xmsend.o \ +xmrecv.o m7recv.o m7send.o hydra.o answer.o chat.o dial.o dietifna.o \ +emsidat.o filelist.o openfile.o openport.o opentcp.o rdoptions.o \ +yoohoo.o recvbark.o respfreq.o sendbark.o tcp.o tcpproto.o wazoo.o \ +filetime.o ftsc.o atoul.o portsel.o ttyio.o lutil.o scanout.o emsi.o \ +ulock.o callstat.o session.o call.o callall.o mbcico.o +mbcico_LDADD = $(LDADD) +mbcico_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbcico_LDFLAGS = +mbout_OBJECTS = outstat.o nlinfo.o mbout.o scanout.o callstat.o +mbout_LDADD = $(LDADD) +mbout_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbout_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbcico_SOURCES) $(mbout_SOURCES) +OBJECTS = $(mbcico_OBJECTS) $(mbout_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbcico/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbcico: $(mbcico_OBJECTS) $(mbcico_DEPENDENCIES) + @rm -f mbcico + $(LINK) $(mbcico_LDFLAGS) $(mbcico_OBJECTS) $(mbcico_LDADD) $(LIBS) + +mbout: $(mbout_OBJECTS) $(mbout_DEPENDENCIES) + @rm -f mbout + $(LINK) $(mbout_LDFLAGS) $(mbout_OBJECTS) $(mbout_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbcico + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +answer.o: answer.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h lutil.h \ + session.h config.h answer.h openport.h portsel.h dial.h \ + rdoptions.h mbcico.h +atoul.o: atoul.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h atoul.h +binkp.o: binkp.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbnode.h ../lib/clcomm.h ttyio.h \ + session.h statetbl.h config.h emsi.h openfile.h respfreq.h \ + filelist.h opentcp.h rdoptions.h lutil.h binkp.h +call.o: call.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h session.h callstat.h call.h \ + config.h dial.h lutil.h portsel.h openport.h opentcp.h \ + rdoptions.h +callall.o: callall.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + config.h ../lib/clcomm.h scanout.h lutil.h callstat.h callall.h +callstat.o: callstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h callstat.h +chat.o: chat.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h config.h portsel.h chat.h ttyio.h +dial.o: dial.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h portsel.h config.h chat.h \ + ttyio.h session.h dial.h +dietifna.o: dietifna.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h emsi.h dietifna.h respfreq.h \ + filelist.h xmrecv.h xmsend.h +emsi.o: emsi.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/dbnode.h ../lib/clcomm.h ttyio.h session.h statetbl.h \ + config.h emsi.h emsidat.h hydra.h rdoptions.h tcp.h wazoo.h +emsidat.o: emsidat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h emsi.h \ + session.h lutil.h config.h emsidat.h filetime.h +filelist.o: filelist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h config.h session.h filelist.h +filetime.o: filetime.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h filetime.h +ftsc.o: ftsc.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h config.h ftsc.h \ + rdoptions.h recvbark.h filelist.h sendbark.h respfreq.h \ + xmrecv.h xmsend.h +hydra.o: hydra.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h filelist.h filetime.h ttyio.h \ + statetbl.h config.h emsi.h openfile.h lutil.h respfreq.h \ + mbcico.h hydra.h +lutil.o: lutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h lutil.h +m7recv.o: m7recv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h statetbl.h ttyio.h m7recv.h +m7send.o: m7send.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h statetbl.h ttyio.h m7send.h +mbcico.o: mbcico.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h config.h answer.h portsel.h call.h callall.h \ + lutil.h mbcico.h session.h +mbout.o: mbout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h outstat.h nlinfo.h +nlinfo.o: nlinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h nlinfo.h +openfile.o: openfile.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h config.h lutil.h openfile.h +openport.o: openport.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ulock.h ttyio.h openport.h +opentcp.o: opentcp.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h session.h \ + ttyio.h openport.h opentcp.h +outstat.o: outstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbnode.h \ + ../lib/dbftn.h scanout.h callstat.h outstat.h +portsel.o: portsel.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h portsel.h +rdoptions.o: rdoptions.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h portsel.h \ + session.h config.h +recvbark.o: recvbark.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h recvbark.h \ + respfreq.h filelist.h +respfreq.o: respfreq.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h session.h lutil.h config.h \ + atoul.h respfreq.h filelist.h +scanout.o: scanout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbftn.h config.h \ + scanout.h lutil.h +sendbark.o: sendbark.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h sendbark.h \ + xmrecv.h +session.o: session.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ttyio.h statetbl.h emsi.h \ + ftsc.h session.h yoohoo.h mbcico.h binkp.h callstat.h +tcp.o: tcp.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/common.h ../lib/clcomm.h ttyio.h \ + session.h statetbl.h config.h emsi.h respfreq.h filelist.h \ + tcpproto.h tcp.h +tcpproto.o: tcpproto.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h config.h emsi.h lutil.h \ + openfile.h filelist.h tcpproto.h +ttyio.o: ttyio.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ttyio.h lutil.h +ulock.o: ulock.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h +wazoo.o: wazoo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h statetbl.h config.h emsi.h \ + respfreq.h filelist.h wazoo.h zmodem.h +xmrecv.o: xmrecv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h config.h lutil.h \ + openfile.h m7recv.h xmrecv.h filetime.h +xmsend.o: xmsend.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h session.h ttyio.h statetbl.h xmsend.h m7send.h \ + filelist.h filetime.h +yoohoo.o: yoohoo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h ../lib/dbnode.h statetbl.h \ + ttyio.h session.h config.h emsi.h hydra.h rdoptions.h wazoo.h \ + dietifna.h yoohoo.h +zmmisc.o: zmmisc.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h zmodem.h +zmrecv.o: zmrecv.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h lutil.h ttyio.h session.h zmodem.h config.h \ + emsi.h openfile.h openport.h +zmrle.o: zmrle.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/clcomm.h \ + ../lib/common.h ttyio.h session.h zmodem.h +zmsend.o: zmsend.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ttyio.h session.h zmodem.h lutil.h emsi.h \ + filelist.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(mkinstalldirs) $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbcico $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbout $(bindir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbcico/README b/mbcico/README new file mode 100644 index 00000000..93aaaccd --- /dev/null +++ b/mbcico/README @@ -0,0 +1,35 @@ +This is the README file for mbcico, the fidonet mailer for MBSE BBS. + +This is a heavily patched version of ifcico from the ifmail package written +by Eugene G. Crosser (crosser@pccross.msk.su), 2:5020/230@fidonet. He deserves +most of the credits for this product. + +Many others have contributed to the original ifcico and utilities. This +version doesn't use the original config file anymore, it uses the databases +that are maintained with mbsetup. Also, mail behaviour is different then +in ifcico. + +I wrote this special version to let it fully integrate with all the other +programs that are distributed with MBSE BBS, so mbcico will hopefully function +in a multiline environment with mixed analogue modems and ISDN lines. + +The reason why I changed the name of this program is only to show that there +is a real difference in the behavior and configuration compared with ifcico. + +If you insist on running the original ifcico on your system, it is still +possible, I used it myself during the development of MBSE BBS. You need to +run ifcico as the mbse admin user in the bbs group. Also make sure that the +order of the nodelists is exactly the same in ifcico and MBSE BBS. + +The following people donated code to the original ifcico, this list is +not complete. It is possible that I forgot someone, but these are the names +that I found in the several ifmail packages. + +Martin Junius +Pablo Saratxaga (srtxg@linux.chanae.stben.be) +Christof Meerwald (cmeerw@htl-sbg.ac.at) +Tseneo Tanaka (tt@efnet.com) telnet TCP + + +Michiel Broek. + diff --git a/mbcico/answer.c b/mbcico/answer.c new file mode 100644 index 00000000..aa38add3 --- /dev/null +++ b/mbcico/answer.c @@ -0,0 +1,163 @@ +/***************************************************************************** + * + * File ..................: mbcico/answer.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "lutil.h" +#include "session.h" +#include "config.h" +#include "answer.h" +#include "openport.h" +#include "portsel.h" +#include "dial.h" +#include "rdoptions.h" +#include "mbcico.h" + + +extern int carrier, online; +extern time_t c_start, c_end; +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; +extern int Loaded; + +int answer(char *stype) +{ + int st, rc; + char *p, *q; + FILE *fp; + + /* + * mgetty set's the environment variable CONNECT and CALLER_ID, + * so if they are present, we might as well make log entries. + */ + if ((q = getenv("CONNECT")) != NULL) + Syslog('+', "CONNECT %s", q); + if ((q = getenv("CALLER_ID")) != NULL) + if (strncmp(q, "none", 4)) + Syslog('+', "CALLER %s", q); + + /* + * Incoming calls from modem/ISDN lines do have a tty. + * Network calls don't have a tty attached. + */ + carrier = TRUE; + p = ttyname(0); + if (p) { + q = strrchr(ttyname(0), '/'); + if (q) + p = q + 1; + if (load_port(p)) + Syslog('d', "Port %s, modem %s", ttyinfo.tty, modem.modem); + else + Syslog('d', "Port and modem not loaded!"); + } + + if ((nlent = getnlent(NULL)) == NULL) { + WriteError("could not get dummy nodelist entry"); + return 1; + } + + c_start = time(NULL); + rdoptions(FALSE); + + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); /* slave session is unsecure by default */ + + if (stype == NULL) { + st=SESSION_UNKNOWN; + } else if (strcmp(stype,"tsync") == 0) { + st=SESSION_FTSC; + IsDoing("Answer ftsc"); + } else if (strcmp(stype,"yoohoo") == 0) { + st=SESSION_YOOHOO; + IsDoing("Answer yoohoo"); + } else if (strncmp(stype,"**EMSI_",7) == 0) { + st=SESSION_EMSI; + IsDoing("Answer EMSI"); + } else if (strncmp(stype,"ibn",3) == 0) { + st=SESSION_BINKP; + IsDoing("Answer Binkp"); + } else { + st=SESSION_UNKNOWN; + IsDoing("Answer unknown"); + } + + if ((rc = rawport()) != 0) + WriteError("Unable to set raw mode"); + else { + nolocalport(); + rc=session(NULL,NULL,SESSION_SLAVE,st,stype); + } + + cookedport(); + if (p) { + /* + * Hangup will write the history record. + */ + hangup(); + } else { + /* + * Network call, write history record. + */ + c_end = time(NULL); + online += (c_end - c_start); + + history.online = c_start; + history.offline = c_end; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = TRUE; + + p = calloc(128, sizeof(char)); + sprintf(p, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(p, "a")) == NULL) + WriteError("$Can't open %s", p); + else { + Syslog('s', "answer() write history"); + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + } + free(p); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + return rc; +} + + diff --git a/mbcico/answer.h b/mbcico/answer.h new file mode 100644 index 00000000..629d58c6 --- /dev/null +++ b/mbcico/answer.h @@ -0,0 +1,8 @@ +#ifndef _ANSWER_H +#define _ANSWER_H + +int answer(char *); + + +#endif + diff --git a/mbcico/atoul.c b/mbcico/atoul.c new file mode 100644 index 00000000..b846e795 --- /dev/null +++ b/mbcico/atoul.c @@ -0,0 +1,44 @@ +/***************************************************************************** + * + * File ..................: mbcico/atoul.c + * Purpose ...............: Fidonet mailer + * Last modification date : 18-Dec-1998 + * + ***************************************************************************** + * Copyright (C) 1997-1998 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "atoul.h" + + +unsigned long atoul(char *str) +{ + unsigned long x; + + if (sscanf(str,"%lu",&x) == 1) + return x; + else return 0xffffffff; +} + diff --git a/mbcico/atoul.h b/mbcico/atoul.h new file mode 100644 index 00000000..50f62b1d --- /dev/null +++ b/mbcico/atoul.h @@ -0,0 +1,8 @@ +#ifndef _ATOUL_H +#define _ATOUL_H + + +unsigned long atoul(char *); + +#endif + diff --git a/mbcico/binkp.c b/mbcico/binkp.c new file mode 100644 index 00000000..658e69f2 --- /dev/null +++ b/mbcico/binkp.c @@ -0,0 +1,1228 @@ +/***************************************************************************** + * + * File ....................: mbcico/binkp.c + * Purpose .................: Fidonet binkd protocol + * Last modification date ..: 07-Jul-2001 + * Binkp protocol copyright : Dima Maloff. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "respfreq.h" +#include "filelist.h" +#include "opentcp.h" +#include "rdoptions.h" +#include "lutil.h" +#include "binkp.h" +#include "config.h" + + +static char rbuf[2048]; + +void binkp_send_data(char *, int); +void binkp_send_control(int id, ...); +int binkp_recv_frame(char *, int *, int *); +void binkp_settimer(int); +int resync(off_t); + + +static int orgbinkp(void); +static int ansbinkp(void); +static int binkp_batch(file_list *); + +extern char *ttystat[]; +extern int Loaded; + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; + +typedef enum {RxWaitFile, RxAcceptFile, RxReceData, RxWriteData, RxEndOfBatch, RxDone} RxType; +typedef enum {TxGetNextFile, TxTryRead, TxReadSend, TxWaitLastAck, TxDone} TxType; +typedef enum {InitTransfer, Switch, Receive, Transmit} TransferType; +typedef enum {Ok, Failure, Continue} TrType; + +static int RxState; +static int TxState; +static int TfState; +static time_t Timer; +static int NRflag = FALSE; +static int MBflag = FALSE; +static int NDflag = FALSE; +static int CRYPTflag = FALSE; +static int CRAMflag = FALSE; +unsigned long nethold, mailhold; +int transferred = FALSE; +int batchnr = 0; + + + +int binkp(int role) +{ + int rc = 0; + fa_list *eff_remote; + file_list *tosend = NULL, *request = NULL, *respond = NULL, *tmpfl; + char *nonhold_mail; + + if (role == 1) { + Syslog('+', "BINKP start outbound session"); + IsDoing("Binkp %s outb", ascfnode(remote->addr, 0x0f)); + if (orgbinkp()) { + rc = 5; + } + } else { + Syslog('+', "BINKP start inbound session"); + IsDoing("Answer binkp"); + if (ansbinkp()) { + rc = 5; + } + } + + if (rc) { + Syslog('!', "BINKP session failed"); + return rc; + } + + if (role) { + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + } else { + nonhold_mail = (char *)ALL_MAIL; + } + + eff_remote = remote; + + /* + * Some systems hang on sending lowercase filenames, setting + * FNC forces old 8.3 uppercase filenames. + */ + if (!nodes.FNC) + remote_flags &= ~SESSION_FNC; + tosend = create_filelist(eff_remote, nonhold_mail, 0); + + request = create_freqlist(remote); + + if (request != NULL) { + Syslog('b', "Inserting request list"); + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + rc = binkp_batch(tosend); + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + + if ((rc == 0) && transferred && MBflag) { + /* + * Running Multiple Batch, only if last batch actually + * did transfer some data. + */ + respond = respond_wazoo(); + /* + * Just create the tosend list again, there may be something + * ready again for this node. + */ + tosend = create_filelist(eff_remote, nonhold_mail, 0); + for (tmpfl = tosend; tmpfl->next; tmpfl = tmpfl->next); + tmpfl->next = respond; + rc = binkp_batch(tosend); + tmpfl->next = NULL; + } + + Syslog('+', "BINKP end transfer rc=%d", rc); + closetcp(); + + if (!MBflag) { + /* + * In singe batch mode we process filerequests after the batch. + * The results will be put on hold for the calling node. + */ + respond = respond_wazoo(); + for (tmpfl = respond; tmpfl; tmpfl = tmpfl->next) { + if (strncmp(tmpfl->local, "/tmp", 4)) { + attach(*remote->addr, tmpfl->local, LEAVE, 'h'); + Syslog('+', "Put on hold: %s", MBSE_SS(tmpfl->local)); + } else { + file_mv(tmpfl->local, pktname(remote->addr, 'h')); + Syslog('+', "New netmail: %s", pktname(remote->addr, 'h')); + } + } + } + + tidy_filelist(request, (rc == 0)); + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + + rc = abs(rc); + return rc; +} + + + +int resync(off_t off) +{ + return 0; +} + + + +/* + * Transmit data frame + */ +void binkp_send_data(char *buf, int len) +{ + unsigned short header = 0; + + Syslog('B', "send_data(%d)", len); + header = ((BINKP_DATA_BLOCK + len) & 0xffff); + + PUTCHAR((header >> 8) & 0x00ff); + PUTCHAR(header & 0x00ff); + if (len) + PUT(buf, len); + FLUSHOUT(); + binkp_settimer(BINKP_TIMEOUT); +} + + + +/* + * Transmit control frame + */ +void binkp_send_control(int id,...) +{ + va_list args; + char *fmt, *s; + binkp_frame frame; + static char buf[1024]; + int sz; + + va_start(args, id); + fmt = va_arg(args, char*); + + if (fmt) { + vsprintf(buf, fmt, args); + sz = ((1 + strlen(buf)) & 0x7fff); + } else { + buf[0]='\0'; + sz = 1; + } + + frame.header = ((BINKP_CONTROL_BLOCK + sz) & 0xffff); + frame.id = (char)id; + frame.data = buf; + + s = (unsigned char *)malloc(sz + 2 + 1); + s[sz + 2] = '\0'; + s[0] = ((frame.header >> 8)&0xff); + s[1] = (frame.header & 0xff); + s[2] = frame.id; + if (frame.data[0]) + strncpy(s + 3, frame.data, sz-1); + + PUT(s, sz+2); + FLUSHOUT(); + + free(s); + va_end(args); + binkp_settimer(BINKP_TIMEOUT); +} + + + +/* + * Receive control frame + */ +int binkp_recv_frame(char *buf, int *len, int *cmd) +{ + int b0, b1; + + *len = *cmd = 0; + + b0 = GETCHAR(180); + if (tty_status) + goto to; + if (b0 & 0x80) + *cmd = 1; + + b1 = GETCHAR(1); + if (tty_status) + goto to; + + *len = (b0 & 0x7f) << 8; + *len += b1; + + GET(buf, *len, 120); + buf[*len] = '\0'; + if (tty_status) + goto to; + +to: + if (tty_status) + WriteError("TCP receive error: %d %s", tty_status, ttystat[tty_status]); + return tty_status; +} + + + +void binkp_settimer(int interval) +{ + Syslog('B', "Set timer %d", interval); + Timer = time((time_t*)NULL) + interval; +} + + + +int binkp_expired(void); +int binkp_expired(void) +{ + time_t now; + + (void)time(&now); + if (now >= Timer) + Syslog('b', "Timer expired"); + return (now >= Timer); +} + + + +void b_banner(int); +void b_banner(int originate) +{ + time_t t; + + binkp_send_control(MM_NUL,"SYS %s", CFG.bbs_name); + binkp_send_control(MM_NUL,"ZYZ %s", CFG.sysop_name); + binkp_send_control(MM_NUL,"LOC %s", CFG.location); + binkp_send_control(MM_NUL,"NDL %s", CFG.Flags); + time(&t); + binkp_send_control(MM_NUL,"TIME %s", rfcdate(t)); + binkp_send_control(MM_NUL,"VER mbcico/%s binkp/1.0", VERSION); + if (strlen(CFG.Phone)) + binkp_send_control(MM_NUL,"PHN %s", CFG.Phone); + if (strlen(CFG.comment)) + binkp_send_control(MM_NUL,"OPM %s", CFG.comment); +} + + + +void b_nul(char *); +void b_nul(char *msg) +{ + if (strncmp(msg, "SYS ", 4) == 0) { + Syslog('+', "System : %s", msg+4); + msg[40] = '\0'; + sprintf(history.system_name, "%s", msg+4); + } else if (strncmp(msg, "ZYZ ", 4) == 0) { + Syslog('+', "Sysop : %s", msg+4); + msg[40] = '\0'; + sprintf(history.sysop, "%s", msg+4); + } else if (strncmp(msg, "LOC ", 4) == 0) { + Syslog('+', "Location: %s", msg+4); + msg[40] = '\0'; + sprintf(history.location, "%s", msg+4); + } else if (strncmp(msg, "NDL ", 4) == 0) + Syslog('+', "Flags : %s", msg+4); + else if (strncmp(msg, "TIME ", 5) == 0) + Syslog('+', "Time : %s", msg+5); + else if (strncmp(msg, "VER ", 4) == 0) + Syslog('+', "Uses : %s", msg+4); + else if (strncmp(msg, "PHN ", 4) == 0) + Syslog('+', "Phone : %s", msg+4); + else if (strncmp(msg, "OPM ", 4) == 0) + Syslog('+', "Remark : %s", msg+4); + else if (strncmp(msg, "TRF ", 4) == 0) + Syslog('+', "Binkp: remote has %s mail/files for us", msg+4); + else if (strncmp(msg, "OPT ", 4) == 0) { + Syslog('+', "Options : %s", msg+4); + if (strstr(msg, (char *)"NR") != NULL) + NRflag = TRUE; + if (strstr(msg, (char *)"MB") != NULL) + MBflag = TRUE; + if (strstr(msg, (char *)"ND") != NULL) + NDflag = TRUE; + if (strstr(msg, (char *)"CRYPT") != NULL) + CRYPTflag = TRUE; + if (strstr(msg, (char *)"CRAM-") != NULL) { + CRAMflag = TRUE; + } + } else + Syslog('+', "M_NUL \"%s\"", msg); +} + + + +/* + * Originate a binkp session + */ +SM_DECL(orgbinkp, (char *)"orgbinkp") +SM_STATES + waitconn, + sendpass, + waitaddr, + authremote, + ifsecure, + waitok +SM_NAMES + (char *)"waitconn", + (char *)"sendpass", + (char *)"waitaddr", + (char *)"authremote", + (char *)"ifsecure", + (char *)"waitok" +SM_EDECL + faddr *primary; + char *p, *q; + int i, rc, bufl, cmd; + fa_list **tmp, *tmpa; + int SendPass = FALSE; + faddr *fa, ra; + +SM_START(waitconn) + +SM_STATE(waitconn) + + Loaded = FALSE; + Syslog('+', "Start binkp session with %s", ascfnode(remote->addr, 0x1f)); + b_banner(TRUE); +// binkp_send_control(MM_NUL,"OPT NR"); + binkp_send_control(MM_NUL,"OPT MB"); + + /* + * Build a list of aka's to send, the primary aka first. + */ + ra.zone = remote->addr->zone; + ra.net = remote->addr->net; + ra.node = remote->addr->node; + ra.point = remote->addr->point; + + primary = bestaka_s(remote->addr); + p = xstrcpy(ascfnode(primary, 0x1f)); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].zone) && (CFG.akavalid[i]) && + ((CFG.aka[i].zone != primary->zone) || + (CFG.aka[i].net != primary->net) || + (CFG.aka[i].node != primary->node) || + (CFG.aka[i].point!= primary->point))) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + binkp_send_control(MM_ADR, "%s", p); + free(p); + tidy_faddr(primary); + SM_PROCEED(sendpass) + +SM_STATE(sendpass) + + if (strlen(nodes.Epasswd)) { + SendPass = TRUE; + binkp_send_control(MM_PWD, "%s", nodes.Epasswd); + } else + binkp_send_control(MM_PWD, "-"); + + SM_PROCEED(waitaddr) + +SM_STATE(waitaddr) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error receiving remote info"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_ADR) { + p = xstrcpy(&rbuf[1]); + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + + for (q = strtok(p, " "); q; q = strtok(NULL, " ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } else { + Syslog('!', "Bad remote address: \"%s\"", printable(q, 0)); + binkp_send_control(MM_ERR, "Bad address"); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "Address : %s", ascfnode(tmpa->addr, 0x1f)); + if (nodelock(tmpa->addr)) { + binkp_send_control(MM_BSY, "Address %s locked", ascfnode(tmpa->addr, 0x1f)); + } + + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + SM_PROCEED(authremote) + + } else if (rbuf[0] == MM_BSY) { + Syslog('!', "Remote is busy"); + SM_ERROR; + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(authremote) + + rc = 0; + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + if ((tmpa->addr->zone == ra.zone) && + (tmpa->addr->net == ra.net) && + (tmpa->addr->node == ra.node) && + (tmpa->addr->point == ra.point)) { + rc = 1; + } + } + + if (rc) { + SM_PROCEED(ifsecure) + } else { + Syslog('!', "Error: the wrong node is reached"); + binkp_send_control(MM_ERR, "No AKAs in common or all AKAs busy"); + SM_ERROR; + } + +SM_STATE(ifsecure) + + if (SendPass) { + SM_PROCEED(waitok) + } + SM_SUCCESS; + +SM_STATE(waitok) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for remote acknowledge"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_OK) { + Syslog('+', "Password protected session"); + SM_SUCCESS; + + } else if (rbuf[0] == MM_BSY) { + Syslog('!', "Remote is busy"); + SM_ERROR; + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_END +SM_RETURN + + + +/* + * Answer a binkp session + */ +SM_DECL(ansbinkp, (char *)"ansbinkp") +SM_STATES + waitconn, + waitaddr, + ispasswd, + waitpwd, + pwdack +SM_NAMES + (char *)"waitconn", + (char *)"waitaddr", + (char *)"ispasswd", + (char *)"waitpwd", + (char *)"pwdack" + +SM_EDECL + char *p, *q; + int i, rc, bufl, cmd; + fa_list **tmp, *tmpa; + faddr *fa; + +SM_START(waitconn) + +SM_STATE(waitconn) + + Loaded = FALSE; + b_banner(FALSE); + p = xstrcpy((char *)""); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].zone) && (CFG.akavalid[i])) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + binkp_send_control(MM_ADR, "%s", p); + free(p); + SM_PROCEED(waitaddr) + +SM_STATE(waitaddr) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for remote info"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_ADR) { + p = xstrcpy(&rbuf[1]); + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + + for (q = strtok(p, " "); q; q = strtok(NULL, " ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } else { + Syslog('!', "Bad remote address: \"%s\"", printable(q, 0)); + binkp_send_control(MM_ERR, "Bad address"); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "Address : %s", ascfnode(tmpa->addr, 0x1f)); + if (nodelock(tmpa->addr)) { + binkp_send_control(MM_BSY, "Address %s locked", ascfnode(tmpa->addr, 0x1f)); + } + + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + if (((nlent = getnlent(tmpa->addr))) && + (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + break; + } + } + if (nlent) + rdoptions(Loaded); + + if (MBflag) { + Syslog('b', "Remote supports MB"); + binkp_send_control(MM_NUL,"OPT MB"); + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + SM_PROCEED(ispasswd) + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(ispasswd) + + if (!Loaded && !strlen(nodes.Epasswd)) { + Syslog('+', "Unprotected session"); + SM_SUCCESS; + } + SM_PROCEED(waitpwd) + +SM_STATE(waitpwd) + + for (;;) { + if ((rc = binkp_recv_frame(rbuf, &bufl, &cmd))) { + Syslog('!', "Error waiting for password"); + SM_ERROR; + } + + if (cmd) { + if (rbuf[0] == MM_PWD) { + SM_PROCEED(pwdack) + + } else if (rbuf[0] == MM_ERR) { + Syslog('!', "Remote error: %s", &rbuf[1]); + SM_ERROR; + + } else if (rbuf[0] == MM_NUL) { + b_nul(&rbuf[1]); + } + } + } + +SM_STATE(pwdack) + if (strcmp(&rbuf[1], nodes.Epasswd) == 0) { + Syslog('+', "Password OK, protected BINKP session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + binkp_send_control(MM_OK, ""); + SM_SUCCESS; + } else { + Syslog('?', "Password error: expected \"%s\", got \"%s\"", nodes.Epasswd, &rbuf[1]); + binkp_send_control(MM_ERR, "*** Password error, check setup ***"); + SM_ERROR; + } + +SM_END + +SM_RETURN + + + +void fill_binkp_list(binkp_list **, file_list *, off_t); +void fill_binkp_list(binkp_list **bll, file_list *fal, off_t offs) +{ + binkp_list **tmpl; + struct stat tstat; + + if (stat(fal->local, &tstat) != 0) { + Syslog('!', "$Can't add %s to sendlist", fal->local); + exit; + } + if (strstr(fal->remote, (char *)".pkt")) + nethold += tstat.st_size; + else + mailhold += tstat.st_size; + + for (tmpl = bll; *tmpl; tmpl = &((*tmpl)->next)); + *tmpl = (binkp_list *)malloc(sizeof(binkp_list)); + + (*tmpl)->next = NULL; + (*tmpl)->state = NoState; + (*tmpl)->get = FALSE; + (*tmpl)->local = xstrcpy(fal->local); + (*tmpl)->remote = xstrcpy(fal->remote); + (*tmpl)->offset = offs; + (*tmpl)->size = tstat.st_size; + (*tmpl)->date = tstat.st_mtime; +} + + + +char *lbstat[]={(char *)"None", + (char *)"Sending", + (char *)"IsSent", + (char *)"Got", + (char *)"Skipped", + (char *)"Get"}; + + +void debug_binkp_list(binkp_list **); +void debug_binkp_list(binkp_list **bll) +{ + binkp_list *tmpl; + + Syslog('B', "Current filelist:"); + + for (tmpl = *bll; tmpl; tmpl = tmpl->next) + Syslog('B', "%s %s %s %ld", MBSE_SS(tmpl->local), MBSE_SS(tmpl->remote), lbstat[tmpl->state], tmpl->offset); +} + + + +int binkp_batch(file_list *to_send) +{ + int rc = 0, NotDone; + static char *txbuf, *rxbuf; + FILE *txfp = NULL; + FILE *rxfp = NULL; + int rxlen = 0, txlen = 0; + long txpos = 0, rxpos = 0; + long stxpos = 0; + time_t rxstarttime, rxendtime; + time_t txstarttime, txendtime; + int sverr, cmd = FALSE, GotFrame = FALSE; + int blklen = 0, c, Found = FALSE; + unsigned short header = 0; + char *rname, *lname; + long rsize, roffs, lsize; + time_t rtime, ltime; + long rxbytes, written; + binkp_list *bll = NULL, *tmp, *cursend = NULL; + file_list *tsl; + + batchnr++; + Syslog('+', "Binkp: starting batch %d", batchnr); + txbuf = calloc(MAX_BLKSIZE + 3, sizeof(unsigned char)); + rxbuf = calloc(MAX_BLKSIZE + 3, sizeof(unsigned char)); + rname = calloc(512, sizeof(char)); + lname = calloc(512, sizeof(char)); + TfState = Switch; + RxState = RxWaitFile; + TxState = TxGetNextFile; + binkp_settimer(BINKP_TIMEOUT); + nethold = mailhold = 0L; + transferred = FALSE; + + /* + * Build a new filelist from the existing filelist. + * This one is special for binkp behaviour. + */ + for (tsl = to_send; tsl; tsl = tsl->next) { + if (tsl->remote != NULL) + fill_binkp_list(&bll, tsl, 0L); + } + debug_binkp_list(&bll); + + Syslog('+', "Binkp: mail %ld, files %ld bytes", nethold, mailhold); + binkp_send_control(MM_NUL, "TRF %ld %ld", nethold, mailhold); + + while ((RxState != RxDone) || (TxState != TxDone)) { + + if (binkp_expired()) { + Syslog('!', "Binkp: Transfer timeout"); + Syslog('b', "Binkp: TxState=%d, RxState=%d, rxlen=%d", TxState, RxState, rxlen); + RxState = RxDone; + TxState = TxDone; + binkp_send_control(MM_ERR, "Transfer timeout"); + rc = -2; + break; + } + + /* + * Receiver binkp frame + */ + for (;;) { + if (GotFrame) { + Syslog('b', "WARNING: frame not processed"); + break; + } else { + c = GETCHAR(0); + if (c < 0) { + c = -c; + if (c == STAT_TIMEOUT) { + usleep(1); + break; + } + Syslog('?', "Binkp: receiver status %s", ttystat[c]); + TxState = TxDone; + RxState = RxDone; + rc = -c; + break; + } else { + switch (rxlen) { + case 0: header = c << 8; + break; + case 1: header += c; + break; + default:rxbuf[rxlen-2] = c; + } + if (rxlen == 1) { + cmd = header & 0x8000; + blklen = header & 0x7fff; + } + if ((rxlen == (blklen + 1) && (rxlen >= 1))) { + GotFrame = TRUE; + binkp_settimer(BINKP_TIMEOUT); + rxbuf[rxlen-1] = '\0'; + break; + } + rxlen++; + } + } + } + + /* + * Transmitter state machine + */ + switch (TxState) { + case TxGetNextFile: + for (tmp = bll; tmp; tmp = tmp->next) { + if (tmp->state == NoState) { + /* + * There is something to send + */ + struct flock txflock; + + txflock.l_type = F_RDLCK; + txflock.l_whence = 0; + txflock.l_start = 0L; + txflock.l_len = 0L; + + txfp = fopen(tmp->local, "r"); + if (txfp == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "Binkp: file %s doesn't exist, removing", MBSE_SS(tmp->local)); + tmp->state = Got; + } else { + WriteError("$Binkp: can't open %s, skipping", MBSE_SS(tmp->local)); + tmp->state = Skipped; + } + break; + } + + if (fcntl(fileno(txfp), F_SETLK, &txflock) != 0) { + WriteError("$Binkp: can't lock file %s, skipping", MBSE_SS(tmp->local)); + fclose(txfp); + tmp->state = Skipped; + break; + } + + txpos = stxpos = tmp->offset; + Syslog('+', "Binkp: send \"%s\" as \"%s\"", MBSE_SS(tmp->local), MBSE_SS(tmp->remote)); + Syslog('+', "Binkp: size %lu bytes, dated %s", (unsigned long)tmp->size, date(tmp->date)); + binkp_send_control(MM_FILE, "%s %lu %ld %ld", MBSE_SS(tmp->remote), + (unsigned long)tmp->size, (long)tmp->date, (unsigned long)tmp->offset); + (void)time(&txstarttime); + tmp->state = Sending; + cursend = tmp; + TxState = TxTryRead; + transferred = TRUE; + break; + } /* if state == NoState */ + } /* for */ + + if (tmp == NULL) { + /* + * No more files to send + */ + TxState = TxWaitLastAck; + Syslog('b', "Binkp: transmitter to WaitLastAck"); + } + break; + + case TxTryRead: + /* + * Check if there is room in the output buffer + */ + if ((WAITPUTGET(-1) & 2) != 0) + TxState = TxReadSend; + break; + + case TxReadSend: + Nopper(); + fseek(txfp, txpos, SEEK_SET); + txlen = fread(txbuf, 1, SND_BLKSIZE, txfp); + + if (txlen == 0) { + + if (ferror(txfp)) { + WriteError("$Binkp: error reading from file"); + TxState = TxGetNextFile; + cursend->state = Skipped; + debug_binkp_list(&bll); + break; + } + + /* + * Send empty dataframe, most binkp mailers need it to detect EOF. + */ + binkp_send_data(txbuf, 0); + + /* + * calculate time needed and bytes transferred + */ + (void)time(&txendtime); + txstarttime = txendtime - txstarttime; + if (txstarttime <= 0L) + txstarttime = 1L; + + /* + * Close transmitter file + */ + fclose(txfp); + + if (txpos >= 0) { + stxpos = txpos - stxpos; + Syslog('+', "Binkp: OK %lu bytes send in %s (%ld cps)", + stxpos, str_time(txstarttime), stxpos/txstarttime); + } else { + Syslog('+', "Binkp: transmitter skipped file after %ld seconds", txstarttime); + } + + cursend->state = IsSent; + TxState = TxGetNextFile; + break; + } else { + txpos += txlen; + sentbytes += txlen; + binkp_send_data(txbuf, txlen); + } + + TxState = TxTryRead; + break; + + case TxWaitLastAck: + debug_binkp_list(&bll); + NotDone = FALSE; + for (tmp = bll; tmp; tmp = tmp->next) + if ((tmp->state != Got) && (tmp->state != Skipped)) { + NotDone = TRUE; + break; + } + Syslog('B', "NotDone=%s", NotDone ? "True" : "False"); + if (tmp == NULL) { + TxState = TxDone; + binkp_send_control(MM_EOB, ""); + Syslog('+', "Binkp: sending EOB"); + } else { + Syslog('b', "tmp != NULL"); + } + break; + + case TxDone: + break; + } + + /* + * Process received frame + */ + if (GotFrame) { + if (cmd) { + switch (rxbuf[0]) { + case MM_ERR: Syslog('+', "Binkp: got ERR: %s", rxbuf+1); + RxState = RxDone; + TxState = TxDone; + break; + + case MM_BSY: Syslog('+', "Binkp: got BSY: %s", rxbuf+1); + RxState = RxDone; + TxState = TxDone; + break; + + case MM_SKIP: Syslog('+', "Got SKIP frame"); + break; + + case MM_GET: Syslog('+', "Got GET frame"); + break; + + case MM_GOT: sscanf(rxbuf+1, "%s %ld %ld", lname, &lsize, <ime); + Found = FALSE; + for (tmp = bll; tmp; tmp = tmp->next) + if ((strcmp(lname, tmp->remote) == 0) && + (lsize == tmp->size) && (ltime == tmp->date)) { + Syslog('+', "Binkp: remote GOT \"%s\"", + tmp->remote); + tmp->state = Got; + Found = TRUE; + } + if (!Found) { + Syslog('!', "Binkp: unexpected GOT \"%s\"", rxbuf+1); + } + break; + + case MM_NUL: b_nul(rxbuf+1); + break; + + case MM_EOB: Syslog('+', "Binkp: received EOB"); + RxState = RxEndOfBatch; + break; + + case MM_FILE: if ((RxState == RxWaitFile) || (RxState == RxEndOfBatch)) { + RxState = RxAcceptFile; + sscanf(rxbuf+1, "%s %ld %ld %ld", rname, &rsize, &rtime, &roffs); + } else { + Syslog('+', "Binkp: got unexpected FILE frame %s", rxbuf+1); + } + break; + + default: Syslog('+', "Binkp: Unexpected frame %d", rxbuf[0]); + } + } else { + if (blklen) { + if (RxState == RxReceData) { + written = fwrite(rxbuf, 1, blklen, rxfp); + if (!written && blklen) { + Syslog('+', "Binkp: file write error"); + RxState = RxDone; + } + rxpos += written; + if (rxpos == rsize) { + binkp_send_control(MM_GOT, "%s %ld %ld", rname, rsize, rtime); + closefile(TRUE); + rxpos = rxpos - rxbytes; + (void)time(&rxendtime); + if ((rxstarttime = rxendtime - rxstarttime) == 0L) + rxstarttime = 1L; + Syslog('+', "Binkp: received OK %lu bytes in %s (%ld cps)", + rxpos, str_time(rxstarttime), rxpos / rxstarttime); + rcvdbytes += rxpos; + RxState = RxWaitFile; + transferred = TRUE; + } + } else { + Syslog('+', "Binkp: unexpected DATA frame %d", rxbuf[0]); + } + } + } + GotFrame = FALSE; + rxlen = 0; + header = 0; + blklen = 0; + } + + switch (RxState) { + case RxWaitFile: + break; + + case RxAcceptFile: + Syslog('+', "Binkp: receive file \"%s\" date %s size %ld offset %ld", rname, date(rtime), rsize, roffs); + rxfp = openfile(rname, rtime, rsize, &rxbytes, resync); + (void)time(&rxstarttime); + rxpos = 0; + + if (!diskfree(CFG.freespace)) { + Syslog('+', "Binkp: low diskspace, sending BSY"); + binkp_send_control(MM_BSY, "Low diskspace, try again later"); + RxState = RxDone; + TxState = TxDone; + break; + } + + if (rsize == rxbytes) { + /* + * We already got this file, send GOT so it will + * be deleted at the remote. + */ + Syslog('+', "Binkp: already got %s, sending GOT", rname); + binkp_send_control(MM_GOT, "%s %ld %ld", rname, rsize, rtime); + RxState = RxWaitFile; + rxfp = NULL; + } else if (!rxfp) { + /* + * Some error, request to skip it + */ + Syslog('+', "Binkp: error file %s, sending SKIP", rname); + binkp_send_control(MM_SKIP, "%s %ld %ld", rname, rsize, rtime); + RxState = RxWaitFile; + } else { + RxState = RxReceData; + } + break; + + case RxReceData: + break; + + case RxEndOfBatch: + if (TxState == TxDone) + RxState = RxDone; + break; + + case RxDone: + break; + } + } + + debug_binkp_list(&bll); + + /* + * Process all send files. + */ + for (tsl = to_send; tsl; tsl = tsl->next) { + if (tsl->remote == NULL) { + execute_disposition(tsl); + } else { + for (tmp = bll; tmp; tmp = tmp->next) { + if ((strcmp(tmp->local, tsl->local) == 0) && + ((tmp->state == Got) || (tmp->state == Skipped))) { + execute_disposition(tsl); + } + } + } + } + + for (tmp = bll; bll; bll = tmp) { + tmp = bll->next; + if (bll->local) + free(bll->local); + if (bll->remote) + free(bll->remote); + free(bll); + } + + free(txbuf); + free(rxbuf); + free(rname); + free(lname); + Syslog('+', "Binkp: batch %d completed rc=%d", batchnr, rc); + return rc; +} + + diff --git a/mbcico/binkp.h b/mbcico/binkp.h new file mode 100644 index 00000000..f33201f8 --- /dev/null +++ b/mbcico/binkp.h @@ -0,0 +1,84 @@ +#ifndef _BINKP_H +#define _BINKP_H + +/* + + binkp's frames: + + +---------------------- 0=data block, 1=message(command) + | +---- data block size / msg's argument size + | | + 7 6543210 76543210 + +-+-------+--------+--- ... ---+ + | | HI LO | | -- data block / msg's argument + +-+-------+--------+--- ... ---+ + + */ + + +/* protocol version */ +#define BINKP_VERSION "1.1" + +#define MAX_BLKSIZE 0x7fff /* Don't change! */ +#define BLK_HDR_SIZE 2 /* 2 bytes header */ +#define BINKP_TIMEOUT 180 /* Global timeout value */ +#define SND_BLKSIZE 4096 /* Blocksize transmitter */ + +#define MM_NUL 0 /* Ignored by binkp (data optionally logged) */ +#define MM_ADR 1 /* System aka's */ +#define MM_PWD 2 /* Password */ +#define MM_FILE 3 +#define MM_OK 4 /* The password is ok (data ignored) */ +#define MM_EOB 5 /* End-of-batch (data ignored) */ +#define MM_GOT 6 /* File received */ +#define MM_ERR 7 /* Misc errors */ +#define MM_BSY 8 /* All AKAs are busy */ +#define MM_GET 9 /* Get a file from offset */ +#define MM_SKIP 10 /* Skip a file */ +#define MM_MAX 10 + +#define MM_DATA 0xff + +#define BINKP_DATA_BLOCK 0x0000 +#define BINKP_CONTROL_BLOCK 0x8000 + + +typedef struct _binkp_frame { + unsigned short header; + unsigned char id; + unsigned char *data; +} binkp_frame; + + + +/* + * Linked list of files to send and responses from the receiver. + */ +typedef enum {NoState, Sending, IsSent, Got, Skipped, Get} FileState; + +typedef struct _binkp_list { + struct _binkp_list *next; + char *remote; /* Remote filename */ + char *local; /* Local filename */ + int state; /* File state */ + int get; /* Boolean GET flag */ + off_t size; /* File size */ + time_t date; /* File date & time */ + off_t offset; /* Start offset */ +} binkp_list; + + + +/* + * state.NR_flag: state of binkp when in NR mode + */ +#define NO_NR 0 +#define WANT_NR 1 +#define WE_NR 2 +#define THEY_NR 3 + + +int binkp(int); + +#endif + diff --git a/mbcico/call.c b/mbcico/call.c new file mode 100644 index 00000000..493433fb --- /dev/null +++ b/mbcico/call.c @@ -0,0 +1,380 @@ +/***************************************************************************** + * + * File ..................: mbcico/call.c + * Purpose ...............: Fidonet mailer + * Last modification date : 22-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "session.h" +#include "callstat.h" +#include "call.h" +#include "config.h" +#include "dial.h" +#include "lutil.h" +#include "portsel.h" +#include "openport.h" +#include "opentcp.h" +#include "rdoptions.h" + + +extern int tcp_mode; +extern int forcedcalls; +extern int immediatecall; +extern char *forcedphone; +extern char *forcedline; +extern char *inetaddr; + + +int checkretry(callstat *); +int checkretry(callstat *st) +{ + Syslog('d', "Checkretry nr %d status %d", st->tryno, st->trystat); + if (st->tryno > 30) + return 2; + return 0; + /* check retries and time; rc=1 - not reached, rc=2 - undialable */ +} + + + +int portopen(faddr *addr) +{ + char *p, *q; + int rc, speed; + pp_list *pl = NULL, *tmp; + + if (inetaddr) { + Syslog('d', "portopen inetaddr %s", inetaddr); + if ((rc = opentcp(inetaddr))) { + Syslog('+', "Cannot connect %s", inetaddr); + nodeulock(addr); + putstatus(addr,1,ST_NOCONN); + return ST_NOCONN; + } + return 0; + } + + if (forcedline) { + Syslog('d', "portopen forcedline %s", forcedline); + p = forcedline; + if ((q = strchr(p, ':'))) { /* Note: DIT KAN WEG ! */ + *q++ = '\0'; + if ((*q == 'l') || (*q == 'L')) + speed=atoi(++q); + else { + speed = atoi(q); + if (nlent->speed < speed) + speed = nlent->speed; + } + } + + if (load_port(p)) { + speed = ttyinfo.portspeed; + rc = openport(p,speed); + if (rc) { + Syslog('+', "Cannot open port %s",p); + nodeulock(addr); + putstatus(addr, 10, ST_PORTERR); + return ST_PORTERR; + } + return 0; + } else { + nodeulock(addr); + putstatus(addr, 0, ST_PORTERR); + return ST_PORTERR; + } + } + + if (make_portlist(nlent, &pl) == 0) { + WriteError("No matching ports defined"); + nodeulock(addr); + putstatus(addr, 10, ST_NOPORT); + return ST_NOPORT; + } + + for (tmp = pl; tmp; tmp = tmp->next) { + if (load_port(tmp->tty)) { + Syslog('+', "Port %s at %ld, modem %s", ttyinfo.tty, ttyinfo.portspeed, modem.modem); + p = xstrcpy(tmp->tty); + speed = ttyinfo.portspeed; + rc = openport(p, speed); + free(p); + if (rc == 0) { + tidy_pplist(&pl); + return 0; + } + } + } + + tidy_pplist(&pl); + nodeulock(addr); + putstatus(addr, 0, ST_PORTERR); + return ST_PORTERR; +} + + + +int call(faddr *addr) +{ + int i, j, rc = 1; + callstat *st; + struct hostent *he; + + /* + * Don't call points, call their boss instead. + */ + addr->point = 0; + + /* + * First check if node is locked, if not lock it immediatly + * or stop further waste of time and logfile space. + */ + if (nodelock(addr)) { + Syslog('+', "System %s is locked", ascfnode(addr, 0x1f)); + putstatus(addr, 0, ST_LOCKED); + return ST_LOCKED; + } + nodeulock(addr); + + if ((nlent = getnlent(addr)) == NULL) { + WriteError("Cannot call %s: fatal in nodelist lookup", ascfnode(addr, 0x1f)); + putstatus(addr,0,ST_LOOKUP); + return ST_LOOKUP; + } + + /* + * Load the noderecord if the node is in the setup. + */ + noderecord(addr); + rdoptions(TRUE); + + /* + * Fill default history info in case we get a FTS0001 session + */ + sprintf(history.system_name, "%s", nlent->name); + sprintf(history.location, "%s", nlent->location); + history.aka.zone = addr->zone; + history.aka.net = addr->net; + history.aka.node = addr->node; + history.aka.point = addr->point; + if (addr->domain && strlen(addr->domain)) + sprintf(history.aka.domain, "%s", addr->domain); + + /* + * First see if this node can be reached over the internet and + * that internet calls are allowed. + */ + if (nlent->iflags && ((localoptions & NOTCP) == 0)) { + if (!inetaddr) { + Syslog('d', "Trying to find IP address..."); + /* + * There is no fdn or IP address at the commandline. + * First check nodesetup for an override in the phone field. + */ + if (strlen(nodes.phone[0])) { + inetaddr = xstrcpy(nodes.phone[0]); + } else if (strlen(nodes.phone[1])) { + inetaddr = xstrcpy(nodes.phone[1]); + } else { + /* + * Try to find the fdn in several places in the nodelist fields. + */ + if ((nlent->phone != NULL) && (strncmp(nlent->phone, (char *)"000-", 4) == 0)) { + inetaddr = xstrcpy(nlent->phone+4); + for (i = 0; i < strlen(inetaddr); i++) + if (inetaddr[i] == '-') + inetaddr[i] = '.'; + Syslog('d', "Got IP address from phone field"); + } else if ((he = gethostbyname(nlent->name))) { + inetaddr = xstrcpy(nlent->name); + Syslog('d', "Got hostname from nodelist system name"); + } else if ((he = gethostbyname(nlent->location))) { + /* + * A fdn at the nodelist location field is not in the specs + * but the real world differs from the specs. + */ + inetaddr = xstrcpy(nlent->location); + Syslog('d', "Got hostname from nodelist location"); + } + } + } + + /* + * If we have an internet address, set protocol + */ + if (inetaddr) { + Syslog('d', "TCP/IP node \"%s\"", MBSE_SS(inetaddr)); + + if (tcp_mode == TCPMODE_NONE) { + /* + * If protocol not forced at the commandline, get it + * from the nodelist. If it fails, fallback to dial. + * Priority IBN, IFC, ITN. + */ + if (nlent->iflags & IP_IBN) + tcp_mode = TCPMODE_IBN; + else if (nlent->iflags & IP_IFC) + tcp_mode = TCPMODE_IFC; + else if (nlent->iflags & IP_ITN) + tcp_mode = TCPMODE_ITN; + else { + Syslog('+', "No common TCP/IP protocols for node %s", nlent->name); + free(inetaddr); + inetaddr = NULL; + } + Syslog('d', "TCP mode set to %d", tcp_mode); + } + } else { + Syslog('d', "No IP address, fallback to dial"); + tcp_mode = TCPMODE_NONE; + } + } + + if (((nlent->oflags & OL_CM) == 0) && (!IsZMH())) { + if (!forcedcalls) { + Syslog('d', "Node is ZMH only and it is not ZMH"); + nodeulock(addr); + putstatus(addr,0,ST_NOTZMH); + return ST_NOTZMH; + } + Syslog('?', "Warning: calling MO system outside ZMH"); + } + + st = getstatus(addr); + if ((rc = checkretry(st))) { + Syslog('+', "Cannot call %s: %s", ascfnode(addr,0x1f), (rc == 1)?"retry time not reached":"node undialable"); + return 5; + } + + /* + * Over TCP/IP we don't do a delay because the node we are + * connecting can't be busy. Also forced calls don't delay. + */ + Syslog('d', "delay=%d inetaddr=%s immediatecall=%s", + CFG.dialdelay, inetaddr?"true":"false", immediatecall?"true":"false"); + if ((CFG.dialdelay > 10) && (!inetaddr) && (!immediatecall)) { + /* + * Generate a random number between CFG.dialdelay and + * CFG.dialdelay / 10, minimum value is 10. + */ + srand(getpid()); + while (TRUE) { + j = 1+(int) (1.0 * CFG.dialdelay * rand() / (RAND_MAX + 1.0)); + if ((j > (CFG.dialdelay / 10)) && (j > 9)) + break; + } + Syslog('d', "Dial delay %d seconds", j); + + for (i = j; i > 0; i--) { + IsDoing("Delay %d seconds", i); + sleep(1); + } + } + + if (nodelock(addr)) { + Syslog('+', "System %s is locked", ascfnode(addr, 0x1f)); + putstatus(addr, 0, ST_LOCKED); + return ST_LOCKED; + } + + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); /* master sessions are secure */ + + /* + * Call when: + * the nodelist has a phone, or phone on commandline, or TCP address given + * and + * nodenumber on commandline, or node is CM and not down, hold, pvt + * and + * nocall is false + */ + if ((nlent->phone || forcedphone || inetaddr ) && ((forcedcalls || (nlent->oflags & OL_CM)) || + (((nlent->pflag & (NL_DUMMY|NL_DOWN|NL_HOLD|NL_PVT)) == 0) && ((localoptions & NOCALL) == 0)))) { + Syslog('+', "Calling %s (%s, phone %s)",ascfnode(addr,0x1f), nlent->name,nlent->phone?nlent->phone:forcedphone); + IsDoing("Call %s", ascfnode(addr, 0x0f)); + rc = portopen(addr); + + if ((rc == 0) && (!inetaddr)) { + if ((rc = dialphone(forcedphone?forcedphone:nlent->phone))) { + Syslog('+', "Dial failed"); + nodeulock(addr); + rc+=1; /* rc=2 - dial fail, rc=3 - could not reset */ + } + } + + if (rc == 0) { + if (!inetaddr) + nolocalport(); + + if (tcp_mode == TCPMODE_IBN) + rc = session(addr,nlent,SESSION_MASTER,SESSION_BINKP,NULL); + else + rc = session(addr,nlent,SESSION_MASTER,SESSION_UNKNOWN,NULL); + + if (rc) + rc=abs(rc)+10; + } + + IsDoing("Disconnect"); + if (inetaddr) { + closetcp(); + } else { + hangup(); + if (rc == 0) + aftercall(); + localport(); + closeport(); + } + } else { + IsDoing("NoCall"); + Syslog('+', "Cannot call %s (%s, phone %s)", ascfnode(addr,0x1f),MBSE_SS(nlent->name), MBSE_SS(nlent->phone)); + if ((nlent->phone || forcedphone || inetaddr )) + rc=ST_NOCALL8; + else + rc=ST_NOCALL7; + putstatus(addr, 10, rc); + nodeulock(addr); + return rc; + } + + if ((rc > 10) && (rc < 20)) /* Session error */ + putstatus(addr, 5, rc); + else if ((rc == 2) || (rc == 30)) + putstatus(addr,1,rc); + else + putstatus(addr,0,rc); + return rc; +} + + diff --git a/mbcico/call.h b/mbcico/call.h new file mode 100644 index 00000000..70d113bf --- /dev/null +++ b/mbcico/call.h @@ -0,0 +1,10 @@ +#ifndef _CALL_H +#define _CALL_H + + +int call(faddr *); + + +#endif + + diff --git a/mbcico/callall.c b/mbcico/callall.c new file mode 100644 index 00000000..05551bc8 --- /dev/null +++ b/mbcico/callall.c @@ -0,0 +1,146 @@ +/***************************************************************************** + * + * File ..................: mbcico/callall.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "config.h" +#include "../lib/clcomm.h" +#include "scanout.h" +#include "lutil.h" +#include "callstat.h" +#include "callall.h" + + +static int each(faddr*, char, int, char*); +static fa_list *alist = NULL; + + + +fa_list *callall(void) +{ + fa_list *tmp; + int rc; + + if (alist) { + for (tmp = alist; tmp; tmp = alist) { + alist = tmp->next; + tidy_faddr(tmp->addr); + free(tmp); + } + alist = NULL; + } + + if ((rc = scanout(each))) { + WriteError("Error scanning outbound, aborting"); + return NULL; + } + + return (fa_list *)alist; +} + + + +static int each(faddr *addr, char flavor, int isflo, char *fname) +{ + fa_list **tmp; + callstat *st; + + if ((flavor == 'h') || + ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_POL))) + return 0; + + /* + * Outside Zone Mail Hour normal flavor will be hold. + */ + if (!IsZMH() && (flavor == 'o')) + return 0; + + /* + * During ZMH only poll and .pkt files will be sent, except + * IMMediate mail, that goes always. + */ + if (flavor != 'i') { + if (IsZMH() && (isflo == OUT_FLO)) + return 0; + } + + /* + * Don't add nodes who are undiable + */ + st = getstatus(addr); + if (st->tryno >= 30) + return 0; + + for (tmp = &alist; *tmp; tmp=&((*tmp)->next)) + if (((*tmp)->addr->zone == addr->zone) && + ((*tmp)->addr->net == addr->net) && + ((*tmp)->addr->node == addr->node) && + ((*tmp)->addr->point == addr->point) && + (((*tmp)->addr->domain == NULL) || + (addr->domain == NULL) || + (strcasecmp((*tmp)->addr->domain,addr->domain) == 0))) + break; + + if (*tmp == NULL) { + *tmp=(fa_list *)malloc(sizeof(fa_list)); + (*tmp)->next=NULL; + (*tmp)->addr=(faddr *)malloc(sizeof(faddr)); + (*tmp)->addr->name=NULL; + (*tmp)->addr->zone=addr->zone; + (*tmp)->addr->net=addr->net; + (*tmp)->addr->node=addr->node; + (*tmp)->addr->point=addr->point; + (*tmp)->addr->domain=xstrcpy(addr->domain); + if (flavor == 'i') + (*tmp)->force = TRUE; + else + (*tmp)->force = FALSE; + if (isflo == OUT_POL) + (*tmp)->force = TRUE; + + switch (flavor) { + case 'i': Syslog('+', "Immediate mail to %s", ascfnode((*tmp)->addr,0x1f)); + break; + case 'c': Syslog('+', "Crash mail to %s", ascfnode((*tmp)->addr,0x1f)); + break; + case 'o': Syslog('+', "Normal mail to %s",ascfnode((*tmp)->addr,0x1f)); + break; + case 'p': Syslog('+', "Poll request to %s",ascfnode((*tmp)->addr,0x1f)); + break; + default : Syslog('+', "Some mail (%c) to %s",flavor,ascfnode((*tmp)->addr,0x1f)); + } + } + + return 0; +} + + diff --git a/mbcico/callall.h b/mbcico/callall.h new file mode 100644 index 00000000..d5dd56a4 --- /dev/null +++ b/mbcico/callall.h @@ -0,0 +1,9 @@ +#ifndef _CALLALL_H +#define _CALLALL_H + + +fa_list *callall(void); + + +#endif + diff --git a/mbcico/callstat.c b/mbcico/callstat.c new file mode 100644 index 00000000..acb306d9 --- /dev/null +++ b/mbcico/callstat.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * + * File ..................: mbcico/callstat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 13-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "callstat.h" + + + +callstat *getstatus(faddr *addr) +{ + static callstat cst; + FILE *fp; + + cst.trytime = 0L; + cst.tryno = 0; + cst.trystat = 0; + + if ((fp = fopen(stsname(addr), "r"))) { + fread(&cst, sizeof(callstat), 1, fp); + fclose(fp); + } + + return &cst; +} + + + +void putstatus(faddr *addr, int incr, int sts) +{ + FILE *fp; + callstat *cst; + + cst = getstatus(addr); + if ((fp = fopen(stsname(addr), "w"))) { + if (sts == 0) + cst->tryno = 0; + else + cst->tryno += incr; + cst->trystat = sts; + (void)time(&cst->trytime); + fwrite(cst, sizeof(callstat), 1, fp); + fclose(fp); + if (cst->tryno >= 30) + WriteError("Node %s is marked undialble.", ascfnode(addr, 0x1f)); + } else { + WriteError("$Cannot create status file for node %s", ascfnode(addr,0x1f)); + } +} + + diff --git a/mbcico/callstat.h b/mbcico/callstat.h new file mode 100644 index 00000000..a27eb37e --- /dev/null +++ b/mbcico/callstat.h @@ -0,0 +1,26 @@ +#ifndef CALLSTAT_H +#define CALLSTAT_H + + +#define ST_PORTERR 1 +#define ST_NOCONN 2 +#define ST_MDMERR 3 +#define ST_LOCKED 4 +#define ST_LOOKUP 6 +#define ST_NOCALL7 7 +#define ST_NOCALL8 8 +#define ST_NOPORT 9 +#define ST_NOTZMH 10 +#define ST_SESSION 30 + + +typedef struct _callstat { + time_t trytime; + int tryno; + int trystat; +} callstat; + +callstat *getstatus(faddr*); +void putstatus(faddr*,int,int); + +#endif diff --git a/mbcico/chat.c b/mbcico/chat.c new file mode 100644 index 00000000..fea4f754 --- /dev/null +++ b/mbcico/chat.c @@ -0,0 +1,253 @@ +/***************************************************************************** + * + * File ..................: mbcico/chat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "config.h" +#include "portsel.h" +#include "chat.h" +#include "ttyio.h" + + +char *tranphone(char *Phone) +{ + static char trp[21]; + char buf[21]; + char *p; + int ln, i, j; + + if (Phone == NULL) + return NULL; + strncpy(trp,Phone,sizeof(trp)-1); + + for (i = 0; i < 40; i++) + if (strlen(CFG.phonetrans[i].match) || strlen(CFG.phonetrans[i].repl)) { + memset(&buf, 0, sizeof(buf)); + strncpy(buf,CFG.phonetrans[i].match,strlen(CFG.phonetrans[i].match)); + ln=strlen(buf); + p = xstrcpy(CFG.phonetrans[i].repl); + + if (strncmp(Phone,buf,ln) == 0) { + strcpy(trp,p); + strncat(trp,Phone+ln,sizeof(trp)-strlen(p)-1); + free(p); + break; + } else { + free(p); + } + } + + if (modem.stripdash) { + j = 0; + for (i = 0; i < strlen(trp); i++) { + if (trp[i] != '-') { + trp[j] = trp[i]; + j++; + } + } + trp[j] = '\0'; + } + return trp; +} + + + +int send_str(char *, char *); +int send_str(char *str, char *Phone) +{ + char *p, *q; + static char logs[81]; + + p = str; + memset(&logs, 0, sizeof(logs)); + q = logs; + + while (*p) { + if (*p == '\\') { + switch (*++p) { + case '\0': p--; break; + case '\\': PUTCHAR('\\'); *q++ = '\\'; break; + case 'r': PUTCHAR('\r'); *q++ = '\\'; *q++ = 'r'; break; + case 'n': PUTCHAR('\n'); *q++ = '\\'; *q++ = 'n'; break; + case 't': PUTCHAR('\t'); *q++ = '\\'; *q++ = 't'; break; + case 'b': PUTCHAR('\b'); *q++ = '\\'; *q++ = 'b'; break; + case 's': PUTCHAR(' '); *q++ = ' '; break; + case ' ': PUTCHAR(' '); *q++ = ' '; break; + case 'd': sleep(1); *q++ = '\\'; *q++ = 'd'; break; + case 'p': usleep(250000L); *q++ = '\\'; *q++ = 'p'; break; + case 'D': if (Phone) { + PUTSTR(Phone); + sprintf(q, "%s", Phone); + } + break; + case 'T': if (Phone) { + PUTSTR(tranphone(Phone)); + sprintf(q, "%s", tranphone(Phone)); + } + break; + default: PUTCHAR(*p); *q++ = *p; break; + } + while (*q) + q++; + } else { + PUTCHAR(*p); + *q++ = *p; + } + p++; + } + Syslog('+', "chat: snd \"%s\"", logs); + + if (STATUS) { + WriteError("$chat: send_str error %d", STATUS); + return 1; + } else + return 0; +} + + + +static int expired = FALSE; + +void almhdl(int); +void almhdl(int sig) +{ + expired = TRUE; + Syslog('c' ,"chat: timeout"); + return; +} + + + +int expect_str(int, char *); +int expect_str(int timeout, char *Phone) +{ + int matched = FALSE; + int smatch = FALSE; + int ematch = FALSE; + int ioerror = FALSE; + int i, rc; + char inbuf[256]; + unsigned char ch = '\0'; + int eol = FALSE; + + expired = FALSE; + signal(SIGALRM, almhdl); + alarm(timeout); + + while (!matched && !expired && !ioerror && !feof(stdin)) { + + eol = FALSE; + i = 0; + memset(&inbuf, 0, sizeof(inbuf)); + + while (!ioerror && !feof(stdin) && !eol && (i < 255)) { + + if ((rc = read(0, &ch, 1)) != 1) { + ioerror = TRUE; + } else { + switch(ch) { + case '\n': break; + case '\r': inbuf[i++] = '\r'; + eol = TRUE; + break; + default: inbuf[i++] = ch; + } + } + if (expired) + Syslog('c', "chat: got TIMEOUT"); + } + + inbuf[i] = '\0'; + Syslog('c', "chat: rcv \"%s\"", printable(inbuf, 0)); + + for (i = 0; (i < 10) && !matched; i++) + if (strlen(modem.error[i])) + if (strncmp(modem.error[i], inbuf, strlen(modem.error[i])) == 0) { + matched = TRUE; + ematch = TRUE; + Syslog('+', "chat: got \"%s\", aborting", printable(inbuf, 0)); + } + + if (Phone != NULL) + for (i = 0; (i < 20) && !matched; i++) + if (strlen(modem.connect[i])) + if (strncmp(modem.connect[i], inbuf, strlen(modem.connect[i])) == 0) { + matched = TRUE; + smatch = TRUE; + Syslog('+', "chat: got \"%s\", continue", printable(inbuf, 0)); + } + + if (!matched) + if (strlen(modem.ok)) + if (strncmp(modem.ok, inbuf, strlen(modem.ok)) == 0) { + matched = TRUE; + smatch = TRUE; + Syslog('+', "chat: got \"%s\", continue", printable(inbuf, 0)); + } + + if (expired) + Syslog('+', "chat: got timeout, aborting"); + else + if (ferror(stdin)) + Syslog('+', "chat: got error, aborting"); + + if (feof(stdin)) + WriteError("$chat: got EOF, aborting"); + } + alarm(0); + signal(SIGALRM, SIG_DFL); + + rc = !(matched && smatch); + return rc; +} + + + +/* + * Chat with modem. If phone is not NULL, then expect also tests the modem + * connect strings, else only the error strings and ok string is tested. + * The phone number must be full international notation unless the \D + * macro is in the dial command. + */ +int chat(char *Send, int timeout, char *Phone) +{ + int rc; + + if ((rc = send_str(Send, Phone)) == 0) + rc = expect_str(timeout, Phone); + + return rc; +} + + diff --git a/mbcico/chat.h b/mbcico/chat.h new file mode 100644 index 00000000..f69bdf33 --- /dev/null +++ b/mbcico/chat.h @@ -0,0 +1,8 @@ +#ifndef _CHAT_H +#define _CHAT_H + +char *tranphone(char *); +int chat(char *, int, char *); + +#endif + diff --git a/mbcico/config.h b/mbcico/config.h new file mode 100644 index 00000000..61daca5c --- /dev/null +++ b/mbcico/config.h @@ -0,0 +1,24 @@ +#ifndef _CONFIG_H +#define _CONFIG_H + +#include "../lib/structs.h" +#include "../lib/common.h" + + +extern long configtime; +extern long maxfsize; +extern long maxmsize; + + +extern char *name; +extern char *phone; +extern char *flags; +extern char *inbound; +extern char *myfqdn; +extern char *debugfile; +extern char *nonpacked; +extern char *magicname; +extern char *dosoutbound; +extern char *uxoutbound; + +#endif diff --git a/mbcico/dial.c b/mbcico/dial.c new file mode 100644 index 00000000..45ca130e --- /dev/null +++ b/mbcico/dial.c @@ -0,0 +1,166 @@ +/***************************************************************************** + * + * File ..................: mbcico/dial.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "portsel.h" +#include "config.h" +#include "chat.h" +#include "ttyio.h" +#include "session.h" +#include "dial.h" + + +extern time_t c_start; +extern time_t c_end; +extern int online; +extern int master; +int carrier; +extern long sentbytes; +extern long rcvdbytes; +extern int Loaded; + + +int initmodem(void) +{ + int i; + + for (i = 0; i < 3; i++) + if (strlen(modem.init[i])) + if (chat(modem.init[i], CFG.timeoutreset, NULL)) { + WriteError("dial: could not reset the modem"); + return 1; + } + return 0; +} + + + +int dialphone(char *Phone) +{ + int rc; + + Syslog('+', "dial: %s (%s)",MBSE_SS(Phone), MBSE_SS(tranphone(Phone))); + carrier = FALSE; + + if (initmodem()) + return 2; + + rc = 0; + if (strlen(nodes.phone[0])) { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, nodes.phone[0]); + else + rc = chat(modem.dial, CFG.timeoutconnect, nodes.phone[0]); + if ((rc == 0) && strlen(nodes.phone[1])) { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, nodes.phone[1]); + else + rc = chat(modem.dial, CFG.timeoutconnect, nodes.phone[1]); + } + } else { + if (strlen(nodes.dial)) + rc = chat(nodes.dial, CFG.timeoutconnect, Phone); + else + rc = chat(modem.dial, CFG.timeoutconnect, Phone); + } + + if (rc) { + Syslog('+', "Could not connect to the remote"); + return 1; + } else { + c_start = time(NULL); + carrier = TRUE; + return 0; + } +} + + + +int hangup() +{ + char *tmp; + FILE *fp; + + FLUSHIN(); + FLUSHOUT(); + if (strlen(modem.hangup)) + chat(modem.hangup, CFG.timeoutreset, NULL); + + if (carrier) { + time(&c_end); + online += (c_end - c_start); + Syslog('+', "Connection time %s", t_elapsed(c_start, c_end)); + carrier = FALSE; + history.offline = c_end; + history.online = c_start; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = ~master; + tmp = calloc(128, sizeof(char)); + sprintf(tmp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(tmp, "a")) == NULL) + WriteError("$Can't open %s", tmp); + else { + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + } + free(tmp); + memset(&history, 0, sizeof(history)); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + FLUSHIN(); + FLUSHOUT(); + return 0; +} + + + +int aftercall() +{ + if (strlen(modem.info)) { + Syslog('d', "Reading link stat (aftercall)"); + FLUSHIN(); + FLUSHOUT(); + chat(modem.info, CFG.timeoutreset, NULL); + } + return 0; +} + + diff --git a/mbcico/dial.h b/mbcico/dial.h new file mode 100644 index 00000000..5874fa0b --- /dev/null +++ b/mbcico/dial.h @@ -0,0 +1,11 @@ +#ifndef _DIAL_H +#define _DIAL_H + +int dialphone(char *); +int hangup(void); +int aftercall(void); + + +#endif + + diff --git a/mbcico/dietifna.c b/mbcico/dietifna.c new file mode 100644 index 00000000..db643577 --- /dev/null +++ b/mbcico/dietifna.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbcico/dietifna.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "emsi.h" +#include "dietifna.h" +#include "respfreq.h" +#include "filelist.h" +#include "xmrecv.h" +#include "xmsend.h" + + +extern int made_request; +static int sendfiles(file_list*); +static int xmrcvfiles(void); + + + +int rxdietifna(void) +{ + int rc; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start DietIFNA session"); + session_flags |= SESSION_IFNA; + session_flags &= ~SESSION_BARK; + tosend = create_filelist(remote, (char *)ALL_MAIL, 0); + + if ((rc = xmrcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + rc = sendfiles(tosend); + /* we are not sending file requests in slave session */ + } + + tidy_filelist(tosend, (rc == 0)); + if (rc) + WriteError("DietIFNA session failed: rc=%d", rc); + else + Syslog('+', "DietIFNA session completed"); + return rc; +} + + + +int txdietifna(void) +{ + int rc; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start DietIFNA session"); + session_flags |= SESSION_IFNA; + session_flags &= ~SESSION_BARK; + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + tosend = create_filelist(remote, nonhold_mail, 2); + + if ((rc = sendfiles(tosend)) == 0) + if ((rc = xmrcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = sendfiles(respond); + /* but we are trying to respond other's file requests in master */ + /* session, though they are not allowed by the DietIFNA protocol */ + + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + if (rc) + WriteError("DietIFNA session failed: rc=%d", rc); + else + Syslog('+', "DietIFNA session completed"); + return rc; +} + + + +int xmrcvfiles(void) +{ + int rc; + + while ((rc = xmrecv(NULL)) == 0); + if (rc == 1) + return 0; + else + return rc; +} + + + +int sendfiles(file_list *tosend) +{ + int c, count = 0; + + while (((c = GETCHAR(15)) >= 0) && (c != NAK) && (c != 'C') && + (count++ < 9)) + Syslog('s', "got '%s' waiting for C/NAK", + printablec(c)); + + if (c == NAK) + session_flags &= ~FTSC_XMODEM_CRC; + else if (c == 'C') + session_flags |= FTSC_XMODEM_CRC; + else if (c < 0) + return c; + else + return 1; + + return xmsndfiles(tosend); +} + + diff --git a/mbcico/dietifna.h b/mbcico/dietifna.h new file mode 100644 index 00000000..4f5057b3 --- /dev/null +++ b/mbcico/dietifna.h @@ -0,0 +1,9 @@ +#ifndef _DIETIFNA_H +#define _DIETIFNA_H + +int rxdietifna(void); +int txdietifna(void); + + +#endif + diff --git a/mbcico/emsi.c b/mbcico/emsi.c new file mode 100644 index 00000000..9d6e3bf3 --- /dev/null +++ b/mbcico/emsi.c @@ -0,0 +1,612 @@ +/***************************************************************************** + * + * File ..................: mbcico/emsi.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "emsidat.h" +#include "hydra.h" +#include "rdoptions.h" +#include "tcp.h" +#include "wazoo.h" + + +#define LOCAL_PROTOS (PROT_ZMO | PROT_ZAP | PROT_HYD | PROT_TCP) + +static int rxemsi(void); +static int txemsi(void); +static char *intro; +static int caller; + +extern int most_debug; + +int emsi_local_lcodes; +int emsi_remote_lcodes; +int emsi_local_protos; +int emsi_remote_protos; +int emsi_local_opts; +int emsi_remote_opts; +char *emsi_local_password = NULL; +char *emsi_remote_password = NULL; +char emsi_remote_comm[4]="8N1"; + + + +int rx_emsi(char *data) +{ + int rc; + fa_list *tmr; + int denypw=0; + + Syslog('+', "Start inbound EMSI session"); + + emsi_local_lcodes = LCODE_RH1; + if (localoptions & NOPUA) + emsi_local_lcodes |= LCODE_PUP; + emsi_remote_lcodes=0; + + emsi_local_protos=LOCAL_PROTOS; + if (localoptions & NOZMODEM) + emsi_local_protos &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + if (localoptions & NOZEDZAP) + emsi_local_protos &= ~PROT_ZAP; + if (localoptions & NOJANUS) + emsi_local_protos &= ~PROT_JAN; + if (localoptions & NOHYDRA) + emsi_local_protos &= ~PROT_HYD; + if ((localoptions & NOTCP) || ((session_flags & SESSION_TCP) == 0)) { + emsi_local_protos &= ~PROT_TCP; + } + + emsi_remote_protos=0; + emsi_local_opts = OPT_XMA; + emsi_remote_opts=0; + emsi_local_password = NULL; + emsi_remote_password = NULL; + intro=data+2; + caller=0; + + if ((rc=rxemsi())) + return rc; + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + Syslog('i', "remote lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_remote_lcodes,emsi_remote_protos,emsi_remote_opts); + + if (emsi_remote_opts & OPT_EII) { + emsi_local_opts |= OPT_EII; + } + + emsi_local_protos &= emsi_remote_protos; + if (emsi_local_protos & PROT_TCP) + emsi_local_protos &= PROT_TCP; + else if (emsi_local_protos & PROT_HYD) + emsi_local_protos &= PROT_HYD; + else if (emsi_local_protos & PROT_JAN) + emsi_local_protos &= PROT_JAN; + else if (emsi_local_protos & PROT_ZAP) + emsi_local_protos &= PROT_ZAP; + else if (emsi_local_protos & PROT_ZMO) + emsi_local_protos &= PROT_ZMO; + else if (emsi_local_protos & PROT_DZA) + emsi_local_protos &= PROT_DZA; + else if (emsi_local_protos & PROT_KER) + emsi_local_protos &= PROT_KER; + + emsi_local_password = NULL; + + for (tmr = remote; tmr; tmr = tmr->next) + if (((nlent = getnlent(tmr->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + break; + } + if (nlent) + rdoptions(TRUE); + + /* + * Added these options, if they are in the setup for this + * calling node, then disable these options. + */ + if (localoptions & NOHYDRA) + emsi_local_opts &= ~PROT_HYD; + if (localoptions & NOZEDZAP) + emsi_local_opts &= ~PROT_ZAP; + if (localoptions & NOZMODEM) + emsi_local_opts &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + + if (localoptions & NOFREQS) + emsi_local_opts |= OPT_NRQ; + + if (strlen(nodes.Epasswd)) { + if ((strncasecmp(emsi_remote_password, nodes.Epasswd, strlen(nodes.Epasswd)) == 0) && + (strlen(emsi_remote_password) == strlen(nodes.Epasswd))) { + emsi_local_password = xstrcpy(nodes.Epasswd); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + Syslog('+', "Password correct, protected EMSI session"); + } else { + denypw = 1; + Syslog('?', "Remote password \"%s\", expected \"%s\"", MBSE_SS(emsi_remote_password), nodes.Epasswd); + emsi_local_password = xstrcpy((char *)"BAD_PASS"); + emsi_local_lcodes = LCODE_HAT; + } + } else { + Syslog('i', "No EMSI password check"); + Syslog('?', "Unexpected remote password \"%s\"", MBSE_SS(emsi_local_password)); + } + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + + if ((rc=txemsi())) + return rc; + + if (denypw || (emsi_local_protos == 0)) { + Syslog('+', "Refusing remote: %s", emsi_local_protos?"bad password presented": "no common protocols"); + return 0; + } + + IsDoing("EMSI %s inb", ascfnode(remote->addr, 0x0f)); + + if ((emsi_remote_opts & OPT_NRQ) == 0) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + + if (emsi_local_protos & PROT_TCP) + return rxtcp(); + else if (emsi_local_protos & PROT_HYD) + return hydra(0); +// else if (emsi_local_protos & PROT_JAN) +// return janus(); + else + return rxwazoo(); +} + + + +int tx_emsi(char *data) +{ + int rc; + + Syslog('+', "Start outbound EMSI session"); + emsi_local_lcodes = LCODE_PUA | LCODE_RH1; + if (localoptions & NOPUA) { + emsi_local_lcodes |= LCODE_PUP; + emsi_local_lcodes &= ~LCODE_PUA; + } + emsi_remote_lcodes = 0; + + emsi_local_protos=LOCAL_PROTOS; + if (localoptions & NOZMODEM) + emsi_local_protos &= ~(PROT_ZMO | PROT_ZAP | PROT_DZA); + if (localoptions & NOZEDZAP) + emsi_local_protos &= ~PROT_ZAP; + if (localoptions & NOJANUS) + emsi_local_protos &= ~PROT_JAN; + if (localoptions & NOHYDRA) + emsi_local_protos &= ~PROT_HYD; + if ((localoptions & NOTCP) || ((session_flags & SESSION_TCP) == 0)) { + emsi_local_protos &= ~PROT_TCP; + } + emsi_remote_protos=0; + emsi_local_opts=OPT_XMA | OPT_EII | OPT_NRQ; +// if (localoptions & NOFREQS) /* 17-Dec-1998, refuse requests when we pay the bill. */ +// emsi_local_opts |= OPT_NRQ; + emsi_remote_opts=0; + emsi_local_password=NULL; + emsi_remote_password=NULL; + intro=data+2; + caller=1; + emsi_local_password=NULL; + + Syslog('i', "local lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_local_lcodes,emsi_local_protos,emsi_local_opts); + + if ((rc=txemsi())) + return rc; + else { + if ((rc=rxemsi())) + return rc; + } + + if ((emsi_remote_opts & OPT_EII) == 0) { + emsi_local_opts &= ~OPT_EII; + } + + Syslog('i', "remote lcodes 0x%04x, protos 0x%04x, opts 0x%04x", emsi_remote_lcodes,emsi_remote_protos,emsi_remote_opts); + + if ((emsi_remote_protos == 0) || (emsi_remote_lcodes & LCODE_HAT)) { + Syslog('+', "Remote refused us: %s", emsi_remote_protos?"traffic held":"no common protos"); + return 0; + } + + IsDoing("EMSI %s out", ascfnode(remote->addr, 0x0f)); + + emsi_local_protos &= emsi_remote_protos; + if ((emsi_remote_opts & OPT_NRQ) == 0) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + + if (emsi_local_protos & PROT_TCP) + return txtcp(); + else if (emsi_local_protos & PROT_HYD) + return hydra(1); +// else if (emsi_local_protos & PROT_JAN) +// return janus(); + else + return txwazoo(); +} + + + +SM_DECL(rxemsi,(char *)"rxemsi") +SM_STATES + waitpkt, + waitchar, + checkemsi, + getdat, + checkpkt, + checkdat, + sendnak, + sendack +SM_NAMES + (char *)"waitpkt", + (char *)"waitchar", + (char *)"checkemsi", + (char *)"getdat", + (char *)"checkpkt", + (char *)"checkdat", + (char *)"sendnak", + (char *)"sendack" +SM_EDECL + + int c = 0; + unsigned short lcrc, rcrc; + int len; + int standby = 0, tries = 0; + char buf[13], *p; + char *databuf = NULL; + + p = buf; + databuf = xstrcpy(intro); + +SM_START(checkpkt) + Syslog('I', "rxemsi START"); + Syslog('i', "RXEMSI: start"); + +SM_STATE(waitpkt) + + Syslog('I', "rxemsi WAITPKT"); + standby = 0; + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('I', "rxemsi WAITCHAR"); + c = GETCHAR(5); + if (c == TIMEOUT) { + if (++tries > 9) { + Syslog('+', "Too many tries waiting EMSI handshake"); + SM_ERROR; + } else { + SM_PROCEED(sendnak); + } + } else if (c < 0) { + SM_ERROR; + } else if ((c >= ' ') && (c <= '~')) { + if (c == '*') { + standby = 1; + p = buf; + *p = '\0'; + } else if (standby) { + if ((p - buf) < (sizeof(buf) - 1)) { + *p++ = c; + *p = '\0'; + } if ((p - buf) >= (sizeof(buf) - 1)) { + standby = 0; + SM_PROCEED(checkemsi); + } + } + } else switch(c) { + case DC1: break; + case '\n': + case '\r': standby = 0; + break; + default: standby = 0; + break; + } + + SM_PROCEED(waitchar); + +SM_STATE(checkemsi) + + Syslog('I', "rxemsi CHECKEMSI"); + Syslog('i', "RXEMSI: rcvd %s", printable(buf, 0)); + + if (strncasecmp(buf, "EMSI_DAT",8) == 0) { + SM_PROCEED(getdat); + } else if (strncasecmp(buf, "EMSI_",5) == 0) { + if (databuf) + free(databuf); + databuf = xstrcpy(buf); + SM_PROCEED(checkpkt); + } else { + SM_PROCEED(waitpkt); + } + +SM_STATE(getdat) + + Syslog('I', "rxemsi GETDAT"); + + if (sscanf(buf+8,"%04x",&len) != 1) { + SM_PROCEED(sendnak); + } + + len += 16; /* strlen("EMSI_DATxxxxyyyy"), include CRC */ + if (databuf) + free(databuf); + databuf = malloc(len + 1); + strcpy(databuf, buf); + p = databuf + strlen(databuf); + + while (((p-databuf) < len) && ((c=GETCHAR(8)) >= 0)) { + *p++ = c; + *p = '\0'; + } + + Syslog('i', "RXEMSI: rcvd %s (%d bytes)", databuf, len); + + if (c == TIMEOUT) { + SM_PROCEED(sendnak); + } else if (c < 0) { + Syslog('+', "Error while reading EMSI_DAT packet"); + SM_ERROR; + } + + SM_PROCEED(checkdat); + +SM_STATE(checkpkt) + + Syslog('I', "rxemsi CHECKPKT"); + if (strncasecmp(databuf,"EMSI_DAT",8) == 0) { + SM_PROCEED(checkdat); + } + + lcrc = crc16xmodem(databuf, 8); + sscanf(databuf + 8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI packet \"%s\" with bad crc: %04x/%04x", printable(databuf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } if (strncasecmp(databuf, "EMSI_HBT", 8) == 0) { + tries = 0; + SM_PROCEED(waitpkt); + } else if (strncasecmp(databuf, "EMSI_INQ", 8) == 0) { + SM_PROCEED(sendnak); + } else { + Syslog('I', "RXEMSI: ignore packet \"%s\"",databuf); + SM_PROCEED(waitpkt); + } + +SM_STATE(checkdat) + + Syslog('I', "rxemsi CHECKDAT"); + sscanf(databuf + 8, "%04x", &len); + if (len != (strlen(databuf) - 16)) { + Syslog('+', "Bad EMSI_DAT length: %d/%d", len, strlen(databuf)); + SM_PROCEED(sendnak); + } + /* Some FD versions send length of the packet including the + trailing CR. Arrrgh! Dirty overwork follows: */ + if (*(p = databuf + strlen(databuf) - 1) == '\r') + *p='\0'; + sscanf(databuf + strlen(databuf) - 4, "%04hx", &rcrc); + *(databuf + strlen(databuf) - 4) = '\0'; + lcrc = crc16xmodem(databuf, strlen(databuf)); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI_DAT packet \"%s\" with bad crc: %04x/%04x", printable(databuf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } if (scanemsidat(databuf + 12) == 0) { + SM_PROCEED(sendack); + } else { + Syslog('+', "Could not parse EMSI_DAT packet \"%s\"",databuf); + SM_ERROR; + } + +SM_STATE(sendnak) + + Syslog('I', "rxemsi SENDNAK"); + if (++tries > 9) { + Syslog('+', "Too many tries getting EMSI_DAT"); + SM_ERROR; + } if (caller) { + PUTSTR((char *)"**EMSI_NAKEEC3\r\021"); + Syslog('i', "RXEMSI: send **EMSI_NAKEEC3"); + } else { + PUTSTR((char *)"**EMSI_REQA77E\r\021"); + Syslog('i', "RXEMSI: send **EMSI_REQA77E"); + if (tries > 1) { + PUTSTR((char *)"**EMSI_NAKEEC3\r\021"); + Syslog('i', "RXEMSI: send **EMSI_NAKEEC3"); + } + } + SM_PROCEED(waitpkt); + +SM_STATE(sendack) + + Syslog('I', "rxemsi SENDACK"); + Syslog('i', "RXEMSI: send **EMSI_ACKA490 (2 times)"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + SM_SUCCESS; + +SM_END + Syslog('I', "rxemsi END"); + Syslog('i', "RXEMSI: end"); + free(databuf); + +SM_RETURN + + + + +SM_DECL(txemsi,(char *)"txemsi") +SM_STATES + senddata, + waitpkt, + waitchar, + checkpkt, + sendack +SM_NAMES + (char *)"senddata", + (char *)"waitpkt", + (char *)"waitchar", + (char *)"checkpkt", + (char *)"sendack" +SM_EDECL + + int c; + unsigned short lcrc, rcrc; + int standby = 0, tries = 0; + char buf[13], *p; + char trailer[8]; + + p = buf; + memset(&buf, 0, sizeof(buf)); + strncpy(buf, intro, sizeof(buf) - 1); + +SM_START(senddata) + Syslog('i', "TXEMSI: start"); + +SM_STATE(senddata) + + Syslog('I', "txemsi SENDDATA"); + p = mkemsidat(caller); + PUTCHAR('*'); + PUTCHAR('*'); + PUTSTR(p); + sprintf(trailer, "%04X\r\021", crc16xmodem(p, strlen(p))); + PUTSTR(trailer); + Syslog('i', "TXEMSI: send **%s%04X", p, crc16xmodem(p, strlen(p))); + free(p); + SM_PROCEED(waitpkt); + +SM_STATE(waitpkt) + + Syslog('I', "txemsi WAITPKT"); + standby = 0; + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('I', "txemsi WAITCHAR"); + c = GETCHAR(8); + if (c == TIMEOUT) { + if (++tries > 9) { + Syslog('+', "too many tries sending EMSI"); + SM_ERROR; + } else { + SM_PROCEED(senddata); + } + } else if (c < 0) { + SM_ERROR; + } else if ((c >= ' ') && (c <= '~')) { + if (c == '*') { + standby = 1; + p = buf; + *p = '\0'; + } else if (standby) { + if ((p - buf) < (sizeof(buf) - 1)) { + *p++ = c; + *p = '\0'; + } if ((p - buf) >= (sizeof(buf) - 1)) { + standby = 0; + SM_PROCEED(checkpkt); + } + } + } else switch(c) { + case DC1: SM_PROCEED(waitchar); + break; + case '\n': + case '\r': standby = 0; + break; + default: standby = 0; + break; + } + SM_PROCEED(waitchar); + +SM_STATE(checkpkt) + + Syslog('I', "txemsi CHECKPKT"); + Syslog('i', "TXEMSI: rcvd %s", buf); + if (strncasecmp(buf, "EMSI_DAT", 8) == 0) { + SM_PROCEED(sendack); + } else if (strncasecmp(buf, "EMSI_", 5) == 0) { + lcrc = crc16xmodem(buf, 8); + sscanf(buf + 8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got EMSI packet \"%s\" with bad crc: %04x/%04x", printable(buf, 0), lcrc, rcrc); + SM_PROCEED(senddata); + } if (strncasecmp(buf, "EMSI_REQ", 8) == 0) { + SM_PROCEED(waitpkt); + } if (strncasecmp(buf, "EMSI_ACK", 8) == 0) { + SM_SUCCESS; + } else { + SM_PROCEED(senddata); + } + } else { + SM_PROCEED(waitpkt); + } + +SM_STATE(sendack) + + Syslog('I', "txemsi SENDACK"); + Syslog('i', "TXEMSI: send **EMSI_ACKA490 (2 times)"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + PUTSTR((char *)"**EMSI_ACKA490\r\021"); + SM_PROCEED(waitpkt); + +SM_END + Syslog('i', "TXEMSI: end"); + +SM_RETURN + + diff --git a/mbcico/emsi.h b/mbcico/emsi.h new file mode 100644 index 00000000..bdade0f1 --- /dev/null +++ b/mbcico/emsi.h @@ -0,0 +1,52 @@ +#define PRODCODE 0xfe /* product code for ifcico */ + +#ifndef EMSI_H +#define EMSI_H + +#define LCODE_PUA 0x0001 +#define LCODE_PUP 0x0002 +#define LCODE_NPU 0x0004 +#define LCODE_HAT 0x0008 +#define LCODE_HXT 0x0010 +#define LCODE_HRQ 0x0020 +#define LCODE_FNC 0x0040 +#define LCODE_RMA 0x0080 +#define LCODE_RH1 0x0100 + +extern int emsi_local_lcodes; +extern int emsi_remote_lcodes; + +#define PROT_DZA 0x0001 +#define PROT_ZAP 0x0002 +#define PROT_ZMO 0x0004 +#define PROT_JAN 0x0008 +#define PROT_KER 0x0010 +#define PROT_HYD 0x0020 +#define PROT_TCP 0x0040 + +extern int emsi_local_protos; +extern int emsi_remote_protos; + +#define OPT_NRQ 0x0002 +#define OPT_ARC 0x0004 +#define OPT_XMA 0x0008 +#define OPT_FNC 0x0010 +#define OPT_CHT 0x0020 +#define OPT_SLK 0x0040 +#define OPT_EII 0x0080 +#define OPT_DFB 0x0100 +#define OPT_FRQ 0x0200 + +extern int emsi_local_opts; +extern int emsi_remote_opts; + +extern char *emsi_local_password; +extern char *emsi_remote_password; +extern char emsi_remote_comm[]; + + +int rx_emsi(char *); +int tx_emsi(char *); + + +#endif diff --git a/mbcico/emsidat.c b/mbcico/emsidat.c new file mode 100644 index 00000000..e50a7cb5 --- /dev/null +++ b/mbcico/emsidat.c @@ -0,0 +1,502 @@ +/***************************************************************************** + * + * File ..................: mbcico/emsidat.c + * Purpose ...............: Fidonet mailer + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "emsi.h" +#include "session.h" +#include "lutil.h" +#include "config.h" +#include "emsidat.h" +#include "filetime.h" + + +extern int Loaded; + + +char *emsiencode(char *s) +{ + char Base16Code[]="0123456789ABCDEF"; + static char *buf; + char *p, *q; + + if (buf) + free(buf); + if ((buf = malloc(2 * strlen(s) + 1 * sizeof(char))) == NULL) { + Syslog('+', "emsiencode:out of memory:string too long:\"%s\"", s); + return s; + } + for (p = s, q = buf; *p != '\0';) { + switch (*p) { + case '\\': *q++ = '\\'; *q++ = *p++; break; + case '[': + case ']': + case '{': + case '}': *q++ = '\\'; + *q++ = Base16Code[(*p >> 4) & 0x0f]; + *q++ = Base16Code[*p & 0x0f]; + p++; break; + default: *q++ = *p++; break; + } + } + *q = '\0'; + + return buf; +} + + + +char *mkemsidat(int caller) +{ + time_t tt; + char cbuf[16]; + char *p; + faddr *primary; + int i; + + p = xstrcpy((char *)"EMSI_DAT0000{EMSI}{"); + + primary = bestaka_s(remote->addr); + p = xstrcat(p, ascfnode(primary, 0x1f)); + + for (i = 0; i < 40; i++) + if ((CFG.aka[i].node) && (CFG.akavalid[i]) && + ((CFG.aka[i].zone != primary->zone) || + (CFG.aka[i].net != primary->net) || + (CFG.aka[i].node != primary->node) || + (CFG.aka[i].point!= primary->point))) { + p = xstrcat(p, (char *)" "); + p = xstrcat(p, aka2str(CFG.aka[i])); + } + + p=xstrcat(p,(char *)"}{"); + tidy_faddr(primary); + + if (emsi_local_password) + p=xstrcat(p,emsi_local_password); + else + if (strlen(nodes.Epasswd)) { + p = xstrcat(p, nodes.Epasswd); + } + + if (emsi_local_opts & OPT_EII) { + p = xstrcat(p, (char *)"}{"); + + if (emsi_local_lcodes & LCODE_FNC) + p = xstrcat(p, (char *)"FNC,"); + if (emsi_local_lcodes & LCODE_RMA) + p = xstrcat(p, (char *)"RMA,"); + if (emsi_local_lcodes & LCODE_RH1) + p = xstrcat(p, (char *)"RH1,"); + + if (emsi_local_lcodes & LCODE_PUA) + p=xstrcat(p,(char *)"PUA,"); + else if (emsi_local_lcodes & LCODE_PUP) + p=xstrcat(p,(char *)"PUP,"); + else if (emsi_local_lcodes & LCODE_NPU) + p=xstrcat(p,(char *)"NPU,"); + if (emsi_local_lcodes & LCODE_HAT) + p=xstrcat(p,(char *)"HAT,"); + if (emsi_local_lcodes & LCODE_HXT) + p=xstrcat(p,(char *)"HXT,"); + if (emsi_local_lcodes & LCODE_HRQ) + p=xstrcat(p,(char *)"HRQ,"); + if (*(p+strlen(p)-1) == ',') + *(p+strlen(p)-1) = '}'; + else + p=xstrcat(p,(char *)"}"); + } else { + p=xstrcat(p,(char *)"}{8N1"); + if (emsi_local_lcodes & LCODE_RH1) + p = xstrcat(p, (char *)",RH1"); + if (caller) { + if (emsi_local_lcodes & LCODE_PUA) + p=xstrcat(p,(char *)",PUA"); + else if (emsi_local_lcodes & LCODE_PUP) + p=xstrcat(p,(char *)",PUP"); + else if (emsi_local_lcodes & LCODE_NPU) + p=xstrcat(p,(char *)",NPU"); + } else { + if (emsi_local_lcodes & LCODE_HAT) + p=xstrcat(p,(char *)",HAT"); + if (emsi_local_lcodes & LCODE_HXT) + p=xstrcat(p,(char *)",HXT"); + if (emsi_local_lcodes & LCODE_HRQ) + p=xstrcat(p,(char *)",HRQ"); + } + + p = xstrcat(p, (char *)"}"); + } + + p=xstrcat(p,(char *)"{"); + if (emsi_local_protos & PROT_TCP) + p=xstrcat(p,(char *)"TCP,"); + if (emsi_local_protos & PROT_HYD) + p=xstrcat(p,(char *)"HYD,"); + if (emsi_local_protos & PROT_JAN) + p=xstrcat(p,(char *)"JAN,"); + if (emsi_local_protos & PROT_ZAP) + p=xstrcat(p,(char *)"ZAP,"); + if (emsi_local_protos & PROT_ZMO) + p=xstrcat(p,(char *)"ZMO,"); + if (emsi_local_protos & PROT_DZA); + p=xstrcat(p,(char *)"DZA,"); + if (emsi_local_protos & PROT_KER) + p=xstrcat(p,(char *)"KER,"); + if (emsi_local_protos == 0) + p=xstrcat(p,(char *)"NCP,"); + if (emsi_local_opts & OPT_NRQ) + p=xstrcat(p,(char *)"NRQ,"); + if (emsi_local_opts & OPT_ARC) + p=xstrcat(p,(char *)"ARC,"); + if (emsi_local_opts & OPT_XMA) + p=xstrcat(p,(char *)"XMA,"); + if (emsi_local_opts & OPT_FNC) + p=xstrcat(p,(char *)"FNC,"); + if (emsi_local_opts & OPT_CHT) + p=xstrcat(p,(char *)"CHT,"); + if (emsi_local_opts & OPT_SLK) + p=xstrcat(p,(char *)"SLK,"); + if (emsi_local_opts & OPT_EII) + p=xstrcat(p,(char *)"EII,"); + if (emsi_local_opts & OPT_DFB) + p=xstrcat(p,(char *)"DFB,"); + if (emsi_local_opts & OPT_FRQ) + p=xstrcat(p,(char *)"FRQ,"); + if (*(p+strlen(p)-1) == ',') + *(p+strlen(p)-1) = '}'; + else + p=xstrcat(p,(char *)"}"); + + sprintf(cbuf,"{%X}",PRODCODE); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"{mbcico}{"); + p=xstrcat(p,(char *)VERSION); + p=xstrcat(p,(char *)"}{"); + p=xstrcat(p,(char *)__DATE__); + p=xstrcat(p,(char *)"}{IDENT}{["); + p=xstrcat(p,name?emsiencode(name):(char *)"Unknown"); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,emsiencode(CFG.location)); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,emsiencode(CFG.sysop_name)); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,phone?emsiencode(phone):(char *)"-Unpublished-"); + p=xstrcat(p,(char *)"]["); + if (CFG.Speed) + sprintf(cbuf,"%ld",CFG.Speed); + else + strcpy(cbuf,"9600"); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"]["); + p=xstrcat(p,flags?emsiencode(flags):(char *)""); + p=xstrcat(p,(char *)"]}{TRX#}{["); + (void)time(&tt); + sprintf(cbuf,"%08lX",mtime2sl(tt)); + p=xstrcat(p,cbuf); + p=xstrcat(p,(char *)"]}{TZUTC}{["); + p=xstrcat(p,gmtoffset(tt)); + p=xstrcat(p,(char *)"]}"); + + sprintf(cbuf,"%04X",(unsigned int)strlen(p+12)); + memcpy(p+8,cbuf,4); + Syslog('I',"Prepared: \"%s\"",p); + return p; +} + + + +char *sel_brace(char*); +char *sel_brace(char *s) +{ + static char *save; + char *p,*q; + int i; + + if (s == NULL) + s=save; + for (;*s && (*s != '{');s++); + if (*s == '\0') { + save=s; + return NULL; + } else + s++; + + for (p=s,q=s;*p;p++) + switch (*p) { + case '}': if (*(p+1) == '}') + *q++=*p++; + else { + *q='\0'; + save=p+1; + goto exit; + } + break; + case '\\': if (*(p+1) == '\\') + *q++=*p++; + else { + sscanf(p+1,"%02x",&i); + *q++=i; + p+=2; + } + break; + default: *q++=*p; + break; + } +exit: + return s; +} + + + +char *sel_bracket(char*); +char *sel_bracket(char *s) +{ + static char *save; + char *p,*q; + int i; + + if (s == NULL) + s=save; + for (;*s && (*s != '[');s++); + if (*s == '\0') { + save=s; + return NULL; + } else + s++; + + for (p=s,q=s;*p;p++) + switch (*p) { + case ']': if (*(p+1) == ']') + *q++=*p++; + else { + *q='\0'; + save=p+1; + goto exit; + } + break; + case '\\': if (*(p+1) == '\\') + *q++=*p++; + else { + sscanf(p+1,"%02x",&i); + *q++=i; + p+=2; + } + break; + default: *q++=*p; + break; + } +exit: + return s; +} + + + +int scanemsidat(char *buf) +{ + char *p,*q; + fa_list **tmp,*tmpa; + faddr *fa; + char *mailer_prod,*mailer_name,*mailer_version,*mailer_serial; + + Syslog('I',"got data packet: \"%s\"",buf); + + p=sel_brace(buf); + if (strcasecmp(p,"EMSI") != 0) { + Syslog('?', "This can never occur. Got \"%s\" instead of \"EMSI\"",p); + return 1; + } + p=sel_brace(NULL); + + /* + * Clear remote address list, and build a new one from EMSI data + */ + tidy_falist(&remote); + remote = NULL; + tmp = &remote; + for (q = strtok(p," "); q; q = strtok(NULL," ")) + if ((fa = parsefnode(q))) { + *tmp = (fa_list*)malloc(sizeof(fa_list)); + (*tmp)->next = NULL; + (*tmp)->addr = fa; + tmp = &((*tmp)->next); + } + + for (tmpa = remote; tmpa; tmpa = tmpa->next) { + Syslog('+', "address : %s",ascfnode(tmpa->addr,0x1f)); + (void)nodelock(tmpa->addr); + /* + * With the loaded flag we prevent removing the noderecord + * when the remote presents us an address we don't know about. + */ + if (!Loaded) { + if (noderecord(tmpa->addr)) + Loaded = TRUE; + } + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + sprintf(history.aka.domain, "%s", remote->addr->domain); + + if (emsi_remote_password) + free(emsi_remote_password); + emsi_remote_password=xstrcpy(sel_brace(NULL)); +// Syslog('+', "password: %s", MBSE_SS(emsi_remote_password)); + + p=sel_brace(NULL); + Syslog('+', "link : %s", MBSE_SS(p)); + for (q=strtok(p,",");q;q=strtok(NULL,",")) { + if (((q[0] >= '5') && (q[0] <= '8')) && + ((toupper(q[1]) == 'N') || + (toupper(q[1]) == 'O') || + (toupper(q[1]) == 'E') || + (toupper(q[1]) == 'S') || + (toupper(q[1]) == 'M')) && + ((q[2] == '1') || (q[2] == '2'))) + { + strncpy(emsi_remote_comm,q,3); + } + else if (strcasecmp(q,"PUA") == 0) emsi_remote_lcodes |= LCODE_PUA; + else if (strcasecmp(q,"PUP") == 0) emsi_remote_lcodes |= LCODE_PUP; + else if (strcasecmp(q,"NPU") == 0) emsi_remote_lcodes |= LCODE_NPU; + else if (strcasecmp(q,"HAT") == 0) emsi_remote_lcodes |= LCODE_HAT; + else if (strcasecmp(q,"HXT") == 0) emsi_remote_lcodes |= LCODE_HXT; + else if (strcasecmp(q,"HRQ") == 0) emsi_remote_lcodes |= LCODE_HRQ; + else if (strcasecmp(q,"FNC") == 0) emsi_remote_lcodes |= LCODE_FNC; + else if (strcasecmp(q,"RMA") == 0) emsi_remote_lcodes |= LCODE_RMA; + else if (strcasecmp(q,"RH1") == 0) emsi_remote_lcodes |= LCODE_RH1; + else Syslog('+', "unrecognized EMSI link code: \"%s\"",q); + } + + p=sel_brace(NULL); + Syslog('+', "comp : %s", p); + for (q=strtok(p,",");q;q=strtok(NULL,",")) + { + if (strcasecmp(q,"DZA") == 0) emsi_remote_protos |= PROT_DZA; + else if (strcasecmp(q,"ZAP") == 0) emsi_remote_protos |= PROT_ZAP; + else if (strcasecmp(q,"ZMO") == 0) emsi_remote_protos |= PROT_ZMO; + else if (strcasecmp(q,"JAN") == 0) emsi_remote_protos |= PROT_JAN; + else if (strcasecmp(q,"HYD") == 0) emsi_remote_protos |= PROT_HYD; + else if (strcasecmp(q,"KER") == 0) emsi_remote_protos |= PROT_KER; + else if (strcasecmp(q,"TCP") == 0) emsi_remote_protos |= PROT_TCP; + else if (strcasecmp(q,"NCP") == 0) emsi_remote_protos = 0; + else if (strcasecmp(q,"NRQ") == 0) emsi_remote_opts |= OPT_NRQ; + else if (strcasecmp(q,"ARC") == 0) emsi_remote_opts |= OPT_ARC; + else if (strcasecmp(q,"XMA") == 0) emsi_remote_opts |= OPT_XMA; + else if (strcasecmp(q,"FNC") == 0) emsi_remote_opts |= OPT_FNC; + else if (strcasecmp(q,"CHT") == 0) emsi_remote_opts |= OPT_CHT; + else if (strcasecmp(q,"SLK") == 0) emsi_remote_opts |= OPT_SLK; + else if (strcasecmp(q,"EII") == 0) emsi_remote_opts |= OPT_EII; + else if (strcasecmp(q,"DFB") == 0) emsi_remote_opts |= OPT_DFB; + else if (strcasecmp(q,"FRQ") == 0) emsi_remote_opts |= OPT_FRQ; + else if (strcasecmp(q,"BBS") == 0) Syslog('+', "remote has BBS activity now"); + else Syslog('+', "unrecognized EMSI proto/option code: \"%s\"",q); + } + if ((emsi_remote_opts & OPT_FNC) == 0) + remote_flags &= ~SESSION_FNC; + + mailer_prod=sel_brace(NULL); + mailer_name=sel_brace(NULL); + mailer_version=sel_brace(NULL); + mailer_serial=sel_brace(NULL); + Syslog('+', "uses : %s [%s] version %s/%s", + mailer_name,mailer_prod,mailer_version,mailer_serial); + + while ((p=sel_brace(NULL))) + if (strcasecmp(p,"IDENT") == 0) { + p=sel_brace(NULL); + Syslog('+', "system : %s",(p=sel_bracket(p))); + sprintf(history.system_name, "%s", p); + history.system_name[36] = '\0'; + Syslog('+', "location: %s",(p=sel_bracket(NULL))); + sprintf(history.location, "%s", p); + Syslog('+', "operator: %s",(p=sel_bracket(NULL))); + sprintf(history.sysop, "%s", p); + if (remote && remote->addr) + remote->addr->name=xstrcpy(p); + Syslog('+', "phone : %s",sel_bracket(NULL)); + Syslog('+', "baud : %s",sel_bracket(NULL)); + Syslog('+', "flags : %s",sel_bracket(NULL)); + } else if (strcasecmp(p, "TZUTC") == 0) { + p = sel_brace(NULL); + p = sel_bracket(p); + if ((strlen(p) == 4) || (strlen(p) == 5)) + Syslog('+', "timezone: %s", p); + else + Syslog('+', "TZUTC : %s", p); + } else if (strcasecmp(p,"TRX#") == 0) { + time_t tt, now; + char ctt[32]; + + now = time(NULL); + p=sel_brace(NULL); + p=sel_bracket(p); + if (sscanf(p,"%08lx",&tt) == 1) { + strcpy(ctt,date(sl2mtime(tt))); + Syslog('+', "time : %s",ctt); + Syslog('+', "tranx : %08lX/%08lX [%ld]", now, sl2mtime(tt), now - sl2mtime(tt)); + } else + Syslog('+', "remote TRX#: %s",p); + } else if (strcasecmp(p, "TRAF") == 0) { + unsigned long tt, tt1; + + p = sel_brace(NULL); + if (sscanf(p, "%08lx %08lx", &tt, &tt1) == 2) { + Syslog('+', "netmail : %u byte(s)", tt); + Syslog('+', "echomail: %u byte(s)", tt1); + } else { + Syslog('+', "TRAF : %s", p); + } + } else if (strcasecmp(p, "MOH#") == 0) { + unsigned long tt; + + p = sel_brace(NULL); + p = sel_bracket(p); + if (sscanf(p, "%08lx", &tt) == 1) + Syslog('+', "on hold : %u byte(s)", tt); + else + Syslog('+', "MOH# : %s", p); + } else { + q=sel_brace(NULL); + Syslog('+', "extra : \"%s\" value: \"%s\"",p,q); + } + + return 0; +} + + diff --git a/mbcico/emsidat.h b/mbcico/emsidat.h new file mode 100644 index 00000000..9fa51132 --- /dev/null +++ b/mbcico/emsidat.h @@ -0,0 +1,10 @@ +#ifndef _EMSIDAT_H +#define _EMSIDAT_H + + +char *mkemsidat(int); +int scanemsidat(char *); + + +#endif + diff --git a/mbcico/filelist.c b/mbcico/filelist.c new file mode 100644 index 00000000..5ea40f7a --- /dev/null +++ b/mbcico/filelist.c @@ -0,0 +1,500 @@ +/***************************************************************************** + * + * File ..................: mbcico/filelist.c + * Purpose ...............: fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "config.h" +#include "session.h" +#include "filelist.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +extern int master; +int made_request; + + + +static char *tmpkname(void); +static char *tmpkname(void) +{ + static char buf[16]; + + sprintf(buf,"%08lx.pkt", sequencer()); + return buf; +} + + + +char *xtodos(char *orig) +{ + int i; + char buf[8+1+3+1],*copy,*p,*q,*r; + + if (orig == NULL) + return NULL; + + if ((remote_flags & SESSION_FNC) == 0) { + Syslog('o', "No filename conversion for \"%s\"",MBSE_SS(orig)); + return xstrcpy(orig); + } + + copy=xstrcpy(orig); + if ((p=strrchr(copy,'/'))) + p++; + else + p=copy; + + if (strcmp(q=copy+strlen(copy)-strlen(".tar.gz"),".tar.gz") == 0) { + *q='\0'; + q=(char *)"tgz"; + } else if (strcmp(q=copy+strlen(copy)-strlen(".tar.z"),".tar.z") == 0) { + *q='\0'; + q=(char *)"tgz"; + } else if (strcmp(q=copy+strlen(copy)-strlen(".tar.Z"),".tar.Z") == 0) { + *q='\0'; + q=(char *)"taz"; + } else if ((q=strrchr(p,'.'))) + *q++='\0'; + else + q=NULL; + + r=buf; + for (i=0;(i<8) && (*p);i++,p++,r++) + switch (*p) { + case '.': + case '\\': *r='_'; break; + default: *r=toupper(*p); + } + + if (q) { + *r++='.'; + for (i=0;(i<3) && (*q);i++,q++,r++) + switch (*q) { + case '.': + case '\\': *r='_'; break; + default: *r=toupper(*q); + } + } + *r++='\0'; + + Syslog('o', "name \"%s\" converted to \"%s\"",MBSE_SS(orig),MBSE_SS(buf)); + + free(copy); + return xstrcpy(buf); +} + + + +/* + * Add the specified entry to the list of files which should be sent + * to the remote system. + * 1. lst file list to add entry to + * 2. local local filename + * 3. remote remote filename + * 4. disposition disposition + * 5. floff offset of entry in flo-file (-1 if this is a flo file) + * 6. flofp FILE * of flo file + * 7. toend append to end of list + */ +void add_list(file_list **lst, char *local, char *Remote, int disposition, off_t floff, FILE *flofp, int toend) +{ + file_list **tmpl; + file_list *tmp; + + Syslog('o', "add_list(\"%s\",\"%s\",%d,%s)", MBSE_SS(local),MBSE_SS(Remote),disposition,toend?"to end":"to beg"); + + if (toend) + for (tmpl = lst; *tmpl; tmpl =&((*tmpl)->next)); + else + tmpl = &tmp; + *tmpl = (file_list*)malloc(sizeof(file_list)); + if (toend) { + (*tmpl)->next = NULL; + } else { + (*tmpl)->next = *lst; + *lst = *tmpl; + } + + (*tmpl)->remote = xtodos(Remote); + (*tmpl)->local = xstrcpy(local); + (*tmpl)->disposition = disposition; + (*tmpl)->floff = floff; + (*tmpl)->flofp = flofp; + return; +} + + + +static void check_flo(file_list **, char *); +static void check_flo(file_list **lst, char *nm) +{ + FILE *fp; + off_t off; + struct flock fl; + char buf[PATH_MAX],buf2[PATH_MAX],*p,*q; + int disposition; + struct stat stbuf; + + Syslog('O', "check_flo(\"%s\")",MBSE_SS(nm)); + + if ((fp = fopen(nm,"r+")) == NULL) { + Syslog('O',"no flo file"); + return; + } + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (fcntl(fileno(fp), F_SETLK, &fl) != 0) { + if (errno != EAGAIN) + WriteError("$cannot read-lock \"%s\"",MBSE_SS(nm)); + else + Syslog('O',"flo file busy"); + fclose(fp); + return; + } + + if (stat(nm, &stbuf) != 0) { + WriteError("$cannot access \"%s\"",MBSE_SS(nm)); + fclose(fp); + return; + } + + while (!feof(fp) && !ferror(fp)) { + off = ftell(fp); + if (fgets(buf, sizeof(buf)-1, fp) == NULL) + continue; + if (buf[0] == '~') + continue; /* skip sent files */ + if (*(p=buf + strlen(buf) -1) == '\n') + *p-- = '\0'; + if (*p == '\r') + *p = '\0'; + + switch (buf[0]) { + case '#': p=buf+1; disposition=TFS; break; + case '-': + case '^': p=buf+1; disposition=KFS; break; + case '@': p=buf+1; disposition=LEAVE; break; + case 0: continue; + default: p=buf; disposition=LEAVE; break; + } + + memset(&buf2, 0, sizeof(buf2)); + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy(buf2,uxoutbound); + for (p+=strlen(CFG.dospath), q=buf2+strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p=p, q=buf2+strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + + if ((q=strrchr(p,'/'))) + q++; + else + q = p; + add_list(lst, p, q, disposition, off, fp, 1); + } + + /* + * Add flo file to file list + */ + add_list(lst, nm, NULL, KFS, -1L, fp, 1); + + /* here, we leave .flo file open, it will be closed by */ + /* execute_disposition */ + + return; +} + + + +file_list *create_filelist(fa_list *al, char *fl, int create) +{ + file_list *st=NULL; + file_list *tmpf; + fa_list *tmpa; + char flavor, *tmpfl; + char *nm; + char tmpreq[13]; + struct stat stbuf; + int packets = 0; + FILE *fp; + unsigned char buffer[2]; + + Syslog('o', "Create_filelist(%s,\"%s\",%d)", al?ascfnode(al->addr,0x1f):"", MBSE_SS(fl), create); + made_request = 0; + + for (tmpa = al; tmpa; tmpa = tmpa->next) { + Syslog('o', "Check address %s", ascfnode(tmpa->addr, 0x1f)); + + /* + * Check spool files. + */ + if (strchr(fl, 'o')) { + nm=splname(tmpa->addr); + if ((fp=fopen(nm,"w"))) + fclose(fp); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) + add_list(&st,nm,NULL,DSF,0L,NULL,1); + } + + /* + * Check .pol files + */ + nm = polname(tmpa->addr); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) + add_list(&st,nm,NULL,DSF,0L,NULL,1); + + /* + * Check other files, all flavors + */ + tmpfl = fl; + while ((flavor = *tmpfl++)) { + /* + * Check normal mail packets + */ + nm=pktname(tmpa->addr,flavor); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) { + packets++; + add_list(&st,nm,tmpkname(),KFS,0L,NULL,1); + } + + /* + * Check .flo files for file attaches + */ + nm=floname(tmpa->addr,flavor); + check_flo(&st,nm); + } + + if ((session_flags & SESSION_WAZOO) && + ((session_flags & SESSION_HYDRA) == 0) && + (master || ((session_flags & SESSION_IFNA) == 0))) { + /* + * we don't distinguish flavoured reqs + */ + nm=reqname(tmpa->addr); + if ((nm != NULL) && (stat(nm,&stbuf) == 0)) { + sprintf(tmpreq,"%04X%04X.REQ", tmpa->addr->net,tmpa->addr->node); + add_list(&st,nm,tmpreq,DSF,0L,NULL,1); + made_request = 1; + } + } + } + + if (((st == NULL) && (create > 1)) || ((st != NULL) && (packets == 0) && (create > 0))) { + Syslog('o',"Create packet for %s",ascfnode(al->addr,0x1f)); + if ((fp = openpkt(NULL, al->addr, 'o'))) { + memset(&buffer, 0, sizeof(buffer)); + fwrite(buffer, 1, 2, fp); + fclose(fp); + } + add_list(&st,pktname(al->addr,'o'),tmpkname(),KFS,0L,NULL,0); + } + + for (tmpf = st; tmpf; tmpf = tmpf->next) + Syslog('O',"flist: \"%s\" -> \"%s\" dsp:%d flofp:%lu floff:%lu", + MBSE_SS(tmpf->local), MBSE_SS(tmpf->remote), tmpf->disposition, + (unsigned long)tmpf->flofp, (unsigned long)tmpf->floff); + + return st; +} + + + +/* + * Create file request list for the Hydra or Binkp protocol. + */ +file_list *create_freqlist(fa_list *al) +{ + file_list *st = NULL, *tmpf; + fa_list *tmpa; + char *nm; + char tmpreq[13]; + struct stat stbuf; + + Syslog('o', "create_freqlist(%s)", al?ascfnode(al->addr, 0x1f):""); + made_request = 0; + + for (tmpa = al; tmpa; tmpa = tmpa->next) { + nm = reqname(tmpa->addr); + if ((nm != NULL) && (stat(nm, &stbuf) == 0)) { + sprintf(tmpreq, "%04X%04X.REQ", tmpa->addr->net, tmpa->addr->node); + add_list(&st, nm, tmpreq, DSF, 0L, NULL, 1); + made_request = 1; + } + } + + for (tmpf = st; tmpf; tmpf = tmpf->next) + Syslog('O', "flist: \"%s\" -> \"%s\" dsp:%d flofp:%lu floff:%lu", + MBSE_SS(tmpf->local), MBSE_SS(tmpf->remote), tmpf->disposition, + tmpf->flofp, tmpf->floff); + + return st; +} + + + +void tidy_filelist(file_list *fl, int dsf) +{ + file_list *tmp; + + if (fl == NULL) + return; + + for (tmp=fl;fl;fl=tmp) { + tmp=fl->next; + if (dsf && (fl->disposition == DSF)) { + Syslog('o',"Removing sent file \"%s\"",MBSE_SS(fl->local)); + if (unlink(fl->local) != 0) { + if (errno == ENOENT) + Syslog('o',"Cannot unlink nonexistent file \"%s\"", MBSE_SS(fl->local)); + else + WriteError("$Cannot unlink file \"%s\"", MBSE_SS(fl->local)); + } + } + if (fl->local) + free(fl->local); + if (fl->remote) + free(fl->remote); + else if (fl->flofp) + fclose(fl->flofp); + free(fl); + } + return; +} + + + +void execute_disposition(file_list *fl) +{ + FILE *fp=NULL; + char *nm; + char tpl='~'; + + Syslog('o', "execute_disposition(%s)", fl->local); + nm = fl->local; + if (fl->flofp) { + /* + * Check for special case: flo-file + */ + if (fl->floff == -1) { + /* + * We check if there are any files left for transmission + * in the flo-file to decide whether to remove or leave + * it on disk. + */ + char buf[PATH_MAX]; + int files_remain = 0; + + if (fseek(fl->flofp, 0L, 0) == 0) { + while (!feof(fl->flofp) && !ferror(fl->flofp)) { + if (fgets(buf, sizeof(buf)-1, fl->flofp) == NULL) + continue; + + /* + * Count nr of files which haven't been + * sent yet + */ + if (buf[0] != '~') + files_remain++; + } + + } else { + WriteError("$Error seeking in .flo to 0"); + files_remain = -1; /* Keep flo-file */ + } + + if (files_remain) { + Syslog('o', "Leaving flo-file \"%s\", %d files remaining", MBSE_SS(nm), files_remain); + fl->disposition = LEAVE; + } else { + fl->disposition = KFS; + } + } else { + /* + * Mark files as sent in flo-file + */ + if (fseek(fl->flofp, fl->floff, 0) == 0) { + if (fwrite(&tpl,1,1,fl->flofp) != 1) { + WriteError("$Error writing '~' to .flo at %lu", (unsigned long)fl->floff); + } + fflush(fl->flofp); + fdatasync(fileno(fl->flofp)); + } else + WriteError("$error seeking in .flo to %lu", (unsigned long)fl->floff); + } + } + + switch (fl->disposition) { + case DSF: + case LEAVE: + break; + case TFS: + Syslog('o', "Truncating sent file \"%s\"",MBSE_SS(nm)); + if ((fp=fopen(nm,"w"))) + fclose(fp); + else + WriteError("$Cannot truncate file \"%s\"",MBSE_SS(nm)); + break; + case KFS: + Syslog('o', "Removing sent file \"%s\"",MBSE_SS(nm)); + if (unlink(nm) != 0) { + if (errno == ENOENT) + Syslog('o', "Cannot unlink nonexistent file \"%s\"", MBSE_SS(nm)); + else + WriteError("$Cannot unlink file \"%s\"", MBSE_SS(nm)); + } + break; + default: WriteError("execute_disposition: unknown disp %d for \"%s\"", + fl->disposition,MBSE_SS(nm)); + break; + } + + return; +} + + diff --git a/mbcico/filelist.h b/mbcico/filelist.h new file mode 100644 index 00000000..83afe41d --- /dev/null +++ b/mbcico/filelist.h @@ -0,0 +1,12 @@ +#ifndef _FILELIST_H +#define _FILELIST_H + +char *xtodos(char *); +void add_list(file_list **, char *, char *, int, off_t, FILE *, int); +file_list *create_filelist(fa_list *, char *, int); +file_list *create_freqlist(fa_list *); +void tidy_filelist(file_list *, int); +void execute_disposition(file_list *); + +#endif + diff --git a/mbcico/filetime.c b/mbcico/filetime.c new file mode 100644 index 00000000..e1385746 --- /dev/null +++ b/mbcico/filetime.c @@ -0,0 +1,121 @@ +/***************************************************************************** + * + * File ..................: mbcico/filetime.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "filetime.h" + + + +time_t gmtoff(time_t); +time_t gmtoff(time_t tt) +{ + struct tm lt; +#ifndef HAVE_TM_GMTOFF + struct tm gt; + time_t offset; + + lt = *localtime(&tt); + gt = *gmtime(&tt); + offset = gt.tm_yday - lt.tm_yday; + if (offset > 1) + offset =- 24; + else + if (offset < -1) + offset = 24; + else + offset *= 24; + + offset += gt.tm_hour - lt.tm_hour; + offset *= 60; + offset += gt.tm_min - lt.tm_min; + offset *= 60; + offset += gt.tm_sec - lt.tm_sec; + return offset; +#else + lt = *localtime(&tt); + return -lt.tm_gmtoff; +#endif +} + + + +/* + * SEAlink time conversion + * FIXME: I think there is one year difference, spec starts at 1 jan 1979, mtime starts at 1 jan 1980 + */ +time_t mtime2sl(time_t tt) +{ + return tt - gmtoff(tt); +} + + + +time_t sl2mtime(time_t tt) +{ + return tt + gmtoff(tt); +} + + + +/* + * Telink time conversion + */ +time_t mtime2tl(time_t tt) +{ + time_t tlt=0L; + struct tm *tm; + + tm=localtime(&tt); + tlt |= ((tm->tm_year)-1980) << 25; + tlt |= (tm->tm_mon) << 21; + tlt |= (tm->tm_mday) << 16; + tlt |= (tm->tm_hour) << 11; + tlt |= (tm->tm_min) << 5; + tlt |= (tm->tm_sec) >> 1; + return tlt; +} + + + +time_t tl2mtime(time_t tt) +{ + struct tm tm; + + tm.tm_year = ((tt >> 25) & 0x7f) + 1980; + tm.tm_mon = (tt >> 21) & 0x0f; + tm.tm_mday = (tt >> 16) & 0x1f; + tm.tm_hour = (tt >> 11) & 0x1f; + tm.tm_min = (tt >> 5 ) & 0x3f; + tm.tm_sec = ((tt ) & 0x1f) * 2; + + return mktime(&tm); +} + diff --git a/mbcico/filetime.h b/mbcico/filetime.h new file mode 100644 index 00000000..7e09c072 --- /dev/null +++ b/mbcico/filetime.h @@ -0,0 +1,11 @@ +#ifndef _FILETIME_H +#define _FILETIME_H + +time_t mtime2sl(time_t); +time_t sl2mtime(time_t); +time_t mtime2tl(time_t); +time_t tl2mtime(time_t); + + +#endif + diff --git a/mbcico/ftsc.c b/mbcico/ftsc.c new file mode 100644 index 00000000..caa74fc6 --- /dev/null +++ b/mbcico/ftsc.c @@ -0,0 +1,486 @@ +/***************************************************************************** + * + * File ..................: mbcico/ftsc.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "ftsc.h" +#include "rdoptions.h" +#include "recvbark.h" +#include "filelist.h" +#include "sendbark.h" +#include "respfreq.h" +#include "xmrecv.h" +#include "xmsend.h" + + + +extern int master; +extern int made_request; +static int rxftsc(void); +static int txftsc(void); +static int recvfiles(void); +static file_list *tosend; +extern int Loaded; + + +int rx_ftsc(void) +{ + int rc; + + Syslog('+', "Start inbound FTS-0001 session"); + IsDoing("FTS-0001 inbound"); + + session_flags |= SESSION_BARK; + if ((rc = rxftsc())) { + WriteError("Session failed: rc=%d",rc); + PUTCHAR(CAN); + PUTCHAR(CAN); + PUTCHAR(CAN); + } else + Syslog('+', "FTS-0001 session completed"); + + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + return rc; +} + + + + +int tx_ftsc(void) +{ + int rc; + + Syslog('+', "Start outbound FTS-0001 session with %s", ascfnode(remote->addr,0x1f)); + IsDoing("FTS-0001 to %s", ascfnode(remote->addr, 0x0f)); + + if ((rc = txftsc())) { + WriteError("Session failed: rc=%d",rc); + PUTCHAR(CAN); + PUTCHAR(CAN); + PUTCHAR(CAN); + } else + Syslog('+', "FTS-0001 session completed"); + + tidy_filelist(tosend, (rc == 0)); + tosend = NULL; + return rc; +} + + + +SM_DECL(txftsc,(char *)"txftsc") +SM_STATES + wait_command, + recv_mail, + send_req, + recv_req +SM_NAMES + (char *)"wait_command", + (char *)"recv_mail", + (char *)"send_req", + (char *)"recv_req" +SM_EDECL + int c,rc; + char *nonhold_mail; + int mailsent = FALSE, mailrcvd = FALSE; + + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + tosend = create_filelist(remote,nonhold_mail,2); + + Syslog('s', "txftsc SEND_MAIL"); + if ((rc = xmsndfiles(tosend))) + return rc; + mailsent = TRUE; + +SM_START(wait_command) + +SM_STATE(wait_command) + + Syslog('s', "txftsc WAIT_COMMAND"); + c = GETCHAR(30); + if (c == TIMEOUT) { + Syslog('+', "timeout waiting for remote action, try receive"); + SM_PROCEED(recv_mail); + } else if (c < 0) { + if (mailrcvd && mailsent) { + /* + * Some systems hangup after sending mail, so if we did + * send and receive mail we consider the session OK. + */ + Syslog('+', "Lost carrier, FTSC session looks complete"); + SM_SUCCESS; + } else { + Syslog('+', "got error waiting for TSYNC: received %d",c); + SM_ERROR; + } + } else switch (c) { + case TSYNC: SM_PROCEED(recv_mail); + break; + case SYN: SM_PROCEED(recv_req); + break; + case ENQ: SM_PROCEED(send_req); + break; + case 'C': + case NAK: PUTCHAR(EOT); + SM_PROCEED(wait_command); + break; + case CAN: SM_SUCCESS; /* this is not in BT */ + break; + default: Syslog('s', "got '%s' waiting command", printablec(c)); + PUTCHAR(SUB); + SM_PROCEED(wait_command); + break; + } + +SM_STATE(recv_mail) + + Syslog('s', "txftsc RECV_MAIL"); + if (recvfiles()) { + SM_ERROR; + } else { + mailrcvd = TRUE; + SM_PROCEED(wait_command); + } + +SM_STATE(send_req) + + Syslog('s', "txftsc SEND_BARK"); + if (sendbark()) { + SM_ERROR; + } else { + SM_SUCCESS; + } + +SM_STATE(recv_req) + + Syslog('s', "txftsc RECV_BARK"); + if (recvbark()) { + SM_ERROR; + } else { + SM_PROCEED(wait_command); + } + +SM_END +SM_RETURN + + + +SM_DECL(rxftsc,(char *)"rxftsc") +SM_STATES + recv_mail, + send_mail, + send_req, + recv_req +SM_NAMES + (char *)"recv_mail", + (char *)"send_mail", + (char *)"send_req", + (char *)"recv_req" +SM_EDECL + int c, count = 0, didwazoo = FALSE; + int sentmail = FALSE, rcvdmail = FALSE; + file_list *request = NULL, *tmpfl; + +SM_START(recv_mail) + +SM_STATE(recv_mail) + + Syslog('s', "rxftsc RECV_MAIL"); + if (recvfiles()) { + SM_ERROR; + } else { + rcvdmail = TRUE; + SM_PROCEED(send_mail); + } + +SM_STATE(send_mail) + + Syslog('s', "rxftsc SEND_MAIL count=%d", count); + if (count++ > 45) { + SM_ERROR; + } + + /* + * If we got a wazoo request, add files now. + */ + request = respond_wazoo(); + if (request != NULL) { + didwazoo = TRUE; + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + if (tosend == NULL) { + count = 0; + SM_PROCEED(send_req); + } + + PUTCHAR(TSYNC); + c = GETCHAR(1); + Syslog('x', "Got char 0x%02x", c); + if (c == TIMEOUT) { + Syslog('x', " timeout"); + SM_PROCEED(send_mail); + } else if (c < 0) { + Syslog('+', "got error waiting for NAK: received %d",c); + SM_ERROR; + } else switch (c) { + case 'C': + case NAK: if (xmsndfiles(tosend)) { + SM_ERROR; + } else { + sentmail = TRUE; + count = 0; + SM_PROCEED(send_req); + } + break; + case CAN: Syslog('+', "Remote refused to pickup mail"); + SM_SUCCESS; + break; + case EOT: PUTCHAR(ACK); + SM_PROCEED(send_mail); + break; + default: Syslog('s', "Got '%s' waiting NAK", printablec(c)); + SM_PROCEED(send_mail); + break; + } + +SM_STATE(send_req) + + Syslog('s', "rxftsc SEND_REQ count=%d", count); + + if (didwazoo) { + SM_SUCCESS; + } + + if (count > 15) { + SM_ERROR; + } + + if (!made_request) { + SM_PROCEED(recv_req); + } + + PUTCHAR(SYN); + c = GETCHAR(5); + Syslog('x', "Got char 0x%02x", c); + count++; + if (c == TIMEOUT) { + Syslog('x', " timeout"); + SM_PROCEED(send_req); + } else if (c < 0) { + Syslog('+', "got error waiting for ENQ: received %d",c); + SM_ERROR; + } else switch (c) { + case ENQ: if (sendbark()) { + SM_ERROR; + } else { + SM_PROCEED(recv_req); + } + break; + case CAN: Syslog('+', "Remote refused to accept request"); + SM_PROCEED(recv_req); + break; + case 'C': + case NAK: PUTCHAR(EOT); + SM_PROCEED(send_req); + break; + case SUB: SM_PROCEED(send_req); + break; + default: Syslog('s', "got '%s' waiting ENQ", printablec(c)); + SM_PROCEED(send_req); + break; + } + +SM_STATE(recv_req) + + Syslog('s', "rxftsc RECV_REQ"); + if (recvbark()) { + if (sentmail && rcvdmail) { + Syslog('+', "Consider session OK"); + SM_SUCCESS; + } else { + SM_ERROR; + } + } else { + SM_SUCCESS; + } + +SM_END +SM_RETURN + + + +SM_DECL(recvfiles,(char *)"recvfiles") +SM_STATES + recv_packet, + scan_packet, + recv_file +SM_NAMES + (char *)"recv_packet", + (char *)"scan_packet", + (char *)"recv_file" +SM_EDECL + int rc=0; + char recvpktname[16]; + char *fpath; + FILE *fp; + faddr f,t; + fa_list **tmpl; + +SM_START(recv_packet) + Loaded = FALSE; + +SM_STATE(recv_packet) + + sprintf(recvpktname,"%08lx.pkt",(unsigned long)sequencer()); + if ((rc = xmrecv(recvpktname)) == 1) { + SM_SUCCESS; + } else if (rc == 0) { + if (master) { + SM_PROCEED(recv_file); + } else { + SM_PROCEED(scan_packet); + } + } else { + SM_ERROR; + } + +SM_STATE(scan_packet) + + fpath = xstrcpy(inbound); + fpath = xstrcat(fpath,(char *)"/"); + fpath = xstrcat(fpath,recvpktname); + fp = fopen(fpath,"r"); + free(fpath); + if (fp == NULL) { + WriteError("$cannot open received packet"); + SM_ERROR; + } + switch (getheader(&f , &t, fp, recvpktname)) { + case 3: Syslog('+', "remote mistook us for %s",ascfnode(&t,0x1f)); + fclose(fp); + SM_ERROR; + case 0: Syslog('+', "accepting session"); + fclose(fp); + for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next)); + (*tmpl)=(fa_list*)malloc(sizeof(fa_list)); + (*tmpl)->next=NULL; + (*tmpl)->addr=(faddr*)malloc(sizeof(faddr)); + (*tmpl)->addr->zone=f.zone; + (*tmpl)->addr->net=f.net; + (*tmpl)->addr->node=f.node; + (*tmpl)->addr->point=f.point; + (*tmpl)->addr->name=NULL; + (*tmpl)->addr->domain=NULL; + for (tmpl=&remote;*tmpl;tmpl=&((*tmpl)->next)) { + (void)nodelock((*tmpl)->addr); + /* try lock all remotes, ignore locking result */ + if (!Loaded) + if (noderecord((*tmpl)->addr)) + Loaded = TRUE; + } + + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + if (remote->addr->domain && strlen(remote->addr->domain)) + sprintf(history.aka.domain, "%s", remote->addr->domain); + + if (((nlent=getnlent(remote->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + sprintf(history.system_name, "%s", nlent->name); + sprintf(history.location, "%s", nlent->location); + } else { + sprintf(history.system_name, "Unknown"); + sprintf(history.location, "Somewhere"); + } + + if (nlent) + rdoptions(Loaded); + + /* + * It appears that if the remote gave no password, the + * getheader function fills in a password itself. Maybe + * that's the reason why E.C did not switch to protected + * inbound, because of the failing password check. MB. + */ + if (f.name) { + Syslog('+', "Password correct, protected FTS-0001 session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + } + + tosend = create_filelist(remote,(char *)ALL_MAIL,1); + if (rc == 0) { + SM_PROCEED(recv_file); + } else { + SM_SUCCESS; + } + default: Syslog('+', "received bad packet apparently from",ascfnode(&f,0x1f)); + fclose(fp); + SM_ERROR; + } + +SM_STATE(recv_file) + + switch (xmrecv(NULL)) { + case 0: SM_PROCEED(recv_file); + break; + case 1: SM_SUCCESS; + break; + default: SM_ERROR; + break; + } + +SM_END +SM_RETURN + diff --git a/mbcico/ftsc.h b/mbcico/ftsc.h new file mode 100644 index 00000000..ddad502c --- /dev/null +++ b/mbcico/ftsc.h @@ -0,0 +1,10 @@ +#ifndef _FTSC_H +#define _FTSC_H + + +int rx_ftsc(void); +int tx_ftsc(void); + + +#endif + diff --git a/mbcico/hydra.c b/mbcico/hydra.c new file mode 100644 index 00000000..e4046007 --- /dev/null +++ b/mbcico/hydra.c @@ -0,0 +1,1690 @@ +/***************************************************************************** + * + * File ..................: mbcico/hydra.c + * Purpose ...............: Fidonet mailer + * Last modification date : 30-Dec-2000 + * Remark ................: See below for more copyright details and credits. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * ifcico v3.0.cm - hydra protocol module + * Copyright (C) 1996-98 Christof Meerwald. + * + * $RCSfile$ - $Author$ + * $Revision$ - $Date$ + */ + +/* + * The HYDRA protocol was designed by + * Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and + * Joaquim H. Homrighausen + * COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "filelist.h" +#include "filetime.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "lutil.h" +#include "respfreq.h" +#include "mbcico.h" +#include "hydra.h" + + + +#define H_RXWINDOW 0L +#define H_TXWINDOW 0L + + + +static int put_binbyte(char *outbuf, char c); +static int put_hexbyte(char *outbuf, char c); +static enum HyPktTypes hyrxpkt(char *rxbuf, int *rxlen, int tot); +static void hytxpkt(enum HyPktTypes pkttype, char *txbuf, int txlen); +static int put_flags(char *buf, unsigned long Flags); +static unsigned long get_flags(char *buf); +static int resync(off_t off); +static int hydra_batch(int role, file_list *to_send); + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; + + + +static struct h_flags_struct { + char *str; + unsigned long val; +} h_flags[] = + { + { (char *)"XON", HOPT_XONXOFF }, + { (char *)"TLN", HOPT_TELENET }, + { (char *)"CTL", HOPT_CTLCHRS }, + { (char *)"HIC", HOPT_HIGHCTL }, + { (char *)"HI8", HOPT_HIGHBIT }, + { (char *)"BRK", HOPT_CANBRK }, + { (char *)"ASC", HOPT_CANASC }, + { (char *)"UUE", HOPT_CANUUE }, + { (char *)"C32", HOPT_CRC32 }, + { (char *)"DEV", HOPT_DEVICE }, + { (char *)"FPT", HOPT_FPT }, + { NULL , 0x0L } +}; + +static int txoptions, rxoptions; + + +static char *put_long(char *buffer, long val) +{ +#if defined(__i386__) + *(unsigned long *) buffer = (unsigned long) val; +#else + buffer[0] = (unsigned long) val & 0xff; + buffer[1] = ((unsigned long) val >> 8) & 0xff; + buffer[2] = ((unsigned long) val >> 16) & 0xff; + buffer[3] = ((unsigned long) val >> 24) & 0xff; +#endif + + return buffer; +} + + + +static long get_long(char *buffer) +{ +#if defined(__i386__) + return *(long *) buffer; +#else + return ((unsigned long) ((unsigned char) buffer[0])) | + ((unsigned long) ((unsigned char) buffer[1]) << 8) | + ((unsigned long) ((unsigned char) buffer[2]) << 16) | + ((unsigned long) ((unsigned char) buffer[3]) << 24); +#endif +} + + + +char *PktS(int); +char *PktS(int c) +{ + switch (c) { + case 'A' : return (char *)"START"; + case 'B' : return (char *)"INIT"; + case 'C' : return (char *)"INITACK"; + case 'D' : return (char *)"FINFO"; + case 'E' : return (char *)"FINFOACK"; + case 'F' : return (char *)"DATA"; + case 'G' : return (char *)"DATAACK"; + case 'H' : return (char *)"RPOS"; + case 'I' : return (char *)"EOF"; + case 'J' : return (char *)"EOFACK"; + case 'K' : return (char *)"END"; + case 'L' : return (char *)"IDLE"; + case 'M' : return (char *)"DEVDATA"; + case 'N' : return (char *)"DEVDACK"; + case 'a' : return (char *)"PKTEND"; + case 'b' : return (char *)"BINPKT"; + case 'c' : return (char *)"HEXPKT"; + case 'd' : return (char *)"ASCPKT"; + case 'e' : return (char *)"UUEPKT"; + default: break; + } + return (char *)""; +} + + + +int put_binbyte(char *outbuf, char c) +{ + static int lastc = -1; + register int count = 0; + register char n; + + + n = c; + if (txoptions & HOPT_HIGHCTL) { + n &= 0x7f; + } + + if ((n == H_DLE) + || ((txoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((txoptions & HOPT_TELENET) && (n == '\r') && (lastc == '@')) + || ((txoptions & HOPT_CTLCHRS) && ((n < 32) || (n == 127)))) { + *outbuf++ = H_DLE; + c ^= 0x40; + count++; + } + + *outbuf++ = c; + lastc = n; + + return count + 1; +} + + + +int put_hexbyte(char *outbuf, char c) +{ + static const char hexdigit[] = "0123456789abcdef"; + register int count = 0; + + if (c & 0x80) { + *outbuf++ = '\\'; + *outbuf++ = hexdigit[(c >> 4) & 0x0f]; + *outbuf++ = hexdigit[c & 0x0f]; + count = 3; + } else if ((c < 32) || (c == 127)) { + *outbuf++ = H_DLE; + *outbuf++ = c ^ 0x40; + count = 2; + } else if (c == '\\') { + *outbuf++ = '\\'; + *outbuf++ = '\\'; + count = 2; + } else { + *outbuf++ = c; + count = 1; + } + + return count; +} + + + +/* TODO: code cleanup */ +/* TODO: error handling */ +enum HyPktTypes hyrxpkt(char *rxbuf, int *rxlen, int tot) +{ + static char rxencbuf[H_BUFLEN]; + static enum HyPktTypes pkttype = H_NOPKT; + static char *inbuf = rxencbuf, *outbuf; + int c, i, n; + static int rxdle = 0; + static enum HyPktFormats format; + + while ((c = GETCHAR(tot)) >= 0) { + if (rxoptions & HOPT_HIGHBIT) + c &= 0x7f; + + n = c; + if (rxoptions & HOPT_HIGHCTL) + n &= 0x7f; + + if ((n != H_DLE) + && (((rxoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((rxoptions & HOPT_CTLCHRS) && ((n < 32) || (n == 127))))) + continue; + + + if ((rxdle) || (c == H_DLE)) { + switch (c) { + case H_DLE: + rxdle++; + if (rxdle >= 5) { + inbuf = rxencbuf; + return H_CANCEL; + } + break; + + case HCHR_PKTEND: + switch (format) { + case HCHR_BINPKT: + *rxlen = inbuf - rxencbuf; + memcpy(rxbuf, rxencbuf, *rxlen); + break; + + case HCHR_HEXPKT: + outbuf = rxencbuf; + *rxlen = 0; + + while (outbuf < inbuf) { + if ((*outbuf == '\\') && (*++outbuf != '\\')) { + i = *outbuf++; + n = *outbuf++; + + if ((i -= '0') > 9) + i -= ('a' - ':'); + if ((n -= '0') > 9) + n -= ('a' - ':'); + + if ((i & ~0x0f) || (n & ~ 0x0f)) { + Syslog('+', "Hydra: RXPKT assert"); + die(1); + break; + } + + rxbuf[*rxlen] = (i << 4) | n; + *rxlen += 1; + } else { + rxbuf[*rxlen] = *outbuf++; + *rxlen += 1; + } + } + break; + + case HCHR_ASCPKT: + case HCHR_UUEPKT: + default: + Syslog('+', "Hydra: RXPKT assert"); + die(1); + } + + if ((format != HCHR_HEXPKT) && (rxoptions & HOPT_CRC32)) { + n = h_crc32test(crc32ccitt(rxbuf, *rxlen)); + *rxlen -= 4; /* remove CRC-32 */ + } else { + n = h_crc16test(crc16ccitt(rxbuf, *rxlen)); + *rxlen -= 2; /* remove CRC-16 */ + } + + *rxlen -= 1; /* remove packet type */ + pkttype = rxbuf[*rxlen]; + + /* check if CRC test succeeded */ + if (n) { + inbuf = rxencbuf; + Syslog('h', "Hydra: RXPKT rcvd %s", PktS(pkttype)); + return pkttype; + } else { + Syslog('+', "Hydra: RXPKT CRC test failed"); + } + break; + + case HCHR_BINPKT: + case HCHR_HEXPKT: + case HCHR_ASCPKT: + case HCHR_UUEPKT: + format = c; + inbuf = rxencbuf; + rxdle = 0; + break; + + default: + *inbuf++ = c ^ 0x40; + rxdle = 0; + break; + } + } else { + *inbuf++ = c; + } + } + + Syslog('h', "GETCHAR returned %i", c); + + if ((c == TERROR) || (c == EOFILE) || (c == HANGUP)) { + return H_CARRIER; + } + + return H_NOPKT; +} + + + +/* TODO: support packet prefix string */ +void hytxpkt(enum HyPktTypes pkttype, char *txbuf, int txlen) +{ + static char txencbuf[H_BUFLEN]; + char *outbuf, *inbuf; + enum HyPktFormats format; + + if (pkttype == 'G') + Syslog('h', "ACK 0x%02x%02x%02x%02x", txbuf[0], txbuf[1], txbuf[2], txbuf[3]); + + /* + * some packets have to be transferred in HEX mode + */ + if ((pkttype == HPKT_START) || (pkttype == HPKT_INIT) || + (pkttype == HPKT_INITACK) || (pkttype == HPKT_END) || + (pkttype == HPKT_IDLE)) { + format = HCHR_HEXPKT; + } else { + /* do we need to strip high bit */ + if (txoptions & HOPT_HIGHBIT) { + if ((txoptions & HOPT_CTLCHRS) && (txoptions & HOPT_CANUUE)) { + format = HCHR_UUEPKT; /* use UUE packet encoding */ + } else if (txoptions & HOPT_CANASC) { + format = HCHR_ASCPKT; /* we can use ASCII packet encoding */ + } else { + format = HCHR_HEXPKT; /* fall back to hex packet encoding */ + } + } else { + format = HCHR_BINPKT; /* we can use binary packet encoding */ + } + } + + /* + * Append format byte to data + */ + txbuf[txlen] = pkttype; + txlen++; + + /* + * check if we can use 32-bit CRC's + */ + if ((format != HCHR_HEXPKT) && (txoptions & HOPT_CRC32)) { + unsigned long crc; + + /* + * Calc CRC-32 of data + pkttype + */ + crc = ~crc32ccitt(txbuf, txlen); + + /* + * Append one's complement of CRC to data, lowbyte first + */ + txbuf[txlen++] = crc; + txbuf[txlen++] = crc >> 8; + txbuf[txlen++] = crc >> 16; + txbuf[txlen++] = crc >> 24; + } else { + unsigned short crc; + + /* + * Calc CRC-16 of data + pkttype + */ + crc = ~crc16ccitt(txbuf, txlen); + + /* + * Append one's complement of CRC to data, lowbyte first + */ + txbuf[txlen++] = crc; + txbuf[txlen++] = crc >> 8; + } + + inbuf = txbuf; + + outbuf = txencbuf; + *outbuf++ = H_DLE; + *outbuf++ = format; + + /* encode packet data */ + switch (format) { + case HCHR_BINPKT: + while (txlen > 0) { + outbuf += put_binbyte(outbuf, *inbuf); + inbuf++; + txlen--; + } + break; + + case HCHR_HEXPKT: + while (txlen > 0) { + outbuf += put_hexbyte(outbuf, *inbuf); + inbuf++; + txlen--; + } + break; + + /* ASCII and UUE packets are not yet supported */ + case HCHR_ASCPKT: + case HCHR_UUEPKT: + default: + Syslog('+', "Hydra: TXPKT assert"); + die(1); + } + + *outbuf++ = H_DLE; + *outbuf++ = HCHR_PKTEND; + + if ((pkttype != HPKT_DATA) && (format != HCHR_BINPKT)) { + *outbuf++ = '\r'; + *outbuf++ = '\n'; + } + + Syslog('h', "Hydra: TXPKT send %s", PktS(pkttype)); + PUT(txencbuf, outbuf - txencbuf); + + return; +} + + + +int put_flags(char *buf, unsigned long Flags) +{ + int i, count = 0; + + for (i = 0; h_flags[i].val; i++) { + if (Flags & h_flags[i].val) { + if (count > 0) { + *buf++ = ','; + count++; + } + + strcpy(buf, h_flags[i].str); + buf += H_FLAGLEN; + count += H_FLAGLEN; + } + } + + *buf = 0; + return count; +} + + + +unsigned long get_flags(char *buf) +{ + unsigned long Flags = 0L; + char *p; + int i; + + + for (p = strtok(buf, ","); p != NULL; p = strtok(NULL, ",")) { + for (i = 0; h_flags[i].val; i++) { + if (!strcmp(p, h_flags[i].str)) { + Flags |= h_flags[i].val; + break; + } + } + } + + return Flags; +} + + + +int resync(off_t off) +{ + return 0; +} + + + +int hydra_batch(int role, file_list *to_send) +{ + static char txbuf[H_BUFLEN], rxbuf[H_BUFLEN]; + struct stat txstat; /* file stat being transmitted */ + FILE *txfp = NULL; /* file currently being transmitted */ + FILE *rxfp = NULL; /* file currently being received */ + char *inbuf, *outbuf; + int rxlen, txlen; /* length of receive/transmit buffer */ + long txwindow, rxwindow; /* window sizes */ + long txpos, rxpos; /* file positions */ + long stxpos, srxpos; + long longnum; + int hdxlink = FALSE; + int txretries, rxretries; + int txlastack, txsyncid; + int rxlastsync, rxsyncid; + int rxlastdatalen; + int blksize; + int goodbytes; + int goodneeded; + enum HyTxStates txstate; + enum HyRxStates rxstate; + int txwaitpkt, rxwaitpkt; + enum HyPktTypes pkttype; + int waitputget = 0; + time_t rxstarttime, rxendtime; + time_t txstarttime, txendtime; + int sverr; + + Syslog('h', "Hydra: resettimers"); + RESETTIMERS(); + + txpos = rxpos = 0; + stxpos = srxpos = 0; + txretries = rxretries = 0; + txlastack = txsyncid = 0; + rxlastsync = rxsyncid = 0; + rxlastdatalen = 0; + blksize = 512; + goodbytes = 0; + goodneeded = 1024; + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_START; + txoptions = HTXI_OPTIONS; + + rxstate = HRX_INIT; + rxoptions = HRXI_OPTIONS; + + while ((txstate != HTX_DONE) && (txstate != HTX_Abort)) { + /* + * Is transmitter waiting for packet? + */ + txwaitpkt = ((txstate == HTX_SWAIT) || (txstate == HTX_INITACK) + || ((txstate == HTX_RINIT) && (rxstate == HRX_INIT)) + || (txstate == HTX_FINFOACK) || (txstate == HTX_DATA) + || (txstate == HTX_DATAACK) + || ((txstate == HTX_XWAIT) && (rxstate != HRX_DONE)) + || (txstate == HTX_EOFACK) || (txstate == HTX_ENDACK) + || (txstate == HTX_REND)); + + /* + * Is receiver waiting for packet? + */ + rxwaitpkt = ((rxstate == HRX_INIT) || (rxstate == HRX_FINFO) || + (rxstate == HRX_DATA) || (rxstate == HRX_DONE)); + + /* + * Do we have to wait for a packet? + */ + if (txwaitpkt && rxwaitpkt) { + /* + * Don't wait for a packet if transmitter is in DATA state + */ + if ((txstate == HTX_DATA) || ((txstate == HTX_REND) && (rxstate == HRX_DONE))) { + if (txstate == HTX_DATA) { + waitputget = WAITPUTGET(-1); + if (waitputget & 1) { + pkttype = hyrxpkt(rxbuf, &rxlen, 0); + } else { + pkttype = H_NOPKT; + } + } else { + pkttype = hyrxpkt(rxbuf, &rxlen, 0); + } + } else { + pkttype = hyrxpkt(rxbuf, &rxlen, -1); + } + + if ((pkttype == H_CARRIER) || (EXPIRED(TIMERNO_BRAIN))) { + Syslog('h', "Hydra: BRAIN timer expired"); + txstate = HTX_Abort; + break; + } + } else { + pkttype = H_NOPKT; + } + + /* + * Special handling for RPOS packet + */ + if ((pkttype == HPKT_RPOS) && (rxlen == 12) + && ((txstate == HTX_DATA) || (txstate == HTX_DATAACK) + || (txstate == HTX_XWAIT) || (txstate == HTX_EOFACK))) { + long rpos_pos = get_long(rxbuf); + long rpos_blksize = get_long(rxbuf + 4); + long rpos_id = get_long(rxbuf + 8); + + if (rpos_pos < 0) { + /* + * this differs from the protocol definition: txpos is used + * instead of rxpos (I think it's wrong in the protocol + * definition as in the example source also txpos is used) + */ + if ((rpos_pos == -2) && (txpos != -2) && (txstate == HTX_EOFACK)) { + txpos = -2; + txstate = HTX_EOF; + } else { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_SkipFile; + } + } + + if (rpos_id == txsyncid) { + txretries++; + + if (txretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + break; + } + } else { + if (rpos_pos >= 0) { + txpos = rpos_pos; + txsyncid = rpos_id; + txretries = 1; + blksize = rpos_blksize; + goodbytes = 0; + goodneeded += 1024; + if (goodneeded > 8192) + goodneeded = 8192; + + /* if we receive an RPOS packet in EOFACK-state we have to + change back to DATA-state */ + if (txstate == HTX_EOFACK) + txstate = HTX_DATA; + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + } + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } + + + switch (txstate) { + /* + * initiate Hydra session + */ + case HTX_START: + Syslog('h', "SM 'HTX' entering 'START'"); + if (txretries < 10) { + PUT((char *)"hydra\r", 6); /* send AutoStart string */ + hytxpkt(HPKT_START, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_START); + SETTIMER(TIMERNO_TX, H_START); + txstate = HTX_SWAIT; + } else { + Syslog('+', "Hydra: transmitter start TIMEOUT"); + txstate = HTX_Abort; + break; + } + break; + + /* + * wait for START packet + */ + case HTX_SWAIT: + Syslog('h', "SM 'HTX' entering 'SWAIT'"); + if (((pkttype == HPKT_START) && (rxlen == 0)) || (pkttype == HPKT_INIT)) { + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_INIT; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_SWAIT)"); + txretries++; + txstate = HTX_START; + } + break; + + /* + * send INIT packet + */ + case HTX_INIT: + Syslog('h', "SM 'HTX' entering 'INIT'"); + if (txretries < 10) { + outbuf = txbuf; + + /* Application ID string */ + outbuf += sprintf(outbuf, "%08lx%s,%s", H_REVSTAMP, "mbcico", VERSION) + 1; + + /* Supported options */ + outbuf += put_flags(outbuf, HCAN_OPTIONS) + 1; + Syslog('h', "Hydra: supported options: %08lx", HCAN_OPTIONS); + + /* Desired options */ + outbuf += put_flags(outbuf, HDEF_OPTIONS & HCAN_OPTIONS & ~HUNN_OPTIONS) + 1; + Syslog('h', "Hydra: desired options : %08lx", HDEF_OPTIONS & HCAN_OPTIONS & ~HUNN_OPTIONS); + + /* Desired transmitter and receiver window size */ + outbuf += sprintf(outbuf, "%08lx%08lx", H_TXWINDOW, H_RXWINDOW) + 1; + + /* Packet prefix string */ + *outbuf++ = 0; + + hytxpkt(HPKT_INIT, txbuf, outbuf - txbuf); + + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + txstate = HTX_INITACK; + } else { + Syslog('+', "Hydra: too many errors waiting for INITACK"); + txstate = HTX_Abort; + break; + } + break; + + /* + * wait for an INIT acknowledge packet + */ + case HTX_INITACK: + Syslog('h', "SM 'HTX' entering 'INITACK'"); + if ((pkttype == HPKT_INITACK) && (rxlen == 0)) { + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + txstate = HTX_RINIT; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: tx timeout"); + txretries++; + txstate = HTX_INIT; + } + break; + + /* + * wait for receiver to leave INIT state + */ + case HTX_RINIT: + Syslog('h', "SM 'HTX' entering 'RINIT'"); + if (rxstate != HRX_INIT) + txstate = HTX_NextFile; + break; + + /* + * prepare next file for transmitting + */ + case HTX_NextFile: + Syslog('h', "SM 'HTX' entering 'NextFile'"); + /* + * skip file with NULL remote name + */ + while (to_send && (to_send->remote == NULL)) { + execute_disposition(to_send); + to_send = to_send->next; + } + + if (to_send) { + struct flock txflock; + + if (to_send->remote == NULL) + break; + + txflock.l_type=F_RDLCK; + txflock.l_whence=0; + txflock.l_start=0L; + txflock.l_len=0L; + + txfp = fopen(to_send->local, "r"); + if (txfp == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(to_send->local)); + execute_disposition(to_send); // Added 18-10-99 MB. + } else { + WriteError("$Hydra: cannot open file %s, skipping", MBSE_SS(to_send->local)); + } + to_send = to_send->next; + break; + } + + if (fcntl(fileno(txfp), F_SETLK, &txflock) != 0) { + WriteError("$Hydra: cannot lock file %s, skipping", MBSE_SS(to_send->local)); + fclose(txfp); + to_send = to_send->next; + break; + } + + if (stat(to_send->local, &txstat) != 0) { + WriteError("$Hydra: cannot access \"%s\", skipping",MBSE_SS(to_send->local)); + fclose(txfp); + to_send = to_send->next; + break; + } + + Syslog('+', "Hydra: send \"%s\" as \"%s\"", MBSE_SS(to_send->local), MBSE_SS(to_send->remote)); + Syslog('+', "Hydra: size %lu bytes, dated %s",(unsigned long)txstat.st_size, date(txstat.st_mtime)); + (void) time(&txstarttime); + } + + txstate = HTX_ToFName; + break; /* TODO: fallthrough */ + + case HTX_ToFName: + Syslog('h', "SM 'HTX' entering 'ToFName'"); + txsyncid = 0; + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_FINFO; + break; /* TODO: fallthrough */ + + /* + * transmit File Information packet + */ + case HTX_FINFO: + Syslog('h', "SM 'HTX' entering 'FINFO'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + if (to_send) { + txlen = sprintf(txbuf, "%08lx%08lx%08lx%08lx%08lx", + mtime2sl(txstat.st_mtime+(txstat.st_mtime%2)), + txstat.st_size, 0UL, 0UL, 0UL); + + /* + * convert file name to DOS-format + */ + outbuf = xtodos(to_send->remote); + strcpy(txbuf + txlen, outbuf); + free(outbuf); + for(; txbuf[txlen]; txlen++) { + txbuf[txlen] = tolower(txbuf[txlen]); + } + txlen++; + + strcpy(txbuf + txlen, to_send->remote); + txlen += strlen(to_send->remote) + 1; + } else { + txbuf[0] = 0; + txlen = 1; + } + + hytxpkt(HPKT_FINFO, txbuf, txlen); + + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + + txstate = HTX_FINFOACK; + } + break; + + /* + * get FINFOACK packet + */ + case HTX_FINFOACK: + Syslog('h', "SM 'HTX' entering 'FINFOACK'"); + if ((pkttype == HPKT_FINFOACK) && (rxlen == 4)) { + txpos = get_long(rxbuf); + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + if (to_send == NULL) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + txstate = HTX_REND; + } else if (txpos >= 0L) { + if (txpos > 0L) + Syslog('+', "Hydra: restart from %lu", txpos); + stxpos = txpos; + txretries = 0; + txlastack = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + } else if (txpos == -1) { + Syslog('+', "Hydra: Receiver already has this file, skipping"); + fclose(txfp); + execute_disposition(to_send); + to_send = to_send->next; + txstate = HTX_NextFile; + } else if (txpos == -2) { + Syslog('+', "Hydra: receiver requested to skip this file for now"); + fclose(txfp); + to_send = to_send->next; + txstate = HTX_NextFile; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_FINFOACK)"); + txretries++; + txstate = HTX_FINFO; + } + break; + + case HTX_DATA: + Syslog('h', "SM 'HTX' entering 'DATA'"); + Syslog('h', "txwindow=%d txpos=%d txlastack=%d", txwindow, txpos, txlastack); + if ((rxstate != HRX_DONE) && (hdxlink)) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + txstate = HTX_XWAIT; + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + Syslog('h', "received 'DATAACK' (0x%08lx)", longnum); + + if (longnum > txlastack) { + txlastack = longnum; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((txwindow) && (txpos >= txlastack + txwindow)) { + /* + * We have to wait for an ACK before we can continue + */ + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('H', "HYDRA: SET TX TIMER %D", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + txstate = HTX_DATAACK; + break; + } else { + /* + * check if there is enough room in output + */ + if ((waitputget & 2) == 0) { + break; + } + + fseek(txfp, txpos, SEEK_SET); + put_long(txbuf, txpos); + Nopper(); + Syslog('h', "Check for more frames here?"); + txlen = fread(txbuf + 4, 1, blksize, txfp); + Syslog('h', "Hydra: send DATA (0x%08lx) %lu", txpos, txlen); + + if (txlen == 0) { + if (ferror(txfp)) { + WriteError("$Hydra: error reading from file"); + txstate = HTX_SkipFile; + } else { + txstate = HTX_EOF; + } + } else { + txpos += txlen; + sentbytes += txlen; + goodbytes += txlen; + txlen += 4; + hytxpkt(HPKT_DATA, txbuf, txlen); + + if (goodbytes > goodneeded) { + blksize *= 2; + if (blksize > H_MAXBLKLEN) { + blksize = H_MAXBLKLEN; + } + } + } + } + break; + + case HTX_SkipFile: + Syslog('h', "SM 'HTX' entering 'SkipFile'"); + /* + * this differs from the protocol definition: -2 is used + * instead of -1 (I think it's wrong in the protocol + * definition as in the example source also -2 is used) + * MB: No, I don't think this is wrong, -1 means file already + * there, -2 means skip for now, try another time. + */ + txpos = -2; + txretries = 0; + txstate = HTX_EOF; + break; + + case HTX_DATAACK: + Syslog('h', "SM 'HTX' entering 'DATAACK'"); + if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + if ((longnum > txlastack) && (txpos < longnum + txwindow)) { + txlastack = longnum; + txretries = 0; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (txretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: tx timeout"); + txretries++; + txstate = HTX_DATA; + } + break; + + case HTX_XWAIT: + Syslog('h', "SM 'HTX' entering 'XWAIT'"); + if (rxstate == HRX_DONE) { + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + txstate = HTX_DATA; + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + if (longnum > txlastack) { + txlastack = longnum; + } + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if (pkttype == HPKT_RPOS) { + /* + * Handle RPOS in state DATA but stay in this state + */ + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0)) { + hdxlink = FALSE; + Syslog('h', "Hydra: reset TX timer"); + RESETTIMER(TIMERNO_TX); + txstate = HTX_DATA; + pkttype = H_NOPKT; /* packet has already been processed */ + + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('h', "Hydra: TX timer expired"); + hytxpkt(HPKT_IDLE, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + break; + + case HTX_EOF: + Syslog('h', "SM 'HTX' entering 'EOF'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + put_long(txbuf, txpos); + hytxpkt(HPKT_EOF, txbuf, 4); + + if (txretries > 0) { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } else { + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_TX, H_MINTIMER); + } + Syslog('h', "Hydra: entering TX EOFACK"); + txstate = HTX_EOFACK; + } + break; + + case HTX_EOFACK: + Syslog('h', "SM 'HTX' entering 'EOFACK'"); + if ((pkttype == HPKT_EOFACK) && (rxlen == 0)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + /* + * calculate time needed and bytes transferred + */ + (void) time(&txendtime); + txstarttime = txendtime - txstarttime; + + if (txstarttime <= 0L) + txstarttime = 1L; + + /* close transmitter file */ + fclose(txfp); + + if (txpos >= 0) { + stxpos = txpos - stxpos; + Syslog('+', "Hydra: OK %lu bytes in %s (%ld cps)", + stxpos, str_time(txstarttime), stxpos/txstarttime); + execute_disposition(to_send); + } else { + Syslog('+', "Hydra: transmitter skipped file after %ld seconds", txstarttime); + } + + to_send = to_send->next; + txstate = HTX_NextFile; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_DATAACK) && (rxlen == 4)) { + longnum = get_long(rxbuf); + txlastack = longnum; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_EOFACK)"); + txretries++; + txstate = HTX_EOF; + } + break; + + case HTX_REND: + Syslog('h', "SM 'HTX' entering 'REND'"); + if (rxstate == HRX_DONE) { + txretries = 0; + txstate = HTX_END; + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('h', "Hydra: TX timer expired"); + hytxpkt(HPKT_IDLE, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + } + break; + + case HTX_END: + Syslog('h', "SM 'HTX' entering 'END'"); + if (txretries >= 10) { + txstate = HTX_Abort; + break; + } else { + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER/2); + SETTIMER(TIMERNO_TX, H_MINTIMER/2); + txstate = HTX_ENDACK; + } + break; + + case HTX_ENDACK: + Syslog('h', "SM 'HTX' entering 'ENDACK'"); + if ((pkttype == HPKT_END) && (rxlen == 0)) { + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + hytxpkt(HPKT_END, txbuf, 0); + txstate = HTX_DONE; + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_TX)) { + Syslog('+', "Hydra: transmitter timeout (HTX_ENDACK)"); + txretries++; + txstate = HTX_END; + } + break; + + case HTX_DONE: + case HTX_Abort: + /* nothing to do */ + break; + + default: + die(1); + } /* switch (txstate) */ + + switch (rxstate) { + case HRX_INIT: + Syslog('h', "SM 'HRX' entering 'INIT'"); + if (pkttype == HPKT_INIT) { + /* TODO: some checking, error handling */ + + /* Skip application ID */ + Syslog('+', "Hydra: remote \"%s\"", rxbuf+8); + inbuf = rxbuf + strlen(rxbuf) + 1; +// Syslog('+', "Hydra: inbuf=\"%s\"", inbuf); + + inbuf += strlen(inbuf) + 1; + + rxoptions = (HDEF_OPTIONS & HCAN_OPTIONS) | HUNN_OPTIONS; + + /* + * get supported options + */ + rxoptions |= get_flags(inbuf); + inbuf += strlen(inbuf) + 1; + + /* + * get desired options + */ + rxoptions &= get_flags(rxbuf + strlen(rxbuf) + 1); + rxoptions &= HCAN_OPTIONS; + + /* + * set options + */ + txoptions = rxoptions; + put_flags(txbuf, rxoptions); + Syslog('h', "Hydra: options: %s (%08lx)", txbuf, rxoptions); + + /* + * get desired window sizes + */ + txwindow = rxwindow = 0; + sscanf(inbuf, "%08lx%08lx", &rxwindow, &txwindow); + + if (rxwindow < 0) + rxwindow = 0; + + if (H_RXWINDOW && ((rxwindow == 0) || (rxwindow > H_RXWINDOW))) + rxwindow = H_RXWINDOW; + + if (txwindow < 0) + txwindow = 0; + + if (H_TXWINDOW && ((txwindow == 0) || (txwindow > H_TXWINDOW))) + txwindow = H_TXWINDOW; + + Syslog('h', "Hydra: txwindow=%d, rxwindow=%d", txwindow, rxwindow); + + hytxpkt(HPKT_INITACK, txbuf, 0); + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_FINFO; + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + case HRX_FINFO: + Syslog('h', "SM 'HRX' entering 'FINFO'"); + if (pkttype == HPKT_FINFO) { + /* + * check if we have received an `End of batch' FINFO packet + */ + if ((rxlen == 1) && (rxbuf[0] == 0)) { + put_long(txbuf, 0); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_DONE; + } + /* + * check if FINFO packet is at least long enough to contain + * file information + */ + else if ((rxlen > 41) && (rxbuf[rxlen - 1] == 0)) { + time_t timestamp; + time_t orgstamp; + long filesize; + char dosname[8 + 1 + 3 + 1], *Name; + + sscanf(rxbuf, "%08lx%08lx%*08x%*08x%*08x", ×tamp, &filesize); + + /* convert timestamp to UNIX time */ + orgstamp = timestamp; + timestamp = sl2mtime(timestamp); + + /* + * check if DOS conforming file name is max. 8+1+3 chars long + */ + if (strlen(rxbuf + 40) <= 12) { + strcpy(dosname, rxbuf + 40); + } else { + strcpy(dosname, "BadWazoo"); + } + + /* + * check if real file name is specified + */ + if ((strlen(rxbuf + 40) + 41) < rxlen) { + Name = rxbuf + strlen(rxbuf + 40) + 41; + + /* + * use DOS-filename if real- and DOS-name only + * differ in case sensitivity + */ + if (strcasecmp(Name, dosname) == 0) { + Name = dosname; + } + } else { + Name = dosname; + } + + Syslog('+', "Hydra: receive \"%s\" (%ld bytes) dated %s", + Name, filesize, date(timestamp)); + + rxfp = openfile(Name, timestamp, filesize, &rxpos, resync); + (void) time(&rxstarttime); + + /* check for error opening file */ + if (rxfp) { + srxpos = rxpos; + rxstate = HRX_ToData; + } else { + if (filesize == rxpos) { + /* Skip this file, it's already here */ + Syslog('+', "Hydra: Skipping file %s", Name); + put_long(txbuf, -1); + } else { + /* Skip this file for now if error opening file */ + put_long(txbuf, -2); + } + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + } + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (pkttype == HPKT_INIT) { + hytxpkt(HPKT_INITACK, txbuf, 0); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_EOF) && (rxlen == 4)) { + hytxpkt(HPKT_EOFACK, txbuf, 0); + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + case HRX_ToData: + Syslog('h', "SM 'HRX' entering 'ToData'"); + put_long(txbuf, rxpos); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + rxsyncid = 0; + rxlastsync = 0; + rxretries = 0; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_DATA; + break; + + case HRX_DATA: + Syslog('h', "SM 'HRX' entering 'DATA'"); + if ((pkttype == HPKT_DATA) && (rxlen > 4)) { + longnum = get_long(rxbuf); + Syslog('h', "Hydra: rcvd DATA (0x%08lx, 0x%08lx) %lu", longnum, rxpos, rxlen-4); + Nopper(); + + if (longnum == rxpos) { + if (fwrite(rxbuf + 4, 1, rxlen - 4, rxfp) != (rxlen - 4)) { + WriteError("$Hydra: error writing to file"); + rxpos = -2; + } else { + rxlastdatalen = rxlen - 4; + rxpos += rxlen - 4; + rcvdbytes += rxlen - 4; + rxretries = 0; + rxlastsync = rxpos; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + if (rxwindow) { + put_long(txbuf, rxpos); + hytxpkt(HPKT_DATAACK, txbuf, 4); + } + } + } else { + if (rxpos >= 0) { + Syslog('+', "Hydra: received bad rxpos"); + } + rxstate = HRX_BadPos; + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_EOF) && (rxlen == 4)) { + longnum = get_long(rxbuf); + + if (longnum == rxpos) { + /* + * calculate time and CPU usage needed + */ + (void) time(&rxendtime); + + if (rxpos >= 0) { + rxfp = NULL; + if (!closefile(1)) { + srxpos = rxpos - srxpos; + + rxstarttime = rxendtime - rxstarttime; + if (rxstarttime <= 0) + rxstarttime = 1L; + + Syslog('+', "Hydra: OK %lu bytes in %s (%ld cps)", + srxpos, str_time(rxstarttime), srxpos/rxstarttime); + + rxstate = HRX_OkEOF; + } else { + Syslog('+', "Hydra: error closing file"); + rxpos = -2; + + /* + * Note: the following state change isn't 100 % + * conformant with the Hydra protocol specification. + */ + rxstate = HRX_BadPos; + } + } else { + Syslog('+', "Hydra: receiver skipped file after %ld seconds", + rxendtime - rxstarttime); + + if (rxfp) { + closefile(0); + rxfp = NULL; + } + + rxstate = HRX_OkEOF; + } + } else if (longnum == -2) { + if (rxfp) { + closefile(0); + rxfp = NULL; + } + + rxstate = HRX_OkEOF; + } else { + if (longnum >= 0) { + Syslog('+', "Hydra: received bad rxpos"); + } + rxstate = HRX_BadPos; /* TODO: fallthrough */ + } + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (pkttype == HPKT_FINFO) { + put_long(txbuf, rxpos); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0) && (hdxlink == FALSE)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if (EXPIRED(TIMERNO_RX)) { + Syslog('h', "Hydra: RX timer expired"); + rxstate = HRX_HdxLink; + } + break; + + case HRX_BadPos: + Syslog('h', "SM 'HRX' entering 'BadPos'"); + longnum = get_long(rxbuf); + + if (longnum <= rxlastsync) { + rxretries = 0; + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + } + rxlastsync = longnum; + rxstate = HRX_Timer; + break; + + case HRX_Timer: + Syslog('h', "SM 'HRX' entering 'Timer'"); + if ((!RUNNING(TIMERNO_RX)) || (EXPIRED(TIMERNO_RX))) { + Syslog('h', "Hydra: RX timer expired"); + rxstate = HRX_HdxLink; + } else { + rxstate = HRX_DATA; + } + break; + + case HRX_HdxLink: + Syslog('h', "SM 'HRX' entering 'HdxLink'"); + if ((rxretries > 4) && (txstate != HTX_REND) && (role == 0) && (hdxlink == FALSE)) { + rxretries = 0; + hdxlink = TRUE; + } + rxstate = HRX_Retries; + break; /* TODO: fallthrough */ + + case HRX_Retries: + Syslog('h', "SM 'HRX' entering 'Retries'"); + rxretries++; + if (rxretries >= 10) { + Syslog('+', "Hydra: too many errors"); + txstate = HTX_Abort; + } else if (rxretries == 1) { + rxsyncid++; + } + rxstate = HRX_RPos; + break; /* TODO: fallthrough */ + + case HRX_RPos: + Syslog('h', "SM 'HRX' entering 'RPos'"); + rxlastdatalen /= 2; + if (rxlastdatalen < 64) + rxlastdatalen = 64; + + put_long(txbuf, rxpos); + put_long(txbuf + 4, rxlastdatalen); + put_long(txbuf + 8, rxsyncid); + + hytxpkt(HPKT_RPOS, txbuf, 12); + Syslog('h', "Hydra: set TX timer %d", H_MINTIMER); + SETTIMER(TIMERNO_RX, H_MINTIMER); + rxstate = HRX_DATA; + break; + + case HRX_OkEOF: + Syslog('h', "SM 'HRX' entering 'OkEOF'"); + hytxpkt(HPKT_EOFACK, txbuf, 0); + Syslog('h', "Hydra: reset RX timer"); + RESETTIMER(TIMERNO_RX); + Syslog('h', "Hydra: set BRAIN timer %d", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + rxstate = HRX_FINFO; + break; + + case HRX_DONE: + Syslog('h', "SM 'HRX' entering 'DONE'"); + if (pkttype == HPKT_FINFO) { + put_long(txbuf, -2); + hytxpkt(HPKT_FINFOACK, txbuf, 4); + + pkttype = H_NOPKT; /* packet has already been processed */ + } else if ((pkttype == HPKT_IDLE) && (rxlen == 0)) { + Syslog('h', "Hydra: set BRAIN timer", H_BRAINDEAD); + SETTIMER(TIMERNO_BRAIN, H_BRAINDEAD); + + pkttype = H_NOPKT; /* packet has already been processed */ + } + break; + + } /* switch(rxstate) */ + + if (pkttype != H_NOPKT) { + Syslog('h', "Hydra: rcvd packet %s - ignored", PktS(pkttype)); + pkttype = H_NOPKT; /* ignore received packet */ + } + + } /* while() */ + + Syslog('h', "Hydra: resettimers"); + RESETTIMERS(); + + if (txstate == HTX_Abort) { + /* check if file is still open */ + if (rxfp) { + rxfp = NULL; + closefile(0); + } + + Syslog('+', "Hydra: signal CAN to remote"); + FLUSHOUT(); + /* 8 times CAN and 10 times BS */ + PUT((char *)"\030\030\030\030\030\030\030\030\010\010\010\010\010\010\010\010\010\010", 18); + sleep(4); /* wait a few seconds... */ + FLUSHIN(); + + return 2; + } + + return 0; +} + + + +int hydra(int role) +{ + int rc; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, *request = NULL, *respond = NULL, *tmpfl; + char *nonhold_mail; + + Syslog('+', "Hydra: start transfer"); + session_flags |= SESSION_HYDRA; /* Hydra special file requests */ + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Hydra: remote requested \"no pickup\", no send"); + eff_remote = NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Hydra: remote requested \"pickup primary\""); + tmpl.addr = remote->addr; + tmpl.next = NULL; + eff_remote = &tmpl; + } else { + eff_remote = remote; + } + + if (role) { + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + } else { + nonhold_mail = (char *)ALL_MAIL; + } + + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Hydra: remote requested \"hold all traffic\", no send"); + tosend = NULL; + } else { + tosend = create_filelist(eff_remote, nonhold_mail, 0); + } + + if (session_flags & SESSION_WAZOO) + request = create_freqlist(remote); + + + /* + * Send only file requests during first batch if remote supports + * "RH1" flag. + */ + if (emsi_remote_lcodes & LCODE_RH1) { + rc = hydra_batch(role, request); + } else { + if (request != NULL) { + tmpfl = tosend; + tosend = request; + for (; request->next; request = request->next); + request->next = tmpfl; + + request = NULL; + } + + rc = hydra_batch(role, tosend); + } + + Syslog('+', "Hydra: start second batch"); + + if (rc == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) + respond = respond_wazoo(); + + if (emsi_remote_lcodes & LCODE_RH1) { + for (tmpfl = tosend; tmpfl->next; tmpfl = tmpfl->next); + tmpfl->next = respond; + + rc = hydra_batch(role, tosend); + tmpfl->next = NULL; /* split filelist into tosend + and respond again */ + } else { + rc = hydra_batch(role, respond); + } + } + + tidy_filelist(request, (rc == 0)); + tidy_filelist(tosend, (rc == 0)); + tidy_filelist(respond, 0); + + Syslog('+', "Hydra: end transfer"); + + return rc; +} + + diff --git a/mbcico/hydra.h b/mbcico/hydra.h new file mode 100644 index 00000000..156aef6f --- /dev/null +++ b/mbcico/hydra.h @@ -0,0 +1,206 @@ +/* As this file has been derived from the HydraCom source, here is the + * original copyright information: + * + * Note that you can find the file LICENSE.DOC from HydraCom in + * misc/HYDRACOM-LICENSE + */ +/*============================================================================= + + HydraCom Version 1.00 + + A sample implementation of the + HYDRA Bi-Directional File Transfer Protocol + + HydraCom was written by + Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT + COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + + The HYDRA protocol was designed by + Arjen G. Lentz, LENTZ SOFTWARE-DEVELOPMENT and + Joaquim H. Homrighausen + COPYRIGHT (C) 1991-1993; ALL RIGHTS RESERVED + + + Revision history: + 06 Sep 1991 - (AGL) First tryout + .. ... .... - Internal development + 11 Jan 1993 - HydraCom version 1.00, Hydra revision 001 (01 Dec 1992) + + + For complete details of the Hydra and HydraCom licensing restrictions, + please refer to the license agreements which are published in their entirety + in HYDRACOM.C and LICENSE.DOC, and also contained in the documentation file + HYDRACOM.DOC + + Use of this file is subject to the restrictions contained in the Hydra and + HydraCom licensing agreements. If you do not find the text of this agreement + in any of the aforementioned files, or if you do not have these files, you + should immediately contact LENTZ SOFTWARE-DEVELOPMENT and/or Joaquim + Homrighausen at one of the addresses listed below. In no event should you + proceed to use this file without having accepted the terms of the Hydra and + HydraCom licensing agreements, or such other agreement as you are able to + reach with LENTZ SOFTWARE-DEVELOMENT and Joaquim Homrighausen. + + + Hydra protocol design and HydraCom driver: Hydra protocol design: + Arjen G. Lentz Joaquim H. Homrighausen + LENTZ SOFTWARE-DEVELOPMENT 389, route d'Arlon + Langegracht 7B L-8011 Strassen + 3811 BT Amersfoort Luxembourg + The Netherlands + FidoNet 2:283/512, AINEX-BBS +31-33-633916 FidoNet 2:270/17 + arjen_lentz@f512.n283.z2.fidonet.org joho@ae.lu + + Please feel free to contact us at any time to share your comments about our + software and/or licensing policies. + +=============================================================================*/ + +#ifndef _HYDRA_H +#define _HYDRA_H + +/* HYDRA Specification Revision/Timestamp ---------Revision------Date------- */ +#define H_REVSTAMP 0x2b1aab00L /* 001 01 Dec 1992 */ +#define H_REVISION 1 + +/* HYDRA Basic Values ------------------------------------------------------ */ +#ifndef XON +#define XON ('Q' - '@') /* Ctrl-Q (^Q) xmit-on character */ +#define XOFF ('S' - '@') /* Ctrl-S (^S) xmit-off character */ +#endif +#define H_DLE ('X' - '@') /* Ctrl-X (^X) HYDRA DataLinkEscape */ +#define H_MINBLKLEN 64 /* Min. length of a HYDRA data block */ +#define H_MAXBLKLEN 2048 /* Max. length of a HYDRA data block */ +#define H_OVERHEAD 8 /* Max. no. control bytes in a pkt */ +#define H_MAXPKTLEN ((H_MAXBLKLEN + H_OVERHEAD + 5) * 3) /* Encoded pkt */ +#define H_BUFLEN (H_MAXPKTLEN + 16) /* Buffer sizes: max.enc.pkt + slack */ +#define H_PKTPREFIX 31 /* Max length of pkt prefix string */ +#define H_FLAGLEN 3 /* Length of a flag field */ +#define H_RETRIES 10 /* No. retries in case of an error */ +#define H_MINTIMER 10 /* Minimum timeout period */ +#define H_MAXTIMER 60 /* Maximum timeout period */ +#define H_START 5 /* Timeout for re-sending startstuff */ +#define H_IDLE 20 /* Idle? tx IDLE pkt every 20 secs */ +#define H_BRAINDEAD 120 /* Braindead in 2 mins (120 secs) */ + +/* HYDRA Return codes ------------------------------------------------------ */ +#define XFER_ABORT (-1) /* Failed on this file & abort xfer */ +#define XFER_SKIP 0 /* Skip this file but continue xfer */ +#define XFER_OK 1 /* File was sent, continue transfer */ + + +/* HYDRA Transmitter States ------------------------------------------------ */ +enum HyTxStates +{ + HTX_DONE, /* All over and done */ + HTX_START, /* Send start autostr + START pkt */ + HTX_SWAIT, /* Wait for any pkt or timeout */ + HTX_INIT, /* Send INIT pkt */ + HTX_INITACK, /* Wait for INITACK pkt */ + HTX_RINIT, /* Wait for HRX_INIT -> HRX_FINFO */ + HTX_NextFile, + HTX_ToFName, + HTX_FINFO, /* Send FINFO pkt */ + HTX_FINFOACK, /* Wait for FINFOACK pkt */ + HTX_DATA, /* Send next packet with file data */ + HTX_SkipFile, + HTX_DATAACK, /* Wait for DATAACK packet */ + HTX_XWAIT, /* Wait for HRX_END */ + HTX_EOF, /* Send EOF pkt */ + HTX_EOFACK, /* End of file, wait for EOFACK pkt */ + HTX_REND, /* Wait for HRX_END && HTD_DONE */ + HTX_END, /* Send END pkt (finish session) */ + HTX_ENDACK, /* Wait for END pkt from other side */ + HTX_Abort, +}; + +/* HYDRA Receiver States --------------------------------------------------- */ +enum HyRxStates +{ + HRX_DONE, /* All over and done */ + HRX_INIT, /* Wait for INIT pkt */ + HRX_FINFO, /* Wait for FINFO pkt of next file */ + HRX_ToData, + HRX_DATA, /* Wait for next DATA pkt */ + HRX_BadPos, + HRX_Timer, + HRX_HdxLink, + HRX_Retries, + HRX_RPos, + HRX_OkEOF, +}; + +/* HYDRA Packet Types ------------------------------------------------------ */ +enum HyPktTypes +{ + HPKT_START = 'A', /* Startup sequence */ + HPKT_INIT = 'B', /* Session initialisation */ + HPKT_INITACK = 'C', /* Response to INIT pkt */ + HPKT_FINFO = 'D', /* File info (name, size, time) */ + HPKT_FINFOACK = 'E', /* Response to FINFO pkt */ + HPKT_DATA = 'F', /* File data packet */ + HPKT_DATAACK = 'G', /* File data position ACK packet */ + HPKT_RPOS = 'H', /* Transmitter reposition packet */ + HPKT_EOF = 'I', /* End of file packet */ + HPKT_EOFACK = 'J', /* Response to EOF packet */ + HPKT_END = 'K', /* End of session */ + HPKT_IDLE = 'L', /* Idle - just saying I'm alive */ + HPKT_DEVDATA = 'M', /* Data to specified device */ + HPKT_DEVDACK = 'N', /* Response to DEVDATA pkt */ + + HPKT_HIGHEST = 'N' /* Highest known pkttype in this imp */ +}; + +/* HYDRA Internal Pseudo Packet Types -------------------------------------- */ +#define H_NOPKT 0 /* No packet (yet) */ +#define H_CANCEL (-1) /* Received cancel sequence 5*Ctrl-X */ +#define H_CARRIER (-2) /* Lost carrier */ +#define H_SYSABORT (-3) /* Aborted by operator on this side */ +#define H_TXTIME (-4) /* Transmitter timeout */ +#define H_DEVTXTIME (-5) /* Device transmitter timeout */ +#define H_BRAINTIME (-6) /* Braindead timeout (quite fatal) */ + +/* HYDRA Packet Format: START[]END ------------------------ */ +enum HyPktFormats +{ + HCHR_PKTEND = 'a', /* End of packet (any format) */ + HCHR_BINPKT = 'b', /* Start of binary packet */ + HCHR_HEXPKT = 'c', /* Start of hex encoded packet */ + HCHR_ASCPKT = 'd', /* Start of shifted 7bit encoded pkt */ + HCHR_UUEPKT = 'e', /* Start of uuencoded packet */ +}; + +/* HYDRA Local Storage of INIT Options (Bitmapped) ------------------------- */ +#define HOPT_XONXOFF (0x00000001L) /* Escape XON/XOFF */ +#define HOPT_TELENET (0x00000002L) /* Escape CR-'@'-CR (Telenet escape) */ +#define HOPT_CTLCHRS (0x00000004L) /* Escape ASCII 0-31 and 127 */ +#define HOPT_HIGHCTL (0x00000008L) /* Escape above 3 with 8th bit too */ +#define HOPT_HIGHBIT (0x00000010L) /* Escape ASCII 128-255 + strip high */ +#define HOPT_CANBRK (0x00000020L) /* Can transmit a break signal */ +#define HOPT_CANASC (0x00000040L) /* Can transmit/handle ASC packets */ +#define HOPT_CANUUE (0x00000080L) /* Can transmit/handle UUE packets */ +#define HOPT_CRC32 (0x00000100L) /* Packets with CRC-32 allowed */ +#define HOPT_DEVICE (0x00000200L) /* DEVICE packets allowed */ +#define HOPT_FPT (0x00000400L) /* Can handle filenames with paths */ + +/* What we can do */ +#define HCAN_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CRC32) +/* Vital options if we ask for any; abort if other side doesn't support them */ +#define HNEC_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CANBRK) +/* Non-vital options; nice if other side supports them, but doesn't matter */ +#define HUNN_OPTIONS (HOPT_CANASC | HOPT_CANUUE | HOPT_CRC32) +/* Default options */ +#define HDEF_OPTIONS (HOPT_CRC32) +/* rxoptions during init (needs to handle ANY link yet unknown at that point */ +#define HRXI_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) +/* ditto, but this time txoptions */ +#define HTXI_OPTIONS (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) + + +#define h_crc16test(crc) (((crc) == 0xf0b8 ) ? 1 : 0) +#define h_crc32test(crc) (((crc) == 0xdebb20e3L) ? 1 : 0) + +int hydra(int); + +#endif + diff --git a/mbcico/lutil.c b/mbcico/lutil.c new file mode 100644 index 00000000..b78f6b74 --- /dev/null +++ b/mbcico/lutil.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * + * File ..................: mbcico/lutil.c + * Purpose ...............: Fidonet mailer + * Last modification date : 12-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "lutil.h" + + +char *myname=(char *)"unknown"; + + +void setmyname(char *arg) +{ + if ((myname = strrchr(arg, '/'))) + myname++; + else + myname = arg; +} + + + +static char *mon[] = { +(char *)"Jan",(char *)"Feb",(char *)"Mar", +(char *)"Apr",(char *)"May",(char *)"Jun", +(char *)"Jul",(char *)"Aug",(char *)"Sep", +(char *)"Oct",(char *)"Nov",(char *)"Dec" +}; + + + +char *date(time_t t) +{ + struct tm ptm; + time_t now; + static char buf[20]; + + if (t) + now=t; + else + time(&now); + ptm=*localtime(&now); + sprintf(buf,"%s %02d %02d:%02d:%02d", + mon[ptm.tm_mon],ptm.tm_mday, + ptm.tm_hour,ptm.tm_min,ptm.tm_sec); + return(buf); +} + + + +int IsZMH() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,2", 7) == 0) + return TRUE; + } + return FALSE; +} + + + diff --git a/mbcico/lutil.h b/mbcico/lutil.h new file mode 100644 index 00000000..b8f648a8 --- /dev/null +++ b/mbcico/lutil.h @@ -0,0 +1,9 @@ +#ifndef LUTIL_H +#define LUTIL_H + + +void setmyname(char *); +char *date(long); +int IsZMH(void); + +#endif diff --git a/mbcico/m7recv.c b/mbcico/m7recv.c new file mode 100644 index 00000000..c8e7b686 --- /dev/null +++ b/mbcico/m7recv.c @@ -0,0 +1,190 @@ +/***************************************************************************** + * + * File ..................: mbcico/m7recv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "statetbl.h" +#include "ttyio.h" +#include "m7recv.h" + + + +static int m7_recv(void); +static char* fn; +static int last; + +int m7recv(char *fname) +{ + int rc; + + fn = fname; + last = 0; + rc = m7_recv(); + if (rc) + return -1; + else if (last) + return 1; + else + return 0; +} + + + +SM_DECL(m7_recv,(char *)"m7recv") +SM_STATES + sendnak, + waitack, + waitchar, + sendack, + sendcheck, + waitckok +SM_NAMES + (char *)"sendnak", + (char *)"waitack", + (char *)"waitchar", + (char *)"sendack", + (char *)"sendcheck", + (char *)"waitckok" +SM_EDECL + + int count = 0; + int c, i = 0; + char *p = fn; + char cs = SUB; + +SM_START(waitchar) + +SM_STATE(sendnak) + + Syslog('X', "m7recv SENDNAK count=%d", count); + if (count++ > 20) { + Syslog('+', "Too many tries getting modem7 name"); + SM_ERROR; + } + p = fn; + cs = SUB; + i = 0; + PUTCHAR(NAK); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('X', "m7recv WAITACK"); + c = GETCHAR(5); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for ACK"); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else { + Syslog('X', "Got 0x%02x %s", c, printablec(c)); + switch (c) { + case ACK: SM_PROCEED(waitchar); + break; + case EOT: last=1; + SM_SUCCESS; + break; + default: Syslog('X', "m7 got '%s' waiting for ACK", printablec(c)); + break; + } + } + +SM_STATE(waitchar) + + Syslog('X', "m7recv WAITCHAR"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for char",c); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else { + Syslog('X', "Got 0x%02x %s", c, printablec(c)); + switch (c) { + case EOT: last=1; + SM_SUCCESS; + break; + case SUB: *p='\0'; + SM_PROCEED(sendcheck); + break; + case 'u': SM_PROCEED(sendnak); + break; + default: cs += c; + if (i < 15) { + if (c != ' ') { + if (i == 8) + *p++='.'; + *p++ = tolower(c); + } + i++; + } + SM_PROCEED(sendack); + break; + } + } + +SM_STATE(sendack) + + Syslog('X', "m7recv SENDACK"); + PUTCHAR(ACK); + SM_PROCEED(waitchar); + +SM_STATE(sendcheck) + + Syslog('X', "m7recv SENDCHECK cs=%d", cs); + PUTCHAR(cs); + SM_PROCEED(waitckok); + +SM_STATE(waitckok) + + Syslog('X', "m7recv WAITCKOK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('X', "m7 got timeout waiting for ack ACK"); + SM_PROCEED(sendnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == ACK) { + SM_SUCCESS; + } else { + SM_PROCEED(sendnak); + } + +SM_END +SM_RETURN + + diff --git a/mbcico/m7recv.h b/mbcico/m7recv.h new file mode 100644 index 00000000..818210c4 --- /dev/null +++ b/mbcico/m7recv.h @@ -0,0 +1,8 @@ +#ifndef _M7RECV_H +#define _M7RECV_H + +int m7recv(char *); + + +#endif + diff --git a/mbcico/m7send.c b/mbcico/m7send.c new file mode 100644 index 00000000..254caff4 --- /dev/null +++ b/mbcico/m7send.c @@ -0,0 +1,191 @@ +/***************************************************************************** + * + * File ..................: mbcico/m7send.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "statetbl.h" +#include "ttyio.h" +#include "m7send.h" + +static int m7_send(void); + +static char *fn; + +int m7send(char *fname) +{ + fn=fname; + return m7_send(); +} + + + +SM_DECL(m7_send,(char *)"m7send") +SM_STATES + waitnak, + sendack, + sendchar, + waitack, + sendsub, + waitcheck, + ackcheck +SM_NAMES + (char *)"waitnak", + (char *)"sendack", + (char *)"sendchar", + (char *)"waitack", + (char *)"sendsub", + (char *)"waitcheck", + (char *)"ackcheck" +SM_EDECL + + char buf[12],*p; + int i,c,count=0; + char cs=SUB; + + memset(buf,' ',sizeof(buf)); + for (i=0,p=fn; (i<8) && (*p) && (*p != '.'); i++,p++) + buf[i] = toupper(*p); + if (*p == '.') + p++; + for (; (i<11) && (*p); i++,p++) + buf[i] = toupper(*p); + for (i=0; i<11; i++) + cs += buf[i]; + buf[11]='\0'; + Syslog('x', "modem7 filename \"%s\", checksum %02x", buf,(unsigned char)cs); + +SM_START(sendack) + +SM_STATE(waitnak) + + Syslog('x', "m7send WAITNAK"); + if (count++ > 20) { + Syslog('+', "too many tries sending modem7 name"); + SM_ERROR; + } + + c=GETCHAR(5); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting NAK"); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == NAK) { + SM_PROCEED(sendack); + } else { + Syslog('x', "m7 got '%s' waiting NAK", printablec(c)); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(sendack) + + Syslog('x', "m7send SENDACK"); + i = 0; + PUTCHAR(ACK); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(sendchar); + } + +SM_STATE(sendchar) + + Syslog('x', "m7send SENDCHAR"); + if (i > 11) { + SM_PROCEED(sendsub); + } + + PUTCHAR(buf[i++]); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('x', "m7send WAITACK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting ACK for char %d",i); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == ACK) { + SM_PROCEED(sendchar); + } else { + Syslog('x', "m7 got '%s' waiting ACK for char %d", printablec(c),i); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(sendsub) + + Syslog('x', "m7send SENDSUB"); + PUTCHAR(SUB); + SM_PROCEED(waitcheck); + +SM_STATE(waitcheck) + + Syslog('x', "m7send WAITCHECK"); + c = GETCHAR(1); + if (c == TIMEOUT) { + Syslog('x', "m7 got timeout waiting check"); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else if (c == cs) { + SM_PROCEED(ackcheck); + } else { + Syslog('x', "m7 got %02x waiting check %02x", (unsigned char)c,(unsigned char)cs); + PUTCHAR('u'); + SM_PROCEED(waitnak); + } + +SM_STATE(ackcheck) + + Syslog('x', "m7send ACKCHECK"); + PUTCHAR(ACK); + if (STATUS) { + SM_ERROR; + } else { + SM_SUCCESS; + } + +SM_END +SM_RETURN + + diff --git a/mbcico/m7send.h b/mbcico/m7send.h new file mode 100644 index 00000000..8a9984ef --- /dev/null +++ b/mbcico/m7send.h @@ -0,0 +1,7 @@ +#ifndef M7SEND_H +#define M7SEND_H + +int m7send(char *); + +#endif + diff --git a/mbcico/mbcico.c b/mbcico/mbcico.c new file mode 100644 index 00000000..5d832f5c --- /dev/null +++ b/mbcico/mbcico.c @@ -0,0 +1,413 @@ +/***************************************************************************** + * + * File ..................: mbcico/mbcico.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "config.h" +#include "answer.h" +#include "portsel.h" +#include "call.h" +#include "callall.h" +#include "lutil.h" +#include "mbcico.h" +#include "session.h" + + + +int master = 0; +int forcedcalls = 0; +int immediatecall = FALSE; +char *forcedphone = NULL; +char *forcedline = NULL; +char *inetaddr = NULL; +char *envptr = NULL; +time_t t_start; +time_t t_end; +time_t c_start; +time_t c_end; +int online = 0; +unsigned long sentbytes = 0; +unsigned long rcvdbytes = 0; +int tcp_mode = TCPMODE_NONE; +int Loaded = FALSE; + + +extern char *myname; +char *inbound; +char *uxoutbound; +char *name; +char *phone; +char *flags; +extern int gotfiles; +extern int mypid; + + + +void usage(void) +{ + fprintf(stderr,"ifcico; (c) Eugene G. Crosser, 1993-1997\n"); + fprintf(stderr,"mbcico ver. %s; (c) %s\n\n", VERSION, ShortRight); + fprintf(stderr,"-r -a ...\n"); + fprintf(stderr,"-r 0|1 1 - master, 0 - slave [0]\n"); + fprintf(stderr,"-n forced phone number\n"); + fprintf(stderr,"-l forced tty device\n"); + fprintf(stderr,"-t must be one of ifc|itn|ibn, forces TCP/IP\n"); + fprintf(stderr,"-a supply internet hostname if not in nodelist\n"); + fprintf(stderr," should be in domain form, e.g. f11.n22.z3\n"); + fprintf(stderr," (this implies master mode)\n"); + fprintf(stderr,"\n or: %s tsync|yoohoo|**EMSI_INQC816|-t ibn|-t ifc|-t itn\n",myname); + fprintf(stderr," (this implies slave mode)\n"); +} + + + +void free_mem(void) +{ + free(inbound); + if (name) + free(name); + if (phone) + free(phone); + if (flags) + free(flags); + if (uxoutbound) + free(uxoutbound); +} + + + +void die(int onsig) +{ + int total = 0; + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + Syslog('+', "Terminated with error %d", onsig); + } + + if (sentbytes || rcvdbytes) { + total = (int)(c_end - c_start); + if (!total) + total = 1; + Syslog('+', "Sent %lu bytes, received %lu bytes, avg %d cps", + sentbytes, rcvdbytes, (sentbytes + rcvdbytes) / total); + } + + if (online) + Syslog('+', "Connected %s", str_time(online)); + + if (gotfiles) + CreateSema((char *)"mailin"); + + time(&t_end); + Syslog(' ', "MBCICO finished in %s", t_elapsed(t_start, t_end)); + free_mem(); + if (envptr) + free(envptr); + ExitClient(onsig); +} + + + +int main(int argc, char *argv[]) +{ + int i, c, uid; + fa_list *callist = NULL, **tmpl; + faddr *tmp; + int rc, maxrc, callno = 0, succno = 0; + char *answermode = NULL, *p = NULL, *cmd = NULL; + struct passwd *pw; + char temp[81]; + FILE *fp; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from inetd or mgetty, + * this will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + pw = getpwuid(getuid()); + if (getenv("MBSE_ROOT") == NULL) { + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + if (argc < 2) { + usage(); + if (envptr) + free(envptr); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(101); + } + + InitConfig(); + InitNode(); + InitFidonet(); + TermInit(1); + time(&t_start); + time(&c_start); + time(&c_end); + + InitClient(pw->pw_name, (char *)"mbcico", CFG.location, CFG.logfile, CFG.cico_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBCICO v%s", VERSION); + + /* + * Catch all signals we can, and handle the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGINT) || (i == SIGBUS) || + (i == SIGFPE) || (i == SIGSEGV)) { + signal(i, (void (*))die); + } else + signal(i, SIG_DFL); + } + + /* + * Check if history file exists, if not create a new one. + */ + cmd = calloc(128, sizeof(char)); + sprintf(cmd, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(cmd, "r")) == NULL) { + if ((fp = fopen(cmd, "a")) == NULL) { + WriteError("$Can't create %s", cmd); + } else { + memset(&history, 0, sizeof(history)); + history.online = time(NULL); + history.offline = time(NULL); + fwrite(&history, sizeof(history), 1, fp); + fclose(fp); + Syslog('+', "Created new %s", cmd); + } + } else { + fclose(fp); + } + free(cmd); + memset(&history, 0, sizeof(history)); + + cmd = xstrcpy((char *)"Cmd: mbcico"); + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + } + Syslog(' ', cmd); + free(cmd); + + setmyname(argv[0]); + + while ((c=getopt(argc,argv,"r:n:l:t:a:I:h")) != -1) + switch (c) { + case 'r': master = atoi(optarg); + if ((master != 0) && (master != 1)) { + usage(); + die(101); + } + break; + + case 'l': forcedline = optarg; + break; + + case 't': p = xstrcpy(optarg); + if (strncmp(p, "ifc", 3) == 0) + tcp_mode = TCPMODE_IFC; + else if (strncmp(p, "itn", 3) == 0) + tcp_mode = TCPMODE_ITN; + else if (strncmp(p, "ibn", 3) == 0) + tcp_mode = TCPMODE_IBN; + else { + usage(); + die(101); + } + free(p); + break; + + case 'a': inetaddr = optarg; + break; + + case 'n': forcedphone = optarg; + break; + + default: usage(); + die(101); + } + + /* + * Load rest of the configuration + */ + inbound = xstrcpy(CFG.inbound); + uxoutbound = xstrcpy(CFG.uxpath); + name = xstrcpy(CFG.bbs_name); + phone = xstrcpy(CFG.Phone); + flags = xstrcpy(CFG.Flags); + + tmpl = &callist; + + while (argv[optind]) { + for (p = argv[optind]; (*p) && (*p == '*'); p++); + + if (strncasecmp(p, "EMSI_NAKEEC3", 12) == 0) { + + Syslog('+', "Detected IEMSI client, starting BBS"); + sprintf(temp, "%s/bin/mbsebbs", getenv("MBSE_ROOT")); + socket_shutdown(mypid); + + if (execl(temp, "mbsebbs", (char *)NULL) == -1) + perror("FATAL: Error loading BBS!"); + + /* + * If this happens, nothing is logged! + */ + printf("\n\nFATAL: Loading of the BBS failed!\n\n"); + sleep(3); + free_mem(); + if (envptr) + free(envptr); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(100); + } + + if ((strcasecmp(argv[optind],"tsync") == 0) || + (strcasecmp(argv[optind],"yoohoo") == 0) || + (strcasecmp(argv[optind],"ibn") == 0) || + (strncasecmp(p,"EMSI_",5) == 0)) { + master = 0; + answermode = argv[optind]; + Syslog('S', "Inbound \"%s\" mode", MBSE_SS(answermode)); + } else { + Syslog('-', "Callist entry \"%s\"", argv[optind]); + if ((tmp = parsefaddr(argv[optind]))) { + *tmpl = (fa_list *)malloc(sizeof(fa_list)); + (*tmpl)->next = NULL; + (*tmpl)->addr = tmp; + tmpl = &((*tmpl)->next); + immediatecall = TRUE; + } else + WriteError("Unrecognizable address \"%s\"", argv[optind]); + } + optind++; + } + + if (callist) { + master = 1; + forcedcalls = 1; + } + + /* + The following witchkraft about uid-s is necessary to make + access() work right. Unforunately, access() checks the real + uid, if mbcico is invoked with supervisor real uid (as when + called by uugetty) it returns X_OK for the magic files that + even do not have `x' bit set. Therefore, `reference' magic + file requests are taken for `execute' requests (and the + actual execution natually fails). Here we set real uid equal + to effective. If real uid is not zero, all these fails, but + in this case it is not necessary anyway. + */ + + uid=geteuid(); + seteuid(0); + setuid(uid); + seteuid(uid); + + umask(066); /* packets may contain confidential information */ + + p = xstrcpy(inbound); + p = xstrcat(p,(char *)"/tmp/fooinb"); + mkdirs(p); + free(p); + + maxrc=0; + if (master) { + /* + * Don't do outbound calls if low diskspace + */ + if (!diskfree(CFG.freespace)) + die(101); + + if (callist == NULL) + callist = callall(); + + for (tmpl = &callist; *tmpl; tmpl = &((*tmpl)->next)) { + callno++; + forcedcalls = (*tmpl)->force; + rc = call((*tmpl)->addr); + Syslog('+', "Call to %s %s (rc=%d)", ascfnode((*tmpl)->addr,0x1f), rc?"failed":"successful",rc); + if (rc > maxrc) + maxrc=rc; + if (rc == 0) { + succno++; + break; + } + } + if (callist == NULL) + if (IsSema((char *)"scanout")) + RemoveSema((char *)"scanout"); + } else { + /* slave */ + if (!answermode && tcp_mode == TCPMODE_IBN) + answermode = xstrcpy((char *)"ibn"); + maxrc = answer(answermode); + callno = 1; + succno = (maxrc == 0); + } + + if (callno) + Syslog('+', "%d of %d calls, maxrc=%d",succno,callno,maxrc); + + tidy_falist(&callist); + + if (maxrc) + die(maxrc+100); + else + die(0); + return 0; +} + + diff --git a/mbcico/mbcico.h b/mbcico/mbcico.h new file mode 100644 index 00000000..caaaaf8a --- /dev/null +++ b/mbcico/mbcico.h @@ -0,0 +1,9 @@ +#ifndef _MBCICO_H +#define _MBCICO_H + +void usage(void); +void free_mem(void); +void die(int); + +#endif + diff --git a/mbcico/mbout.c b/mbcico/mbout.c new file mode 100644 index 00000000..fd3ffcdb --- /dev/null +++ b/mbcico/mbout.c @@ -0,0 +1,344 @@ +/***************************************************************************** + * + * File ..................: mbcico/mbout.c + * Purpose ...............: MBSE BBS Outbound Manager + * Last modification date : 31-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "outstat.h" +#include "nlinfo.h" + + +extern int do_quiet; /* Supress screen output */ +int do_attach = FALSE; /* Send file attaches */ +int do_node = FALSE; /* Query the nodelist */ +int do_poll = FALSE; /* Poll a node */ +int do_req = FALSE; /* Request files from a node */ +int do_stat = FALSE; /* Show outbound status */ +int do_stop = FALSE; /* Stop polling a node */ +int e_pid = 0; /* Pid of child */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void); +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBOUT: MBSE BBS %s Outbound Manager\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int); +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (show_log) + do_quiet = FALSE; + + if (!do_quiet) + colour(3, 0); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBOUT finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +void Help(void); +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbout [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" a att Attach a file to a node\n"); + printf(" n node Show nodelist information\n"); + printf(" p poll [node..node] Poll node(s) (always crash)\n"); + printf(" r req [file..file] Request file(s) from node\n"); + printf(" sta stat Show outbound status\n"); + printf(" sto stop [node..node] Stop polling node(s)\n"); + printf("\n"); + printf(" Should be in domain form, e.g. f16.n2801.z2.domain\n"); + printf(" Flavor's are: crash | immediate | normal | hold\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + die(0); +} + + + +void Fatal(char *); +void Fatal(char *msg) +{ + show_log = TRUE; + if (!do_quiet) { + colour(12, 0); + printf("%s\n", msg); + } + WriteError(msg); + die(100); +} + + + +int main(int argc, char *argv[]) +{ + char *cmd, flavor = 'x'; + int i, j, rc = 0; + struct passwd *pw; + faddr *addr = NULL; + node *nlent; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + InitNode(); + InitFidonet(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbout"); + + if (argc > 1) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[1]); + + if (!strncasecmp(argv[1], "a", 1)) + do_attach = TRUE; + if (!strncasecmp(argv[1], "n", 1)) + do_node = TRUE; + if (!strncasecmp(argv[1], "p", 1)) + do_poll = TRUE; + if (!strncasecmp(argv[1], "r", 1)) + do_req = TRUE; + if (!strncasecmp(argv[1], "sta", 3)) + do_stat = TRUE; + if (!strncasecmp(argv[1], "sto", 3)) + do_stop = TRUE; + } + + for (i = 2; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbout", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBOUT v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_stat) { + rc = outstat(); + if (rc) + rc += 100; + die(rc); + } + + /* + * Get node number from commandline + */ + if (do_attach || do_node || do_poll || do_stop || do_req) { + if (argc < 3) + Fatal((char *)"Not enough parameters"); + } + + if (do_attach || do_node || do_req) { + if ((addr = parsefaddr(argv[2])) == NULL) + Fatal((char *)"Unrecognizable address"); + } + + if (do_node) { + rc = nlinfo(addr); + tidy_faddr(addr); + if (rc) + rc += 100; + die(rc); + } + + if (do_poll || do_stop) { + for (i = 3; i <= argc; i++) { + if (strncasecmp(argv[i-1], "-q", 2)) { + if ((addr = parsefaddr(argv[i-1])) == NULL) + Fatal((char *)"Unrecognizable address"); + j = poll(addr, do_stop); + tidy_faddr(addr); + if (j > rc) + rc = j; + } + } + if (rc) + rc = 100; + die(rc); + } + + if (do_attach) { + if (argc < 5) + Fatal((char *)"Not enough parameters"); + flavor = tolower(argv[3][0]); + switch (flavor) { + case 'n' : flavor = 'f'; break; + case 'i' : flavor = 'i'; break; + case 'c' : flavor = 'c'; break; + case 'h' : flavor = 'h'; break; + default : Fatal((char *)"Invalid flavor, must be: immediate, crash, normal or hold"); + } + + nlent = getnlent(addr); + if (nlent->pflag == NL_DUMMY) + Fatal((char *)"Node is not in nodelist"); + if (nlent->pflag == NL_DOWN) + Fatal((char *)"Node has status Down"); + if (nlent->pflag == NL_HOLD) + Fatal((char *)"Node has status Hold"); + if (((nlent->oflags & OL_CM) == 0) && (flavor == 'c')) + Fatal((char *)"Node is not CM, must use Immediate, Normal or Hold flavor"); + + if (argv[4][0] == '-') + Fatal((char *)"Invalid filename given"); + if (file_exist(argv[4], R_OK) != 0) + Fatal((char *)"File doesn't exist"); + + if (attach(*addr, argv[4], LEAVE, flavor)) { + Syslog('+', "File attach %s is successfull", argv[4]); + if (!do_quiet) + printf("File attach %s is successfull", argv[4]); + CreateSema((char *)"scanout"); + die(0); + } else { + Fatal((char *)"File attach failed"); + } + } + + if (do_req) { + if (argc < 4) + Fatal((char *)"Not enough parameters"); + for (i = 4; i <= argc; i++) { + if (strncasecmp(argv[i-1], "-q", 2)) { + rc = freq(addr, argv[i-1]); + if (rc) + break; + } + } + if (rc) + rc += 100; + die(rc); + } + + Help(); +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + diff --git a/mbcico/nlinfo.c b/mbcico/nlinfo.c new file mode 100644 index 00000000..cc882a8e --- /dev/null +++ b/mbcico/nlinfo.c @@ -0,0 +1,129 @@ +/***************************************************************************** + * + * File ..................: mbcico/nlinfo.c + * Purpose ...............: MBSE BBS Outbound Manager + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "nlinfo.h" + + + +int nlinfo(faddr *addr) +{ + node *nlent; + int i; + char flagbuf[256]; + + if (addr == NULL) + return 0; + + Syslog('s', "Search nodelist info for %s", ascfnode(addr, 0x1f)); + nlent = getnlent(addr); + + if (nlent->pflag != NL_DUMMY) { + colour(3, 0); + printf("System : %s\n", nlent->name); + printf("Sysop : %s@%s\n", nlent->sysop, ascinode(addr, 0x3f)); + printf("Location : %s\n", nlent->location); + if (nlent->phone) + printf("Phone : %s\n", nlent->phone); + else + printf("Phone : -Unpublished-\n"); + printf("Speed : %d\n", nlent->speed); + + flagbuf[0] = 0; + + /* + * Get all normal nodelist flags + */ + for (i = 0; fkey[i].flag != 0; i++) + if ((nlent->mflags & fkey[i].flag) == fkey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", fkey[i].key); + for (i = 0; dkey[i].flag != 0; i++) + if ((nlent->dflags & dkey[i].flag) == dkey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", dkey[i].key); + for (i = 0; ikey[i].flag != 0; i++) + if ((nlent->iflags & ikey[i].flag) == ikey[i].flag) + sprintf(flagbuf + strlen(flagbuf), "%s,", ikey[i].key); + + + switch (nlent->xflags) { + case RQ_XA: sprintf(flagbuf + strlen(flagbuf), "XA"); break; + case RQ_XB: sprintf(flagbuf + strlen(flagbuf), "XB"); break; + case RQ_XC: sprintf(flagbuf + strlen(flagbuf), "XC"); break; + case RQ_XP: sprintf(flagbuf + strlen(flagbuf), "XP"); break; + case RQ_XR: sprintf(flagbuf + strlen(flagbuf), "XR"); break; + case RQ_XW: sprintf(flagbuf + strlen(flagbuf), "XW"); break; + case RQ_XX: sprintf(flagbuf + strlen(flagbuf), "XX"); break; + } + + printf("Flags : %s\n", flagbuf); + + /* + * Show User flags + */ + flagbuf[0] = 0; + for (i = 0; nlent->uflags[i]; i++) { + sprintf(flagbuf + strlen(flagbuf), "%s,", nlent->uflags[i]); + } + if (strlen(flagbuf)) { + flagbuf[strlen(flagbuf) - 1] = 0; + printf("U-Flags : %s\n", flagbuf); + } + + /* + * Show P flags + */ + printf("P Flag :"); + if (nlent->pflag & 0x01) + printf(" Down"); + if (nlent->pflag & 0x02) + printf(" Hold"); + if (nlent->pflag & 0x04) + printf(" Pvt"); + if (nlent->pflag & 0x10) + printf(" ISDN"); + if (nlent->pflag & 0x20) + printf(" TCP/IP"); + printf("\n"); + printf("Uplink : %u/%u\n", nlent->upnet, nlent->upnode); + printf("Region : %u\n", nlent->region); + } + + if (nlent->addr.domain) + free(nlent->addr.domain); + + return 0; +} + + + diff --git a/mbcico/nlinfo.h b/mbcico/nlinfo.h new file mode 100644 index 00000000..9b08810f --- /dev/null +++ b/mbcico/nlinfo.h @@ -0,0 +1,9 @@ +#ifndef _NLINFO_H +#define _NLINFO_H + + +int nlinfo(faddr *); + + +#endif + diff --git a/mbcico/openfile.c b/mbcico/openfile.c new file mode 100644 index 00000000..b82c4c5d --- /dev/null +++ b/mbcico/openfile.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * + * File ..................: mbcico/openfile.c + * Purpose ...............: Fidonet mailer + * Last modification date : 12-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "config.h" +#include "lutil.h" +#include "openfile.h" + + +static FILE *infp=NULL; +static char *infpath=NULL; +static time_t intime; +static int isfreq; +char *freqname=NULL; +int gotfiles = FALSE; + + +/* + * Try to find present (probably incomplete) file with the same timestamp + * (it might be renamed), open it for append and store resync offset. + * Store 0 in resync offset if the file is new. Return FILE* or NULL. + * resync() must accept offset in bytes and return 0 on success, nonzero + * otherwise (and then the file will be open for write). For Zmodem, + * resync is always possible, but for SEAlink it is not. Do not try + * any resyncs if remsize == 0. + */ +FILE *openfile(char *fname, time_t remtime, off_t remsize, off_t *resofs, int(*resync)(off_t)) +{ + char *opentype; + char *p, x; + char ctt[32]; + int rc, ncount; + struct stat st; + struct flock fl; + char tmpfname[16]; + + fl.l_type = F_WRLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + strcpy(ctt,date(remtime)); + + Syslog('S', "openfile(\"%s\",%s,%lu,...)", MBSE_SS(fname), MBSE_SS(ctt),(unsigned long)remsize); + + if ((fname == NULL) || (fname[0] == '\0')) { + sprintf(tmpfname,"%08lx.pkt",(unsigned long)sequencer()); + fname=tmpfname; + } + + if ((strlen(fname) == 12) && (strspn(fname,"0123456789abcdefABCDEF") == 8) && (strcasecmp(fname+8,".req") == 0)) { + Syslog('s', "Received wazoo freq file"); + isfreq = TRUE; + } else + isfreq = FALSE; + + /* + * First check if the file is already in the real inbound directory. + * If it's there, resoffs will be set equal to remsize to signal the + * receiving protocol to skip the file. + */ + if (infpath) + free(infpath); + infpath = xstrcpy(inbound); + infpath = xstrcat(infpath, (char *)"/"); + infpath = xstrcat(infpath, fname); + if (stat(infpath, &st) == 0) { + Syslog('S', "remtine=%ld, st_time=%ld, remsize=%ld, st_size=%ld", remtime, st.st_mtime, remsize, st.st_size); + + if ((remtime == st.st_mtime) && (remsize == st.st_size)) { + Syslog('+', "File %s is already here", fname); + *resofs = st.st_size; + free(infpath); + infpath = NULL; + return NULL; + } + } + + /* + * If the file is not already in the inbound, but there is a file + * with the same name, the new file will be renamed. + * + * If the file is 0 bytes, erase it so it can be received again. + * + * Renaming algorythm is as follows: start with the present name, + * increase the last character of the file name, jumping from + * '9' to 'a', from 'z' to 'A', from 'Z' to '0'. If _all_ these + * names are occupied, create random name. + */ + if (infpath) + free(infpath); + infpath = xstrcpy(inbound); + infpath = xstrcat(infpath, (char *)"/tmp/"); + infpath = xstrcat(infpath, fname); + + if (((rc = stat(infpath, &st)) == 0) && (st.st_size == 0)) { + Syslog('+', "Zero bytes file in the inbound, unlinking"); + unlink(infpath); + } + + p = infpath + strlen(infpath) -1; + x = *p; + ncount = 0; + while (((rc = stat(infpath, &st)) == 0) && (remtime != st.st_mtime) && (ncount++ < 62)) { + if (x == '9') + x = 'a'; + else if (x == 'z') + x = 'A'; + else if (x == 'Z') + x = '0'; + else + x++; + *p = x; + } + + if (ncount >= 62) { /* names exhausted */ + rc = 1; + p = strrchr(infpath,'/'); + *p = '\0'; + sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); + free(infpath); + infpath = xstrcpy(p); + infpath = xstrcat(infpath, ctt); + } + + *resofs = 0L; + opentype = (char *)"w"; + if ((rc == 0) && (remsize != 0)) { + Syslog('+', "Resyncing at offset %lu of \"%s\"", (unsigned long)st.st_size, infpath); + if (resync(st.st_size) == 0) { + opentype = (char *)"a"; + *resofs = st.st_size; + } + } + + Syslog('S', "try fopen(\"%s\",\"%s\")",infpath,opentype); + + /* + * If first attempt doesn't succeed, create tmp directory + * and try again. + */ + if ((infp = fopen(infpath,opentype)) == NULL) { + mkdirs(infpath); + if ((infp = fopen(infpath, opentype)) == NULL) { + WriteError("$Cannot open local file \"%s\" for \"%s\"", infpath,opentype); + free(infpath); + infpath=NULL; + return NULL; + } + } + + fl.l_pid = getpid(); + if (fcntl(fileno(infp),F_SETLK,&fl) != 0) { + Syslog('+', "$cannot lock local file \"%s\"",infpath); + fclose(infp); + infp = NULL; + free(infpath); + infpath = NULL; + return NULL; + } + intime=remtime; + + if (isfreq) { + if (freqname) + free(freqname); + freqname = xstrcpy(infpath); + } + + Syslog('S', "opened file \"%s\" for \"%s\", restart at %lu", infpath,opentype,(unsigned long)*resofs); + return infp; +} + + + +/* + * close file and if (success) { move it to the final location } + */ +int closefile(int success) +{ + char *newpath, *p, ctt[32]; + int rc=0,ncount; + char x; + struct stat st; + struct utimbuf ut; + + Syslog('S', "closefile(%d), for file \"%s\"",success, MBSE_SS(infpath)); + + if ((infp == NULL) || (infpath == NULL)) { + WriteError("Internal error: try close unopened file!"); + return 1; + } + + rc = fclose(infp); + infp = NULL; + + if (rc == 0) { + ut.actime = intime; + ut.modtime = intime; + if ((rc = utime(infpath,&ut))) + WriteError("$utime failed"); + } + + if (isfreq) { + if ((rc != 0) || (!success)) { + Syslog('+', "Removing unsuccessfuly received wazoo freq"); + unlink(freqname); + free(freqname); + freqname=NULL; + } + isfreq = FALSE; + } else if ((rc == 0) && success) { + newpath = xstrcpy(inbound); + newpath = xstrcat(newpath, strrchr(infpath,'/')); + + p = newpath + strlen(newpath) - 1; + x = *p; + ncount = 0; + while (((rc = stat(newpath, &st)) == 0) && (ncount++ < 62)) { + if (x == '9') + x = 'a'; + else if (x == 'z') + x = 'A'; + else if (x == 'Z') + x = '0'; + else + x++; + *p = x; + } + if (ncount >= 62) { /* names exhausted */ + rc = 1; + p = strrchr(newpath,'/'); + *p = '\0'; + sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); + free(newpath); + newpath = xstrcpy(p); + newpath = xstrcat(newpath, ctt); + } + + Syslog('S', "moving \"%s\" -> \"%s\"", MBSE_SS(infpath), MBSE_SS(newpath)); + rc = rename(infpath, newpath); + if (rc) + WriteError("$error renaming \"%s\" -> \"%s\"", MBSE_SS(infpath),MBSE_SS(newpath)); + else + gotfiles = TRUE; + free(newpath); + } + free(infpath); + infpath = NULL; + return rc; +} + + diff --git a/mbcico/openfile.h b/mbcico/openfile.h new file mode 100644 index 00000000..3d1ee023 --- /dev/null +++ b/mbcico/openfile.h @@ -0,0 +1,9 @@ +#ifndef _OPENFILE_H +#define _OPENFILE_H + +FILE *openfile(char *, time_t, off_t, off_t *, int(*)(off_t)); +int closefile(int); + + +#endif + diff --git a/mbcico/openport.c b/mbcico/openport.c new file mode 100644 index 00000000..7d945a89 --- /dev/null +++ b/mbcico/openport.c @@ -0,0 +1,617 @@ +/***************************************************************************** + * + * File ..................: mbcico/openport.c + * Purpose ...............: Fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ulock.h" +#include "ttyio.h" +#include "openport.h" + + +static char *openedport = NULL, *pname; +static int need_detach = 1; +extern int f_flags; +static speed_t transpeed(int); +int hanged_up = 0; + + + +void linedrop(int sig) +{ + Syslog('+', "openport: Lost Carrier"); + hanged_up=1; + return; +} + + + +void sigpipe(int sig) +{ + Syslog('+', "openport: Got SIGPIPE"); + hanged_up=1; + return; +} + + + +void interrupt(int sig) +{ + Syslog('+', "openport: Got SIGINT"); + signal(SIGINT,interrupt); + return; +} + + + +int openport(char *port, int speed) +{ + int rc, rc2; + char *errtty=NULL; + int fd; + int outflags; + + Syslog('t', "Try opening port \"%s\" at %d",MBSE_SS(port),speed); + if (openedport) + free(openedport); + openedport = NULL; + if (port[0] == '/') + openedport = xstrcpy(port); + else { + openedport = xstrcpy((char *)"/dev/"); + openedport = xstrcat(openedport, port); + } + pname = strrchr(openedport, '/'); + + if ((rc = lock(pname))) { + Syslog('+', "Port %s is locked (rc = %d)", port, rc); + free(openedport); + openedport = NULL; + return rc; + } + + if (need_detach) { + fflush(stdin); + fflush(stdout); + setbuf(stdin, NULL); + setbuf(stdout, NULL); + close(0); + close(1); + + /* + * If we were manual started the error tty must be closed. + */ + if ((errtty = ttyname(2))) { + Syslog('t', "openport: stderr was on \"%s\", closing",errtty); + fflush(stderr); + close(2); + } + +// if (setpgrp() < 0) { +// WriteError("$openport: setpgrp failed"); +// ulock(pname); +// return 1; +// } + } + tty_status = 0; + hanged_up = 0; + signal(SIGHUP, linedrop); + signal(SIGPIPE, sigpipe); + signal(SIGINT, interrupt); + rc = 0; + rc2 = 0; + + Syslog('T', "Try open %s", MBSE_SS(openedport)); + if ((fd = open(openedport,O_RDONLY|O_NONBLOCK)) != 0) { + rc = 1; + Syslog('+', "$Cannot open \"%s\" as stdin",MBSE_SS(openedport)); + fd = open("/dev/null",O_RDONLY); + } + + if ((fd = open(openedport,O_WRONLY|O_NONBLOCK)) != 1) { + rc = 1; + Syslog('+', "$Cannot open \"%s\" as stdout",MBSE_SS(openedport)); + fd = open("/dev/null",O_WRONLY); + } + + clearerr(stdin); + clearerr(stdout); + if (need_detach) { +#ifdef TIOCSCTTY + if ((rc2 = ioctl(0,TIOCSCTTY,1L)) < 0) { + Syslog('t', "$TIOCSCTTY failed rc = %d", rc2); + } +#endif + if (errtty) { + rc = rc || (open(errtty,O_WRONLY) != 2); + } + need_detach=0; + } + + Syslog('T', "after open rc=%d",rc); + + if (rc) + Syslog('+', "cannot switch i/o to port \"%s\"",MBSE_SS(openedport)); + else { + if (tty_raw(speed)) { + WriteError("$cannot set raw mode for \"%s\"",MBSE_SS(openedport)); + rc=1; + } + + if (((f_flags = fcntl(0, F_GETFL, 0L)) == -1) || ((outflags = fcntl(1, F_GETFL, 0L)) == -1)) { + rc = 1; + WriteError("$GETFL error"); + f_flags = 0; + outflags = 0; + } else { + Syslog('t', "Return to blocking mode"); + f_flags &= ~O_NONBLOCK; + outflags &= ~O_NONBLOCK; + if ((fcntl(0, F_SETFL, f_flags) != 0) || (fcntl(1, F_SETFL, outflags) != 0)) { + rc = 1; + WriteError("$SETFL error"); + } + } + Syslog('T', "File flags: stdin: 0x%04x, stdout: 0x%04x", f_flags,outflags); + } + + if (rc) + closeport(); + else + SetTTY(port); + + return rc; +} + + + +/* + * Set port to local, hangup using DTR drop. + */ +void localport(void) +{ + Syslog('t', "Setting port \"%s\" local",MBSE_SS(openedport)); + signal(SIGHUP,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + if (isatty(0)) + tty_local(); + return; +} + + + +void nolocalport(void) +{ + Syslog('t', "Setting port \"%s\" non-local",MBSE_SS(openedport)); + if (isatty(0)) + tty_nolocal(); + return; +} + + + +int rawport(void) +{ + tty_status = 0; + signal(SIGHUP,linedrop); + signal(SIGPIPE,sigpipe); + + if (isatty(0)) + return tty_raw(0); + else + return 0; +} + + + +int cookedport(void) +{ + signal(SIGHUP,SIG_IGN); + signal(SIGPIPE,SIG_IGN); + if (isatty(0)) + return tty_cooked(); + else + return 0; +} + + + +void closeport(void) +{ + if (openedport == NULL) + return; + + Syslog('t', "Closing port \"%s\"",MBSE_SS(openedport)); + fflush(stdin); + fflush(stdout); + tty_cooked(); + close(0); + close(1); + ulock(pname); + if (openedport) + free(openedport); + openedport = NULL; + SetTTY((char *)"-"); + return; +} + + + +void sendbrk(void) +{ + Syslog('t', "Send break"); + if (isatty(0)) +#if (defined(TIOCSBRK)) + Syslog('t', "TIOCSBRK"); + ioctl(0, TIOCSBRK, 0L); +#elif (defined(TCSBRK)) + Syslog('t', "TCSBRK"); + ioctl(0, TCSBRK, 0L); +#else /* any ideas about BSD? */ + ; +#endif +} + + +static struct termios savetios; +static struct termios tios; + + +char *bstr(speed_t); +char *bstr(speed_t sp) +{ + switch(sp & CBAUD) { + case 0: return (char *)"0"; +#if defined(B50) + case B50: return (char *)"50"; +#endif +#if defined(B75) + case B75: return (char *)"75"; +#endif +#if defined(B110) + case B110: return (char *)"110"; +#endif +#if defined(B134) + case B134: return (char *)"134"; +#endif +#if defined(B150) + case B150: return (char *)"150"; +#endif +#if defined(B200) + case B200: return (char *)"200"; +#endif +#if defined(B300) + case B300: return (char *)"300"; +#endif +#if defined(B600) + case B600: return (char *)"600"; +#endif +#if defined(B1200) + case B1200: return (char *)"1.200"; +#endif +#if defined(B1800) + case B1800: return (char *)"1.800"; +#endif +#if defined(B2400) + case B2400: return (char *)"2.400"; +#endif +#if defined(B4800) + case B4800: return (char *)"4.800"; +#endif +#if defined(B9600) + case B9600: return (char *)"9.600"; +#endif +#if defined(B19200) + case B19200: return (char *)"19.200"; +#endif +#if defined(B38400) + case B38400: return (char *)"38.400"; +#endif +#if defined(B57600) + case B57600: return (char *)"57.600"; +#endif +#if defined(B115200) + case B115200: return (char *)"115.200"; +#endif +#if defined(B230400) + case B230400: return (char *)"230.400"; +#endif +#if defined(B460800) + case B460800: return (char *)"460.800"; +#endif +#if defined(B500000) + case B500000: return (char *)"500.000"; +#endif +#if defined(B576000) + case B576000: return (char *)"576.000"; +#endif +#if defined(B921600) + case B921600: return (char *)"921.600"; +#endif +#if defined(B1000000) + case B1000000: return (char *)"1.000.000"; +#endif +#if defined(B1152000) + case B1152000: return (char *)"1.152.000"; +#endif +#if defined(B1500000) + case B1500000: return (char *)"1.500.000"; +#endif +#if defined(B2000000) + case B2000000: return (char *)"2.000.000"; +#endif +#if defined(B2500000) + case B2500000: return (char *)"2.500.000"; +#endif +#if defined(B3000000) + case B3000000: return (char *)"3.000.000"; +#endif +#if defined(B3500000) + case B3500000: return (char *)"3.500.000"; +#endif +#if defined(B4000000) + case B4000000: return (char *)"4.000.000"; +#endif + default: return (char *)"Unknown"; + } +} + + + + +int tty_raw(int speed) +{ + int rc; + speed_t tspeed, is, os; + + Syslog('t', "Set tty raw"); + tspeed = transpeed(speed); + + if ((rc = tcgetattr(0,&savetios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } else { + Syslog('T', "savetios.c_iflag=0x%08x",savetios.c_iflag); + Syslog('T', "savetios.c_oflag=0x%08x",savetios.c_oflag); + Syslog('T', "savetios.c_cflag=0x%08x",savetios.c_cflag); + Syslog('T', "savetios.c_lflag=0x%08x",savetios.c_lflag); + Syslog('T', "savetios.c_cc=\"%s\"",printable(savetios.c_cc,NCCS)); + Syslog('T', "file flags: stdin: 0x%04x, stdout: 0x%04x", fcntl(0,F_GETFL,0L),fcntl(1,F_GETFL,0L)); + } + + tios = savetios; + tios.c_iflag = 0; + tios.c_oflag = 0; + tios.c_cflag &= ~(CSTOPB | PARENB | PARODD); + tios.c_cflag |= CS8 | CREAD | HUPCL | CLOCAL; + tios.c_lflag = 0; + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; + + if (tspeed) { + cfsetispeed(&tios,tspeed); + cfsetospeed(&tios,tspeed); + } + + if ((rc = tcsetattr(0,TCSADRAIN,&tios))) + WriteError("$tcsetattr(0,TCSADRAIN,raw) return %d",rc); + + is = cfgetispeed(&tios); + os = cfgetospeed(&tios); + + return rc; +} + + + +int tty_local(void) +{ + struct termios Tios; + tcflag_t cflag; + speed_t ispeed, ospeed; + int rc; + + if ((rc = tcgetattr(0,&Tios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } + Syslog('-', "Dropping DTR"); + + cflag = Tios.c_cflag | CLOCAL; + + ispeed = cfgetispeed(&tios); + ospeed = cfgetospeed(&tios); + cfsetispeed(&Tios,0); + cfsetospeed(&Tios,0); + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + WriteError("$tcsetattr(0,TCSADRAIN,hangup) return %d",rc); + + sleep(1); /* as far as I notice, DTR goes back high on next op. */ + + Tios.c_cflag = cflag; + cfsetispeed(&Tios,ispeed); + cfsetospeed(&Tios,ospeed); + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); + return rc; +} + + + +int tty_nolocal(void) +{ + struct termios Tios; + int rc; + + if ((rc = tcgetattr(0,&Tios))) { + WriteError("$tcgetattr(0,save) return %d",rc); + return rc; + } + Tios.c_cflag &= ~CLOCAL; + Tios.c_cflag |= CRTSCTS; + + if ((rc = tcsetattr(0,TCSADRAIN,&Tios))) + Syslog('t', "$tcsetattr(0,TCSADRAIN,clocal) return %d",rc); + return rc; +} + + + +int tty_cooked(void) +{ + int rc; + + if ((rc = tcsetattr(0,TCSAFLUSH,&savetios))) + Syslog('t', "$tcsetattr(0,TCSAFLUSH,save) return %d",rc); + return rc; +} + + + +speed_t transpeed(int speed) +{ + speed_t tspeed; + + switch (speed) + { + case 0: tspeed=0; break; +#if defined(B50) + case 50: tspeed=B50; break; +#endif +#if defined(B75) + case 75: tspeed=B75; break; +#endif +#if defined(B110) + case 110: tspeed=B110; break; +#endif +#if defined(B134) + case 134: tspeed=B134; break; +#endif +#if defined(B150) + case 150: tspeed=B150; break; +#endif +#if defined(B200) + case 200: tspeed=B200; break; +#endif +#if defined(B300) + case 300: tspeed=B300; break; +#endif +#if defined(B600) + case 600: tspeed=B600; break; +#endif +#if defined(B1200) + case 1200: tspeed=B1200; break; +#endif +#if defined(B1800) + case 1800: tspeed=B1800; break; +#endif +#if defined(B2400) + case 2400: tspeed=B2400; break; +#endif +#if defined(B4800) + case 4800: tspeed=B4800; break; +#endif +#if defined(B7200) + case 7200: tspeed=B7200; break; +#endif +#if defined(B9600) + case 9600: tspeed=B9600; break; +#endif +#if defined(B12000) + case 12000: tspeed=B12000; break; +#endif +#if defined(B14400) + case 14400: tspeed=B14400; break; +#endif +#if defined(B19200) + case 19200: tspeed=B19200; break; +#elif defined(EXTA) + case 19200: tspeed=EXTA; break; +#endif +#if defined(B38400) + case 38400: tspeed=B38400; break; +#elif defined(EXTB) + case 38400: tspeed=EXTB; break; +#endif +#if defined(B57600) + case 57600: tspeed=B57600; break; +#endif +#if defined(B115200) + case 115200: tspeed=B115200; break; +#endif +#if defined(B230400) + case 230400: tspeed=B230400; break; +#endif +#if defined(B460800) + case 460800: tspeed=B460800; break; +#endif +#if defined(B500000) + case 500000: tspeed=B500000; break; +#endif +#if defined(B576000) + case 576000: tspeed=B576000; break; +#endif +#if defined(B921600) + case 921600: tspeed=B921600; break; +#endif +#if defined(B1000000) + case 1000000: tspeed=B1000000; break; +#endif +#if defined(B1152000) + case 1152000: tspeed=B1152000; break; +#endif +#if defined(B1500000) + case 1500000: tspeed=B1500000; break; +#endif +#if defined(B2000000) + case 2000000: tspeed=B2000000; break; +#endif +#if defined(B2500000) + case 2500000: tspeed=B2500000; break; +#endif +#if defined(B3000000) + case 3000000: tspeed=B3000000; break; +#endif +#if defined(B3500000) + case 3500000: tspeed=B3500000; break; +#endif +#if defined(B4000000) + case 4000000: tspeed=B4000000; break; +#endif + default: WriteError("requested invalid speed %d",speed); + tspeed=0; break; + } + + return tspeed; +} + + diff --git a/mbcico/openport.h b/mbcico/openport.h new file mode 100644 index 00000000..50a71a70 --- /dev/null +++ b/mbcico/openport.h @@ -0,0 +1,25 @@ +#ifndef _OPENPORT_H +#define _OPENPORT_H + + +void linedrop(int); +void interrupt(int); +#ifdef TIOCWONLINE +void alarmsig(int); +#endif +int openport(char *, int); +void localport(void); +void nolocalport(void); +int rawport(void); +int cookedport(void); +void closeport(void); +void sendbrk(void); + +int tty_raw(int); +int tty_local(void); +int tty_nolocal(void); +int tty_cooked(void); + + +#endif + diff --git a/mbcico/opentcp.c b/mbcico/opentcp.c new file mode 100644 index 00000000..fae29c40 --- /dev/null +++ b/mbcico/opentcp.c @@ -0,0 +1,303 @@ +/***************************************************************************** + * + * File ..................: mbcico/opentcp.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "session.h" +#include "ttyio.h" +#include "openport.h" +#include "opentcp.h" + + +#define BINKPORT 24554 +#define TELNPORT 23 +#define FIDOPORT 60179 /* Eugene G. Crossers birthday */ + + +static int fd=-1; +extern int f_flags; +extern int tcp_mode; +extern time_t c_start; +extern time_t c_end; +extern int online; +extern int master; +extern int carrier; +extern long sentbytes; +extern long rcvdbytes; +extern int Loaded; + + +char telnet_options[256]; +char do_dont_resp[256]; +char will_wont_resp[256]; + +void tel_enter_binary(int rw); +void tel_leave_binary(int rw); +void send_do(register int); +void send_dont(register int); +void send_will(register int); +void send_wont(register int); + +static int tcp_is_open = FALSE; + + +/* opentcp() was rewritten by Martin Junius */ +/* telnet mode was written by T.Tanaka */ + +int opentcp(char *name) +{ + struct servent *se; + struct hostent *he; + int a1,a2,a3,a4; + char *errmsg; + char *portname; + int Fd; + short portnum; + struct sockaddr_in server; + + Syslog('d', "Try open tcp connection to %s",MBSE_SS(name)); + + tcp_is_open = FALSE; + memset(&telnet_options, 0, sizeof(telnet_options)); + server.sin_family = AF_INET; + + if ((portname = strchr(name,':'))) { + *portname++='\0'; + if ((portnum = atoi(portname))) + server.sin_port=htons(portnum); + else if ((se = getservbyname(portname, "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(FIDOPORT); + } else { + switch (tcp_mode) { + case TCPMODE_IFC: if ((se = getservbyname("fido", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(FIDOPORT); + break; + case TCPMODE_ITN: if ((se = getservbyname("tfido", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(TELNPORT); + break; + case TCPMODE_IBN: if ((se = getservbyname("binkd", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(BINKPORT); + break; + default: server.sin_port = htons(FIDOPORT); + } + } + + if (sscanf(name,"%d.%d.%d.%d",&a1,&a2,&a3,&a4) == 4) + server.sin_addr.s_addr = inet_addr(name); + else if ((he = gethostbyname(name))) + memcpy(&server.sin_addr,he->h_addr,he->h_length); + else { + switch (h_errno) { + case HOST_NOT_FOUND: errmsg=(char *)"Authoritative: Host not found"; break; + case TRY_AGAIN: errmsg=(char *)"Non-Authoritive: Host not found"; break; + case NO_RECOVERY: errmsg=(char *)"Non recoverable errors"; break; + default: errmsg=(char *)"Unknown error"; break; + } + Syslog('+', "No IP address for %s: %s\n", name, errmsg); + return -1; + } + + Syslog('d', "Trying %s at port %d", + inet_ntoa(server.sin_addr),(int)ntohs(server.sin_port)); + + signal(SIGPIPE,linedrop); + fflush(stdin); + fflush(stdout); + setbuf(stdin,NULL); + setbuf(stdout,NULL); + close(0); + close(1); + if ((Fd = socket(AF_INET,SOCK_STREAM,0)) != 0) { + WriteError("$Cannot create socket (got %d, expected 0"); + open("/dev/null",O_RDONLY); + open("/dev/null",O_WRONLY); + return -1; + } + if (dup(Fd) != 1) { + WriteError("$Cannot dup socket"); + open("/dev/null",O_WRONLY); + return -1; + } + clearerr(stdin); + clearerr(stdout); + if (connect(Fd,(struct sockaddr *)&server,sizeof(server)) == -1) { + Syslog('+', "Cannot connect %s",inet_ntoa(server.sin_addr)); + return -1; + } + + f_flags=0; + + switch (tcp_mode) { + case TCPMODE_ITN: tel_enter_binary(3); + Syslog('+', "Established ITN/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + case TCPMODE_IFC: Syslog('+', "Established IFC/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + case TCPMODE_IBN: Syslog('+', "Established IBN/TCP connection with %s", inet_ntoa(server.sin_addr)); + break; + default: WriteError("Established TCP connection with unknow protocol"); + } + c_start = time(NULL); + carrier = TRUE; + tcp_is_open = TRUE; + return 0; +} + + + +void closetcp(void) +{ + FILE *fph; + char *tmp; + + if (!tcp_is_open) + return; + + Syslog('d', "Closing TCP connection"); + + if (tcp_mode == TCPMODE_ITN) + tel_leave_binary(3); + + shutdown(fd,2); + signal(SIGPIPE,SIG_DFL); + + if (carrier) { + c_end = time(NULL); + online += (c_end - c_start); + Syslog('+', "Connection time %s", t_elapsed(c_start, c_end)); + carrier = FALSE; + history.offline = c_end; + history.online = c_start; + history.sent_bytes = sentbytes; + history.rcvd_bytes = rcvdbytes; + history.inbound = ~master; + tmp = calloc(128, sizeof(char)); + sprintf(tmp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fph = fopen(tmp, "a")) == NULL) + WriteError("$Can't open %s", tmp); + else { + Syslog('s', "closetcp() write history"); + fwrite(&history, sizeof(history), 1, fph); + fclose(fph); + } + free(tmp); + memset(&history, 0, sizeof(history)); + if (Loaded) { + Syslog('s', "Updateing noderecord %s", aka2str(nodes.Aka[0])); + nodes.LastDate = time(NULL); + UpdateNode(); + } + } + tcp_is_open = FALSE; +} + + + +void tel_enter_binary(int rw) +{ + Syslog('d', "Telnet enter binary %d", rw); + if (rw & 1) + send_do(TELOPT_BINARY); + if (rw & 2) + send_will(TELOPT_BINARY); + + send_dont(TELOPT_ECHO); + send_do(TELOPT_SGA); + send_dont(TELOPT_RCTE); + send_dont(TELOPT_TTYPE); + + send_wont(TELOPT_ECHO); + send_will(TELOPT_SGA); + send_wont(TELOPT_RCTE); + send_wont(TELOPT_TTYPE); +} + + + +void tel_leave_binary(int rw) +{ + Syslog('d', "Telnet leave binary %d", rw); + if (rw & 1) + send_dont(TELOPT_BINARY); + if (rw & 2) + send_wont(TELOPT_BINARY); +} + + + +/* + * These routines are in charge of sending option negotiations + * to the other side. + * The basic idea is that we send the negotiation if either side + * is in disagreement as to what the current state should be. + */ + +void send_do(register int c) +{ + NET2ADD(IAC, DO); + NETADD(c); +} + + +void send_dont(register int c) +{ + NET2ADD(IAC, DONT); + NETADD(c); +} + + +void send_will(register int c) +{ + NET2ADD(IAC, WILL); + NETADD(c); +} + + +void send_wont(register int c) +{ + NET2ADD(IAC, WONT); + NETADD(c); +} + + + diff --git a/mbcico/opentcp.h b/mbcico/opentcp.h new file mode 100644 index 00000000..431c8311 --- /dev/null +++ b/mbcico/opentcp.h @@ -0,0 +1,81 @@ +#ifndef _OPENTCP_H +#define _OPENTCP_H + +int opentcp(char *); +void closetcp(void); + +#define PUTCHAR(x) tty_putc(x) + +#define ClearArray(x) memset((char *)x, 0, sizeof x) + +#define NETADD(c) { PUTCHAR(c); } +#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } + +#define MY_STATE_WILL 0x01 +#define MY_WANT_STATE_WILL 0x02 +#define MY_STATE_DO 0x04 +#define MY_WANT_STATE_DO 0x08 +#define my_state_is_do(opt) (telnet_options[opt]&MY_STATE_DO) +#define my_state_is_will(opt) (telnet_options[opt]&MY_STATE_WILL) +#define my_want_state_is_do(opt) (telnet_options[opt]&MY_WANT_STATE_DO) +#define my_want_state_is_will(opt) (telnet_options[opt]&MY_WANT_STATE_WILL) +#define my_state_is_dont(opt) (!my_state_is_do(opt)) +#define my_state_is_wont(opt) (!my_state_is_will(opt)) +#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) +#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) +#define set_my_want_state_do(opt) {telnet_options[opt] |= MY_WANT_STATE_DO;} +#define set_my_want_state_will(opt) {telnet_options[opt] |= MY_WANT_STATE_WILL;} +#define set_my_want_state_dont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_DO;} +#define set_my_want_state_wont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_WILL;} + +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_ENVIRON 36 /* Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ + + +#endif + diff --git a/mbcico/outstat.c b/mbcico/outstat.c new file mode 100644 index 00000000..50c6507e --- /dev/null +++ b/mbcico/outstat.c @@ -0,0 +1,354 @@ +/***************************************************************************** + * + * File ..................: mbcico/outstat.c + * Purpose ...............: Show mail outbound status + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "scanout.h" +#include "callstat.h" +#include "outstat.h" + + +extern int do_quiet; + + +static struct _alist +{ + struct _alist *next; + faddr addr; + int flavors; + time_t time; + off_t size; +} *alist = NULL; + + +#define F_NORMAL 1 +#define F_CRASH 2 +#define F_IMM 4 +#define F_HOLD 8 +#define F_FREQ 16 +#define F_POLL 32 + + + +int outstat() +{ + int rc; + struct _alist *tmp, *old; + char flstr[6]; + time_t age; + char temp[81]; + + if ((rc = scanout(each))) { + WriteError("Error scanning outbound, aborting"); + return rc; + } + + if (!do_quiet) { + colour(10, 0); + printf("flavor size age address\n"); + colour(3, 0); + } + + Syslog('+', "Flavor Size Age Address"); + for (tmp = alist; tmp; tmp = tmp->next) { + if ((tmp->flavors & F_FREQ) || (tmp->size) || 1) { + strcpy(flstr,"......"); + if ((tmp->flavors) & F_IMM ) flstr[0]='I'; + if ((tmp->flavors) & F_CRASH ) flstr[1]='C'; + if ((tmp->flavors) & F_NORMAL) flstr[2]='N'; + if ((tmp->flavors) & F_HOLD ) flstr[3]='H'; + if ((tmp->flavors) & F_FREQ ) flstr[4]='R'; + if ((tmp->flavors) & F_POLL ) flstr[5]='P'; + + (void)time(&age); + age -= tmp->time; + sprintf(temp, "%s %8lu %s %s", flstr, (long)tmp->size, str_time(age), ascfnode(&(tmp->addr), 0x1f)); + + if (!do_quiet) + printf("%s\n", temp); + Syslog('+', "%s", temp); + } + } + + for (tmp = alist; tmp; tmp = old) { + old = tmp->next; + free(tmp->addr.domain); + free(tmp); + } + alist = NULL; + + return 0; +} + + + +int each(faddr *addr, char flavor, int isflo, char *fname) +{ + struct _alist **tmp; + struct stat st; + FILE *fp; + char buf[256], *p; + + if ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_REQ) && (isflo != OUT_POL)) + return 0; + + for (tmp = &alist; *tmp; tmp = &((*tmp)->next)) + if (((*tmp)->addr.zone == addr->zone) && ((*tmp)->addr.net == addr->net) && + ((*tmp)->addr.node == addr->node) && ((*tmp)->addr.point == addr->point) && + (((*tmp)->addr.domain == NULL) || (addr->domain == NULL) || + (strcasecmp((*tmp)->addr.domain,addr->domain) == 0))) + break; + if (*tmp == NULL) { + *tmp = (struct _alist *)malloc(sizeof(struct _alist)); + (*tmp)->next = NULL; + (*tmp)->addr.name = NULL; + (*tmp)->addr.zone = addr->zone; + (*tmp)->addr.net = addr->net; + (*tmp)->addr.node = addr->node; + (*tmp)->addr.point = addr->point; + (*tmp)->addr.domain = xstrcpy(addr->domain); + (*tmp)->flavors = 0; + time(&((*tmp)->time)); + (*tmp)->size = 0L; + } + + if ((isflo == OUT_FLO) || (isflo == OUT_PKT)) + switch (flavor) { + case '?': break; + case 'i': (*tmp)->flavors |= F_IMM; break; + case 'o': (*tmp)->flavors |= F_NORMAL; break; + case 'c': (*tmp)->flavors |= F_CRASH; break; + case 'h': (*tmp)->flavors |= F_HOLD; break; + default: WriteError("Unknown flavor: '%c'\n",flavor); break; + } + + if (stat(fname,&st) != 0) { + WriteError("$Can't stat %s", fname); + st.st_size = 0L; + (void)time(&st.st_mtime); + } + + /* + * Find the oldest time + */ + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + + if (isflo == OUT_FLO) { + if ((fp = fopen(fname,"r"))) { + while (fgets(buf, sizeof(buf) - 1, fp)) { + if (*(p = buf + strlen(buf) - 1) == '\n') + *p-- = '\0'; + while (isspace(*p)) + *p-- = '\0'; + for (p = buf; *p; p++) + if (*p == '\\') + *p='/'; + for (p = buf; *p && isspace(*p); p++); + if (*p == '~') continue; + if ((*p == '#') || (*p == '-') || (*p == '^') || (*p == '@')) + p++; + if (stat(p, &st) != 0) { + if (strlen(CFG.dospath)) { + if (stat(Dos2Unix(p), &st) != 0) { + /* + * Fileattach dissapeared, maybe + * the node doesn't poll enough and + * is losing mail or files. + */ + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } else { + if (stat(p, &st) != 0) { + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } + } + + if ((p = strrchr(fname,'/'))) + p++; + else + p = fname; + if ((strlen(p) == 12) && (strspn(p,"0123456789abcdefABCDEF") == 8) && (p[8] == '.')) { + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + } + (*tmp)->size += st.st_size; + } + fclose(fp); + } else + WriteError("Can't open %s", fname); + + } else if (isflo == OUT_PKT) { + (*tmp)->size += st.st_size; + } else if (isflo == OUT_REQ) { + (*tmp)->flavors |= F_FREQ; + } else if (isflo == OUT_POL) { + (*tmp)->flavors |= F_POLL; + } + + return 0; +} + + + +int IsZMH(void); +int IsZMH() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,2", 7) == 0) + return TRUE; + } + return FALSE; +} + + + +int poll(faddr *addr, int stop) +{ + char *pol; + int rc = 0; + FILE *fp; + callstat *cst; + node *nlent; + + if (addr == NULL) + return 0; + + pol = polname(addr); + + if (stop) { + if (access(pol, R_OK) == 0) { + rc = unlink(pol); + if (rc == 0) { + Syslog('+', "Removed poll for %s", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Removed poll for %s\n", ascfnode(addr, 0x1f)); + } + } else { + Syslog('+', "No poll found for %s", ascfnode(addr, 0x1f)); + } + } else { + nlent = getnlent(addr); + if (nlent->pflag == NL_DUMMY) { + Syslog('+', "Node %s not in nodelist", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s not in nodelist", ascfnode(addr, 0x1f)); + return 1; + } + if (nlent->pflag == NL_DOWN) { + Syslog('+', "Node %s has status Down", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s has status Down", ascfnode(addr, 0x1f)); + return 1; + } + if (nlent->pflag == NL_HOLD) { + Syslog('+', "Node %s has status Hold", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Node %s has status Hold", ascfnode(addr, 0x1f)); + return 1; + } + + if ((fp = fopen(pol, "w+")) == NULL) { + WriteError("$Can't create poll for %s", ascfnode(addr, 0x1f)); + rc = 1; + } else { + fclose(fp); + if (((nlent->oflags & OL_CM) == 0) && (!IsZMH())) { + Syslog('+', "Created poll for %s, non-CM node outside ZMH", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Created poll for %s, non-CM node outside ZMH\n", ascfnode(addr, 0x1f)); + } else { + Syslog('+', "Created poll for %s", ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("Created poll for %s\n", ascfnode(addr, 0x1f)); + } + cst = getstatus(addr); + if ((cst->trystat == 5) || + (cst->trystat == ST_NOTZMH) || + (cst->trystat == ST_NOCONN) || + (cst->trystat == ST_NOCALL7) || + (cst->trystat == ST_NOCALL8) || + (cst->trystat > 10)) { + putstatus(addr, 0, 0); + } + CreateSema((char *)"scanout"); + } + } + + return 0; +} + + + +int freq(faddr *addr, char *fname) +{ + char *req; + FILE *fp; + + Syslog('o', "Freq %s %s", ascfnode(addr, 0x1f), fname); + + /* + * Append filename to .req file + */ + req = xstrcpy(reqname(addr)); + if ((fp = fopen(req, "a")) == NULL) { + WriteError("$Can't append to %s", req); + if (!do_quiet) + printf("File request failed\n"); + free(req); + return 1; + } + fprintf(fp, "%s\r\n", fname); + fclose(fp); + + Syslog('+', "File request \"%s\" from %s", fname, ascfnode(addr, 0x1f)); + if (!do_quiet) + printf("File request \"%s\" from %s\n", fname, ascfnode(addr, 0x1f)); + + free(req); + return 0; +} + + + diff --git a/mbcico/outstat.h b/mbcico/outstat.h new file mode 100644 index 00000000..d6b600cd --- /dev/null +++ b/mbcico/outstat.h @@ -0,0 +1,12 @@ +#ifndef _OUTSTAT_H +#define _OUTSTAT_H + + +int each(faddr *, char, int, char *); +int outstat(void); +int poll(faddr *, int); +int freq(faddr *, char *); + + +#endif + diff --git a/mbcico/portsel.c b/mbcico/portsel.c new file mode 100644 index 00000000..c24bb3b1 --- /dev/null +++ b/mbcico/portsel.c @@ -0,0 +1,254 @@ +/***************************************************************************** + * + * File ..................: mbcico/portsel.c + * Purpose ...............: Fidonet mailer + * Last modification date : 06-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "portsel.h" + + +extern char *name, *phone, *flags; + + +/* + * Tidy the portlist array + */ +void tidy_pplist(pp_list ** fdp) +{ + pp_list *tmp, *old; + int i; + + Syslog('D', "tidy_pplist"); + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + for (i = 0; i < MAXUFLAGS; i++) + if (tmp->uflags[i]) + free(tmp->uflags[i]); + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a port to the array + */ +void fill_pplist(pp_list **fdp, pp_list *new) +{ + pp_list *tmp, *ta; + int i; + + tmp = (pp_list *)malloc(sizeof(pp_list)); + tmp->next = NULL; + sprintf(tmp->tty, "%s", new->tty); + tmp->mflags = new->mflags; + tmp->dflags = new->dflags; + tmp->iflags = new->iflags; + moflags(new->mflags); + diflags(new->dflags); + ipflags(new->iflags); + tmp->match = TRUE; + for (i = 0; i < MAXUFLAGS; i++) + tmp->uflags[i] = xstrcpy(new->uflags[i]); + + if (*fdp == NULL) + *fdp = tmp; + else { + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (pp_list *)tmp; + break; + } + } +} + + + +/* + * Make a list of available ports to use for dialout. The ports + * are selected on the available modem flags and the remote node + * modem type. + */ +int make_portlist(node *nlent, pp_list **tmp) +{ + char *temp, *p, *q; + FILE *fp; + int count = 0, j, ixflag, stdflag; + pp_list new; + + tidy_pplist(tmp); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return 0; + } + + Syslog('d', "Building portlist..."); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + + if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && (ttyinfo.available) && (ttyinfo.callout)) { + memset(&new, 0, sizeof(new)); + sprintf(new.tty, "%s", ttyinfo.tty); + stdflag = TRUE; + ixflag = 0; + q = xstrcpy(ttyinfo.flags); + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + new.mflags |= fkey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + new.dflags |= dkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + new.uflags[ixflag++] = p; + } + } + } + } + Syslog('d', "flags: nodelist port %s", new.tty); + Syslog('d', "modem %08lx %08lx", nlent->mflags, new.mflags); + Syslog('d', "ISDN %08lx %08lx", nlent->dflags, new.dflags); + + if ((nlent->mflags & new.mflags) || (nlent->dflags & new.dflags)) { + fill_pplist(tmp, &new); + count++; + Syslog('d', "make_portlist add %s", ttyinfo.tty); + } + } + } + + fclose(fp); + free(temp); + + /* FIXME: sort ports on priority and remove ports with low speed. */ + + Syslog('d', "make_portlist %d ports", count); + return count; +} + + + +int load_port(char *tty) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + + free(temp); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + if ((strcmp(ttyinfo.tty, tty) == 0) && (ttyinfo.available)) { + fclose(fp); + + /* + * Override EMSI parameters. + */ + if (strlen(ttyinfo.phone)) { + free(phone); + phone = xstrcpy(ttyinfo.phone); + } + if (strlen(ttyinfo.flags)) { + free(flags); + flags = xstrcpy(ttyinfo.flags); + } + if (strlen(ttyinfo.name)) { + free(name); + name = xstrcpy(ttyinfo.name); + } + + if ((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) + return load_modem(ttyinfo.modem); + else + return TRUE; + } + } + + fclose(fp); + memset(&ttyinfo, 0, sizeof(ttyinfo)); + return FALSE; +} + + + +int load_modem(char *ModemName) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + + free(temp); + fread(&modemhdr, sizeof(modemhdr), 1, fp); + + while (fread(&modem, modemhdr.recsize, 1, fp) == 1) { + if ((strcmp(modem.modem, ModemName) == 0) && (modem.available)) { + fclose(fp); + return TRUE; + } + } + + fclose(fp); + memset(&modem, 0, sizeof(modem)); + return FALSE; +} + + diff --git a/mbcico/portsel.h b/mbcico/portsel.h new file mode 100644 index 00000000..22b60c25 --- /dev/null +++ b/mbcico/portsel.h @@ -0,0 +1,24 @@ +#ifndef _PORTSEL_H +#define _PORTSEL_H + + +typedef struct _pp_list { + struct _pp_list *next; + char tty[7]; /* tty name of the port */ + unsigned long mflags; /* Analogue Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + char *uflags[MAXUFLAGS]; /* User flags */ + int match; /* Does port match */ +} pp_list; + + +void tidy_pplist(pp_list **); +void fill_pplist(pp_list **, pp_list *); +int make_portlist(node *, pp_list **); +int load_port(char *); +int load_modem(char *); + + +#endif + diff --git a/mbcico/rdoptions.c b/mbcico/rdoptions.c new file mode 100644 index 00000000..65ea7f56 --- /dev/null +++ b/mbcico/rdoptions.c @@ -0,0 +1,138 @@ +/***************************************************************************** + * + * File ..................: mbcico/rdoptions.c + * Purpose ...............: Fidonet mailer + * Last modification date : 13-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "portsel.h" +#include "session.h" +#include "config.h" + +int localoptions; + + +static struct _ktab { + char *key; + int flag; +} ktab[] = { + {(char *)"Call", NOCALL}, + {(char *)"Hold", NOHOLD}, + {(char *)"PUA", NOPUA}, + {(char *)"WaZOO", NOWAZOO}, + {(char *)"EMSI", NOEMSI}, + {(char *)"Freqs", NOFREQS}, + {(char *)"Zmodem", NOZMODEM}, + {(char *)"ZedZap", NOZEDZAP}, + {(char *)"Hydra", NOHYDRA}, + {(char *)"Tcp", NOTCP}, + {NULL, 0} +}; + + + +void logoptions(void) +{ + int i; + char *s = NULL; + + for (i=0;ktab[i].key;i++) { + s=xstrcat(s,(char *)" "); + if (localoptions & ktab[i].flag) + s=xstrcat(s,(char *)"No"); + s=xstrcat(s,ktab[i].key); + } + + Syslog('+', "Options:%s",s); + free(s); +} + + + +void rdoptions(int Loaded) +{ + localoptions=0; + if (CFG.NoFreqs) + localoptions |= NOFREQS; + if (CFG.NoCall) + localoptions |= NOCALL; + if (CFG.NoHold) + localoptions |= NOHOLD; + if (CFG.NoPUA) + localoptions |= NOPUA; + if (CFG.NoEMSI) + localoptions |= NOEMSI; + if (CFG.NoWazoo) + localoptions |= NOWAZOO; + if (CFG.NoZmodem) + localoptions |= NOZMODEM; + if (CFG.NoZedzap) + localoptions |= NOZEDZAP; + if (CFG.NoHydra) + localoptions |= NOHYDRA; + if (CFG.NoTCP) + localoptions |= NOTCP; + + if (nodes.Aka[0].zone == 0) { + if (Loaded) + Syslog('s', "Node not in setup, using default options"); + logoptions(); + return; + } + + Syslog('s', "rdoptions node %s %s", nodes.Sysop, aka2str(nodes.Aka[0])); + + if (nodes.NoEMSI) + localoptions |= NOEMSI; + if (nodes.NoWaZOO) + localoptions |= NOWAZOO; + if (nodes.NoFreqs) + localoptions |= NOFREQS; + if (nodes.NoCall) + localoptions |= NOCALL; + if (nodes.NoHold) + localoptions |= NOHOLD; + if (nodes.NoPUA) + localoptions |= NOPUA; + if (nodes.NoZmodem) + localoptions |= NOZMODEM; + if (nodes.NoZedzap) + localoptions |= NOZEDZAP; + if (nodes.NoHydra) + localoptions |= NOHYDRA; + if (nodes.NoTCP) + localoptions |= NOTCP; + + logoptions(); +} + diff --git a/mbcico/rdoptions.h b/mbcico/rdoptions.h new file mode 100644 index 00000000..759d625e --- /dev/null +++ b/mbcico/rdoptions.h @@ -0,0 +1,7 @@ +#ifndef _RDOPTIONS_H +#define _RDOPTIONS_H + +void rdoptions(int); + +#endif + diff --git a/mbcico/recvbark.c b/mbcico/recvbark.c new file mode 100644 index 00000000..dcafdf9d --- /dev/null +++ b/mbcico/recvbark.c @@ -0,0 +1,230 @@ +/***************************************************************************** + * + * File ..................: mbcico/recvbark.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "recvbark.h" +#include "respfreq.h" +#include "filelist.h" + + +static int recv_bark(void); +extern int xmsndfiles(file_list*); + + +int recvbark(void) +{ + if ((session_flags & SESSION_BARK) && !(localoptions & NOFREQS)) { + return recv_bark(); + } else { /* deny requests */ + PUTCHAR(CAN); + return STATUS; + } +} + + + +SM_DECL(recv_bark,(char *)"recvbark") +SM_STATES + sendenq, + waitack, + waitchar, + scanreq, + sendack, + waitnak, + sendfiles +SM_NAMES + (char *)"sendenq", + (char *)"waitack", + (char *)"waitchar", + (char *)"scanreq", + (char *)"sendack", + (char *)"waitnak", + (char *)"sendfiles" +SM_EDECL + + int c, c1, c2; + short lcrc, rcrc; + char buf[256], *p = NULL; + int count = 0,rc = 0; + file_list *tosend = NULL; + +SM_START(sendenq) + +SM_STATE(sendenq) + + Syslog('s', "recvbark SENDINQ"); + + count = 0; + PUTCHAR(ENQ); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('s', "recvbark WAITACK"); + + if (count++ > 10) { + Syslog('+', "Wait for Bark Request: timeout"); + PUTCHAR(ETB); + SM_SUCCESS; /* Yes, this is allright. */ + } + + c = GETCHAR(2); + if (c == TIMEOUT) { + Syslog('s', " timeout, send ENQ"); + PUTCHAR(ENQ); + SM_PROCEED(waitack); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: p = buf; + SM_PROCEED(waitchar); + break; + case ETB: SM_SUCCESS; + break; + case ENQ: PUTCHAR(ETB); + SM_PROCEED(sendenq); + break; + case EOT: PUTCHAR(ACK); + SM_PROCEED(waitack); + break; + default: Syslog('s', "Recvbark got '%s' waiting for ACK", printablec(c)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(waitchar) + + Syslog('s', "recvbark WAITCHAR"); + c=GETCHAR(15); + if (c == TIMEOUT) { + Syslog('s', "Recvbark got timeout waiting for char"); + SM_PROCEED(sendenq); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: SM_PROCEED(waitchar); + break; + case ETX: *p = '\0'; + SM_PROCEED(scanreq); + break; + case SUB: SM_PROCEED(sendenq); + break; + default: if ((p - buf) < sizeof(buf)) + *p++= c; + SM_PROCEED(waitchar); + break; + } + +SM_STATE(scanreq) + + Syslog('s', "recvbark SCANREQ"); + lcrc = crc16xmodem(buf, strlen(buf)); + c1 = GETCHAR(15); + if (c1 == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c1 < 0) { + SM_ERROR; + } + c2 = GETCHAR(15); + if (c2 == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c2 < 0) { + SM_ERROR; + } + rcrc = (c2 << 8) + (c1 & 0xff); + if (lcrc != rcrc) { + Syslog('s', "lcrc 0x%04x != rcrc 0x%04x", lcrc, rcrc); + PUTCHAR(NAK); + SM_PROCEED(sendenq); + } + SM_PROCEED(sendack); + +SM_STATE(sendack) + + Syslog('s', "recvbark SENDACK"); + count = 0; + PUTCHAR(ACK); + tosend = respond_bark(buf); + SM_PROCEED(waitnak); + +SM_STATE(waitnak) + + Syslog('s', "recvbark WAITNAK count=%d, count"); + + if (count++ > 5) { + SM_ERROR; + } + c = GETCHAR(3); + if (c == TIMEOUT) { + Syslog('s', " timeout"); + PUTCHAR(ACK); + SM_PROCEED(waitnak); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case NAK: session_flags &= ~FTSC_XMODEM_CRC; /* fallthrough */ + case 'C': session_flags |= FTSC_XMODEM_CRC; + SM_PROCEED(sendfiles); + break; + case ENQ: PUTCHAR(ETB); + SM_PROCEED(waitack); + break; + case SUB: SM_PROCEED(sendenq); + break; + default: Syslog('s', "Recvbark got '%s' waiting for NAK", printablec(c)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(sendfiles) + + Syslog('s', "recvbark SENDFILES"); + rc = xmsndfiles(tosend); + tidy_filelist(tosend, 0); + if (rc == 0) { + SM_PROCEED(sendenq); + } else { + SM_ERROR; + } + +SM_END +SM_RETURN + diff --git a/mbcico/recvbark.h b/mbcico/recvbark.h new file mode 100644 index 00000000..31b0512f --- /dev/null +++ b/mbcico/recvbark.h @@ -0,0 +1,7 @@ +#ifndef _RECVBARK_H +#define _RECVBARK_H + +int recvbark(void); + +#endif + diff --git a/mbcico/respfreq.c b/mbcico/respfreq.c new file mode 100644 index 00000000..edd52a79 --- /dev/null +++ b/mbcico/respfreq.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbcico/respfreq.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "lutil.h" +#include "config.h" +#include "atoul.h" +#include "respfreq.h" +#include "filelist.h" + + +#ifndef S_ISDIR +#define S_ISDIR(st_mode) (((st_mode) & S_IFMT) == S_IFDIR) +#endif +#ifndef S_ISREG +#define S_ISREG(st_mode) (((st_mode) & S_IFMT) == S_IFREG) +#endif + + +extern char *freqname; + +static void attach_report(file_list**); +static void add_report(char *, ...); +static char *report_text = NULL; +static unsigned long report_total = 0L; +static unsigned long report_count = 0L; +static int no_more = FALSE; + + + +file_list *respond_wazoo(void) +{ + char buf[256]; + char *nm, *pw, *dt, *p; + file_list *fl=NULL, **tmpl; + FILE *fp; + + if (freqname == NULL) + return NULL; + + if ((fp=fopen(freqname,"r")) == NULL) { + WriteError("$cannot open received wazoo freq \"%s\"",freqname); + unlink(freqname); + free(freqname); + freqname=NULL; + return NULL; + } + + tmpl=&fl; + while (fgets(buf,sizeof(buf)-1,fp)) { + nm = NULL; + pw = NULL; + dt = NULL; + p = strtok(buf," \n\r"); + if ((p == NULL) || (*p == '\0')) + continue; + nm = p; + p = strtok(NULL," \n\r"); + if (p && (*p == '!')) + pw = p+1; + else + if (p && ((*p == '+') || (*p == '-'))) + dt = p; + p = strtok(NULL," \n\r"); + if (p && (*p == '!')) + pw = p+1; + else + if (p && ((*p == '+') || (*p == '-'))) + dt = p; + *tmpl = respfreq(nm, pw, dt); + while (*tmpl) tmpl=&((*tmpl)->next); + if (no_more) + break; + } + + fclose(fp); + unlink(freqname); + free(freqname); + freqname = NULL; + for (tmpl = &fl; *tmpl; tmpl = &((*tmpl)->next)) { + Syslog('F', "resplist: %s",MBSE_SS((*tmpl)->local)); + } + attach_report(&fl); + return fl; +} + + + +file_list *respond_bark(char *buf) +{ + char *nm, *pw, *dt, *p; + file_list *fl; + + nm = buf; + pw = (char *)""; + dt = (char *)"0"; + while (isspace(*nm)) + nm++; + for (p = nm; *p && (!isspace(*p)); p++); + if (*p) { + *p++ = '\0'; + dt = p; + while (isspace(*dt)) + dt++; + for (p = dt; *p && (!isspace(*p)); p++); + if (*p) { + *p++ = '\0'; + pw = p; + while (isspace(*pw)) + pw++; + for (p = pw; *p && (!isspace(*p)); p++); + *p = '\0'; + } + } + fl = respfreq(nm, pw, dt); + attach_report(&fl); + return fl; +} + + + +file_list *respfreq(char *nm, char *pw, char *dt) +{ + file_list *fl = NULL; + struct stat st; + char mask[256], *p, *q; + char *tnm, *t; + time_t upd = 0L; + int newer = 1; + FILE *fa, *fb, *fi; + long Area; + int Send; + struct FILEIndex idx; + + if (localoptions & NOFREQS) { + Syslog('+', "File requests disabled"); + add_report((char *)"ER: \"%s\" denied: file requests disabled", nm); + return NULL; + } + + if (strchr(nm, '/') || strchr(nm, '\\') || strchr(nm, ':')) { + Syslog('+', "Illegal characters in request"); + add_report((char *)"ER: \"%s\" denied: illegal characters", nm); + return NULL; + } + + if (dt) { + if (*dt == '+') { + newer = 1; + dt++; + } else if (*dt == '-') { + newer = 0; + dt++; + } else + newer = 1; + upd=atoul(dt); + } + + if (strlen(CFG.req_magic)) { + /* + * Check for uppercase and lowercase magic names. + */ + tnm = xstrcpy(CFG.req_magic); + tnm = xstrcat(tnm,(char *)"/"); + tnm = xstrcat(tnm,tl(xstrcpy(nm))); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode))) { + if (access(tnm, X_OK) == 0) { + return respmagic(tnm); + /* respmagic will free(tnm) */ + } else if (access(tnm, R_OK) == 0) { + return resplist(tnm, pw, dt); + /* resplist will free(tnm) */ + } else + free(tnm); + } else + free(tnm); + + tnm = xstrcpy(CFG.req_magic); + tnm = xstrcat(tnm,(char *)"/"); + t = xstrcpy(nm); + tnm = xstrcat(tnm,tu(t)); + free(t); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode))) { + if (access(tnm, X_OK) == 0) { + return respmagic(tnm); + /* respmagic will free(tnm) */ + } else if (access(tnm, R_OK) == 0) { + return resplist(tnm, pw, dt); + /* resplist will free(tnm) */ + } else + free(tnm); + } else free(tnm); + } + + Syslog('+', "File request : %s (update (%s), password \"%s\")",MBSE_SS(nm),MBSE_SS(dt),MBSE_SS(pw)); + add_report((char *)"RQ: Regular file \"%s\"",nm); + p = tl(nm); + q = mask; + *q++ = '^'; + while ((*p) && (q < (mask + sizeof(mask) - 4))) { + switch (*p) { + case '\\': *q++ = '\\'; *q++ = '\\'; break; + case '?': *q++ = '.'; break; + case '.': *q++ = '\\'; *q++ = '.'; break; + case '+': *q++ = '\\'; *q++ = '+'; break; + case '*': *q++ = '.'; *q++ = '*'; break; + default: *q++ = toupper(*p); break; + } + p++; + } + *q++ = '$'; + *q = '\0'; + Syslog('f', "Search mask \"%s\"", mask); + re_comp(mask); + + /* + * Open the areas database and request index. + */ + p = xstrcpy(getenv("MBSE_ROOT")); + p = xstrcat(p, (char *)"/etc/fareas.data"); + if ((fa = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + return NULL; + } + free(p); + fread(&areahdr, sizeof(areahdr), 1, fa); + + p = xstrcpy(getenv("MBSE_ROOT")); + p = xstrcat(p, (char *)"/etc/request.index"); + if ((fi = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + return NULL; + } + Area = 0L; + free(p); + + while (!no_more && (fread(&idx, sizeof(idx), 1, fi) == 1)) { + if (re_exec(idx.Name) || re_exec(idx.LName)) { + Syslog('f', "Index found %s area %d record %d", idx.LName, idx.AreaNum, idx.Record); + if (fseek(fa, ((idx.AreaNum - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET) == -1) { + WriteError("$Can't seek in fareas.data"); + return NULL; + } + if (fread(&area, areahdr.recsize, 1, fa) != 1) { + WriteError("$Can't read record %d in fareas.data", idx.AreaNum); + return NULL; + } + Syslog('f', "Area %s", area.Name); + p = calloc(128, sizeof(char)); + sprintf(p, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), idx.AreaNum); + if ((fb = fopen(p, "r+")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + } else { + free(p); + if (fseek(fb, idx.Record * sizeof(file), SEEK_SET) == -1) { + WriteError("$Can't seek filerecord %d", idx.Record); + } else { + if (fread(&file, sizeof(file), 1, fb) != 1) { + WriteError("$Can't read filerecord %d", idx.Record); + } else { + Send = FALSE; + Syslog('f', "Found \"%s\" in %s", file.Name, area.Name); + tnm = xstrcpy(area.Path); + tnm = xstrcat(tnm, (char *)"/"); + tnm = xstrcat(tnm, file.Name); + if ((stat(tnm, &st) == 0) && + (S_ISREG(st.st_mode)) && + (access(tnm, R_OK) == 0) && + ((upd == 0L) || + ((newer) && (st.st_mtime <= upd)))) { + Send = TRUE; + } + + /* + * If no password is given, we do not respond + * on requests to password protected areas + * or files in case it was a wildcard request. + * Wrong passwords are honored with an error + * response. + */ + if (Send && strlen(area.Password)) { + if (pw != NULL) { + if (strcasecmp(area.Password, pw)) { + Send = FALSE; + Syslog('+', "Bad password for area %s", area.Name); + add_report((char *)"ER: bad password for area %s", area.Name); + } + } else { + Send = FALSE; + } + } + + if (Send && strlen(file.Password)) { + if (pw != NULL) { + if (strcasecmp(file.Password, pw)) { + Send = FALSE; + Syslog('+', "Bad password for file %s", file.Name); + add_report((char *)"ER: bad password for file %s", file.Name); + } + } else { + Send = FALSE; + } + } + + if (Send && CFG.Req_Files) { + if (report_count >= CFG.Req_Files) { + Send = FALSE; + add_report((char *)"ER: too many files requested"); + Syslog('+', "Exceeding maximum files limit"); + no_more = TRUE; + } + } + + if (Send && CFG.Req_MBytes) { + if ((st.st_size + report_total) > (CFG.Req_MBytes * 1048576)) { + Send = FALSE; + add_report((char *)"ER: file %s will exceed the request limit", file.Name); + Syslog('+', "Exceeding request size limit"); + no_more = TRUE; + } + } + + if (Send) { + Syslog('f', "Will send %s", file.LName); + report_total += st.st_size; + report_count++; + add_report((char *)"OK: Sending \"%s\" (%lu bytes)", file.Name, file.Size); + add_list(&fl, tnm, file.Name, 0, 0L, NULL, 1); + /* + * Update file information + */ + file.TimesReq++; + file.LastDL = time(NULL); + fseek(fb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fb); + } + free(tnm); + } + } + fclose(fb); + } + } + } + + fclose(fa); + fclose(fi); + + if (fl == NULL) + add_report((char *)"ER: No matching files found"); + + return fl; +} + + + +#define MAXRECURSE 5 +static int recurse=0; + +/* + * Magic filerquests. + */ +file_list *resplist(char *listfn, char *pw, char *dt) +{ + FILE *fp; + char buf[256], *p; + file_list *fl = NULL, **pfl; + + Syslog('+', "Magic request: %s (update (%s), password \"%s\")", + strrchr(xstrcpy(listfn), '/')+1, MBSE_SS(dt), MBSE_SS(pw)); + + if (++recurse > MAXRECURSE) { + WriteError("Excessive recursion in file lists for \"%s\"", MBSE_SS(listfn)); + add_report((char *)"ER: Exessive recursion for magic filename \"%s\", contact sysop", listfn); + recurse = 0; + free(listfn); + return NULL; + } + + pfl = &fl; + if ((fp = fopen(listfn,"r")) == NULL) { + WriteError("$cannot open file list \"%s\"",listfn); + add_report((char *)"ER: Could not open magic file \"%s\", contact sysop", listfn); + free(listfn); + recurse--; + return NULL; + } + + p = xstrcpy(listfn); + add_report((char *)"RQ: Magic filename \"%s\"", strrchr(p, '/')+1); + free(p); + + while (fgets(buf, sizeof(buf)-1, fp)) { + if ((p = strchr(buf, '#'))) + *p = '\0'; + if ((p = strtok(buf," \t\n\r"))) { + *pfl = respfreq(p, pw, dt); + while (*pfl) + pfl = &((*pfl)->next); + } + } + fclose(fp); + + free(listfn); + recurse--; + return fl; +} + + + +file_list *respmagic(char *cmd) /* must free(cmd) before exit */ +{ + struct stat st; + char cmdbuf[256]; + char tmpfn[PATH_MAX], tmptx[PATH_MAX]; + char remname[32], *p, *q, *z, *buf; + int i, escaped; + file_list *fl = NULL; + FILE *fp, *ft; + long zeroes = 0L; + ftnmsg fmsg; + char *svname; + + Syslog('+', "Magic execute: %s", strrchr(xstrcpy(cmd), '/')+1); + add_report((char *)"RQ: Magic \"%s\"",cmd); + sprintf(tmpfn, "%s/tmp/%08lX", getenv((char *)"MBSE_ROOT"), (unsigned long)sequencer()); + Syslog('+', "tmpfn \"%s\"", tmpfn); + if ((p = strrchr(cmd,'/'))) + p++; + else + p = cmd; + strncpy(remname, p, sizeof(remname)-1); + remname[sizeof(remname)-1] = '\0'; + if (remote->addr->name == NULL) + remote->addr->name = xstrcpy((char *)"Sysop"); + strncpy(cmdbuf, cmd, sizeof(cmdbuf)-2); + cmdbuf[sizeof(cmdbuf)-2] = '\0'; + q = cmdbuf + strlen(cmdbuf); + z = cmdbuf + sizeof(cmdbuf)-2; + *q++ = ' '; + escaped = 0; + for (p = ascfnode(remote->addr,0x7f); *p && (q < z); p++) { + if (escaped) { + escaped = 0; + } else switch (*p) { + case '\\': escaped = 1; break; + case '\'': + case '`': + case '"': + case '(': + case ')': + case '<': + case '>': + case '|': + case ';': + case '$': *q++ = '\\'; break; + } + *q++ = *p; + } + *q++ = '\0'; + + /* + * Execute the shell, output goes into tmpfn + */ + if (execsh(cmdbuf,(char *)"/dev/null",tmpfn,(char *)"/dev/null")) { + WriteError("$Execute magic error"); + add_report((char *)"ER: Magic command execution failed"); + unlink(tmpfn); + } else { + if (stat(tmpfn, &st) == 0) { + sprintf(tmptx, "%s/tmp/%08lX", getenv((char *)"MBSE_ROOT"), (unsigned long)sequencer()); + Syslog('+', "tmptx \"%s\"", tmptx); + + if ((fp = fopen(tmptx, "w"))) { + fmsg.flags = M_PVT|M_KILLSENT; + fmsg.from = bestaka_s(remote->addr); + svname = fmsg.from->name; + fmsg.from->name = (char *)"mbcico FREQ processor"; + fmsg.to = remote->addr; + fmsg.date = time((time_t*)NULL); + fmsg.subj = strrchr(xstrcpy(cmd), '/')+1; + fmsg.msgid_s = NULL; + fmsg.msgid_a = xstrcpy(ascfnode(fmsg.from, 0x1f)); + fmsg.msgid_n = sequencer(); + fmsg.reply_s = NULL; + fmsg.reply_a = NULL; + fmsg.reply_n = 0L; + fmsg.origin = NULL; + fmsg.area = NULL; + (void)ftnmsghdr(&fmsg, fp, NULL, 'f', (char *)"MBSE-CICO"); + free(fmsg.msgid_a); + + if ((ft = fopen(tmpfn, "r")) == NULL) { + WriteError("$Can't open %s", tmpfn); + } else { + buf = calloc(2049, sizeof(char)); + while ((fgets(buf, 2048, ft)) != NULL) { + for (i = 0; i < strlen(buf); i++) { + if (*(buf + i) == '\0') + break; + if (*(buf + i) == '\n') + *(buf + i) = '\r'; + } + fputs(buf, fp); + } + fprintf(fp, "\r--- mbcico v%s\r", VERSION); + free(buf); + } + fwrite(&zeroes, 1, 3, fp); + fclose(fp); + sprintf(remname, "%08lX.PKT", (unsigned long)sequencer()); + + add_list(&fl, tmptx, remname, KFS, 0L, NULL, 0); + fmsg.from->name = svname; + add_report((char *)"OK: magic output is send by mail"); + unlink(tmpfn); + } else { + WriteError("$cannot open temp file \"%s\"",MBSE_SS(tmpfn)); + } + } else { + WriteError("$cannot stat() magic stdout \"%s\"",tmpfn); + add_report((char *)"ER: Could not get magic command output, contact sysop"); + } + } + + free(cmd); + return fl; +} + + + +static void attach_report(file_list **fl) +{ + FILE *fp; + char tmpfn[L_tmpnam]; + char remname[14]; + long zeroes = 0L; + ftnmsg fmsg; + char *svname; + + if (report_text == NULL) { + WriteError("Empty FREQ report"); + add_report((char *)"ER: empty request report, contact sysop"); + } + + add_report((char *)"\rTotal to send: %lu files, %lu bytes", report_count, report_total); + + if (!CFG.Req_Files) + add_report((char *)"Maximum files: unlimited"); + else + add_report((char *)"Maximum files: %d", CFG.Req_Files); + if (!CFG.Req_MBytes) + add_report((char *)"Maximum size : unlimited"); + else + add_report((char *)"Maximum size : %d MBytes", CFG.Req_MBytes); + + add_report((char *)"\r--- mbcico v%s\r", VERSION); + + (void)tmpnam(tmpfn); + + if ((fp = fopen(tmpfn,"w"))) { + fmsg.flags = M_PVT|M_KILLSENT; + fmsg.from = bestaka_s(remote->addr); + svname = fmsg.from->name; + fmsg.from->name = (char *)"mbcico FREQ processor"; + fmsg.to = remote->addr; + /* + * If we don't know the sysops name, fake it. + */ + if (fmsg.to->name == NULL) + fmsg.to->name = xstrcpy((char *)"Sysop"); + fmsg.date = time((time_t*)NULL); + fmsg.subj = (char *)"File request status report"; + fmsg.msgid_s = NULL; + fmsg.msgid_a = xstrcpy(ascfnode(fmsg.from, 0x1f)); + fmsg.msgid_n = sequencer(); + fmsg.reply_s = NULL; + fmsg.reply_a = NULL; + fmsg.reply_n = 0L; + fmsg.origin = NULL; + fmsg.area = NULL; + (void)ftnmsghdr(&fmsg, fp, NULL, 'f', (char *)"MBSE-CICO"); + free(fmsg.msgid_a); + fwrite(report_text, 1, strlen(report_text), fp); + fwrite(&zeroes, 1, 3, fp); + fclose(fp); + sprintf(remname, "%08lX.PKT", (unsigned long)sequencer()); + add_list(fl, tmpfn, remname, KFS, 0L, NULL, 0); + fmsg.from->name = svname; + } else { + WriteError("$cannot open temp file \"%s\"",MBSE_SS(tmpfn)); + } + + report_total = 0L; + free(report_text); + report_text = NULL; +} + + + +static void add_report(char *format, ...) +{ + va_list va_ptr; + char buf[1024]; + + if (report_text == NULL) { + sprintf(buf, +" Status of file request\r\ + ======================\r\r\ + Received By: %s\r\ +", + ascfnode(bestaka_s(remote->addr),0x1f)); + sprintf(buf+strlen(buf), +" From: %s\r\ + On: %s\r\r\ +", + ascfnode(remote->addr,0x1f), + date(0L)); + report_text = xstrcat(report_text,buf); + } + + va_start(va_ptr, format); + vsprintf(buf, format, va_ptr); + va_end(va_ptr); + strcat(buf,"\r"); + report_text = xstrcat(report_text,buf); +} + diff --git a/mbcico/respfreq.h b/mbcico/respfreq.h new file mode 100644 index 00000000..77d4e73b --- /dev/null +++ b/mbcico/respfreq.h @@ -0,0 +1,11 @@ +#ifndef _RESPFREQ_H +#define _RESPFREQ_H + +file_list *respond_wazoo(void); +file_list *respond_bark(char *); +file_list *respfreq(char *, char *, char *); +file_list *resplist(char *, char *, char *); +file_list *respmagic(char *); + +#endif + diff --git a/mbcico/scanout.c b/mbcico/scanout.c new file mode 100644 index 00000000..46829ce6 --- /dev/null +++ b/mbcico/scanout.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * + * File ..................: mbcico/scanout.c + * Purpose ...............: Fidonet mailer + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbftn.h" +#include "config.h" +#include "scanout.h" +#include "lutil.h" + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + + +static faddr addr = { + NULL, + 0,0,0,0, + NULL +}; + + +extern time_t t_start; + + +static int scan_dir(int (*)(faddr*,char,int,char*),char*,int); +static int scan_dir(int (*fn)(faddr *, char, int, char *), char *dname, int ispoint) +{ + char fname[PATH_MAX]; + char flavor = '?'; + DIR *dp = NULL; + struct dirent *de; + int rc = 0, isflo, fage; + + Syslog('o' ,"scan_dir \"%s\" (%s)",MBSE_SS(dname),ispoint?"point":"node"); + + if ((dp = opendir(dname)) == NULL) { + Syslog('-', "Creating directory %s", dname); + /* + * Create a fake filename, mkdirs() likes that. + */ + sprintf(fname, "%s/foo", dname); + (void)mkdirs(fname); + if ((dp = opendir(dname)) == NULL) { + Syslog('o' ,"\"%s\" cannot be opened, proceed",MBSE_SS(dname)); + return 0; + } + } + + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && (de->d_name[8] == '.') && + (strspn(de->d_name,"0123456789abcdefABCDEF") == 8)) { + Syslog('o' ,"checking: \"%s\"",de->d_name); + addr.point= 0; + strncpy(fname,dname,PATH_MAX-2); + strcat(fname,"/"); + strncat(fname,de->d_name,PATH_MAX-strlen(fname)-2); + + if ((strcasecmp(de->d_name+9,"pnt") == 0) && !ispoint) { + sscanf(de->d_name,"%04x%04x",&addr.net,&addr.node); + if ((rc = scan_dir(fn, fname, 1))) + goto exout; + } else if ((strcasecmp(de->d_name+8,".out") == 0) || + (strcasecmp(de->d_name+8,".cut") == 0) || + (strcasecmp(de->d_name+8,".hut") == 0) || + (strcasecmp(de->d_name+8,".iut") == 0) || + (strcasecmp(de->d_name+8,".opk") == 0) || + (strcasecmp(de->d_name+8,".cpk") == 0) || + (strcasecmp(de->d_name+8,".hpk") == 0) || + (strcasecmp(de->d_name+8,".ipk") == 0) || + (strcasecmp(de->d_name+8,".flo") == 0) || + (strcasecmp(de->d_name+8,".clo") == 0) || + (strcasecmp(de->d_name+8,".hlo") == 0) || + (strcasecmp(de->d_name+8,".ilo") == 0) || + (strcasecmp(de->d_name+8,".req") == 0) || + (strcasecmp(de->d_name+8,".pol") == 0)) { + if (ispoint) + sscanf(de->d_name,"%08x", &addr.point); + else + sscanf(de->d_name,"%04x%04x", &addr.net,&addr.node); + flavor = tolower(de->d_name[9]); + if (flavor == 'f') + flavor='o'; + if (strcasecmp(de->d_name+10,"ut") == 0) + isflo=OUT_PKT; + else if (strcasecmp(de->d_name+10,"pk") == 0) + isflo=OUT_DIR; + else if (strcasecmp(de->d_name+10,"lo") == 0) + isflo=OUT_FLO; + else if (strcasecmp(de->d_name+9,"req") == 0) + isflo=OUT_REQ; + else if (strcasecmp(de->d_name+9,"pol") == 0) + isflo=OUT_POL; + else + isflo=-1; + Syslog('o' ,"%s \"%s\"", + (isflo == OUT_FLO) ? "flo file" : "packet", + de->d_name); + if ((rc=fn(&addr,flavor,isflo,fname))) + goto exout; + } else if ((strncasecmp(de->d_name+9,"su",2) == 0) || + (strncasecmp(de->d_name+9,"mo",2) == 0) || + (strncasecmp(de->d_name+9,"tu",2) == 0) || + (strncasecmp(de->d_name+9,"we",2) == 0) || + (strncasecmp(de->d_name+9,"th",2) == 0) || + (strncasecmp(de->d_name+9,"fr",2) == 0) || + (strncasecmp(de->d_name+9,"sa",2) == 0)) { + isflo = OUT_ARC; + if ((rc = fn(&addr, flavor, isflo, fname))) + goto exout; + + Syslog('o' ,"arcmail file \"%s\"",de->d_name); + sprintf(fname, "%s/%s", dname, de->d_name); + fage = (int)((t_start - file_time(fname)) / 86400); + + if (file_size(fname) == 0) { + Syslog('o', "Age %d days", fage); + /* + * Remove truncated ARCmail that has a day extension + * other then the current day or if the file is older + * then 6 days. + */ + if ((strncasecmp(de->d_name+9, dayname(), 2)) || (fage > 6)) { + if (unlink(fname) == 0) + Syslog('-', "Removed truncated ARCmail file %s", fname); + } + } + + if (CFG.toss_days && (fage > CFG.toss_days)) { + /* + * Remove ARCmail that is on hold too long. + */ + if (unlink(fname) == 0) + Syslog('+', "Removed ARCmail %s, %d days", fname, fage); + } + } else { + Syslog('o' ,"skipping \"%s\"",de->d_name); + } + } + +exout: + closedir(dp); + return rc; +} + + + +int scanout(int (*fn)(faddr *, char, int, char *)) +{ + int i, j, rc = 0; + unsigned short zone = 0; + char fext[5]; + char *p = NULL, *q = NULL; + DIR *dp; + + if ((dp = opendir(CFG.outbound)) == NULL) { + WriteError("$Can't open outbound directory \"%s\" for reading", MBSE_SS(CFG.outbound)); + return 1; + } + closedir(dp); + + /* + * Build outbound directory names with zone numbers. + */ + for (i = 0; i < 40; i++) { + if ((CFG.aka[i].zone) && (CFG.aka[i].zone != zone)) { + zone = CFG.aka[i].zone; + if (SearchFidonet(zone)) { + for (j = 0; j < 6; j++) { + /* + * Create outbound directory name for + * the primary aka of that zone. + */ + p = xstrcpy(CFG.outbound); + if (zone != CFG.aka[0].zone) { + if ((q = strrchr(p, '/'))) + *q = '\0'; + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, fidonet.domain); + } + + /* + * Not primary zones in the domain get + * a directory extension. + */ + if (fidonet.zone[j]) { + if (j) { + sprintf(fext, ".%03x", fidonet.zone[j]); + p = xstrcat(p, fext); + } + Syslog('o', "Zone %d Dir %s", fidonet.zone[j], p); + addr.zone = fidonet.zone[j]; + addr.domain = fidonet.domain; + + if ((rc = scan_dir(fn, p, 0))) { + if (p) + free(p); + p = NULL; + return rc; + } + } + + if (p) + free(p); + p = NULL; + } + } + } + } + return rc; +} + + diff --git a/mbcico/scanout.h b/mbcico/scanout.h new file mode 100644 index 00000000..b5dcdfc2 --- /dev/null +++ b/mbcico/scanout.h @@ -0,0 +1,13 @@ +#ifndef SCANOUT_H +#define SCANOUT_H + +#define OUT_PKT 0 +#define OUT_DIR 1 +#define OUT_FLO 2 +#define OUT_ARC 3 +#define OUT_REQ 4 +#define OUT_POL 5 + +extern int scanout(int (*)(faddr*,char,int,char*)); + +#endif diff --git a/mbcico/sendbark.c b/mbcico/sendbark.c new file mode 100644 index 00000000..f1a4c03e --- /dev/null +++ b/mbcico/sendbark.c @@ -0,0 +1,186 @@ +/***************************************************************************** + * + * File ..................: mbcico/sendbark.c + * Purpose ...............: Fidonet mailer + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "sendbark.h" +#include "xmrecv.h" + + + +static int send_bark(void); +static char *nm,*pw,*dt; + + +int sendbark(void) +{ + char *fn; + FILE *fp; + char buf[256], *p; + int rc = 0; + + fn = reqname(remote->addr); + if ((fp = fopen(fn,"r")) == NULL) { + Syslog('s', "no request file for this node"); + PUTCHAR(ETB); + return 0; + } + + while (fgets(buf,sizeof(buf)-1,fp)) { + nm = buf; + pw = strchr(buf, '!'); + dt = strchr(buf, '+'); + + if (pw) + *pw++= '\0'; + if (dt) + *dt++= '\0'; + + if (nm) { + while (isspace(*nm)) + nm++; + for (p = nm; (*p != '!') && (*p != '+') && (!isspace(*p)); p++); + *p = '\0'; + } + + if (pw) { + while (isspace(*pw)) + pw++; + for (p = pw; (*p != '!') && (*p != '+') && (!isspace(*p)); p++); + *p = '\0'; + } else + pw = (char *)""; + + if (dt) { + while (isspace(*nm)) + nm++; + for (p = nm; (*p != '!') && (*p != '+') && (*p != '-') && (!isspace(*p)); p++); + *p = '\0'; + } else + dt = (char *)"0"; + + if (*nm == ';') + continue; + + Syslog('+', "Sending bark request for \"%s\", password \"%s\", update \"%s\"",MBSE_SS(nm),MBSE_SS(pw),MBSE_SS(dt)); + if ((rc = send_bark())) + break; + } + if (rc == 0) + PUTCHAR(ETB); + fclose(fp); + if (rc == 0) + unlink(fn); + + return rc; +} + + + +SM_DECL(send_bark,(char *)"sendbark") +SM_STATES + Send, + waitack, + getfile +SM_NAMES + (char *)"send", + (char *)"waitack", + (char *)"getfile" +SM_EDECL + + int c; + char buf[256]; + unsigned short crc; + int count = 0; + + Syslog('s', "send_bark INIT"); + sprintf(buf,"%s %s %s",nm,dt,pw); + crc = crc16xmodem(buf, strlen(buf)); + Syslog('s', "sending bark packet \"%s\", crc = 0x%04x", buf, crc); + +SM_START(Send) + +SM_STATE(Send) + + Syslog('s', "send_bark SEND"); + if (count++ > 5) { + Syslog('+', "Bark request failed"); + SM_ERROR; + } + + PUTCHAR(ACK); + PUT(buf, strlen(buf)); + PUTCHAR(ETX); + PUTCHAR(crc & 0xff); + PUTCHAR((crc >> 8) & 0xff); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + +SM_STATE(waitack) + + Syslog('s', "send_bark WAITACK"); + c = GETCHAR(10); + if (c == TIMEOUT) { + Syslog('s', "sendbark got timeout waiting for ACK"); + SM_PROCEED(Send); + } else if (c < 0) { + SM_PROCEED(Send); + } else if (c == ACK) { + SM_PROCEED(getfile); + } else { + Syslog('s', "sendbark got %s waiting for ACK", printablec(c)); + SM_PROCEED(Send); + } + +SM_STATE(getfile) + + Syslog('s', "send_bark GETFILE"); + switch (xmrecv(NULL)) { + case 0: SM_PROCEED(getfile); + break; + case 1: SM_SUCCESS; + break; + default: SM_ERROR; + break; + } + +SM_END +SM_RETURN + + diff --git a/mbcico/sendbark.h b/mbcico/sendbark.h new file mode 100644 index 00000000..10fee0ec --- /dev/null +++ b/mbcico/sendbark.h @@ -0,0 +1,7 @@ +#ifndef _SENDBARK_H +#define _SENDBARK_H + +int sendbark(void); + +#endif + diff --git a/mbcico/session.c b/mbcico/session.c new file mode 100644 index 00000000..3ad4af27 --- /dev/null +++ b/mbcico/session.c @@ -0,0 +1,572 @@ +/***************************************************************************** + * + * File ..................: mbcico/session.c + * Purpose ...............: Fidonet mailer + * Last modification date : 02-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "statetbl.h" +#include "emsi.h" +#include "ftsc.h" +#include "session.h" +#include "yoohoo.h" +#include "mbcico.h" +#include "binkp.h" +#include "callstat.h" + + +extern int tcp_mode; + +node *nlent; +fa_list *remote=NULL; +int session_flags; +int remote_flags; + +int tx_define_type(void); +int rx_define_type(void); + +static int type; +static char *data=NULL; + + + +char *typestr(int); +char *typestr(int tp) +{ + switch (tp) { + case SESSION_FTSC: return (char *)"FTSC"; + case SESSION_YOOHOO: return (char *)"YooHoo/2U2"; + case SESSION_EMSI: return (char *)"EMSI"; + case SESSION_BINKP: return (char *)"Binkp"; + default: return (char *)"Unknown"; + } +} + + + +int session(faddr *a, node *nl, int role, int tp, char *dt) +{ + int rc = 1; + fa_list *tmpl; + struct sockaddr_in peeraddr; + int addrlen = sizeof(struct sockaddr_in); + + session_flags = 0; + type = tp; + nlent = nl; + + if (role) { + Syslog('s', "Start outbound session type %s with %s", typestr(type), ascfnode(a,0x1f)); + IsDoing("Outb %s", ascfnode(a, 0x0f)); + } else + Syslog('s', "Start inbound session type %s", typestr(type)); + + if (getpeername(0,(struct sockaddr*)&peeraddr,&addrlen) == 0) { + Syslog('s', "TCP connection: len=%d, family=%hd, port=%hu, addr=%s", + addrlen,peeraddr.sin_family, peeraddr.sin_port, inet_ntoa(peeraddr.sin_addr)); + if (role == 0) { + if (tcp_mode == TCPMODE_IBN) + Syslog('+', "Incoming IBN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_ITN) + Syslog('+', "Incoming ITN/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_IFC) + Syslog('+', "Incoming IFC/TCP connection from %s", inet_ntoa(peeraddr.sin_addr)); + else if (tcp_mode == TCPMODE_NONE) { + WriteError("Unknown TCP connection, parameter missing"); + die(101); + } + + IsDoing("Answer TCP"); + } + session_flags |= SESSION_TCP; + } + + if (data) + free(data); + data=NULL; + + if (dt) + data=xstrcpy(dt); + + emsi_local_protos=0; + emsi_local_opts=0; + emsi_local_lcodes=0; + + tidy_falist(&remote); + remote=NULL; + if (a) { + remote=(fa_list*)malloc(sizeof(fa_list)); + remote->next=NULL; + remote->addr=(faddr*)malloc(sizeof(faddr)); + remote->addr->zone=a->zone; + remote->addr->net=a->net; + remote->addr->node=a->node; + remote->addr->point=a->point; + remote->addr->domain=xstrcpy(a->domain); + remote->addr->name=NULL; + } else { + remote=NULL; + } + + remote_flags=SESSION_FNC; + + if (role) { + if (type == SESSION_UNKNOWN) + (void)tx_define_type(); + switch(type) { + case SESSION_UNKNOWN: rc=20; break; + case SESSION_FTSC: rc=tx_ftsc(); break; + case SESSION_YOOHOO: rc=tx_yoohoo(); break; + case SESSION_EMSI: rc=tx_emsi(data); break; + case SESSION_BINKP: rc=binkp(role); break; + } + } else { + if (type == SESSION_FTSC) + session_flags |= FTSC_XMODEM_CRC; + if (type == SESSION_UNKNOWN) + (void)rx_define_type(); + switch(type) { + case SESSION_UNKNOWN: rc=20; break; + case SESSION_FTSC: rc=rx_ftsc(); break; + case SESSION_YOOHOO: rc=rx_yoohoo(); break; + case SESSION_EMSI: rc=rx_emsi(data); break; + case SESSION_BINKP: rc=binkp(role); break; + } + } + sleep(2); + for (tmpl = remote; tmpl; tmpl = tmpl->next) { + /* + * Unlock all nodes, locks not owned by us are untouched. + */ + (void)nodeulock(tmpl->addr); + /* + * If successfull session, reset all status records. + */ + if (rc == 0) + putstatus(tmpl->addr, 0, 0); + } + tidy_falist(&remote); + if (data) + free(data); + data = NULL; + + if (emsi_local_password) + free(emsi_local_password); + if (emsi_remote_password) + free(emsi_remote_password); + + if (nlent->addr.domain) + free(nlent->addr.domain); + + return rc; +} + + + +SM_DECL(tx_define_type,(char *)"tx_define_type") +SM_STATES + skipjunk, + wake, + waitchar, + nextchar, + checkintro, + sendinq +SM_NAMES + (char *)"skipjunk", + (char *)"wake", + (char *)"waitchar", + (char *)"nextchar", + (char *)"checkintro", + (char *)"sendinq" +SM_EDECL + int c=0; + int count=0; + char buf[256],*p; + char ebuf[13],*ep; + int standby=0; + + int maybeftsc=0; + int maybeyoohoo=0; + + type=SESSION_UNKNOWN; + ebuf[0]='\0'; + ep=ebuf; + buf[0]='\0'; + p=buf; + +SM_START(skipjunk) + +SM_STATE(skipjunk) + + Syslog('S', "tx_define_type SKIPJUNK"); + while ((c = GETCHAR(1)) >= 0) /*nothing*/ ; + if (c == TIMEOUT) { + SM_PROCEED(wake); + } else { + SM_ERROR; + } + +SM_STATE(wake) + + Syslog('S', "tx_define_type WAKE"); + if (count++ > 20) { + Syslog('+', "Remote did not respond"); + SM_ERROR; + } + + p=buf; + PUTCHAR('\r'); + if ((c = GETCHAR(2)) == TIMEOUT) { + SM_PROCEED(wake); + } else if (c < 0) { + WriteError("Error while waking remote"); + SM_ERROR; + } else { + count = 0; + Syslog('S', "Got %c wakeup", c); + SM_PROCEED(nextchar); + } + +SM_STATE(waitchar) + + Syslog('S', "tx_define_type WAITCHAR"); + if ((c = GETCHAR(2)) == TIMEOUT) { /* Was 4 seconds */ + standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (count++ > 30) { /* Was 8 loops */ + Syslog('+', "Too many tries waking remote"); + SM_ERROR; + } + SM_PROCEED(sendinq); + } else if (c < 0) { + Syslog('+', "Error while getting intro from remote"); + SM_ERROR; + } else { + SM_PROCEED(nextchar); + } + +SM_STATE(nextchar) + + Syslog('S', "tx_define_type NEXTCHAR"); + if (c == 'C') { + session_flags |= FTSC_XMODEM_CRC; + maybeftsc++; + } + if (c == NAK) { + session_flags &= ~FTSC_XMODEM_CRC; + maybeftsc++; + } + if (c == ENQ) + maybeyoohoo++; + + if (((localoptions & NOWAZOO) == 0) && (maybeyoohoo > 1)) { + type = SESSION_YOOHOO; + SM_SUCCESS; + } + + if (maybeftsc > 1) { + type = SESSION_FTSC; + SM_SUCCESS; + } + + if ((c >= ' ') && (c <= '~')) { + if (c != 'C') + maybeftsc = 0; + maybeyoohoo = 0; + + if ((p-buf) < (sizeof(buf)-1)) { + *p++ = c; + *p = '\0'; + } + + if (c == '*') { + standby = 1; + ep = ebuf; + buf[0] = '\0'; + } else if (standby) { + if ((ep - ebuf) < (sizeof(ebuf) - 1)) { + *ep++ = c; + *ep = '\0'; + } + if ((ep - ebuf) >= (sizeof(ebuf) - 1)) { + standby = 0; + SM_PROCEED(checkintro); + } + } + } else switch (c) { + case DC1: break; + case '\r': + case '\n': standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (buf[0]) + Syslog('+', "Intro: \"%s\"", printable(buf, 0)); + p = buf; + buf[0] = '\0'; + break; + default: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + Syslog('i', "Got '%s' reading intro", printablec(c)); + break; + } + + SM_PROCEED(waitchar); + +SM_STATE(checkintro) + + Syslog('S', "tx_define_type CHECKINTRO"); + Syslog('i', "Check \"%s\" for being EMSI request",ebuf); + + if (((localoptions & NOEMSI) == 0) && (strncasecmp(ebuf,"EMSI_REQA77E",12) == 0)) { + type = SESSION_EMSI; + data = xstrcpy((char *)"**EMSI_REQA77E"); + Syslog('i', "Sending **EMSI_INQC816 (2 times)"); + PUTSTR((char *)"\r**EMSI_INQC816\r**EMSI_INQC816\r\021"); + SM_SUCCESS; + } else { + p = buf; + buf[0] = '\0'; + SM_PROCEED(waitchar); + } + +SM_STATE(sendinq) + + Syslog('S', "tx_define_type SENDINQ"); + PUTCHAR(DC1); + if ((localoptions & NOEMSI) == 0) { + Syslog('S', "send **EMSI_INQC816 (2 times)"); + PUTSTR((char *)"\r**EMSI_INQC816**EMSI_INQC816"); + } + if ((localoptions & NOWAZOO) == 0) { + Syslog('S', "send YOOHOO char"); + PUTCHAR(YOOHOO); + } + Syslog('S', "send TSYNC char"); + PUTCHAR(TSYNC); + if ((localoptions & NOEMSI) == 0) + PUTSTR((char *)"\r\021"); + SM_PROCEED(waitchar); + +SM_END +SM_RETURN + + + +SM_DECL(rx_define_type,(char *)"rx_define_type") +SM_STATES + sendintro, + waitchar, + nextchar, + checkemsi, + getdat +SM_NAMES + (char *)"sendintro", + (char *)"waitchar", + (char *)"nextchar", + (char *)"checkemsi", + (char *)"getdat" +SM_EDECL + int count=0; + int c=0; + int maybeftsc=0,maybeyoohoo=0; + char ebuf[13],*ep; + char *p; + int standby=0; + int datasize; + + type=SESSION_UNKNOWN; + session_flags|=FTSC_XMODEM_CRC; + ebuf[0]='\0'; + ep=ebuf; + Syslog('S', "rxdefine_type INIT"); + +SM_START(sendintro) + +SM_STATE(sendintro) + + Syslog('S', "rxdefine_type SENDINTRO"); + if (count++ > 6) { /* Was 16, is 6 according to the EMSI spec */ + Syslog('+', "Too many tries to get anything from the caller"); + SM_ERROR; + } + + standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + + if ((localoptions & NOEMSI) == 0) { + PUTSTR((char *)"**EMSI_REQA77E\r\021"); + } + PUTSTR((char *)"\r\rAddress: "); + PUTSTR(aka2str(CFG.aka[0])); + PUTSTR((char *)" using mbcico "); + PUTSTR((char *)VERSION); + switch (tcp_mode) { + case TCPMODE_IFC: PUTSTR((char *)"; IFC"); + break; + case TCPMODE_ITN: PUTSTR((char *)"; ITN"); + break; + case TCPMODE_IBN: PUTSTR((char *)"; IBN"); + break; + } + PUTCHAR('\r'); + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitchar); + } + +SM_STATE(waitchar) + + Syslog('S', "rxdefine_type WAITCHAR"); + if ((c=GETCHAR(20)) == TIMEOUT) { /* Timeout was 8, must be 20. */ + SM_PROCEED(sendintro); + } else if (c < 0) { + Syslog('+', "EMSI error while getting from caller"); + SM_ERROR; + } else { + SM_PROCEED(nextchar); + } + +SM_STATE(nextchar) + + Syslog('S', "rxdefine_type NEXTCHAR"); + if ((c >= ' ') && (c <= 'z')) { + if (c == '*') { + standby = 1; + ep = ebuf; + ebuf[0] = '\0'; + } else if (standby) { + if ((ep - ebuf) < (sizeof(ebuf) - 1)) { + *ep++ = c; + *ep = '\0'; + } + if ((ep - ebuf) >= (sizeof(ebuf) - 1)) { + standby = 0; + SM_PROCEED(checkemsi); + } + } + SM_PROCEED(waitchar); + } else switch (c) { + case DC1: SM_PROCEED(waitchar); + break; + case TSYNC: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (++maybeftsc > 1) { + type = SESSION_FTSC; + SM_SUCCESS; + } else { + SM_PROCEED(waitchar); + } + break; + case YOOHOO: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (++maybeyoohoo > 1) { + type = SESSION_YOOHOO; + SM_SUCCESS; + } else { + SM_PROCEED(waitchar); + } + break; + case '\r': + case '\n': standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + if (ebuf[0]) { + SM_PROCEED(checkemsi); + } else { + SM_PROCEED(sendintro); + } + break; + default: standby = 0; + ep = ebuf; + ebuf[0] = '\0'; + Syslog('i', "Got '%s' from remote", printablec(c)); + SM_PROCEED(waitchar); + break; + } + +SM_STATE(checkemsi) + + Syslog('S', "rxdefine_type CHECKEMSI"); + Syslog('i', "check \"%s\" for being EMSI inquery or data",ebuf); + + if (localoptions & NOEMSI) { + SM_PROCEED(sendintro); + } + + if (strncasecmp(ebuf, "EMSI_INQC816", 12) == 0) { + type = SESSION_EMSI; + data = xstrcpy((char *)"**EMSI_INQC816"); + SM_SUCCESS; + } else if (strncasecmp(ebuf, "EMSI_DAT", 8) == 0) { + SM_PROCEED(getdat); + } else { + SM_PROCEED(sendintro); + } + +SM_STATE(getdat) + + Syslog('S', "rxdefine_type GETDAT"); + Syslog('i', "Try get emsi_dat packet starting with \"%s\"",ebuf); + + if (sscanf(ebuf+8, "%04x", &datasize) != 1) { + SM_PROCEED(sendintro); + } + + datasize += 18; /* strlen("**EMSI_DATxxxxyyyy"), include CRC */ + data=malloc(datasize+1); + strcpy(data,"**"); + strcat(data, ebuf); + p = data + strlen(data); + + while (((p - data) < datasize) && ((c = GETCHAR(8)) >= 0)) { + *p++ = c; + *p= '\0'; + } + if (c == TIMEOUT) { + SM_PROCEED(sendintro); + } else if (c < 0) { + Syslog('+', "Error while reading EMSI_DAT from the caller"); + SM_ERROR; + } + type = SESSION_EMSI; + SM_SUCCESS; + +SM_END +SM_RETURN + diff --git a/mbcico/session.h b/mbcico/session.h new file mode 100644 index 00000000..f2e87c2d --- /dev/null +++ b/mbcico/session.h @@ -0,0 +1,69 @@ +#ifndef _SESSION_H +#define _SESSION_H + +#define TCPMODE_NONE 0 +#define TCPMODE_IFC 1 /* ifcico native EMSI on raw TCP */ +#define TCPMODE_ITN 2 /* EMSI encapsulation through telnet */ +#define TCPMODE_IBN 3 /* Binkp protocol */ + +#define SESSION_UNKNOWN 0 +#define SESSION_FTSC 1 +#define SESSION_YOOHOO 2 +#define SESSION_EMSI 3 +#define SESSION_BINKP 4 + +#define SESSION_SLAVE 0 +#define SESSION_MASTER 1 + +extern node *nlent; +extern fa_list *remote; + +typedef struct _file_list { + struct _file_list *next; + char *local; + char *remote; + int disposition; + FILE *flofp; + off_t floff; +} file_list; + +#define HOLD_MAIL "h" +#define NONHOLD_MAIL "ico" +#define ALL_MAIL "coh" + +extern int session_flags; +extern int remote_flags; +#define FTSC_XMODEM_CRC 1 /* xmodem-crc */ +#define FTSC_XMODEM_RES 2 /* sealink-resync */ +#define FTSC_XMODEM_SLO 4 /* sealink-overdrive */ +#define FTSC_XMODEM_XOF 8 /* xoff flow control, aka macflow */ +#define WAZOO_ZMODEM_ZAP 1 /* ZedZap allowed */ + +#define SESSION_WAZOO 0x8000 /* WaZOO type file requests */ +#define SESSION_BARK 0x4000 /* bark type file requests */ +#define SESSION_IFNA 0x2000 /* DietIFNA transfer from Yoohoo session */ +#define SESSION_FNC 0x1000 /* Filename conversion sending files */ + +#define SESSION_TCP 0x0800 /* Established over TCP/IP link */ +#define SESSION_HYDRA 0x0400 /* Hydra special file requests */ + +extern int localoptions; +#define NOCALL 0x0001 +#define NOHOLD 0x0002 +#define NOPUA 0x0004 +#define NOWAZOO 0x0008 +#define NOEMSI 0x0010 +#define NOFREQS 0x0020 +#define NOZMODEM 0x0040 +#define NOZEDZAP 0x0080 +#define NOJANUS 0x0100 +#define NOHYDRA 0x0200 +#define NOTCP 0x0400 + + +struct _history history; /* History record for sessions */ + +int session(faddr*,node*,int,int,char*); + +#endif + diff --git a/mbcico/statetbl.h b/mbcico/statetbl.h new file mode 100644 index 00000000..8a9ceece --- /dev/null +++ b/mbcico/statetbl.h @@ -0,0 +1,48 @@ +#ifndef STATETBL_H +#define STATETBL_H + +#define SM_DECL(proc,name) \ +int proc(void)\ +{\ + int sm_success=0;\ + char *sm_name=name; + +#define SM_STATES \ + enum { + +#define SM_NAMES \ + } sm_state; \ + char * sm_sname[] = { + +#define SM_EDECL \ + }; + +#define SM_START(x) \ + sm_state=x;\ + Syslog('S', "Statemachine %s start %s (%d)",sm_name,sm_sname[sm_state],sm_state); \ + while (!sm_success) switch (sm_state)\ + {\ + default: WriteError("Statemachine %s error: state=%d",sm_name,sm_state);\ + sm_success=-1; + +#define SM_STATE(x) \ + break;\ + case x: + +#define SM_END \ + }\ + +#define SM_RETURN \ + return (sm_success != 1);\ +} + +#define SM_PROCEED(x) \ + sm_state=x; break; + +#define SM_SUCCESS \ + sm_success=1; break; + +#define SM_ERROR \ + sm_success=-1; break; + +#endif diff --git a/mbcico/tcp.c b/mbcico/tcp.c new file mode 100644 index 00000000..0e842df7 --- /dev/null +++ b/mbcico/tcp.c @@ -0,0 +1,136 @@ +/***************************************************************************** + * + * File ..................: mbcico/tcp.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + contributed by Stanislav Voronyi +*/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "respfreq.h" +#include "filelist.h" +#include "tcpproto.h" +#include "tcp.h" + + +extern int made_request; + + +int rxtcp(void) +{ + int rc = 0; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start TCP session"); + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Remote requested \"no pickup\", no send"); + eff_remote=NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Remote requested \"pickup primary\""); + tmpl.addr=remote->addr; + tmpl.next=NULL; + eff_remote=&tmpl; + } else + eff_remote=remote; + + tosend = create_filelist(eff_remote, (char *)ALL_MAIL, 0); + + if ((rc=tcprcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = tcpsndfiles(tosend); + + if ((rc == 0) && (made_request)) { + Syslog('+', "Freq was made, trying to receive files"); + rc = tcprcvfiles(); + } + } + + tidy_filelist(tosend,(rc == 0)); + + if (rc) + WriteError("TCP session failed: rc=%d", rc); + else + Syslog('+', "TCP session completed"); + return rc; +} + + + +int txtcp(void) +{ + int rc=0; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start TCP session"); + + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Remote asked to \"hold all traffic\", no send"); + tosend=NULL; + } else + tosend = create_filelist(remote,nonhold_mail,0); + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = tcpsndfiles(tosend); + if (rc == 0) + if ((rc = tcprcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = tcpsndfiles(respond); + + tidy_filelist(tosend,(rc == 0)); + tidy_filelist(respond,0); + + if (rc) + WriteError("TCP session failed: rc=%d", rc); + else + Syslog('+', "TCP session completed"); + return rc; +} + diff --git a/mbcico/tcp.h b/mbcico/tcp.h new file mode 100644 index 00000000..5f61c86a --- /dev/null +++ b/mbcico/tcp.h @@ -0,0 +1,9 @@ +#ifndef _TCP_H +#define _TCP_H + +int rxtcp(void); +int txtcp(void); + + +#endif + diff --git a/mbcico/tcpproto.c b/mbcico/tcpproto.c new file mode 100644 index 00000000..f5877825 --- /dev/null +++ b/mbcico/tcpproto.c @@ -0,0 +1,478 @@ +/***************************************************************************** + * + * File ..................: mbcico/tcpproto.c + * Purpose ...............: Fidonet mailer + * Last modification date : 24-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + contributed by Stanislav Voronyi +*/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "config.h" +#include "emsi.h" +#include "lutil.h" +#include "openfile.h" +#include "filelist.h" +#include "tcpproto.h" + + +#define TCP_CMD 0x87 +#define TCP_DATA 0xe1 + +static FILE *fout; +static FILE *in; +static char txbuf[2048]; +static char rxbuf[2048]; +static int rx_type; +static long startime,endtime,rxbytes,sbytes; + +static int sendfile(char *,char *); +static int finsend(void); +static int receivefile(char *,time_t,off_t); +static int resync(off_t); +static int closeit(int); +static int tcp_sblk(char *,int,int); +static int tcp_rblk(char *,int *); +static int getsync(void); + +extern unsigned long sentbytes; +extern unsigned long rcvdbytes; +extern char *ttystat[]; + + +int tcpsndfiles(file_list *lst) +{ + int rc = 0, maxrc = 0; + file_list *tmpf; + + Syslog('+', "Start TCP send%s",lst?"":" (dummy)"); + + if (getsync()) { + WriteError("Can't get synchronization"); + return 1; + } + + for (tmpf = lst; tmpf && (maxrc == 0); tmpf = tmpf->next) { + if (tmpf->remote) { + rc = sendfile(tmpf->local,tmpf->remote); + rc = abs(rc); + if (rc > maxrc) + maxrc=rc; + if (rc == 0) + execute_disposition(tmpf); + } else + if (maxrc == 0) + execute_disposition(tmpf); + } + + if (maxrc < 2) { + rc = finsend(); + rc = abs(rc); + } + + if (rc > maxrc) + maxrc=rc; + + if (rc) + WriteError("TCP send error: rc=%d",maxrc); + return maxrc; +} + + + +int tcprcvfiles(void) +{ + int rc, bufl; + long filesize, filetime; + char *filename, *p; + + Syslog('+', "Start TCP receive"); + if (getsync()) { + WriteError("Can't get synchronization"); + return 1; + } +next: + if ((rc = tcp_rblk(rxbuf, &bufl)) == 0) { + if (strncmp(rxbuf, "SN", 2) == 0) { + rc = tcp_sblk((char *)"RN", 2, TCP_CMD); + return rc; + } else if (*rxbuf == 'S') { + p = strchr(rxbuf+2, ' '); + if (p != NULL) + *p=0; + else + return 1; + filename = xstrcpy(rxbuf+2); + p++; + filesize = strtol(p, &p, 10); + filetime = strtol(++p, (char **)NULL, 10); + } else + return rc==0?1:rc; + + if (strlen(filename) && filesize && filetime) + rc = receivefile(filename,filetime,filesize); + + if (fout) { + if (closeit(0)) + WriteError("Error closing file"); + (void)tcp_sblk((char *)"FERROR",6,TCP_CMD); + } else + goto next; + } + + if (rc) + WriteError("TCP receive error: rc=%d", rc); + return abs(rc); +} + + + +static int sendfile(char *ln, char *rn) +{ + int rc=0; + struct stat st; + struct flock fl; + int bufl, sverr; + long offset; + + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + + if ((in = fopen(ln,"r")) == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(ln)); + return 0; + } else { + WriteError("$tcpsend: cannot open file %s, skipping", MBSE_SS(ln)); + return 1; + } + } + + if (fcntl(fileno(in), F_SETLK, &fl) != 0) { + Syslog('+', "$tcpsend: cannot lock file %s, skipping", MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (stat(ln, &st) != 0) { + Syslog('+', "$tcpsend: cannot access \"%s\", skipping", MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (st.st_size > 0) { + Syslog('+', "TCP send \"%s\" as \"%s\"", MBSE_SS(ln), MBSE_SS(rn)); + Syslog('+', "TCP size %lu bytes, dated %s", (unsigned long)st.st_size, date(st.st_mtime)); + (void)time(&startime); + } else { + Syslog('+', "File \"%s\" has 0 size, skiped",ln); + return 0; + } + + sprintf(txbuf,"S %s %lu %lu",rn,(unsigned long)st.st_size,st.st_mtime+(st.st_mtime%2)); + bufl = strlen(txbuf); + rc = tcp_sblk(txbuf, bufl, TCP_CMD); + rc = tcp_rblk(rxbuf, &bufl); + + if (strncmp(rxbuf,"RS",2) == 0) { + Syslog('+', "File %s already received, skipping",rn); + return 0; + } else if (strncmp(rxbuf,"RN",2) == 0) { + Syslog('+', "Remote refused file, aborting",rn); + return 2; + } else if (strncmp(rxbuf,"ROK",3) == 0) { + if (bufl > 3 && rxbuf[3]==' ') { + offset = strtol(rxbuf+4,(char **)NULL,10); + if (fseek(in,offset,SEEK_SET) != 0) { + WriteError("$tcpsend cannot seek in file %s",ln); + return 1; + } + } else + offset = 0; + } else + return rc; + + while ((bufl = fread(&txbuf, 1, 1024, in)) != 0) { + if ((rc = tcp_sblk(txbuf, bufl, TCP_DATA)) > 0) + break; + } + + fclose(in); + if (rc == 0){ + strcpy(txbuf, "EOF"); + rc = tcp_sblk(txbuf, 3, TCP_CMD); + rc = tcp_rblk(rxbuf, &bufl); + } + + if (rc == 0 && strncmp(rxbuf,"FOK",3) == 0) { + (void)time(&endtime); + + if ((startime=endtime-startime) == 0) + startime = 1; + Syslog('a', "st_size %d, offset %d",st.st_size,offset); + Syslog('+', "Sent %lu bytes in %s (%ld cps)", + (unsigned long)st.st_size-offset, + str_time(startime), + (long)(st.st_size-offset)/startime); + sentbytes += (unsigned long)st.st_size - offset; + return 0; + } else if(strncmp(rxbuf,"FERROR",6) == 0){ + WriteError("$tcpsend remote file error",ln); + return rc==0?1:rc; + } else + return rc==0?1:rc; +} + + + +static int resync(off_t off) +{ + sprintf(txbuf,"ROK %ld",(long)off); + return 0; +} + + + +static int closeit(int success) +{ + int rc; + + rc = closefile(success); + fout = NULL; + sbytes = rxbytes - sbytes; + (void)time(&endtime); + + if ((startime = endtime - startime) == 0L) + startime = 1L; + Syslog('+', "%s %lu bytes in %s (%ld cps)", + success?"OK":"dropped after", + sbytes, str_time(startime), sbytes / startime); + rcvdbytes += sbytes; + return rc; +} + + + +static int finsend(void) +{ + int rc,bufl; + + rc = tcp_sblk((char *)"SN",2,TCP_CMD); + if(rc) + return rc; + + rc = tcp_rblk(rxbuf,&bufl); + if (strncmp(rxbuf, "RN", 2) == 0) + return rc; + else + return 1; +} + + + +static int receivefile(char *fn, time_t ft, off_t fs) +{ + int rc, bufl; + + Syslog('+', "TCP receive \"%s\" (%lu bytes) dated %s",fn,fs,date(ft)); + strcpy(txbuf,"ROK"); + fout = openfile(fn, ft, fs, &rxbytes, resync); + (void)time(&startime); + sbytes = rxbytes; + + if (fs == rxbytes) { + Syslog('+', "Skipping %s", fn); + fout = NULL; + rc = tcp_sblk((char *)"RS",2,TCP_CMD); + return rc; + } + + if (!fout) + return 1; + + bufl = strlen(txbuf); + rc = tcp_sblk(txbuf,bufl,TCP_CMD); + + while ((rc = tcp_rblk(rxbuf, &bufl)) == 0) { + if (rx_type == TCP_CMD) + break; + if (fwrite(rxbuf, 1, bufl, fout) != bufl) + break; + rxbytes += bufl; + } + + if (rc) + return rc; + + if (rx_type == TCP_CMD && bufl == 3 && strncmp(rxbuf,"EOF",3) == 0) { + if (ftell(fout) == fs) { + closeit(1); + rc = tcp_sblk((char *)"FOK",3,TCP_CMD); + return rc; + } else + return 1; + } else + return 1; +} + + + +static int tcp_sblk(char *buf, int len, int typ) +{ + Nopper(); + if (typ == TCP_CMD) + Syslog('A', "tcp_sblk: cmd: %s", buf); + else + Syslog('A', "tcp_sblk: data: %d bytes", len); + + PUTCHAR(0xc6); + PUTCHAR(typ); + PUTCHAR((len >> 8) & 0x0ff); + PUTCHAR(len & 0x0ff); + PUT(buf, len); + PUTCHAR(0x6c); + FLUSHOUT(); + if (tty_status) + WriteError("TCP send error: %s", ttystat[tty_status]); + else + Syslog('A', "tcp_sblk: complete"); + return tty_status; +} + + + +static int tcp_rblk(char *buf, int *len) +{ + int c; + + Syslog('A', "tcp_rblk: start"); + *len = 0; + + /* + * Wait up to 3 minutes for the header + */ + c = GETCHAR(180); + if (tty_status) + goto to; + if (c != 0xc6) { + WriteError("tcp_rblk: got %d instead of block header", c); + return c; + } + + /* + * Get block type + */ + c = GETCHAR(120); + if (tty_status) + goto to; + rx_type = c; + if (c != TCP_CMD && c != TCP_DATA) { + WriteError("tcp_rblk: got %d character instead of DATA/CMD", c); + return c; + } + + /* + * Get block length + */ + c = GETCHAR(120); + if (tty_status) + goto to; + *len = c << 8; + c = GETCHAR(120); + if (tty_status) + goto to; + *len += c; + Syslog('A', "tcp_rblk: expecting %d bytes", *len); + + /* + * Get actual data block + */ + GET(buf, *len, 120); + if (tty_status) + goto to; + + /* + * Get block trailer + */ + c = GETCHAR(120); + if (tty_status) + goto to; + if (c != 0x6c) + return c; + + if (rx_type == TCP_CMD) { + buf[*len] = '\0'; + Syslog('A', "tcp_rblk: cmd: %s", buf); + } else + Syslog('A', "tcp_rblk: data: %d bytes", *len); + +to: + if (tty_status) + WriteError("TCP receive error: %s", ttystat[tty_status]); + return tty_status; +} + + + +static int getsync(void) +{ + int c; + + PUTCHAR(0xaa); + PUTCHAR(0x55); + FLUSHOUT(); + Syslog('a', "getsync try to synchronize"); + +gs: + if (tty_status) { + WriteError("TCP getsync failed %s", ttystat[tty_status]); + return 1; + } + while ((c = GETCHAR(180)) != 0xaa) + if (tty_status) { + WriteError("TCP getsync failed: %s", ttystat[tty_status]); + return 1; + } + + if ((c = GETCHAR(120)) != 0x55) + goto gs; + + Syslog('a', "getsync done, tty_status %s", ttystat[tty_status]); + return tty_status; +} + + diff --git a/mbcico/tcpproto.h b/mbcico/tcpproto.h new file mode 100644 index 00000000..9a5da755 --- /dev/null +++ b/mbcico/tcpproto.h @@ -0,0 +1,9 @@ +#ifndef _TCPPROTO_H +#define _TCPPROTO_H + +int tcpsndfiles(file_list *); +int tcprcvfiles(void); + + +#endif + diff --git a/mbcico/ttyio.c b/mbcico/ttyio.c new file mode 100644 index 00000000..df9d2afe --- /dev/null +++ b/mbcico/ttyio.c @@ -0,0 +1,590 @@ +/***************************************************************************** + * + * File ..................: mbcico/ttyio.c + * Purpose ...............: Fidonet mailer + * Last modification date : 23-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* ### Modified by P.Saratxaga on 25 Oct 1995 ### + * - Added if (inetaddr) code from T. Tanaka + */ +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "lutil.h" + +extern int hanged_up; +extern char *inetaddr; + +#define TT_BUFSIZ 1024 +#define NUMTIMERS 3 + + +int tty_status = 0; +int f_flags; +static char buffer[TT_BUFSIZ]; +static char *next; +static int left = 0; + + +static time_t timer[NUMTIMERS]; + +char *ttystat[]= {(char *)"Ok", + (char *)"Error", + (char *)"TimeOut", + (char *)"EOF", + (char *)"Hangup", + (char *)"Empty"}; + + + + +/* + * timer functions + */ + +int tty_resettimer(int tno) +{ + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for resettimer()"); + return -1; + } + + Syslog('T', "ttyio: resettimer(%d)", tno); + timer[tno] = (time_t) 0; + return 0; +} + + + +void tty_resettimers(void) +{ + int i; + + Syslog('T', "ttyio: resettimers"); + for (i = 0; i < NUMTIMERS; i++) + timer[i] = (time_t)0; +} + + + +int tty_settimer(int tno, int interval) +{ + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for settimer()"); + return -1; + } + + Syslog('T', "ttyio: settimer(%d,%d)",tno,interval); + timer[tno]=time((time_t*)NULL)+interval; + return 0; +} + + + +int tty_expired(int tno) +{ + time_t now; + + if (tno >= NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer No for expired(%d)", tno); + return -1; + } + + /* + * Check if timer is running + */ + if (timer[tno] == (time_t) 0) + return 0; + + (void)time(&now); + Syslog('T', "ttyio: expired(%d) now=%lu,timer=%lu,return %s", + tno,now,timer[tno],(now >= timer[tno])?"yes":"no"); + return (now >= timer[tno]); +} + + + +int tty_running(int tno) +{ + if (tno > NUMTIMERS) { + errno = EINVAL; + WriteError("$ttyio: invalid timer for tty_running(%d)", tno); + return -1; + } + + /* + * check if timer is running + */ + if (timer[tno] == (time_t) 0) + return 0; + else + return 1; +} + + + +/* + * private r/w functions + */ + +static int tty_read(char *buf, int size, int tot) +{ + time_t timeout, now; + int i, rc; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + Syslog('T', "tty_read: (%08lx,%d,%d)",buf,size,tot); + if (size == 0) + return 0; + tty_status = 0; + + (void)time(&now); + timeout = (time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < TIMERNO_TX; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status=STAT_TIMEOUT; + Syslog('t', "tty_read: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout=timer[i]-now; + } + } + } + if ((tot != -1) && (timeout > tot)) + timeout=tot; + + Syslog('T', "tty_read: timeout = %d", timeout); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(0,&readfds); + FD_SET(0,&exceptfds); + seltimer.tv_sec=timeout; + seltimer.tv_usec=0; + + rc = select(1,&readfds,&writefds,&exceptfds,&seltimer); + + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("$tty_read: hanged_up flag"); + } else { + WriteError("$tty_read: select for read failed"); + tty_status = STAT_ERROR; + } + } else if (rc == 0) { + tty_status = STAT_TIMEOUT; + } else { /* rc > 0 */ + if (FD_ISSET(0,&exceptfds)) { + Syslog('+', "$tty_read: exeption error"); + tty_status = STAT_ERROR; + } + } + + if (tty_status) { + Syslog('T', "tty_read: return after select: %s",ttystat[tty_status]); + return -tty_status; + } + + if (!FD_ISSET(0,&readfds)) { + WriteError("tty_read: Cannot be: select returned but read fd not set"); + tty_status = STAT_ERROR; + return -tty_status; + } + + rc = read(0,buf,size); + if (rc <= 0) { + Syslog('t', "tty_read: return %d",rc); + if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { + tty_status = STAT_HANGUP; + WriteError("$tty_read: hanged_up flag"); + } else + tty_status = STAT_ERROR; + rc=-tty_status; + } else + Syslog('T', "tty_read: %s %d characters", printable(buf, rc), rc); + return rc; +} + + + +int tty_write(char *buf, int size) +{ + int result; + + Syslog('T', "tty_write(%08lx,%d)",buf,size); + + tty_status=0; + result = write(1,buf,size); + + if (result != size) { + if (hanged_up || (errno == EPIPE) || (errno == ECONNRESET)) { + tty_status = STAT_HANGUP; + WriteError("$tty_write: hanged_up flag"); + } else + tty_status=STAT_ERROR; + } + if (tty_status) + Syslog('t', "tty_write: error %s", ttystat[tty_status]); + + return -tty_status; +} + + + +/* public r/w functions */ + +/** + * Check if there is data available on stdin. + */ +int tty_check(void) +{ + int rc; + + // try to read available (timeout = 0) data if we have no data in + // our buffer + + if (!left) { + rc = tty_read(buffer, TT_BUFSIZ, 0); + if (rc > 0) { + left = rc; + } + } + + return (left > 0); +} + + + +int tty_putcheck(int size) +{ + fd_set set; + struct timeval timeout; + + /* + * Initialize the file descriptor set. + */ + FD_ZERO(&set); + FD_SET(1, &set); + + /* + * Initialize the timeout data structure. + */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + /* + * `select' returns 0 if timeout, 1 if input available, -1 if error. + */ + return select(FD_SETSIZE, NULL, &set, NULL, &timeout); +} + + + +int tty_waitputget(int tot) +{ + int i, rc; + time_t timeout, now; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + tty_status=0; + (void)time(&now); + timeout=(time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < NUMTIMERS; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status = STAT_TIMEOUT; + WriteError("tty_waitputget: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout = timer[i]-now; + } + } + } + if ((tot != -1) && (timeout > tot)) + timeout=tot; + Syslog('t', "tty_waitputget: timeout=%d",timeout); + + /* + * Initialize the file descriptor set. + */ + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + + FD_SET(0, &readfds); + FD_SET(1, &writefds); + FD_SET(0, &exceptfds); + FD_SET(1, &exceptfds); + + /* + * Initialize the timeout data structure. + */ + seltimer.tv_sec = timeout; + seltimer.tv_usec = 0; + + /* + * `select' returns 0 if timeout, 1 if input available, -1 if error. + */ + rc = select(FD_SETSIZE, &readfds, &writefds, &exceptfds, &seltimer); + + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("tty_waitputget: hanged_up flag"); + } else { + WriteError("$tty_waitputget: select failed"); + tty_status=STAT_ERROR; + } + } else if (rc == 0) { + tty_status=STAT_TIMEOUT; + } else { + /* rc > 0 */ + if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { + WriteError("$tty_waitputget: exeption error"); + tty_status=STAT_ERROR; + } + } + + if (tty_status) { + Syslog('t', "tty_waitputget: return after select status %s",ttystat[tty_status]); + return -tty_status; + } + + rc = 0; + + if (FD_ISSET(0,&readfds)) + rc |= 1; + + if (FD_ISSET(1,&writefds)) + rc |= 2; + + return rc; +} + + + +void tty_flushin(void) +{ + tcflush(0, TCIFLUSH); +} + + + +void tty_flushout(void) +{ + tcflush(1, TCOFLUSH); +} + + + +int tty_ungetc(int c) +{ + if (next == buffer) { + if (left >= TT_BUFSIZ) { + return -1; + } + + next = buffer + TT_BUFSIZ - left; + memcpy(next, buffer, left); + } + + next--; + *next = c; + left++; + + return 0; +} + + + +int tty_getc(int tot) +{ + if (!left) { + left=tty_read(buffer,TT_BUFSIZ,tot); + next=buffer; + } + + if (left <= 0) { + left=0; + return -tty_status; + } else { + left--; + return (*next++)&0xff; + } +} + + + +int tty_get(char *buf, int size, int tot) +{ + int result=0; + + if (left >= size) { + memcpy(buf,next,size); + next += size; + left -= size; + return 0; + } + + if (left > 0) { + memcpy(buf,next,left); + buf += left; + next += left; + size -= left; + left=0; + } + + while ((result=tty_read(buf,size,tot)) > 0) { + buf += result; + size -= result; + } + + return result; +} + + + +int tty_putc(int c) +{ + char buf = c; + + return tty_write(&buf,1); +} + + + +int tty_put(char *buf, int size) +{ + return tty_write(buf,size); +} + + + +int tty_putget(char **obuf, int *osize, char **ibuf, int *isize) +{ + time_t timeout, now; + int i, rc; + fd_set readfds, writefds, exceptfds; + struct timeval seltimer; + + tty_status = 0; + (void)time(&now); + timeout = (time_t)300; /* maximum of 5 minutes */ + + for (i = 0; i < NUMTIMERS; i++) { + if (timer[i]) { + if (now >= timer[i]) { + tty_status = STAT_TIMEOUT; + WriteError("tty_putget: timer %d already expired, return",i); + return -tty_status; + } else { + if (timeout > (timer[i]-now)) + timeout=timer[i]-now; + } + } + } + + Syslog('t', "tty_putget: timeout=%d",timeout); + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptfds); + FD_SET(0,&readfds); + FD_SET(1,&writefds); + FD_SET(0,&exceptfds); + FD_SET(1,&exceptfds); + seltimer.tv_sec=timeout; + seltimer.tv_usec=0; + + rc=select(2,&readfds,&writefds,&exceptfds,&seltimer); + if (rc < 0) { + if (hanged_up) { + tty_status=STAT_HANGUP; + WriteError("tty_putget: hanged_up flag"); + } else { + WriteError("$tty_putget: select failed"); + tty_status=STAT_ERROR; + } + } else if (rc == 0) { + tty_status=STAT_TIMEOUT; + } else { + /* rc > 0 */ + if ((FD_ISSET(0,&exceptfds)) || (FD_ISSET(1,&exceptfds))) { + WriteError("$tty_putget: exeption error"); + tty_status=STAT_ERROR; + } + } + + if (tty_status) { + Syslog('t', "tty_putget: return after select status %s",ttystat[tty_status]); + return -tty_status; + } + + if (FD_ISSET(0,&readfds) && *isize) { + rc=read(0,*ibuf,*isize); + if (rc < 0) { + WriteError("$tty_putget: read failed"); + tty_status=STAT_ERROR; + } else { + (*ibuf)+=rc; + (*isize)-=rc; + } + } + + if (FD_ISSET(1,&writefds) && *osize) { + rc=write(1,*obuf,*osize); + if (rc < 0) { + WriteError("$tty_putget: write failed"); + tty_status=STAT_ERROR; + } else { + (*obuf)+=rc; + (*osize)-=rc; + } + } + + if (tty_status) + return -tty_status; + else + return ((*isize == 0) | ((*osize == 0) << 1)); +} + diff --git a/mbcico/ttyio.h b/mbcico/ttyio.h new file mode 100644 index 00000000..c33ff2c8 --- /dev/null +++ b/mbcico/ttyio.h @@ -0,0 +1,183 @@ +#ifndef TTYIO_H +#define TTYIO_H + +/* + * Timer numbers for Hydra + */ +#define TIMERNO_BRAIN 0 +#define TIMERNO_RX 1 +#define TIMERNO_TX 2 + +#define RESETTIMER(x) tty_resettimer(x) +#define RESETTIMERS() tty_resettimers() +#define SETTIMER(x,y) tty_settimer(x,y) +#define EXPIRED(x) tty_expired(x) +#define RUNNING(x) tty_running(x) + +#define TCHECK() tty_check() +#define PUTCHECK(x) tty_putcheck(x) +#define WAITPUTGET(x) tty_waitputget(x) +#define FLUSHOUT() tty_flushout() +#define FLUSHIN() tty_flushin() +#define PUTCHAR(x) tty_putc(x) +#define PUT(x,y) tty_put(x,y) +#define PUTSTR(x) tty_put(x,strlen(x)) +#define GETCHAR(x) tty_getc(x) +#define UNGETCHAR(x) tty_ungetc(x) +#define GET(x,y,z) tty_get(x,y,z) +#define PUTGET(a,b,x,y) tty_putget(a,b,x,y) +#define STATUS tty_status + +#define STAT_SUCCESS 0 +#define STAT_ERROR 1 +#define STAT_TIMEOUT 2 +#define STAT_EOFILE 3 +#define STAT_HANGUP 4 +#define STAT_EMPTY 5 + +#define SUCCESS (STATUS == 0) +#define TERROR (-STAT_ERROR) +#define TIMEOUT (-STAT_TIMEOUT) +#define EOFILE (-STAT_EOFILE) +#define HANGUP (-STAT_HANGUP) +#define EMPTY (-STAT_EMPTY) + +#define GET_COMPLETE(x) (x & 1) +#define PUT_COMPLETE(x) (x & 2) + +#ifndef NUL +#define NUL 0x00 +#endif +#define SOH 0x01 +#define STX 0x02 +#define ETX 0x03 +#define EOT 0x04 +#define ENQ 0x05 +#define ACK 0x06 +#define BEL 0x07 +#define BS 0x08 +#define HT 0x09 +#define LF 0x0a +#define VT 0x0b +#ifndef FF +#define FF 0x0c +#endif +#ifndef CR +#define CR 0x0d +#endif +#define SO 0x0e +#define SI 0x0f +#define DLE 0x10 +#define XON 0x11 +#define DC1 0x11 +#define DC2 0x12 +#define XOFF 0x13 +#define DC3 0x13 +#define DC4 0x14 +#define NAK 0x15 +#define SYN 0x16 +#define ETB 0x17 +#define CAN 0x18 +#define EM 0x19 +#define SUB 0x1a +#ifndef ESC +#define ESC 0x1b +#endif +#define RS 0x1e +#define US 0x1f +#define TSYNC 0xae +#define YOOHOO 0xf1 + +/* ### Modifned by T.Tanaka on 4 Dec 1995 */ +#define ClearArray(x) memset((char *)x, 0, sizeof x) + +#define NETADD(c) { PUTCHAR(c); } +#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); } + +#define MY_STATE_WILL 0x01 +#define MY_WANT_STATE_WILL 0x02 +#define MY_STATE_DO 0x04 +#define MY_WANT_STATE_DO 0x08 +#define my_state_is_do(opt) (telnet_options[opt]&MY_STATE_DO) +#define my_state_is_will(opt) (telnet_options[opt]&MY_STATE_WILL) +#define my_want_state_is_do(opt) (telnet_options[opt]&MY_WANT_STATE_DO) +#define my_want_state_is_will(opt) (telnet_options[opt]&MY_WANT_STATE_WILL) +#define my_state_is_dont(opt) (!my_state_is_do(opt)) +#define my_state_is_wont(opt) (!my_state_is_will(opt)) +#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt)) +#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt)) +#define set_my_want_state_do(opt) {telnet_options[opt] |= MY_WANT_STATE_DO;} +#define set_my_want_state_will(opt) {telnet_options[opt] |= MY_WANT_STATE_WILL;} +#define set_my_want_state_dont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_DO;} +#define set_my_want_state_wont(opt) {telnet_options[opt] &= ~MY_WANT_STATE_WILL;} + +#define IAC 255 /* interpret as command: */ +#define DONT 254 /* you are not to use option */ +#define DO 253 /* please, you use option */ +#define WONT 252 /* I won't use option */ +#define WILL 251 /* I will use option */ + +/* telnet options */ +#define TELOPT_BINARY 0 /* 8-bit data path */ +#define TELOPT_ECHO 1 /* echo */ +#define TELOPT_RCP 2 /* prepare to reconnect */ +#define TELOPT_SGA 3 /* suppress go ahead */ +#define TELOPT_NAMS 4 /* approximate message size */ +#define TELOPT_STATUS 5 /* give status */ +#define TELOPT_TM 6 /* timing mark */ +#define TELOPT_RCTE 7 /* remote controlled transmission and echo */ +#define TELOPT_NAOL 8 /* negotiate about output line width */ +#define TELOPT_NAOP 9 /* negotiate about output page size */ +#define TELOPT_NAOCRD 10 /* negotiate about CR disposition */ +#define TELOPT_NAOHTS 11 /* negotiate about horizontal tabstops */ +#define TELOPT_NAOHTD 12 /* negotiate about horizontal tab disposition */ +#define TELOPT_NAOFFD 13 /* negotiate about formfeed disposition */ +#define TELOPT_NAOVTS 14 /* negotiate about vertical tab stops */ +#define TELOPT_NAOVTD 15 /* negotiate about vertical tab disposition */ +#define TELOPT_NAOLFD 16 /* negotiate about output LF disposition */ +#define TELOPT_XASCII 17 /* extended ascic character set */ +#define TELOPT_LOGOUT 18 /* force logout */ +#define TELOPT_BM 19 /* byte macro */ +#define TELOPT_DET 20 /* data entry terminal */ +#define TELOPT_SUPDUP 21 /* supdup protocol */ +#define TELOPT_SUPDUPOUTPUT 22 /* supdup output */ +#define TELOPT_SNDLOC 23 /* send location */ +#define TELOPT_TTYPE 24 /* terminal type */ +#define TELOPT_EOR 25 /* end or record */ +#define TELOPT_TUID 26 /* TACACS user identification */ +#define TELOPT_OUTMRK 27 /* output marking */ +#define TELOPT_TTYLOC 28 /* terminal location number */ +#define TELOPT_3270REGIME 29 /* 3270 regime */ +#define TELOPT_X3PAD 30 /* X.3 PAD */ +#define TELOPT_NAWS 31 /* window size */ +#define TELOPT_TSPEED 32 /* terminal speed */ +#define TELOPT_LFLOW 33 /* remote flow control */ +#define TELOPT_LINEMODE 34 /* Linemode option */ +#define TELOPT_XDISPLOC 35 /* X Display Location */ +#define TELOPT_ENVIRON 36 /* Environment variables */ +#define TELOPT_AUTHENTICATION 37/* Authenticate */ +#define TELOPT_ENCRYPT 38 /* Encryption option */ +#define TELOPT_EXOPL 255 /* extended-options-list */ +/* ### */ + +extern int tty_status; + +extern int tty_check(void); +extern int tty_waitputget(int); +extern int tty_ungetc(int); +extern int tty_getc(int); +extern int tty_get(char*,int,int); +extern int tty_putcheck(int); +extern int tty_putc(int); +extern int tty_put(char*,int); +extern int tty_putget(char**,int*,char**,int*); +extern void tty_flushout(void); +extern void tty_flushin(void); +extern void sendbrk(void); +extern int tty_resettimer(int tno); +extern void tty_resettimers(void); +extern int tty_settimer(int,int); +extern int tty_expired(int); +extern int tty_running(int); + +#endif diff --git a/mbcico/ulock.c b/mbcico/ulock.c new file mode 100644 index 00000000..06f2e5b1 --- /dev/null +++ b/mbcico/ulock.c @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * File ..................: mbcico/ulock.c + * Purpose ...............: Fidonet mailer + * Last modification date : 18-Dec-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" + +#ifndef LOCKDIR +#define LOCKDIR "/var/lock" +#endif + +#define LCKPREFIX LOCKDIR"/LCK.." +#define LCKTMP LOCKDIR"/TMP." + +#ifdef DONT_HAVE_PID_T +#define pid_t int +#endif + + + +int lock(char *line) +{ + pid_t mypid,rempid=0; + int tmppid; + char tmpname[256],lckname[256]; + char *p; + int i,rc; + FILE *f; + + rc=-1; + if ((p=strrchr(line,'/')) == NULL) + p=line; + else + p++; + mypid = getpid(); + sprintf(tmpname,"%s%d",LCKTMP,mypid); + if ((f = fopen(tmpname,"w")) == NULL) { + WriteError("$ulock: can't create %s",tmpname); + return(-1); + } + + fprintf(f,"%10d\n",mypid); + fclose(f); + chmod(tmpname,0444); + sprintf(lckname,"%s%s",LCKPREFIX,p); + p=lckname+strlen(lckname)-1; + *p=tolower(*p); + + for (i=0; (i++<5) && ((rc = link(tmpname, lckname)) != 0) && + (errno == EEXIST);) + { + if ((f=fopen(lckname,"r")) == NULL) { + Syslog('l', "$Can't open existing lock file"); + } else { + fscanf(f,"%d",&tmppid); + rempid=tmppid; + fclose(f); + Syslog('l', "lock: file read for process %d",rempid); + } + + if (kill(rempid,0) && (errno == ESRCH)) { + Syslog('l', "process inactive, unlink file"); + unlink(lckname); + } else { + Syslog('l', "process active, sleep a bit"); + sleep(2); + } + } + + if (rc) + Syslog('l', "$ulock: result %d (errno %d)",rc,errno); + unlink(tmpname); + return(rc); +} + + + +int ulock(char *line) +{ + pid_t mypid,rempid; + int tmppid; + char lckname[256]; + char *p; + int rc; + FILE *f; + + rc=-1; + if ((p=strrchr(line,'/')) == NULL) + p=line; + else + p++; + mypid=getpid(); + sprintf(lckname,"%s%s",LCKPREFIX,p); + p=lckname+strlen(lckname)-1; + *p=tolower(*p); + + if ((f=fopen(lckname,"r")) == NULL) + { + WriteError("$cannot open lock file %s",lckname); + return rc; + } + + fscanf(f,"%d",&tmppid); + rempid=tmppid; + fclose(f); + if (rempid == mypid) { + rc = unlink(lckname); + if (rc) + Syslog('l', "Unlock %s rc=%d", lckname, rc); + } + return(rc); +} + + diff --git a/mbcico/ulock.h b/mbcico/ulock.h new file mode 100644 index 00000000..0f25b4d3 --- /dev/null +++ b/mbcico/ulock.h @@ -0,0 +1,8 @@ +#ifndef _ULOCK_H +#define _ULOCK_H + +int lock(char *); +int ulock(char *); + +#endif + diff --git a/mbcico/wazoo.c b/mbcico/wazoo.c new file mode 100644 index 00000000..c26124ed --- /dev/null +++ b/mbcico/wazoo.c @@ -0,0 +1,128 @@ +/***************************************************************************** + * + * File ..................: mbcico/wazoo.c + * Purpose ...............: Fidonet mailer + * Last modification date : 01-Feb-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "statetbl.h" +#include "config.h" +#include "emsi.h" +#include "respfreq.h" +#include "filelist.h" +#include "wazoo.h" +#include "zmodem.h" + + +extern int made_request; + + +int rxwazoo(void) +{ + int rc = 0; + fa_list *eff_remote, tmpl; + file_list *tosend = NULL, **tmpfl; + + Syslog('+', "Start WaZOO session"); + + if (emsi_remote_lcodes & LCODE_NPU) { + Syslog('+', "Remote requested \"no pickup\", no send"); + eff_remote=NULL; + } else if (emsi_remote_lcodes & LCODE_PUP) { + Syslog('+', "Remote requested \"pickup primary\""); + tmpl.addr = remote->addr; + tmpl.next = NULL; + eff_remote = &tmpl; + } else eff_remote=remote; + + tosend = create_filelist(eff_remote,(char *)ALL_MAIL,0); + + if ((rc = zmrcvfiles()) == 0) { + if ((emsi_local_opts & OPT_NRQ) == 0) { + for (tmpfl = &tosend; *tmpfl; tmpfl = &((*tmpfl)->next)); + *tmpfl = respond_wazoo(); + } + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = zmsndfiles(tosend); + + if ((rc == 0) && (made_request)) { + Syslog('+', "Freq was made, trying to receive files"); + rc = zmrcvfiles(); + } + } + + tidy_filelist(tosend, (rc == 0)); + + if (rc) + WriteError("WaZOO session failed: rc=%d", rc); + else + Syslog('+', "WaZOO session completed"); + return rc; +} + + + +int txwazoo(void) +{ + int rc = 0; + file_list *tosend = NULL, *respond = NULL; + char *nonhold_mail; + + Syslog('+', "Start WaZOO session"); + if (localoptions & NOHOLD) + nonhold_mail = (char *)ALL_MAIL; + else + nonhold_mail = (char *)NONHOLD_MAIL; + if (emsi_remote_lcodes & LCODE_HAT) { + Syslog('+', "Remote asked to \"hold all traffic\", no send"); + tosend = NULL; + } else tosend = create_filelist(remote, nonhold_mail, 0); + + if ((tosend != NULL) || ((emsi_remote_lcodes & LCODE_NPU) == 0)) + rc = zmsndfiles(tosend); + if (rc == 0) + if ((rc = zmrcvfiles()) == 0) + if ((emsi_local_opts & OPT_NRQ) == 0) + if ((respond = respond_wazoo())) + rc = zmsndfiles(respond); + + tidy_filelist(tosend,(rc == 0)); + tidy_filelist(respond,0); + if (rc) + WriteError("WaZOO session failed: rc=%d", rc); + else + Syslog('+', "WaZOO session completed"); + return rc; +} + diff --git a/mbcico/wazoo.h b/mbcico/wazoo.h new file mode 100644 index 00000000..5e1a74f2 --- /dev/null +++ b/mbcico/wazoo.h @@ -0,0 +1,8 @@ +#ifndef _WAZOO_H +#define _WAZOO_H + +int rxwazoo(void); +int txwazoo(void); + +#endif + diff --git a/mbcico/xmrecv.c b/mbcico/xmrecv.c new file mode 100644 index 00000000..3c19f7ff --- /dev/null +++ b/mbcico/xmrecv.c @@ -0,0 +1,604 @@ +/***************************************************************************** + * + * File ..................: mbcico/xmrecv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 04-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "config.h" +#include "lutil.h" +#include "openfile.h" +#include "m7recv.h" +#include "xmrecv.h" +#include "filetime.h" + + +#define XMBLKSIZ 128 + + +static int xm_recv(void); +static int resync(off_t); +static int closeit(int); + +static char *recvname=NULL; +static char *fpath=NULL; +static FILE *fp=NULL; +static int last; +static time_t stm,etm; +static off_t startofs; +static long recv_blk; + +extern unsigned long rcvdbytes; + + + +int xmrecv(char *Name) +{ + int rc; + + Syslog('+', "Xmodem start receive \"%s\"",MBSE_SS(Name)); + recvname = Name; + last = 0; + rc = xm_recv(); + if (fp) + closeit(0); + if (rc) + return -1; + else + if (last) + return 1; + else + return 0; +} + + + +int closeit(int success) +{ + off_t endofs; + + endofs = recv_blk*XMBLKSIZ; + (void)time(&etm); + if (etm == stm) + etm++; + Syslog('+', "Xmodem %s %lu bytes in %s (%lu cps)", success?"received":"dropped after", + (unsigned long)(endofs-startofs),str_time(etm-stm), (unsigned long)(endofs-startofs)/(etm-stm)); + rcvdbytes += (unsigned long)(endofs-startofs); + fp = NULL; + return closefile(success); +} + + + +SM_DECL(xm_recv,(char *)"xmrecv") +SM_STATES + sendnak0, + waitblk0, + sendnak, + waitblk, + recvblk, + sendack, + checktelink, + recvm7, + goteof +SM_NAMES + (char *)"sendnak0", + (char *)"waitblk0", + (char *)"sendnak", + (char *)"waitblk", + (char *)"recvblk", + (char *)"sendack", + (char *)"checktelink", + (char *)"recvm7", + (char *)"goteof" +SM_EDECL + + int tmp, i; + int SEAlink = FALSE, Slo = FALSE; + int crcmode = session_flags & FTSC_XMODEM_CRC; + int count=0,junk=0,cancount=0; + int header = 0; + struct _xmblk { + unsigned char n1,n2; + unsigned char data[XMBLKSIZ]; + unsigned char c1,c2; + } xmblk; + unsigned short localcrc,remotecrc; + unsigned char localcs,remotecs; + long ackd_blk=-1L; + long next_blk=1L; + long last_blk=0L; + off_t resofs; + char tmpfname[16]; + off_t wsize; + time_t remtime=0L; + off_t remsize=0; + int goteot = FALSE; + + Syslog('x', "xmrecv INIT"); + (void)time(&stm); + recv_blk=-1L; + + memset(&tmpfname, 0, sizeof(tmpfname)); + if (recvname) + strncpy(tmpfname,recvname,sizeof(tmpfname)-1); + +SM_START(sendnak0) + +SM_STATE(sendnak0) + + Syslog('x', "xmrecv SENDNAK0 count=%d mode=%s", count, crcmode?"crc":"cksum"); + if (count++ > 9) { + Syslog('+', "too many errors while xmodem receive init"); + SM_ERROR; + } + if ((ackd_blk < 0) && crcmode && (count > 5)) { + Syslog('x', "no responce to 'C', try checksum mode"); + session_flags &= ~FTSC_XMODEM_CRC; + crcmode = FALSE; + } + + if (crcmode) + PUTCHAR('C'); + else + PUTCHAR(NAK); + junk = 0; + SM_PROCEED(waitblk0); + +SM_STATE(waitblk0) + + Syslog('x', "xmrecv WAITBLK0"); + header = GETCHAR(5); + if (header == TIMEOUT) { + Syslog('x', "timeout waiting for xmodem block 0 header, count=%d", count); + if ((count > 2) && (session_flags & SESSION_IFNA)) { + Syslog('+', "Timeout waiting for file in WaZOO session, report success"); + last=1; + SM_SUCCESS; + } + SM_PROCEED(sendnak0); + } else if (header < 0) { + Syslog('x', "Error"); + SM_ERROR; + } else { + switch (header) { + case EOT: Syslog('x', "got EOT"); + Slo = FALSE; + if (ackd_blk == -1L) + last=1; + else { + ackd_blk++; + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + } + if (STATUS) { + SM_ERROR; + } + SM_SUCCESS; + break; + case CAN: Syslog('+', "Got CAN while xmodem receive init"); + SM_ERROR; + break; + case SOH: SEAlink = TRUE; + Syslog('x', "Got SOH, SEAlink mode"); + SM_PROCEED(recvblk); + break; + case SYN: SEAlink = FALSE; + Syslog('x', "Got SYN, Telink mode"); + SM_PROCEED(recvblk); + break; + case ACK: SEAlink = FALSE; + Syslog('x', "Got ACK, Modem7 mode"); + SM_PROCEED(recvm7); + break; + case TSYNC: Syslog('x', "Got TSYSNC char"); + SM_PROCEED(sendnak0); + break; + case NAK: + case 'C': Syslog('x', "Got %s waiting for block 0, sending EOT", printablec(header)); + PUTCHAR(EOT); /* other end still waiting us to send? */ + SM_PROCEED(waitblk0); + break; + default: Syslog('x', "Got '%s' waiting for block 0", printablec(header)); + if (junk++ > 300) { + SM_PROCEED(sendnak0); + } else { + SM_PROCEED(waitblk0); + } + break; + } + } + +SM_STATE(sendnak) + + Syslog('x', "xmrecv SENDNAK"); + if (ackd_blk < 0) { + SM_PROCEED(sendnak0); + } + + if (count++ > 9) { + Syslog('+', "too many errors while xmodem receive"); + SM_ERROR; + } + + junk = 0; + + if (remote_flags & FTSC_XMODEM_RES) { + if (resync(ackd_blk*XMBLKSIZ)) { + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + } else { /* simple NAK */ + Syslog('x', "negative acknowlege block %ld",ackd_blk+1); + + if (crcmode) + PUTCHAR('C'); + else + PUTCHAR(NAK); + if (SEAlink) { + PUTCHAR(ackd_blk+1); + PUTCHAR(~(ackd_blk+1)); + } + if (STATUS) { + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + } + +SM_STATE(sendack) + + Syslog('x', "xmrecv SENDACK block=%d", recv_blk); + ackd_blk = recv_blk; + count = 0; + cancount = 0; + + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + if (STATUS) { + SM_ERROR; + } + if (goteot) { + SM_SUCCESS; + } + SM_PROCEED(waitblk); + +SM_STATE(waitblk) + + Syslog('x', "xmrecv WAITBLK"); + header = GETCHAR(15); + if (header == TIMEOUT) { + Syslog('x', "timeout waiting for xmodem block header, count=%d", count); + SM_PROCEED(sendnak); + } else if (header < 0) { + SM_ERROR; + } else { + switch (header) { + case EOT: if (last_blk && (ackd_blk != last_blk)) { + Syslog('x', "false EOT after %ld block, need after %ld", ackd_blk,last_blk); + SM_PROCEED(waitblk); + } else { + SM_PROCEED(goteof); + } + break; + case CAN: if (cancount++ > 4) { + closeit(0); + Syslog('+', "Got CAN while xmodem receive"); + SM_ERROR; + } else { + SM_PROCEED(waitblk); + } + break; + case SOH: SM_PROCEED(recvblk); + break; + default: Syslog('x', "got '%s' waiting SOH", printablec(header)); + if (junk++ > 200) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + break; + } + } + +SM_STATE(recvblk) + + Syslog('x', "xmrecv RECVBLK"); + Nopper(); + GET((char*)&xmblk,(crcmode && (header != SYN))? sizeof(xmblk): sizeof(xmblk)-1,15); + if (STATUS == STAT_TIMEOUT) { + Syslog('x', "xmrecv timeout waiting for block body"); + SM_PROCEED(sendnak); + } + if (STATUS) { + SM_ERROR; + } + if ((xmblk.n1 & 0xff) != ((~xmblk.n2) & 0xff)) { + Syslog('x', "bad block number: 0x%02x/0x%02x (0x%02x)", xmblk.n1,xmblk.n2,(~xmblk.n2)&0xff); + SM_PROCEED(waitblk); + } + recv_blk = xmblk.n1 + (ackd_blk & ~0xff); + if (abs(recv_blk - ackd_blk) > 128) + recv_blk += 256; + + if (crcmode && (header != SYN)) { + remotecrc = (short)xmblk.c1 << 8 | xmblk.c2; + localcrc = crc16xmodem(xmblk.data, sizeof(xmblk.data)); + if (remotecrc != localcrc) { + Syslog('x', "bad crc: 0x%04x/0x%04x",remotecrc,localcrc); + if (recv_blk == (ackd_blk+1)) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + } + } else { + remotecs = xmblk.c1; + localcs = checksum(xmblk.data, sizeof(xmblk.data)); + if (remotecs != localcs) { + Syslog('x', "bad checksum: 0x%02x/0x%02x",remotecs,localcs); + if (recv_blk == (ackd_blk+1)) { + SM_PROCEED(sendnak); + } else { + SM_PROCEED(waitblk); + } + } + } + if ((ackd_blk == -1L) && (recv_blk == 0L)) { + SM_PROCEED(checktelink); + } + if ((ackd_blk == -1L) && (recv_blk == 1L)) { + if (count < 3) { + SM_PROCEED(sendnak0); + } else + ackd_blk=0L; + } + if (recv_blk < (ackd_blk+1L)) { + Syslog('x', "old block number %ld after %ld, go on", recv_blk,ackd_blk); + SM_PROCEED(waitblk); + } else if (recv_blk > (ackd_blk+1L)) { + Syslog('x', "bad block order: %ld after %ld, go on", recv_blk,ackd_blk); + SM_PROCEED(waitblk); + } + + Syslog('X', "received block %ld \"%s\"", recv_blk,printable(xmblk.data,128)); + + if (fp == NULL) { + if ((fp = openfile(tmpfname,remtime,remsize,&resofs,resync)) == NULL) { + SM_ERROR; + } else { + if (resofs) + ackd_blk=(resofs-1)/XMBLKSIZ+1L; + else + ackd_blk=-1L; + } + startofs=resofs; + Syslog('+', "Xmodem receive: \"%s\"",tmpfname); + } + + if (recv_blk > next_blk) { + WriteError("xmrecv internal error: recv_blk %ld > next_blk %ld", recv_blk,next_blk); + SM_ERROR; + } + if (recv_blk == next_blk) { + if (recv_blk == last_blk) + wsize=remsize%XMBLKSIZ; + else + wsize=XMBLKSIZ; + if (wsize == 0) + wsize=XMBLKSIZ; + if ((tmp = fwrite(xmblk.data,wsize,1,fp)) != 1) { + WriteError("$error writing block %l (%d bytes) to file \"%s\" (fwrite return %d)", + recv_blk,wsize,fpath,tmp); + SM_ERROR; + } else + Syslog('x', "Block %ld size %d written (ret %d)", recv_blk,wsize,tmp); + next_blk++; + } else { + Syslog('x', "recv_blk %ld < next_blk %ld, ack without writing", recv_blk,next_blk); + } + SM_PROCEED(sendack); + +SM_STATE(checktelink) + + Syslog('x', "xmrecv CHECKTELINK"); + Syslog('X', "checktelink got \"%s\"",printable(xmblk.data,45)); + if (tmpfname[0] == '\0') { + strncpy(tmpfname,xmblk.data+8,16); + /* + * Some systems fill the rest of the filename with spaces, sigh. + */ + for (i = 16; i; i--) { + if ((tmpfname[i] == ' ') || (tmpfname[i] == '\0')) + tmpfname[i] = '\0'; + else + break; + } + } else { + Syslog('+', "Remote uses %s",printable(xmblk.data+25,-14)); + Syslog('X', "Remote file name \"%s\" discarded", printable(xmblk.data+8,-16)); + } + remsize = ((off_t)xmblk.data[0]) + ((off_t)xmblk.data[1]<<8) + ((off_t)xmblk.data[2]<<16) + ((off_t)xmblk.data[3]<<24); + last_blk = (remsize-1)/XMBLKSIZ+1; + if (header == SOH) { + /* + * SEAlink block + */ + remtime=sl2mtime(((time_t)xmblk.data[4])+ ((time_t)xmblk.data[5]<<8)+ + ((time_t)xmblk.data[6]<<16)+ ((time_t)xmblk.data[7]<<24)); + if (xmblk.data[40]) { + Slo = TRUE; + remote_flags |= FTSC_XMODEM_SLO; + } else + remote_flags &= ~FTSC_XMODEM_SLO; + if (xmblk.data[41]) + remote_flags |= FTSC_XMODEM_RES; + else + remote_flags &= ~FTSC_XMODEM_RES; + if (xmblk.data[42]) + remote_flags |= FTSC_XMODEM_XOF; + else + remote_flags &= ~FTSC_XMODEM_XOF; + } else if (header == SYN) { + /* + * Telink block + */ + remtime=tl2mtime(((time_t)xmblk.data[4])+ ((time_t)xmblk.data[5]<<8)+ + ((time_t)xmblk.data[6]<<16)+ ((time_t)xmblk.data[7]<<24)); + if (xmblk.data[41]) + session_flags |= FTSC_XMODEM_CRC; + else + session_flags &= ~FTSC_XMODEM_CRC; + } else { + WriteError("Got data block with header 0x%02x", header); + SM_PROCEED(sendnak0); + } + + Syslog('x', "%s block, session_flags=0x%04x, remote_flags=0x%04x", + (header == SYN)?"Telink":"Sealink",session_flags,remote_flags); + + if ((fp = openfile(tmpfname,remtime,remsize,&resofs,resync)) == NULL) { + SM_ERROR; + } + if (resofs) + ackd_blk=(resofs-1)/XMBLKSIZ+1L; + else + ackd_blk=-1L; + startofs=resofs; + + Syslog('+', "Xmodem %s receive: \"%s\" %ld bytes dated %s", (header == SYN)?"Telink":"Sealink", + tmpfname, remsize, rfcdate(remtime)); + + if (ackd_blk == -1) { + SM_PROCEED(sendack); + } else { + SM_PROCEED(waitblk); + } + +SM_STATE(recvm7) + + Syslog('x', "xmrecv RECVM7"); + switch (m7recv(tmpfname)) { + case 0: ackd_blk=0; + SM_PROCEED(sendnak); + break; + case 1: last=1; + SM_SUCCESS; + break; + default: SM_PROCEED(sendnak); + } + +SM_STATE(goteof) + + Syslog('x', "xmrecv GOTEOF"); + Slo = FALSE; + closeit(1); + if (ackd_blk == -1L) + last=1; + else { + ackd_blk++; + PUTCHAR(ACK); + if (SEAlink) { + PUTCHAR(ackd_blk); + PUTCHAR(~ackd_blk); + } + } + if (STATUS) { + SM_ERROR; + } + SM_SUCCESS; + +SM_END +SM_RETURN + + + +int resync(off_t resofs) +{ + char resynbuf[16]; + short lcrc; + int count=0; + int gotack,gotnak; + int c; + long sblk; + + Syslog('x', "trying to resync at offset %ld",resofs); + + sblk=resofs/XMBLKSIZ+1; + sprintf(resynbuf,"%ld",sblk); + lcrc=crc16xmodem(resynbuf,strlen(resynbuf)); + gotack=0; + gotnak=0; + + do { + count++; + PUTCHAR(SYN); + PUTSTR(resynbuf); + PUTCHAR(ETX); + PUTCHAR(lcrc&0xff); + PUTCHAR(lcrc>>8); + do { + if ((c=GETCHAR(5)) == ACK) { + if ((c=GETCHAR(1)) == SOH) + gotack=1; + UNGETCHAR(c); + } else if (c == NAK) { + if ((c=GETCHAR(1)) == TIMEOUT) + gotnak=1; + UNGETCHAR(c); + } + } + while (!gotack && !gotnak && (c >= 0)); + if ((c < 0) && (c != TIMEOUT)) + return 1; + } + while (!gotack && !gotnak && (count < 6)); + + if (gotack) { + Syslog('x', "resyncing at offset %ld",resofs); + return 0; + } else { + Syslog('+', "sealink resync at offset %ld failed",resofs); + return 1; + } +} + + diff --git a/mbcico/xmrecv.h b/mbcico/xmrecv.h new file mode 100644 index 00000000..18b70e16 --- /dev/null +++ b/mbcico/xmrecv.h @@ -0,0 +1,7 @@ +#ifndef _XMRECV_H +#define _XMRECV_H + +int xmrecv(char *); + +#endif + diff --git a/mbcico/xmsend.c b/mbcico/xmsend.c new file mode 100644 index 00000000..a2d87974 --- /dev/null +++ b/mbcico/xmsend.c @@ -0,0 +1,523 @@ +/***************************************************************************** + * + * File ..................: mbcico/xmsend.c + * Purpose ...............: Fidonet mailer + * Last modification date : 04-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "session.h" +#include "ttyio.h" +#include "statetbl.h" +#include "xmsend.h" +#include "m7send.h" +#include "filelist.h" +#include "filetime.h" + + +#define XMBLKSIZ 128 +#define DEFAULT_WINDOW 127 + + +static char *ln,*rn; +static int flg; +static int xm_send(void); + +extern unsigned long sentbytes; + + +int xmsend(char *local, char *Remote, int fl) +{ + int rc; + + ln=local; + rn=Remote; + flg=fl; + rc=xm_send(); + if (rc) + Syslog('+', "xmsend failed"); + return rc; +} + + + +SM_DECL(xm_send,(char *)"xmsend") +SM_STATES + sendm7, + sendblk0, + waitack0, + sendblk, + writeblk, + waitack, + resync, + sendeot +SM_NAMES + (char *)"sendm7", + (char *)"sendblk0", + (char *)"waitack0", + (char *)"sendblk", + (char *)"writeblk", + (char *)"waitack", + (char *)"resync", + (char *)"sendeot" +SM_EDECL + + FILE *fp; + struct stat st; + struct flock fl; + unsigned short lcrc=0,rcrc; + int startstate; + int crcmode,seamode,telink; + int a,a1,a2; + int i; + time_t seatime; + time_t stm,etm; + unsigned char header=SOH; + struct _xmblk { + unsigned char n1; + unsigned char n2; + char data[XMBLKSIZ]; + unsigned char c1; + unsigned char c2; + } xmblk; + int count=0; + int cancount=0; + int window; + long last_blk; + long send_blk; + long next_blk; + long ackd_blk; + long tmp; + char resynbuf[16]; + + fl.l_type=F_RDLCK; + fl.l_whence=0; + fl.l_start=0L; + fl.l_len=0L; + + Syslog('x', "xmsend INIT"); + (void)time(&stm); + + /* if we got 'C' than hopefully remote is sealink capable... */ + + if (session_flags & FTSC_XMODEM_CRC) { + telink=0; + crcmode=1; + session_flags |= FTSC_XMODEM_RES; + session_flags |= FTSC_XMODEM_SLO; + session_flags |= FTSC_XMODEM_XOF; + window=DEFAULT_WINDOW; + send_blk=0L; + next_blk=0L; + ackd_blk=-1L; + startstate=sendblk0; + } else { + telink=1; + crcmode=0; + session_flags &= ~FTSC_XMODEM_RES; + session_flags |= FTSC_XMODEM_SLO; + session_flags |= FTSC_XMODEM_XOF; + window=1; + send_blk=0L; + next_blk=0L; + ackd_blk=-1L; + if (flg && !(session_flags & SESSION_IFNA)) + startstate = sendm7; + else + startstate = sendblk0; + } + + seamode=-1; /* not yet sure about numbered ACKs */ + + if (stat(ln,&st) != 0) { + WriteError("$cannot stat local file \"%s\" to send",MBSE_SS(ln)); + return 1; + } + last_blk=(st.st_size-1)/XMBLKSIZ+1; + + if ((fp=fopen(ln,"r")) == NULL) { + WriteError("$cannot open local file \"%s\" to send",MBSE_SS(ln)); + return 1; + } + fl.l_pid = getpid(); + if (fcntl(fileno(fp),F_SETLK,&fl) != 0) { + WriteError("$cannot lock local file \"%s\" to send, skip it",MBSE_SS(ln)); + return 0; + } + if (stat(ln,&st) != 0) { + WriteError("$cannot access local file \"%s\" to send, skip it",MBSE_SS(ln)); + return 0; + } + + Syslog('+', "Xmodem send \"%s\" as \"%s\", size=%lu", MBSE_SS(ln),MBSE_SS(rn),(unsigned long)st.st_size); + sentbytes += (unsigned long)st.st_size; + +SM_START(startstate) + +SM_STATE(sendm7) + + Syslog('x', "xmsend SENDM7"); + if (m7send(rn)) { + SM_PROCEED(sendblk0); + } else { + SM_ERROR; + } + +SM_STATE(sendblk0) + + Syslog('X', "xmsend SENDBLK0"); + Syslog('x', "xmsendblk0 send:%ld, next:%ld, ackd:%ld, last:%ld", send_blk,next_blk,ackd_blk,last_blk); + + memset(xmblk.data,0,sizeof(xmblk.data)); + + xmblk.data[0]=(st.st_size)&0xff; + xmblk.data[1]=(st.st_size>>8)&0xff; + xmblk.data[2]=(st.st_size>>16)&0xff; + xmblk.data[3]=(st.st_size>>24)&0xff; + seatime=mtime2sl(st.st_mtime); + xmblk.data[4]=(seatime)&0xff; + xmblk.data[5]=(seatime>>8)&0xff; + xmblk.data[6]=(seatime>>16)&0xff; + xmblk.data[7]=(seatime>>24)&0xff; + strncpy(xmblk.data+8,rn,17); + if (telink) + for (i=23;(i>8) && (xmblk.data[i] == '\0');i--) + xmblk.data[i]=' '; + sprintf(xmblk.data+25,"mbcico %s",VERSION); + xmblk.data[40]=((session_flags & FTSC_XMODEM_SLO) != 0); + xmblk.data[41]=((session_flags & FTSC_XMODEM_RES) != 0); + xmblk.data[42]=((session_flags & FTSC_XMODEM_XOF) != 0); + + Syslog('X', "sealink block: \"%s\"",printable(xmblk.data,44)); + + next_blk=send_blk+1; + SM_PROCEED(sendblk); + +SM_STATE(sendblk) + + Syslog('X', "xmsend SENDBLK %d", send_blk); + if (send_blk == 0) { + SM_PROCEED(writeblk); + } + + Syslog('x', "xmsendblk send:%ld, next:%ld, ackd:%ld, last:%ld", send_blk,next_blk,ackd_blk,last_blk); + + if (send_blk > last_blk) { + Syslog('X', "send_blk > last_blk"); + if (send_blk == (last_blk+1)) { + SM_PROCEED(sendeot); + } else if (ackd_blk < last_blk) { + SM_PROCEED(waitack); + } else { + (void)time(&etm); + if (etm == stm) + etm++; + Syslog('+', "sent %lu bytes in %s (%lu cps)", (unsigned long)st.st_size,str_time(etm-stm), + (unsigned long)st.st_size/(etm-stm)); + sentbytes += (unsigned long)st.st_size; + fclose(fp); + SM_SUCCESS; + } + } + + memset(xmblk.data, SUB, sizeof(xmblk.data)); + + if (send_blk != next_blk) + if (fseek(fp,(send_blk-1)*XMBLKSIZ,SEEK_SET) != 0) { + WriteError("$fseek error setting block %ld (byte %lu) in file \"%s\"", + send_blk,(send_blk-1)*XMBLKSIZ,MBSE_SS(ln)); + SM_ERROR; + } + if (fread(xmblk.data,1,XMBLKSIZ,fp) <= 0) { + WriteError("$read error for block %lu in file \"%s\"", send_blk,MBSE_SS(ln)); + SM_ERROR; + } + next_blk=send_blk+1; + + SM_PROCEED(writeblk); + +SM_STATE(writeblk) + + Syslog('X', "xmsend WRITEBLK"); + Nopper(); + xmblk.n1=send_blk&0xff; + xmblk.n2=~xmblk.n1; + if (crcmode) { + lcrc=crc16xmodem(xmblk.data,sizeof(xmblk.data)); + xmblk.c1=(lcrc>>8)&0xff; + xmblk.c2=lcrc&0xff; + } else { + xmblk.c1=checksum(xmblk.data,sizeof(xmblk.data)); + } + + PUTCHAR(header); + PUT((char*)&xmblk,crcmode?sizeof(xmblk):sizeof(xmblk)-1); + if (STATUS) { + SM_ERROR; + } + if (crcmode) + Syslog('x', "sent '0x%02x',no 0x%02x, %d bytes crc 0x%04x", header, xmblk.n1, XMBLKSIZ, lcrc); + else + Syslog('x', "sent '0x%02x',no 0x%02x, %d bytes checksum 0x%02x", header, xmblk.n1, XMBLKSIZ, xmblk.c1); + send_blk++; + SM_PROCEED(waitack); + +SM_STATE(waitack) + + Syslog('x', "xmsend WAITACK"); + if ((count > 4) && (ackd_blk < 0)) { + Syslog('+', "Cannot send sealink block, try xmodem"); + window=1; + ackd_blk++; + SM_PROCEED(sendblk); + } + if (count > 9) { + Syslog('+', "Too many errors in xmodem send"); + SM_ERROR; + } + + if (!((ackd_blk < 0) || (send_blk > (last_blk+1)) || ((send_blk-ackd_blk) > window))) { + if ((WAITPUTGET(0) & 3) == 2) { + SM_PROCEED(sendblk); + } + } + + a = GETCHAR(20); + Syslog('X', "xmsend got 0x%02x", a); + if (a == TIMEOUT) { + if (count++ > 9) { + Syslog('+', "too many tries to send block"); + SM_ERROR; + } + Syslog('x', "timeout waiting for ACK"); + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + } else if (a < 0) { + SM_ERROR; + } else switch (a) { + case ACK: + Syslog('x', "got ACK seamode=%d", seamode); + count=0; + cancount=0; + switch (seamode) { + case -1:if ((a1=GETCHAR(1)) < 0) { + seamode=0; + UNGETCHAR(a); + SM_PROCEED(waitack); + } else if ((a2=GETCHAR(1)) < 0) { + seamode=0; + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } else if ((a1&0xff) != ((~a2)&0xff)) { + seamode=0; + UNGETCHAR(a2); + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } else { + seamode=1; + UNGETCHAR(a2); + UNGETCHAR(a1); + UNGETCHAR(a); + SM_PROCEED(waitack); + } + break; + case 0: + ackd_blk++; + SM_PROCEED(sendblk); + break; + case 1: + a1=GETCHAR(1); + a2=GETCHAR(1); + Syslog('X', "got block ACK %d", a1); + if ((a1 < 0) || (a2 < 0) || (a1 != ((~a2)&0xff))) { + Syslog('x', "bad ACK: 0x%02x/0x%02x, ignore", a1,a2); + SM_PROCEED(sendblk); + } else { + if (a1 == ((send_blk-1) & 0xff)) { + /* FD seems only to ACK last received block which is allright, 31-12-2000 MB. */ + Syslog('x', "got ACK %d", a1); + } else if (a1 != ((ackd_blk+1) & 0xff)) { + Syslog('x', "got ACK %d, expected %d", a1,(ackd_blk+1)&0xff); + ackd_blk++; + } + tmp=send_blk-((send_blk-a1)&0xff); + if ((tmp > ackd_blk) && (tmp < send_blk)) + ackd_blk=tmp; + else + Syslog('x', "bad ACK: %ld, ignore", a1,a2); + if ((ackd_blk+1) == send_blk) { + SM_PROCEED(sendblk); + } else { /* read them all if more than 1 */ + SM_PROCEED(waitack); + } + } + break; + } + break; + case NAK: if (ackd_blk <= 0) + crcmode=0; + count++; + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + break; + case SYN: SM_PROCEED(resync); + break; + case DC3: if (session_flags & FTSC_XMODEM_XOF) { + while (((a=GETCHAR(15)) > 0) && (a != DC1)) + Syslog('x', "got '%s' waiting for DC1", printablec(a)); + } + SM_PROCEED(waitack); + break; + case CAN: if (cancount++ > 5) { + Syslog('+', "Remote requested cancel transfer"); + SM_ERROR; + } else { + SM_PROCEED(waitack); + } + break; + case 'C': if (ackd_blk < 0) { + crcmode=1; + count++; + send_blk=ackd_blk+1; + SM_PROCEED(sendblk); + } + /* fallthru */ + default: Syslog('x', "Got '%s' waiting for ACK",printablec(a)); + SM_PROCEED(waitack); + break; + } + +SM_STATE(resync) + + Syslog('x', "xmsend RESYNC"); + if (count++ > 9) { + Syslog('+', "too may tries to resync"); + SM_ERROR; + } + + i=-1; + do { + a=GETCHAR(15); + resynbuf[++i]=a; + } + while ((a >= '0') && (a <= '9') && (i < sizeof(resynbuf)-1)); + resynbuf[i]='\0'; + Syslog('x', "got resync \"%s\", i=%d",resynbuf,i); + lcrc=crc16xmodem(resynbuf,strlen(resynbuf)); + rcrc=0; + if (a != ETX) { + if (a > 0) + Syslog('+', "Got %d waiting for resync",a); + else + Syslog('+', "Got %s waiting for resync",printablec(a)); + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + if ((a=GETCHAR(1)) < 0) { + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + rcrc=a&0xff; + if ((a=GETCHAR(1)) < 0) { + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + rcrc |= (a << 8); + if (rcrc != lcrc) { + Syslog('+', "Bad resync crc: 0x%04x != 0x%04x",lcrc,rcrc); + PUTCHAR(NAK); + SM_PROCEED(waitack); + } + send_blk=atol(resynbuf); + ackd_blk=send_blk-1; + Syslog('+', "Resyncing at block %ld (byte %lu)", send_blk,(send_blk-1L)*XMBLKSIZ); + PUTCHAR(ACK); + SM_PROCEED(sendblk); + +SM_STATE(sendeot) + + Syslog('x', "xmsend SENDEOT"); + PUTCHAR(EOT); + if (STATUS) { + SM_ERROR; + } + send_blk++; + SM_PROCEED(waitack); + +SM_END +SM_RETURN + + + +int xmsndfiles(file_list *tosend) +{ + int rc,c = 0,gotnak,count; + file_list *nextsend; + + Syslog('x', "Xmodem send files start"); + for (nextsend=tosend;nextsend;nextsend=nextsend->next) { + if (*(nextsend->local) != '~') { + if (nextsend->remote) { + if ((rc=xmsend(nextsend->local,nextsend->remote, (nextsend != tosend)))) {/* send m7 for rest */ + Syslog('x', "Xmodem send files failed, rc=%d", rc); + return rc; /* and thus avoid execute_disposition() */ + } else { + gotnak=0; + count=0; + while (!gotnak && (count < 6)) { + c=GETCHAR(15); + if (c < 0) + return STATUS; + if (c == CAN) { + Syslog('+', "Remote refused receiving"); + return 1; + } + if ((c == 'C') || (c == NAK)) + gotnak=1; + else + Syslog('x', "Got '%s' waiting NAK", printablec(c)); + } + if (c == 'C') + session_flags |= FTSC_XMODEM_CRC; + if (!gotnak) + return 1; + } + } + execute_disposition(nextsend); + } + } + Syslog('x', "Xmodem send files finished"); + PUTCHAR(EOT); + return STATUS; +} + + diff --git a/mbcico/xmsend.h b/mbcico/xmsend.h new file mode 100644 index 00000000..7140f13e --- /dev/null +++ b/mbcico/xmsend.h @@ -0,0 +1,9 @@ +#ifndef _XMSEND_H +#define _XMSEND_H + +int xmsend(char *, char *, int); +int xmsndfiles(file_list *); + + +#endif + diff --git a/mbcico/yoohoo.c b/mbcico/yoohoo.c new file mode 100644 index 00000000..900d9b7b --- /dev/null +++ b/mbcico/yoohoo.c @@ -0,0 +1,637 @@ +/***************************************************************************** + * + * File ..................: mbcico/yoohoo.c + * Purpose ...............: Fidonet mailer + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* Added modifications made on 9 Jun 1996 by P.Saratxaga + * - added "Hello" structure (from FTS-0006) so we can more easily + * parse it. + * - added domain support in hello packet (in Hello.name, reading after + * first \0 there is the domain) + * - added support for 16 bit product code + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "statetbl.h" +#include "ttyio.h" +#include "session.h" +#include "config.h" +#include "emsi.h" +#include "hydra.h" +#include "rdoptions.h" +#include "wazoo.h" +#include "dietifna.h" +#include "yoohoo.h" + + +/*------------------------------------------------------------------------*/ +/* YOOHOO CAPABILITY VALUES */ +/*------------------------------------------------------------------------*/ +#define Y_DIETIFNA 0x0001 /* Can do fast "FTS-0001" 0000 0000 0000 0001 */ +#define FTB_USER 0x0002 /* Full-Tilt Boogie 0000 0000 0000 0010 */ +#define ZED_ZIPPER 0x0004 /* Does ZModem, 1K blocks 0000 0000 0000 0100 */ +#define ZED_ZAPPER 0x0008 /* Can do ZModem variant 0000 0000 0000 1000 */ +#define DOES_IANUS 0x0010 /* Can do Janus 0000 0000 0001 0000 */ +#define DOES_HYDRA 0x0020 /* Can do Hydra 0000 0000 0010 0000 */ +#define Bit_6 0x0040 /* reserved by FTSC 0000 0000 0100 0000 */ +#define Bit_7 0x0080 /* reserved by FTSC 0000 0000 1000 0000 */ +#define Bit_8 0x0100 /* reserved by FTSC 0000 0001 0000 0000 */ +#define Bit_9 0x0200 /* reserved by FTSC 0000 0010 0000 0000 */ +#define Bit_a 0x0400 /* reserved by FTSC 0000 0100 0000 0000 */ +#define Bit_b 0x0800 /* reserved by FTSC 0000 1000 0000 0000 */ +#define Bit_c 0x1000 /* reserved by FTSC 0001 0000 0000 0000 */ +#define Bit_d 0x2000 /* reserved by FTSC 0010 0000 0000 0000 */ +#define DO_DOMAIN 0x4000 /* Packet contains domain 0100 0000 0000 0000 */ +#define WZ_FREQ 0x8000 /* WZ file req. ok 1000 0000 0000 0000 */ + +#define LOCALCAPS (Y_DIETIFNA|ZED_ZIPPER|ZED_ZAPPER|DOES_HYDRA|DO_DOMAIN) + + +static int rxyoohoo(void); +static int txyoohoo(void); +static void fillhello(unsigned short,char*); +static int checkhello(void); + +static int iscaller; +static struct _hello { + unsigned char data[128]; + unsigned char crc[2]; +} hello; + +typedef struct _Hello { + unsigned short signal; /* always 'o' (0x6f) */ + unsigned short hello_version; /* currently 1 (0x01) */ + unsigned short product; /* product code */ + unsigned short product_maj; /* major revision of the product */ + unsigned short product_min; /* minor revision of the product */ + unsigned char my_name[60]; /* Other end's name, will include domain */ + /* if DO_DOMAIN is set in capabilities */ + unsigned char sysop[20]; /* sysop's name */ + unsigned short my_zone; /* 0== not supported */ + unsigned short my_net; /* out primary net number */ + unsigned short my_node; /* our primary node number */ + unsigned short my_point; /* 0 == not supported */ + unsigned char my_password[8]; /* This isn't necessarily null-terminated */ + unsigned char reserved2[8]; /* reserved by Opus */ + unsigned short capabilities; /* see below */ + unsigned char reserved3[12]; /* for non-Opus systems with "approval" */ + /* total size 128 bytes */ +} Hello; + + +extern int Loaded; + +Hello hello2; +Hello gethello2(unsigned char[]); + + + +int rx_yoohoo(void) +{ + int rc; + unsigned short capabilities,localcaps; + char *pwd = NULL; + + Syslog('+', "Start inbound YooHoo session"); + + pwd = NULL; + localcaps = LOCALCAPS; + if (localoptions & NOZMODEM) localcaps &= ~(ZED_ZAPPER|ZED_ZIPPER); + if (localoptions & NOZEDZAP) localcaps &= ~ZED_ZAPPER; + if (localoptions & NOHYDRA) localcaps &= ~DOES_HYDRA; + emsi_local_opts = 0; + emsi_remote_opts = 0; + iscaller = 0; + + if ((rc = rxyoohoo()) == 0) { + Loaded = checkhello(); + capabilities = hello2.capabilities; + if (capabilities & WZ_FREQ) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + localcaps &= capabilities; + if (localcaps & DOES_HYDRA) + localcaps &= DOES_HYDRA; + else if (localcaps & ZED_ZAPPER) + localcaps &= ZED_ZAPPER; + else if (localcaps & ZED_ZIPPER) + localcaps &= ZED_ZIPPER; + else if (localcaps & FTB_USER) + localcaps &= FTB_USER; + else if (localcaps & Y_DIETIFNA) + localcaps &= Y_DIETIFNA; + if ((localoptions & NOFREQS) == 0) + localcaps |= WZ_FREQ; + else + emsi_local_opts |= OPT_NRQ; + + if (((nlent=getnlent(remote->addr))) && (nlent->pflag != NL_DUMMY)) { + Syslog('+', "Remote is a listed system"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.inbound); + sprintf(history.location, "%s", nlent->location); + } + if (nlent) + rdoptions(Loaded); + + if (strlen(nodes.Epasswd)) { + if ((strncasecmp((char*)hello2.my_password, nodes.Epasswd, strlen(nodes.Epasswd)) == 0) && + (strlen((char*)hello2.my_password) == strlen(nodes.Epasswd))) { + Syslog('+', "Password correct, protected mail session"); + if (inbound) + free(inbound); + inbound = xstrcpy(CFG.pinbound); + pwd = xstrcpy(nodes.Epasswd); + } else { + pwd = (char *)"BAD_PASS"; + Syslog('?', "Remote password \"%s\", expected \"%s\"", (char*)hello2.my_password, nodes.Epasswd); + localcaps = 0; + } + } else + Syslog('s', "No YooHoo password check"); + fillhello(localcaps,pwd); + + rc = txyoohoo(); + if (pwd) + free(pwd); + } + + if ((rc == 0) && ((localcaps & LOCALCAPS) == 0)) { + Syslog('+', "No common protocols or bad password"); + return 0; + } + if (rc) + return rc; + + IsDoing("Inbound %s", ascfnode(remote->addr, 0x0f)); + + session_flags |= SESSION_WAZOO; + if (localcaps & DOES_HYDRA) + return hydra(0); + else if ((localcaps & ZED_ZAPPER) || (localcaps & ZED_ZIPPER)) { + if (localcaps & ZED_ZAPPER) + emsi_local_protos = PROT_ZAP; + else + emsi_local_protos = PROT_ZMO; + return rxwazoo(); + } else if (localcaps & Y_DIETIFNA) + return rxdietifna(); + else + WriteError("YooHoo internal error - no proto for 0x%04xh",localcaps); + return 1; +} + + + +int tx_yoohoo(void) +{ + int rc; + unsigned short capabilities; + char *pwd; + + Syslog('+', "Start outbound YooHoo session"); + + if (strlen(nodes.Epasswd)) + pwd = xstrcpy(nodes.Epasswd); + else + pwd = NULL; + + capabilities = LOCALCAPS; + if (localoptions & NOZMODEM) + capabilities &= ~(ZED_ZAPPER|ZED_ZIPPER); + if (localoptions & NOZEDZAP) + capabilities &= ~ZED_ZAPPER; + if (localoptions & NOHYDRA) + capabilities &= ~DOES_HYDRA; + if ((localoptions & NOFREQS) == 0) + capabilities |= WZ_FREQ; + else + emsi_local_opts |= OPT_NRQ; + + fillhello(capabilities,pwd); + iscaller=1; + + if ((rc = txyoohoo()) == 0) { + rc = rxyoohoo(); + checkhello(); + capabilities = hello2.capabilities; + if (capabilities & WZ_FREQ) + session_flags |= SESSION_WAZOO; + else + session_flags &= ~SESSION_WAZOO; + } + + if ((rc == 0) && ((capabilities & LOCALCAPS) == 0)) { + Syslog('+', "No common protocols"); + return 0; + } + + if (rc) + return rc; + + IsDoing("Outbound %s", ascfnode(remote->addr, 0x0f)); + + session_flags |= SESSION_WAZOO; + if (capabilities & DOES_HYDRA) + return hydra(1); + else if ((capabilities & ZED_ZAPPER) || (capabilities & ZED_ZIPPER)) { + if (capabilities & ZED_ZAPPER) + emsi_local_protos = PROT_ZAP; + else + emsi_local_protos = PROT_ZMO; + return txwazoo(); + } else if (capabilities & Y_DIETIFNA) + return txdietifna(); + else + WriteError("YooHoo internal error - no proto for 0x%04xh",capabilities); + return 1; +} + + + +SM_DECL(rxyoohoo,(char *)"rxyoohoo") +SM_STATES + sendenq, + waitchar, + getpacket, + sendnak, + sendack +SM_NAMES + (char *)"sendenq", + (char *)"waitchar", + (char *)"getpacket", + (char *)"sendnak", + (char *)"sendack" +SM_EDECL + + int c; + int count=0; + unsigned short lcrc,rcrc; + +SM_START(sendenq) + +SM_STATE(sendenq) + + Syslog('S', "rxyoohoo SENDENQ"); + if (count++ > 12) { + Syslog('+', "Too many tries to get hello packet"); + SM_ERROR; + } + PUTCHAR(ENQ); + SM_PROCEED(waitchar) + +SM_STATE(waitchar) + + Syslog('S', "rxyoohoo WAITCHAR"); + c=GETCHAR(10); + if (c == TIMEOUT) { + SM_PROCEED(sendenq); + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case 0x1f: SM_PROCEED(getpacket); + break; + case YOOHOO: SM_PROCEED(sendenq); + break; + default: SM_PROCEED(waitchar); + break; + } + +SM_STATE(getpacket) + + Syslog('S', "rxyoohoo GETPACKET"); + GET((char*)&hello, sizeof(hello), 30); + if (STATUS) { + SM_ERROR; + } + + lcrc = crc16xmodem((char*)hello.data, sizeof(hello.data)); + rcrc = (hello.crc[0] << 8) + hello.crc[1]; + if (lcrc != rcrc) { + Syslog('+',"crc does not match in hello packet: %04xh/%04xh", rcrc,lcrc); + SM_PROCEED(sendnak); + } else { + SM_PROCEED(sendack); + } + +SM_STATE(sendnak) + + Syslog('S', "rxyoohoo SENDNAK"); + if (count++ > 9) { + Syslog('+', "Too many tries to get hello packet"); + SM_ERROR; + } + PUTCHAR('?'); + SM_PROCEED(waitchar); + +SM_STATE(sendack) + + Syslog('S', "rxyoohoo SENDACK"); + PUTCHAR(ACK); + SM_SUCCESS; + +SM_END +SM_RETURN + + + +SM_DECL(txyoohoo,(char *)"txyoohoo") +SM_STATES + sendyoohoo, + waitenq, + sendpkt, + waitchar +SM_NAMES + (char *)"sendyoohoo", + (char *)"waitenq", + (char *)"sendpkt", + (char *)"waitchar" +SM_EDECL + + int c; + int count=0; + int startstate; + unsigned short lcrc; + + if (iscaller) + startstate = sendpkt; + else + startstate = sendyoohoo; + + lcrc = crc16xmodem((char*)hello.data, sizeof(hello.data)); + hello.crc[0] = lcrc >> 8; + hello.crc[1] = lcrc & 0xff; + Syslog('S', "txyoohoo INIT"); + +SM_START(startstate) + +SM_STATE(sendyoohoo) + + Syslog('S', "txyoohoo SENDYOOHOO"); + PUTCHAR(YOOHOO); + SM_PROCEED(waitenq); + +SM_STATE(waitenq) + + Syslog('S', "txyoohoo WAITENQ"); + c=GETCHAR(10); + if (c == TIMEOUT) { + if (count++ > 9) { + Syslog('+', "Timeout waiting ENQ"); + SM_ERROR; + } else { + SM_PROCEED(sendyoohoo); + } + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ENQ: SM_PROCEED(sendpkt); + case YOOHOO: SM_PROCEED(waitenq); + default: Syslog('+',"Got '%s' waiting hello ACK", printablec(c)); + SM_PROCEED(waitchar); + break; + } + +SM_STATE(sendpkt) + + Syslog('S', "txyoohoo SENDPKT"); + if (count++ > 9) { + Syslog('+', "Too many tries to send hello packet"); + SM_ERROR; + } + + PUTCHAR(0x1f); + PUT((char*)&hello, sizeof(hello)); + if (STATUS) { + SM_ERROR; + } + SM_PROCEED(waitchar); + +SM_STATE(waitchar) + + Syslog('S', "txyoohoo WAITCHAR"); + c=GETCHAR(30); + if (c == TIMEOUT) { + Syslog('+', "Timeout waiting hello ACK"); + SM_ERROR; + } else if (c < 0) { + SM_ERROR; + } else switch (c) { + case ACK: Syslog('S', "Handshake successfull"); + SM_SUCCESS; + break; + case '?': SM_PROCEED(sendpkt); + break; + case ENQ: SM_PROCEED(sendpkt); + break; + default: SM_PROCEED(waitchar); + break; + } + +SM_END +SM_RETURN + + + + +void fillhello(unsigned short capabilities, char *password) +{ + faddr *best; + unsigned short majver, minver; + + Syslog('S',"fillhello(0x%04hx)",capabilities); + + best = bestaka_s(remote->addr); + + sscanf(VERSION,"%hd.%hd", &majver, &minver); + memset(&hello, 0, sizeof(hello)); + hello.data[0] = 'o'; /* signal */ + hello.data[2] = 1; /* hello-version */ + hello.data[4] = PRODCODE; /* product */ + hello.data[6] = majver&0xff; /* prod-ver-major */ + hello.data[7] = majver>>8; /* prod-ver-major */ + hello.data[8] = minver&0xff; /* prod-ver-minor */ + hello.data[9] = minver>>8; /* prod-ver-minor */ + strncpy((char*)hello.data+10, name?name:"Unavailable",59); /* name */ + if (name) { + hello.data[10+strlen(name)] = '\0'; + strncpy((char*)hello.data+11 + strlen(name), + best->domain, 58-strlen(name)); /* domain */ + } else + strncpy((char*)hello.data + 22, best->domain, 47); /* domain */ + strncpy((char*)hello.data+70, CFG.sysop_name,19); /* sysop */ + hello.data[90] = best->zone&0xff; /* zone */ + hello.data[91] = best->zone>>8; /* zone */ + hello.data[92] = best->net&0xff; /* net */ + hello.data[93] = best->net>>8; /* net */ + hello.data[94] = best->node&0xff; /* node */ + hello.data[95] = best->node>>8; /* node */ + hello.data[96] = best->point&0xff; /* point */ + hello.data[97] = best->point>>8; /* point */ + + if (password) + strncpy((char*)hello.data + 98, password, 8); + + hello.data[114] = capabilities & 0xff; /* capabilities */ + hello.data[115] = capabilities >> 8; /* capabilities */ + tidy_faddr(best); + Syslog('S',"filled hello \"%s\"",printable((char*)hello.data,128)); +} + + + +int checkhello(void) +{ + unsigned short i, majver = 0, minver = 0; + fa_list **tmpl,*tmpn; + faddr remaddr; + char *prodnm, *q; + int loaded = FALSE; + + Syslog('S',"check hello \"%s\"",printable((char*)hello.data,128)); + + hello2 = gethello2(hello.data); + + if ((hello2.signal != 0x6f) || + (hello2.hello_version != 0x01)) { + Syslog('+', "Got \"%s\" instead of \"o\\000\\001\000\"", printable((char*)hello.data,3)); + } + + prodnm = xstrcpy((char *)""); + for (i = 0; ftscprod[i].name; i++) + if (ftscprod[i].code == hello2.product) { + free(prodnm); + prodnm = xstrcpy(ftscprod[i].name); + majver = hello2.product_maj; + minver = hello2.product_min; + break; + } + + remaddr.zone = hello2.my_zone; + remaddr.net = hello2.my_net; + remaddr.node = hello2.my_node; + remaddr.point = hello2.my_point; + remaddr.name = NULL; + remaddr.domain = NULL; + if (hello2.my_name[0]) + remaddr.domain = hello2.my_name + (strlen(hello2.my_name)) + 1; + if (remaddr.domain[0]) { + if ((q = strchr(remaddr.domain, '.'))) + *q = '\0'; + } else { + remaddr.domain = NULL; + } + if (remote) + Syslog('S',"Remote known address: %s",ascfnode(remote->addr,0x1f)); + + for (tmpl = &remote; *tmpl; tmpl = &((*tmpl)->next)); + if ((remote == NULL) || (metric(remote->addr, &remaddr) != 0)) { + (*tmpl) = (fa_list*)malloc(sizeof(fa_list)); + (*tmpl)->next = NULL; + (*tmpl)->addr = (faddr*)malloc(sizeof(faddr)); + (*tmpl)->addr->zone = remaddr.zone; + (*tmpl)->addr->net = remaddr.net; + (*tmpl)->addr->node = remaddr.node; + (*tmpl)->addr->point = remaddr.point; + (*tmpl)->addr->domain = xstrcpy(remaddr.domain); + (*tmpl)->addr->name = NULL; /* Added 15-Dec-1998 */ + } else { + tmpl=&remote; + Syslog('S',"Using single remote address"); + } + + for (tmpn = remote; tmpn; tmpn = tmpn->next) { + (void)nodelock(tmpn->addr); + /* + * lock all remotes, ignore locking result + */ + if (!loaded) + if (noderecord(tmpn->addr)) + loaded = TRUE; + } + + Syslog('+', " address: %s",ascfnode(remote->addr,0x1f)); + history.aka.zone = remote->addr->zone; + history.aka.net = remote->addr->net; + history.aka.node = remote->addr->node; + history.aka.point = remote->addr->point; + Syslog('S', "password: %s",(char*)hello2.my_password); + if (hello2.product < 0x0100) + Syslog('+', " uses: %s [%02X] version %d.%d", prodnm, hello2.product, majver, minver); + else + Syslog('+', " uses: %s [%04X] version %d.%d", prodnm, hello2.product, majver, minver); + Syslog('+', " system: %s",(char*)hello2.my_name); + sprintf(history.system_name, "%s", hello2.my_name); + history.system_name[36] = '\0'; + Syslog('+', " sysop: %s",(char*)hello2.sysop); + sprintf(history.sysop, "%s", hello2.sysop); + sprintf(history.location, "Somewhere"); + + free(prodnm); + return loaded; +} + + + +Hello gethello2(unsigned char Hellop[]) +{ + int i; + Hello p; + + p.signal=Hellop[0]+(Hellop[1]<<8); + p.hello_version=Hellop[2]+(Hellop[3]<<8); + p.product=Hellop[4]+(Hellop[5]<<8); + p.product_maj=Hellop[6]+(Hellop[7]<<8); + p.product_min=Hellop[8]+(Hellop[9]<<8); + for (i=0;i<60;i++) + p.my_name[i]=Hellop[10+i]; + for (i=0;i<20;i++) + p.sysop[i]=Hellop[70+i]; + p.my_zone=Hellop[90]+(Hellop[91]<<8); + p.my_net=Hellop[92]+(Hellop[93]<<8); + p.my_node=Hellop[94]+(Hellop[95]<<8); + p.my_point=Hellop[96]+(Hellop[97]<<8); + for (i=0;i<8;i++) + p.my_password[i]=Hellop[98+i]; + for (i=0;i<8;i++) + p.reserved2[i]=Hellop[106+i]; + p.capabilities=Hellop[114]+(Hellop[115]<<8); + for (i=0;i<12;i++) + p.reserved3[i]=Hellop[116+i]; + + return p; +} + diff --git a/mbcico/yoohoo.h b/mbcico/yoohoo.h new file mode 100644 index 00000000..d02eac6f --- /dev/null +++ b/mbcico/yoohoo.h @@ -0,0 +1,8 @@ +#ifndef _YOOHOO_H +#define _YOOHOO_H + +int rx_yoohoo(void); +int tx_yoohoo(void); + +#endif + diff --git a/mbcico/zmmisc.c b/mbcico/zmmisc.c new file mode 100644 index 00000000..c21b1dd7 --- /dev/null +++ b/mbcico/zmmisc.c @@ -0,0 +1,999 @@ +/* + * Z M . C + * Copyright 1994 Omen Technology Inc All Rights Reserved + * ZMODEM protocol primitives + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr) receive header - binary or hex + * zsdata(buf, len, frameend) send data + * zrdata(buf, len) receive data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + * + * + * This version implements numerous enhancements including ZMODEM + * Run Length Encoding and variable length headers. These + * features were not funded by the original Telenet development + * contract. + * + * This software may be freely used for educational (didactic + * only) purposes. This software may also be freely used to + * support file transfer operations to or from licensed Omen + * Technology products. Use with other commercial or shareware + * programs (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION. + * + * Any programs which use part or all of this software must be + * provided in source form with this notice intact except by + * written permission from Omen Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + */ + +static void zputhex(int); +static void zsbh32(int,char*,int,int); +static void zsda32(char*,int,int); +static int zrdat32(char*,int); +static int noxrd7(void); +static int zrbhd32(char*); +static int zrbhdr(char*); +static int zrhhdr(char*); +static int zgethex(void); +static int zgeth1(void); +static void garbitch(void); + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" + + +/* Original zm.c timing was in tenths of seconds, but our current ttyio driver + does timing in whole seconds. +*/ +static int Rxtimeout = 10; /* Seconds to wait for something */ +int Zctlesc; + +/* Globals used by ZMODEM functions */ +int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +int Rxtype; /* Type of header received */ +int Rxhlen; /* Length of header received */ +int Rxcount; /* Count of data bytes received */ +char Rxhdr[ZMAXHLEN]; /* Received header */ +char Txhdr[ZMAXHLEN]; /* Transmitted header */ +long Rxpos; /* Received file position */ +long Txpos; /* Transmitted file position */ +int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +int Crc32t; /* Controls 32 bit CRC being sent */ + /* 1 == CRC32, 2 == CRC32 + RLE */ +int Crc32r; /* Indicates/controls 32 bit CRC being received */ + /* 0 == CRC16, 1 == CRC32, 2 == CRC32 + RLE */ +int Usevhdrs; /* Use variable length headers */ +int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +char *Altcan; /* Alternate canit string */ + +char *txbuf=NULL; +char *rxbuf=NULL; + +static int lastsent; /* Last char we sent */ +static int Not8bit; /* Seven bits seen on header */ + +char *frametypes[] = { + (char *)"EMPTY", /* -16 */ + (char *)"Can't be (-15)", + (char *)"Can't be (-14)", + (char *)"Can't be (-13)", + (char *)"Can't be (-12)", + (char *)"Can't be (-11)", + (char *)"Can't be (-10)", + (char *)"Can't be (-9)", + (char *)"HANGUP", /* -8 */ + (char *)"Can't be (-7)", + (char *)"Can't be (-6)", + (char *)"Can't be (-5)", + (char *)"EOFILE", /* -4 */ + (char *)"Can't be (-3)", + (char *)"TIMEOUT", /* -2 */ + (char *)"ERROR", /* -1 */ + (char *)"ZRQINIT", + (char *)"ZRINIT", + (char *)"ZSINIT", + (char *)"ZACK", + (char *)"ZFILE", + (char *)"ZSKIP", + (char *)"ZNAK", + (char *)"ZABORT", + (char *)"ZFIN", + (char *)"ZRPOS", + (char *)"ZDATA", + (char *)"ZEOF", + (char *)"ZFERR", + (char *)"ZCRC", + (char *)"ZCHALLENGE", + (char *)"ZCOMPL", + (char *)"ZCAN", + (char *)"ZFREECNT", + (char *)"ZCOMMAND", + (char *)"ZSTDERR", + (char *)"xxxxx" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; + + +/***** Hack by mj ***********************************************************/ +/* + * Buffer for outgoing frames. Sending them with single character write()'s + * is a waste of processor time and causes severe performance degradation + * on TCP and ISDN connections. + */ +#define FRAME_BUFFER_SIZE 16384 +static char *frame_buffer=NULL; +static int frame_length = 0; + +#define BUFFER_CLEAR() do { frame_length=0; } while(0) +#define BUFFER_BYTE(c) do { frame_buffer[frame_length++]=(c); } while(0) +#define BUFFER_FLUSH() do { PUT(frame_buffer, frame_length); \ + frame_length=0; } while(0); +/****************************************************************************/ + +void get_frame_buffer(void) +{ + if (frame_buffer == NULL) + frame_buffer = malloc(FRAME_BUFFER_SIZE); +} + + +void free_frame_buffer(void) +{ + if (frame_buffer) + free(frame_buffer); + frame_buffer = NULL; +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zsbhdr: %c %d %s %lx", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + if (type == ZDATA) + for (n = Znulls; --n >=0; ) + BUFFER_BYTE(0); + + BUFFER_BYTE(ZPAD); BUFFER_BYTE(ZDLE); + + switch (Crc32t=Txfcs32) { + case 2: + zsbh32(len, shdr, type, Usevhdrs?ZVBINR32:ZBINR32); + BUFFER_FLUSH(); break; + case 1: + zsbh32(len, shdr, type, Usevhdrs?ZVBIN32:ZBIN32); break; + default: + if (Usevhdrs) { + BUFFER_BYTE(ZVBIN); + zsendline(len); + } + else + BUFFER_BYTE(ZBIN); + zsendline(type); + crc = updcrc16(type, 0); + + for (n=len; --n >= 0; ++shdr) { + zsendline(*shdr); + crc = updcrc16((0377& *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); + zsendline(crc); + } + + BUFFER_FLUSH(); +} + + + +/* + * Send ZMODEM binary header hdr of type type + */ +void zsbh32(int len, register char *shdr, int type, int flavour) +{ + register int n; + register unsigned long crc; + + BUFFER_BYTE(flavour); + if (Usevhdrs) + zsendline(len); + zsendline(type); + crc = 0xFFFFFFFFL; crc = updcrc32(type, crc); + + for (n=len; --n >= 0; ++shdr) { + crc = updcrc32((0377 & *shdr), crc); + zsendline(*shdr); + } + crc = ~crc; + for (n=4; --n >= 0;) { + zsendline((int)crc); + crc >>= 8; + } +} + + + +/* + * Send ZMODEM HEX header hdr of type type + */ +void zshhdr(int len, int type, register char *shdr) +{ + register int n; + register unsigned short crc; + + Syslog('z', "zshhdr: %c %d %s %ld", Usevhdrs?'v':'f', len, frametypes[type+FTOFFSET], rclhdr(shdr)); + + BUFFER_CLEAR(); + + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZPAD); + BUFFER_BYTE(ZDLE); + if (Usevhdrs) { + BUFFER_BYTE(ZVHEX); + zputhex(len); + } + else + BUFFER_BYTE(ZHEX); + zputhex(type); + Crc32t = 0; + + crc = updcrc16(type, 0); + for (n=len; --n >= 0; ++shdr) { + zputhex(*shdr); crc = updcrc16((0377 & *shdr), crc); + } + crc = updcrc16(0,updcrc16(0,crc)); + zputhex(((int)(crc>>8))); zputhex(crc); + + /* + * Make it printable on remote machine + */ + BUFFER_BYTE(015); + BUFFER_BYTE(0212); + + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + BUFFER_BYTE(021); + + BUFFER_FLUSH(); +} + + + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +char *Zendnames[] = {(char *)"ZCRCE",(char *)"ZCRCG",(char *)"ZCRCQ",(char *)"ZCRCW"}; +void zsdata(register char *buf, int length, int frameend) +{ + register unsigned short crc; + + Syslog('z', "zsdata: %d %s", length, Zendnames[(frameend-ZCRCE)&3]); + + BUFFER_CLEAR(); + + switch (Crc32t) { + case 1: + zsda32(buf, length, frameend); break; + case 2: + zsdar32(buf, length, frameend); break; + default: + crc = 0; + for (;--length >= 0; ++buf) { + zsendline(*buf); crc = updcrc16((0377 & *buf), crc); + } + BUFFER_BYTE(ZDLE); BUFFER_BYTE(frameend); + crc = updcrc16(frameend, crc); + + crc = updcrc16(0,updcrc16(0,crc)); + zsendline(((int)(crc>>8))); zsendline(crc); + } + if (frameend == ZCRCW) + BUFFER_BYTE(XON); + + BUFFER_FLUSH(); +} + + + +void zsda32(register char *buf, int length, int frameend) +{ + register int c; + register unsigned long crc; + + crc = 0xFFFFFFFFL; + for (;--length >= 0; ++buf) { + c = *buf & 0377; + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else + zsendline(c); + crc = updcrc32(c, crc); + } + BUFFER_BYTE(ZDLE); + BUFFER_BYTE(frameend); + crc = updcrc32(frameend, crc); + + crc = ~crc; + for (c=4; --c >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + + +/* + * Receive array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + * NB: On errors may store length+1 bytes! + */ +int zrdata(register char *buf, int length) +{ + register int c; + register unsigned short crc; + register char *end; + register int d; + + switch (Crc32r) { + case 1: + return zrdat32(buf, length); + case 2: + return zrdatr32(buf, length); + } + + crc = Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + crc = updcrc16((((d=c))&0377), crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrdata: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + Syslog('z', "zrdata: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT receiving data"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc16(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +int zrdat32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrdat32: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + + Syslog('z', "zrdat32: %d %s", Rxcount, Zendnames[(d-GOTCRCE)&3]); + + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Carrier lost while receiving"); + return c; + default: + garbitch(); + return c; + } + } + *buf++ = c; + crc = updcrc32(c, crc); + } + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + + + +void garbitch(void) +{ + Syslog('+', "Zmodem: Garbled data subpacket"); +} + + + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * + * Set Rxhlen to size of header (default 4) (valid if good hdr) + * On success, set Zmodem to 1, set Rxpos and return type of header. + * Otherwise return negative on error. + * Return ERROR instantly if ZCRCW sequence, for fast error recovery. + */ +int zgethdr(char *shdr) +{ + register int c, n, cancount; + + int Zrwindow = 1400; + int Baudrate = 9600; + n = Zrwindow + Baudrate; + Rxframeind = Rxtype = 0; + +startover: + cancount = 5; +again: + /* + * Return immediate ERROR if ZCRCW sequence seen + */ + if (((c = GETCHAR(Rxtimeout)) < 0) && (c != TIMEOUT)) + goto fifi; + else switch(c) { + case 021: case 0221: + goto again; + case HANGUP: + case TIMEOUT: + goto fifi; + case CAN: +gotcan: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + switch (c = GETCHAR(Rxtimeout)) { + case TIMEOUT: + goto again; + case ZCRCW: + switch (GETCHAR(Rxtimeout)) { + case TIMEOUT: + c = TERROR; goto fifi; + case HANGUP: + goto fifi; + default: + goto agn2; + } + case HANGUP: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: +#define GCOUNT (-4) + if ( --n == 0) { + c = GCOUNT; goto fifi; + } + goto startover; + case ZPAD|0200: /* This is what we want. */ + Not8bit = c; + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case HANGUP: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + break; + } + + + Rxhlen = 4; /* Set default length */ + Rxframeind = c = noxrd7(); + switch (c) { + case ZVBIN32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZBIN32: + if (Usevhdrs) + goto agn2; + Crc32r = 1; c = zrbhd32(shdr); break; + case ZVBINR32: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case ZBINR32: + if (Usevhdrs) + goto agn2; + Crc32r = 2; c = zrbhd32(shdr); break; + case HANGUP: + case TIMEOUT: + goto fifi; + case ZVBIN: + if ((Rxhlen = c = zdlread()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZBIN: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrbhdr(shdr); break; + case ZVHEX: + if ((Rxhlen = c = zgethex()) < 0) + goto fifi; + if (c > ZMAXHLEN) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case ZHEX: + if (Usevhdrs) + goto agn2; + Crc32r = 0; c = zrhhdr(shdr); break; + case CAN: + goto gotcan; + default: + goto agn2; + } + for (n = Rxhlen; ++n < ZMAXHLEN; ) /* Clear unused hdr bytes */ + shdr[n] = 0; + Rxpos = shdr[ZP3] & 0377; + Rxpos = (Rxpos<<8) + (shdr[ZP2] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP1] & 0377); + Rxpos = (Rxpos<<8) + (shdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case TERROR: + case TIMEOUT: + case HANGUP: + Syslog('+', "Zmodem: Got %s", frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ + default: + if (c >= -FTOFFSET && c <= FRTYPES) + Syslog('z', "zgethdr: %c %d %s %ld", Rxframeind, Rxhlen, frametypes[c+FTOFFSET], Rxpos); + else + Syslog('z', "zgethdr: %c %d %ld", Rxframeind, c, Rxpos); + } + /* Use variable length headers if we got one */ + if (c >= 0 && c <= FRTYPES && Rxframeind & 040) + Usevhdrs = 1; + return c; +} + + + +/* + * Receive a binary style header (type and position) + */ +int zrbhdr(register char *shdr) +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrbhdr: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a binary style header (type and position) with 32 bit FCS + */ +int zrbhd32(register char *shdr) +{ + register int c, n; + register unsigned long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = 0xFFFFFFFFL; crc = updcrc32(c, crc); + + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + *shdr = c; + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + } + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc32(c, crc); + Syslog('Z', "zrbhd32 c=%X crc=%lX", c, crc); + } + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrbhd32: Bad CRC"); + return TERROR; + } + return Rxtype; +} + + + +/* + * Receive a hex style header (type and position) + */ +int zrhhdr(char *shdr) +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc16(c, 0); + + for (n=Rxhlen; --n >= 0; ++shdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + *shdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc16(c, crc); + if (crc & 0xFFFF) { + Syslog('+', "Zmodem zrhhdr: Bad CRC"); + return TERROR; + } + switch (c = GETCHAR(Rxtimeout)) { + case 0215: + Not8bit = c; + /* **** FALL THRU TO **** */ + case 015: + /* Throw away possible cr/lf */ + switch (c = GETCHAR(Rxtimeout)) { + case 012: + Not8bit |= c; + } + } + if (c < 0) + return c; + return Rxtype; +} + + + +/* + * Send a byte as two hex digits + */ +void zputhex(register int c) +{ + static char digits[] = "0123456789abcdef"; + + Syslog('Z', "zputhex: %02X", c); + BUFFER_BYTE(digits[(c&0xF0)>>4]); + BUFFER_BYTE(digits[(c)&0xF]); +} + + + +/* + * Send character c with ZMODEM escape sequence encoding. + * Escape XON, XOFF. Escape CR following @ (Telenet net escape) + */ +void zsendline(int c) +{ + /* Quick check for non control characters */ + if (c & 0140) + BUFFER_BYTE(lastsent = c); + else { + switch (c &= 0377) { + case ZDLE: + BUFFER_BYTE(ZDLE); + BUFFER_BYTE (lastsent = (c ^= 0100)); + break; + case 015: + case 0215: + if (!Zctlesc && (lastsent & 0177) != '@') + goto sendit; + /* **** FALL THRU TO **** */ + case 020: + case 021: + case 023: + case 0220: + case 0221: + case 0223: + BUFFER_BYTE(ZDLE); + c ^= 0100; + sendit: + BUFFER_BYTE(lastsent = c); + break; + default: + if (Zctlesc && ! (c & 0140)) { + BUFFER_BYTE(ZDLE); + c ^= 0100; + } + BUFFER_BYTE(lastsent = c); + } + } +} + + + +/* Decode two lower case hex digits into an 8 bit byte value */ +int zgethex(void) +{ + register int c; + + c = zgeth1(); + Syslog('Z', "zgethex: %02X", c); + return c; +} + + + +int zgeth1(void) +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return TERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return TERROR; + c += (n<<4); + return c; +} + + + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +int zdlread(void) +{ + register int c; + +again: + /* Quick check for non control characters */ + if ((c = GETCHAR(Rxtimeout)) & 0140) + return c; + switch (c) { + case ZDLE: + break; + case 023: + case 0223: + case 021: + case 0221: + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case 023: + case 0223: + case 021: + case 0221: + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + Syslog('+', "Zmodem: Bad escape sequence 0x%x", c); + return TERROR; +} + + + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +int noxrd7(void) +{ + register int c; + + for (;;) { + if ((c = GETCHAR(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + } +} + + + +/* + * Store long integer pos in Txhdr + */ +void stohdr(long pos) +{ + Txhdr[ZP0] = pos; + Txhdr[ZP1] = pos>>8; + Txhdr[ZP2] = pos>>16; + Txhdr[ZP3] = pos>>24; +} + + + +/* + * Recover a long integer from a header + */ +long rclhdr(register char *shdr) +{ + register long l; + + l = (shdr[ZP3] & 0377); + l = (l << 8) | (shdr[ZP2] & 0377); + l = (l << 8) | (shdr[ZP1] & 0377); + l = (l << 8) | (shdr[ZP0] & 0377); + return l; +} + +/* End of zmmisc.c */ diff --git a/mbcico/zmodem.h b/mbcico/zmodem.h new file mode 100644 index 00000000..4af097bc --- /dev/null +++ b/mbcico/zmodem.h @@ -0,0 +1,199 @@ +#ifndef ZMODEM_H +#define ZMODEM_H + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef OK +#define OK 0 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define RETRYMAX 10 +#define MAXBLOCK 8192 + +/* + * Z M O D E M . H Manifest constants for ZMODEM + * application to application file transfer protocol + * 04-17-89 Chuck Forsberg Omen Technology Inc + */ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator (CRC-16) */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ +#define ZBINR32 'D' /* RLE packed Binary frame with 32 bit FCS */ +#define ZVBIN 'a' /* Binary frame indicator (CRC-16) */ +#define ZVHEX 'b' /* HEX frame indicator */ +#define ZVBIN32 'c' /* Binary frame with 32 bit FCS */ +#define ZVBINR32 'd' /* RLE packed Binary frame with 32 bit FCS */ +#define ZRESC 0176 /* RLE flag/escape character */ +#define ZMAXHLEN 16 /* Max header information length NEVER CHANGE */ +#define ZMAXSPLEN 1024 /* Max subpacket length NEVER CHANGE */ + +/* Frame types (see array "frametypes" in zm.c) */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ZDLE sequences */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* Byte positions within header array */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + +/* Parameters for ZRINIT header */ +#define ZRPXWN 8 /* 9th byte in header contains window size/256 */ +#define ZRPXQQ 9 /* 10th to 14th bytes contain quote mask */ +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 01 /* Rx can send and receive true FDX */ +#define CANOVIO 02 /* Rx can receive data during disk I/O */ +#define CANBRK 04 /* Rx can send a break signal */ +#define CANRLE 010 /* Receiver can decode RLE */ +#define CANLZW 020 /* Receiver can uncompress */ +#define CANFC32 040 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0100 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0200 /* Receiver expects 8th bit to be escaped */ + +/* Bit Masks for ZRINIT flags byte ZF1 */ +#define CANVHDR 01 /* Variable headers OK */ +#define ZRRQWN 8 /* Receiver specified window size in ZRPXWN */ +#define ZRRQQQ 16 /* Additional control chars to quote in ZRPXQQ */ +#define ZRQNVH (ZRRQWN|ZRRQQQ) /* Variable len hdr reqd to access info */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +#define ALTCOFF ZF1 /* Offset to alternate canit string, 0 if not used */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ +/* Management include options, one of these ored in ZF1 */ +#define ZMSKNOLOC 0200 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZMMASK 037 /* Mask for the choices below */ +#define ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZMCLOB 4 /* Replace existing file */ +#define ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZMPROT 7 /* Protect destination file */ +#define ZMCHNG 8 /* Change filename if destination exists */ +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ +#define ZCANVHDR 01 /* Variable headers OK */ +/* Receiver window size override */ +#define ZRWOVR 4 /* byte position for receive window override/256 */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +long rclhdr(register char *); + +/* Globals used by ZMODEM functions */ +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame */ +extern int Rxtype; /* Type of header received */ +extern int Rxcount; /* Count of data bytes received */ +extern int long Rxpos; /* Received file position */ +extern int long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32r; /* Display flag indicating 32 bit CRC being received */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Rxhdr[]; +extern char Txhdr[]; +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern char *Altcan; /* Alternate canit string */ +extern char *Zendnames[]; +extern char *txbuf; +extern char *rxbuf; + +/* End of ZMODEM.H */ + +char Zsendmask[33]; /* Additional control characters to mask */ + +extern int Effbaud; +extern int Zmodem; +extern int Zctlesc; +extern int Filesleft; +extern long Totalleft; + +extern char *frametypes[]; +#define FTOFFSET 16 + +extern void zsbhdr(int,int,char*); +extern void zshhdr(int,int,char*); +extern int zgethdr(char*); +extern void zsdata(char*,int,int); +extern int zrdata(char*,int); +extern void stohdr(long); + +extern void zsendline(int); +extern void zsdar32(char*,int,int); +extern int zrdatr32(char*,int); +extern int zdlread(void); + +extern unsigned short crc16xmodemtab[]; +extern unsigned long crc32tab[]; +#define updcrc16(cp,crc) (crc16xmodemtab[(((int)crc >> 8) & 0xff)] ^ (crc << 8) ^ cp) +#define updcrc32(cp,crc) (crc32tab[((int)crc ^ cp) & 0xff] ^ ((crc >> 8) & 0x00ffffff)) + +int zmsndfiles(file_list *); +int zmrcvfiles(void); + +#endif + diff --git a/mbcico/zmrecv.c b/mbcico/zmrecv.c new file mode 100644 index 00000000..9b15dd20 --- /dev/null +++ b/mbcico/zmrecv.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: mbcico/zmrecv.c + * Purpose ...............: Fidonet mailer + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "lutil.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" +#include "config.h" +#include "emsi.h" +#include "openfile.h" +#include "openport.h" + + +#ifndef BELEIVE_ZFIN +#define BELEIVE_ZFIN 2 +#endif + +static FILE *fout=NULL; + +static int Usevhdrs; +static long rxbytes; +static int Eofseen; /* indicates cpm eof (^Z) has been received */ +static int errors; +static time_t startime,etime; +static long sbytes; + +#define DEFBYTL 2000000000L /* default rx file size */ +static long Bytesleft; /* number of bytes of incoming file left */ +static long Modtime; /* Unix style mod time for incoming file */ +static int Filemode; /* Unix style mode for incoming file */ +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +static int Thisbinary; /* current file is to be received in bin mode */ +char Lzconv; /* Local ZMODEM file conversion request */ +char Lzmanag; /* Local file management request */ + +static char *secbuf=0; + +static int tryzhdrtype; +static char zconv; /* ZMODEM file conversion request */ +static char zmanag; /* ZMODEM file management request */ +static char ztrans; /* ZMODEM file transport request */ + +static int resync(off_t); +static int tryz(void); +static int rzfiles(void); +static int rzfile(void); +static void zmputs(char*); +int closeit(int); +static int putsec(char*,int); +static int procheader(char*); +static int ackbibi(void); +static long getfree(void); + + +void get_frame_buffer(void); +void free_frame_buffer(void); + +extern unsigned long rcvdbytes; + + + +int zmrcvfiles(void) +{ + int rc; + + Syslog('+', "Zmodem: start %s receive", (emsi_local_protos & PROT_ZAP)?"ZedZap":"Zmodem"); + + get_frame_buffer(); + + if (secbuf == NULL) + secbuf = malloc(MAXBLOCK+1); + tryzhdrtype = ZRINIT; + if ((rc = tryz()) < 0) { + Syslog('+', "Zmodem: could not initiate receive, rc=%d",rc); + } else + switch (rc) { + case ZCOMPL: rc = 0; break; + case ZFILE: rc = rzfiles(); break; + } + + if (fout) { + if (closeit(0)) { + WriteError("Zmodem: Error closing file"); + } + } + + if (secbuf) + free(secbuf); + secbuf = NULL; + free_frame_buffer(); + + Syslog('z', "Zmodem: receive rc=%d",rc); + return abs(rc); +} + + + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +int tryz(void) +{ + int c, n; + int cmdzack1flg; + + for (n = 15; --n >= 0; ) { + /* + * Set buffer length (0) and capability flags + */ + Syslog('z', "tryz attempt %d", n); + stohdr(0L); + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; + if (Zctlesc) + Txhdr[ZF0] |= TESCCTL; + Txhdr[ZF0] |= CANRLE; + Txhdr[ZF1] = CANVHDR; + zshhdr(4, tryzhdrtype, Txhdr); + if (tryzhdrtype == ZSKIP) /* Don't skip too far */ + tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ +again: + switch (zgethdr(Rxhdr)) { + case ZRQINIT: + if (Rxhdr[ZF3] & 0x80) + Usevhdrs = TRUE; /* we can var header */ + continue; + case ZEOF: + continue; + case TIMEOUT: + Syslog('+', "Zmodem: tryz() timeout attempt %d", n); + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + if (Rxhdr[ZF3] & ZCANVHDR) + Usevhdrs = TRUE; + tryzhdrtype = ZRINIT; + c = zrdata(secbuf, MAXBLOCK); + if (c == GOTCRCW) + return ZFILE; + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZSINIT: + Zctlesc = TESCCTL & Rxhdr[ZF0]; + if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { + stohdr(1L); + zshhdr(4,ZACK, Txhdr); + goto again; + } + zshhdr(4,ZNAK, Txhdr); + goto again; + case ZFREECNT: + stohdr(getfree()); + zshhdr(4,ZACK, Txhdr); + goto again; + case ZCOMMAND: + cmdzack1flg = Rxhdr[ZF0]; + if (zrdata(secbuf, MAXBLOCK) == GOTCRCW) { + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + Syslog('+', "Zmodem: request for command \"%s\" ignored", printable(secbuf,-32)); + stohdr(0L); + do { + zshhdr(4,ZCOMPL, Txhdr); + } while (++errors<20 && zgethdr(Rxhdr) != ZFIN); + return ackbibi(); + } + zshhdr(4,ZNAK, Txhdr); goto again; + case ZCOMPL: + goto again; + case ZRINIT: + case ZFIN: /* do not beleive in first ZFIN */ + ackbibi(); return ZCOMPL; + case TERROR: + case HANGUP: + case ZCAN: + return TERROR; + default: + continue; + } + } + return 0; +} + + + +/* + * Receive 1 or more files with ZMODEM protocol + */ +int rzfiles(void) +{ + int c; + + Syslog('z', "rzfiles"); + + for (;;) { + switch (c = rzfile()) { + case ZEOF: + case ZSKIP: + case ZFERR: + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return TERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case TERROR: + return TERROR; + } + } + /* NOTREACHED */ +} + + + +/* + * Receive a file with ZMODEM protocol + * Assumes file name frame is in secbuf + */ +int rzfile(void) +{ + int c, n; + + Syslog('z', "rzfile"); + + Eofseen=FALSE; + rxbytes = 0l; + if ((c = procheader(secbuf))) { + return (tryzhdrtype = c); + } + + n = 20; + + for (;;) { + stohdr(rxbytes); + zshhdr(4,ZRPOS, Txhdr); +nxthdr: + switch (c = zgethdr(Rxhdr)) { + default: + Syslog('z', "rzfile: Wrong header %d", c); + if ( --n < 0) { + Syslog('+', "Zmodem: wrong header %d", c); + return TERROR; + } + continue; + case ZCAN: + Syslog('+', "Zmodem: sender CANcelled"); + return TERROR; + case ZNAK: + if ( --n < 0) { + Syslog('+', "Zmodem: Got ZNAK"); + return TERROR; + } + continue; + case TIMEOUT: + if ( --n < 0) { + Syslog('+', "Zmodem: TIMEOUT"); + return TERROR; + } + continue; + case ZFILE: + zrdata(secbuf, MAXBLOCK); + continue; + case ZEOF: + if (rclhdr(Rxhdr) != rxbytes) { + /* + * Ignore eof if it's at wrong place - force + * a timeout because the eof might have gone + * out before we sent our zrpos. + */ + errors = 0; + goto nxthdr; + } + if (closeit(1)) { + tryzhdrtype = ZFERR; + Syslog('+', "Zmodem: error closing file"); + return TERROR; + } + fout=NULL; + Syslog('z', "rzfile: normal EOF"); + return c; + case HANGUP: + Syslog('+', "Zmodem: Lost Carrier"); + return TERROR; + case TERROR: /* Too much garbage in header search error */ + if (--n < 0) { + Syslog('+', "Zmodem: Too many errors"); + return TERROR; + } + zmputs(Attn); + continue; + case ZSKIP: + Modtime = 1; + closeit(1); + Syslog('+', "Zmodem: Sender SKIPPED file"); + return c; + case ZDATA: + if (rclhdr(Rxhdr) != rxbytes) { + if ( --n < 0) { + Syslog('+', "Zmodem: Data has bad address"); + return TERROR; + } + zmputs(Attn); continue; + } +moredata: + Syslog('z', "%7ld ZMODEM%s ", + rxbytes, Crc32r?" CRC-32":""); + Nopper(); + switch (c = zrdata(secbuf, MAXBLOCK)) { + case ZCAN: + Syslog('+', "Zmodem: sender CANcelled"); + return TERROR; + case HANGUP: + Syslog('+', "Zmodem: Lost Carrier"); + return TERROR; + case TERROR: /* CRC error */ + if (--n < 0) { + Syslog('+', "Zmodem: Too many errors"); + return TERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: + if ( --n < 0) { + Syslog('+', "Zmodem: TIMEOUT"); + return TERROR; + } + continue; + case GOTCRCW: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + PUTCHAR(XON); + zshhdr(4,ZACK, Txhdr); + goto nxthdr; + case GOTCRCQ: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + stohdr(rxbytes); + zshhdr(4,ZACK, Txhdr); + goto moredata; + case GOTCRCG: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto moredata; + case GOTCRCE: + n = 20; + putsec(secbuf, Rxcount); + rxbytes += Rxcount; + goto nxthdr; + } + } + } +} + + + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +void zmputs(char *s) +{ + int c; + + Syslog('z', "zmputs: \"%s\"", printable(s, strlen(s))); + + while (*s) { + switch (c = *s++) { + case '\336': + Syslog('z', "zmputs: sleep(1)"); + sleep(1); continue; + case '\335': + Syslog('z', "zmputs: send break"); + sendbrk(); continue; + default: + PUTCHAR(c); + } + } +} + + + +int resync(off_t off) +{ + return 0; +} + + + +int closeit(int success) +{ + int rc; + + rc = closefile(success); + fout = NULL; + sbytes = rxbytes - sbytes; + (void)time(&etime); + if ((startime = etime - startime) == 0L) + startime = 1L; + Syslog('+', "Zmodem: %s %lu bytes in %s (%ld cps)", success?"OK":"dropped after", + sbytes, str_time(startime), sbytes / startime); + rcvdbytes += sbytes; + return rc; +} + + + +/* + * Ack a ZFIN packet, let byegones be byegones + */ +int ackbibi(void) +{ + int n; + int c; + + Syslog('z', "ackbibi:"); + stohdr(0L); + for (n=3; --n>=0; ) { + zshhdr(4,ZFIN, Txhdr); + switch ((c=GETCHAR(10))) { + case 'O': + GETCHAR(1); /* Discard 2nd 'O' */ + Syslog('z', "Zmodem: ackbibi complete"); + return ZCOMPL; + case TERROR: + case HANGUP: + Syslog('z', "Zmodem: ackbibi got %d, ignore",c); + return 0; + case TIMEOUT: + default: + Syslog('z', "Zmodem: ackbibi got '%s', continue", printablec(c)); + break; + } + } + return ZCOMPL; +} + + + +/* + * Process incoming file information header + */ +int procheader(char *Name) +{ + register char *openmode, *p; + static int dummy; + char ctt[32]; + + Syslog('z', "procheader \"%s\"",printable(Name,0)); + /* set default parameters and overrides */ + openmode = (char *)"w"; + + /* + * Process ZMODEM remote file management requests + */ + Thisbinary = (zconv != ZCNL); /* Remote ASCII override */ + if (zmanag == ZMAPND) + openmode = (char *)"a"; + + Bytesleft = DEFBYTL; + Filemode = 0; + Modtime = 0L; + + p = Name + 1 + strlen(Name); + sscanf(p, "%ld%lo%o%o%d%d%d%d", &Bytesleft, &Modtime, &Filemode, &dummy, &dummy, &dummy, &dummy, &dummy); + strcpy(ctt,date(Modtime)); + Syslog('+', "Zmodem: \"%s\" %ld bytes, %s mode %o", Name, Bytesleft, ctt, Filemode); + + fout = openfile(Name,Modtime,Bytesleft,&rxbytes,resync); + (void)time(&startime); + sbytes = rxbytes; + + if (Bytesleft == rxbytes) { + Syslog('+', "Zmodem: Skipping %s", Name); + fout = NULL; + return ZSKIP; + } else if (!fout) + return ZFERR; + else + return 0; +} + + + +/* + * Putsec writes the n characters of buf to receive file fout. + * If not in binary mode, carriage returns, and all characters + * starting with CPMEOF are discarded. + */ +int putsec(char *buf, int n) +{ + register char *p; + + if (n == 0) + return OK; + + if (Thisbinary) { + for (p = buf; --n>=0; ) + putc( *p++, fout); + } else { + if (Eofseen) + return OK; + for (p = buf; --n>=0; ++p ) { + if ( *p == '\r') + continue; + if (*p == SUB) { + Eofseen=TRUE; + return OK; + } + putc(*p ,fout); + } + } + return OK; +} + + + +long getfree(void) +{ + struct statfs sfs; + + if (statfs(inbound, &sfs) != 0) { + WriteError("$cannot statfs \"%s\", assume enough space", inbound); + return -1L; + } else + return (sfs.f_bsize * sfs.f_bfree); +} + + diff --git a/mbcico/zmrle.c b/mbcico/zmrle.c new file mode 100644 index 00000000..3bdefd07 --- /dev/null +++ b/mbcico/zmrle.c @@ -0,0 +1,197 @@ +/* + * File: zmr.c + * Copyright 1988, 1994 Omen Technology Inc All Rights Reserved + * + * + * + * This module implements ZMODEM Run Length Encoding, an + * extension that was not funded by the original Telenet + * development contract. + * + * This software may be freely used for non commercial and + * educational (didactic only) purposes. This software may also + * be freely used to support file transfer operations to or from + * licensed Omen Technology products. Any programs which use + * part or all of this software must be provided in source form + * with this notice intact except by written permission from Omen + * Technology Incorporated. + * + * Use of this software for commercial or administrative purposes + * except when exclusively limited to interfacing Omen Technology + * products requires a per port license payment of $20.00 US per + * port (less in quantity). Use of this code by inclusion, + * decompilation, reverse engineering or any other means + * constitutes agreement to these conditions and acceptance of + * liability to license the materials and payment of reasonable + * legal costs necessary to enforce this license agreement. + * + * + * Omen Technology Inc FAX: 503-621-3745 + * Post Office Box 4681 + * Portland OR 97208 + * + * This code is made available in the hope it will be useful, + * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY + * DAMAGES OF ANY KIND. + * + * ZMODEM RLE compression and decompression functions + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" + + + +/* + * Send data subpacket RLE encoded with 32 bit FCS + */ +void zsdar32(char *buf, int length, int frameend) +{ + register int c, l, n; + register unsigned long crc; + + crc = 0xFFFFFFFFL; l = *buf++ & 0377; + if (length == 1) { + zsendline(l); crc = updcrc32(l, crc); + if (l == ZRESC) { + zsendline(1); crc = updcrc32(1, crc); + } + } else { + for (n = 0; --length >= 0; ++buf) { + if ((c = *buf & 0377) == l && n < 126 && length>0) { + ++n; continue; + } + switch (n) { + case 0: + zsendline(l); + crc = updcrc32(l, crc); + if (l == ZRESC) { + zsendline(0100); crc = updcrc32(0100, crc); + } + l = c; break; + case 1: + if (l != ZRESC) { + zsendline(l); zsendline(l); + crc = updcrc32(l, crc); + crc = updcrc32(l, crc); + n = 0; l = c; break; + } + /* **** FALL THRU TO **** */ + default: + zsendline(ZRESC); crc = updcrc32(ZRESC, crc); + if (l == 040 && n < 34) { + n += 036; + zsendline(n); crc = updcrc32(n, crc); + } + else { + n += 0101; + zsendline(n); crc = updcrc32(n, crc); + zsendline(l); crc = updcrc32(l, crc); + } + n = 0; l = c; break; + } + } + } + PUTCHAR(ZDLE); PUTCHAR(frameend); + crc = updcrc32(frameend, crc); + + crc = ~crc; + for (length=4; --length >= 0;) { + zsendline((int)crc); crc >>= 8; + } +} + + +/* + * Receive data subpacket RLE encoded with 32 bit FCS + */ +int zrdatr32(register char *buf, int length) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; Rxcount = 0; end = buf + length; + d = 0; /* Use for RLE decoder state */ + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; c &= 0377; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc32(c, crc); + if (crc != 0xDEBB20E3) { + Syslog('+', "Zmodem zrdatr32: Bad CRC"); + return TERROR; + } + Rxcount = length - (end - buf); + + Syslog('z', "zrdatr32: %d %s", Rxcount, + Zendnames[(d-GOTCRCE)&3]); + + return d; + case GOTCAN: + Syslog('+', "Zmodem: Sender Canceled"); + return ZCAN; + case TIMEOUT: + Syslog('+', "Zmodem: TIMEOUT"); + return c; + default: + Syslog('+', "Zmodem: Bad data subpacket"); + return c; + } + } + crc = updcrc32(c, crc); + switch (d) { + case 0: + if (c == ZRESC) { + d = -1; continue; + } + *buf++ = c; continue; + case -1: + if (c >= 040 && c < 0100) { + d = c - 035; c = 040; goto spaces; + } + if (c == 0100) { + d = 0; + *buf++ = ZRESC; continue; + } + d = c; continue; + default: + d -= 0100; + if (d < 1) + goto badpkt; +spaces: + if ((buf + d) > end) + goto badpkt; + while ( --d >= 0) + *buf++ = c; + d = 0; continue; + } + } +badpkt: + Syslog('+', "Zmodem: Data subpacket too long"); + return TERROR; +} + diff --git a/mbcico/zmsend.c b/mbcico/zmsend.c new file mode 100644 index 00000000..23e4b432 --- /dev/null +++ b/mbcico/zmsend.c @@ -0,0 +1,695 @@ +/***************************************************************************** + * + * File ..................: mbcico/zmsend.c + * Purpose ...............: Fidonet mailer + * Last modification date : 07-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "ttyio.h" +#include "session.h" +#include "zmodem.h" +#include "lutil.h" +#include "emsi.h" +#include "filelist.h" + +static int initsend(void); +static int sendfile(char*,char*); +static int finsend(void); + +static int getzrxinit(void); +static int sendzsinit(void); +static int zfilbuf(void); +static int zsendfile(char*,int); +static int zsendfdata(void); +static int getinsync(int); +void initzsendmsk(char *); + +static FILE *in; +static int Eofseen; /* EOF seen on input set by zfilbuf */ +static int Rxflags = 0; +static int Usevhdrs; +static int Wantfcs32=TRUE; /* Want to send 32 bit FCS */ +static int Rxbuflen; +static unsigned Txwindow; /* Control the size of the transmitted window */ +static unsigned Txwspac; /* Spacing between zcrcq requests */ +static unsigned Txwcnt; /* Counter used to space ack requests */ +//static long Tframlen = 0; /* Override for tx frame length */ +static int blklen = 128; /* Length of transmitted records */ +static int blkopt; /* Override value for zmodem blklen */ +static int errors; +static int Lastsync; +static long bytcnt; +static int Lrxpos=0; +static int Lztrans=0; +static int Lzmanag=0; +static int Lskipnocor=0; +static int Lzconv=0; +static int Beenhereb4; +static char Myattn[]={0}; +static long startime,endtime; +static long skipsize; + +extern unsigned long sentbytes; +extern int Rxhlen; +extern void get_frame_buffer(void); +extern void free_frame_buffer(void); + + +int zmsndfiles(file_list *lst) +{ + int rc, maxrc = 0; + file_list *tmpf; + + Syslog('+', "Zmodem: start %s send", (emsi_local_protos & PROT_ZAP)?"ZedZap":"Zmodem"); + + get_frame_buffer(); + + if ((rc = initsend())) { + if (txbuf) + free(txbuf); + txbuf = NULL; + free_frame_buffer(); + return abs(rc); + } + + for (tmpf = lst; tmpf && (maxrc < 2); tmpf = tmpf->next) { + if (tmpf->remote) { + rc = sendfile(tmpf->local, tmpf->remote); + rc = abs(rc); + if (rc > maxrc) + maxrc = rc; + if (rc == 0) + execute_disposition(tmpf); + } else if (maxrc == 0) + execute_disposition(tmpf); + } + + if (maxrc < 2) { + rc = finsend(); + rc = abs(rc); + } + + if (rc > maxrc) + maxrc = rc; + + if (txbuf) + free(txbuf); + txbuf = NULL; + free_frame_buffer(); + + Syslog('z', "Zmodem: send rc=%d", maxrc); + return (maxrc < 2)?0:maxrc; +} + + + +static int initsend(void) +{ + Syslog('z', "Zmodem: initsend"); + + PUTSTR((char *)"rz\r"); + stohdr(0x80L); /* Show we can do var header */ + zshhdr(4, ZRQINIT, Txhdr); + + if (getzrxinit()) { + Syslog('+', "Zmodem: Unable to initiate send"); + return 1; + } + + return 0; +} + + + +/* + * Say "bibi" to the receiver, try to do it cleanly + */ +static int finsend(void) +{ + int i, rc = 0; + + Syslog('z', "Zmodem: finsend"); + while (GETCHAR(1) >= 0) /*nothing*/; + for (i = 0; i < 30; i++) { + stohdr(0L); + zshhdr(4, ZFIN, Txhdr); + if ((rc = zgethdr(Rxhdr)) == ZFIN) + PUTSTR((char *)"OO"); + if ((rc == ZFIN) || (rc == ZCAN) || (rc < 0)) + break; + } + return (rc != ZFIN); +} + + + +static int sendfile(char *ln, char *rn) +{ + int rc=0; + struct stat st; + struct flock fl; + int bufl; + int sverr; + + fl.l_type = F_RDLCK; + fl.l_whence = 0; + fl.l_start = 0L; + fl.l_len = 0L; + if (txbuf == NULL) + txbuf = malloc(MAXBLOCK); + + skipsize = 0L; + if ((in = fopen(ln, "r")) == NULL) { + sverr = errno; + if ((sverr == ENOENT) || (sverr == EINVAL)) { + Syslog('+', "File %s doesn't exist, removing", MBSE_SS(ln)); + return 0; + } else { + WriteError("$Zmodem: cannot open file %s, skipping", MBSE_SS(ln)); + return 1; + } + } + + if (fcntl(fileno(in),F_SETLK,&fl) != 0) { + Syslog('+', "$Zmodem: cannot lock file %s, skipping",MBSE_SS(ln)); + fclose(in); + return 1; + } + + if (stat(ln,&st) != 0) { + Syslog('+', "$Zmodem: cannot access \"%s\", skipping",MBSE_SS(ln)); + fclose(in); + return 1; + } + + Syslog('+', "Zmodem: send \"%s\" as \"%s\"", MBSE_SS(ln), MBSE_SS(rn)); + Syslog('+', "Zmodem: size %lu bytes, dated %s", (unsigned long)st.st_size, date(st.st_mtime)); + (void)time(&startime); + + sprintf(txbuf,"%s %lu %lo %o 0 0 0", rn,(unsigned long)st.st_size, st.st_mtime+(st.st_mtime%2), st.st_mode); + bufl = strlen(txbuf); + *(strchr(txbuf,' ')) = '\0'; /*hope no blanks in filename*/ + + Eofseen = 0; + rc = zsendfile(txbuf,bufl); + if (rc == ZSKIP) { + Syslog('+', "Zmodem: remote skipped %s, is OK",MBSE_SS(ln)); + return 0; + } else if ((rc == OK) && (st.st_size - skipsize)) { + (void)time(&endtime); + if ((startime = endtime - startime) == 0) + startime = 1; + Syslog('+', "Zmodem: OK %lu bytes in %s (%ld cps)", (unsigned long)st.st_size - skipsize, str_time(startime), + (long)(st.st_size-skipsize) / startime); + sentbytes += (unsigned long)st.st_size - skipsize; + return 0; + } else + return 2; +} + + + +/* + * Get the receiver's init parameters + */ +int getzrxinit(void) // CHECKED BUT NOT WELL TESTED +{ + int n; + + Syslog('z', "getzrxinit"); + for (n=10; --n>=0; ) { + + switch (zgethdr(Rxhdr)) { + case ZCHALLENGE: /* Echo receiver's challenge numbr */ + stohdr(Rxpos); + zshhdr(4, ZACK, Txhdr); + continue; + case ZCOMMAND: /* They didn't see out ZRQINIT */ + stohdr(0L); + zshhdr(4, ZRQINIT, Txhdr); + continue; + case ZRINIT: + Rxflags = 0377 & Rxhdr[ZF0]; + Usevhdrs = Rxhdr[ZF1] & CANVHDR; + Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); + Zctlesc |= Rxflags & TESCCTL; + Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); + if ( !(Rxflags & CANFDX)) + Txwindow = 0; + Syslog('z', "Zmodem: Remote allowed Rxbuflen=%d", Rxbuflen); + + /* Set initial subpacket length */ + if (blklen < 1024) { /* Command line override? */ + blklen = 1024; + } + if (Rxbuflen && blklen>Rxbuflen) + blklen = Rxbuflen; + if (blkopt && blklen > blkopt) + blklen = blkopt; + Syslog('z', "Rxbuflen=%d blklen=%d", Rxbuflen, blklen); + Syslog('z', "Txwindow = %u Txwspac = %d", Txwindow, Txwspac); + + if (Lztrans == ZTRLE && (Rxflags & CANRLE)) + Txfcs32 = 2; + else + Lztrans = 0; + + return (sendzsinit()); + case ZCAN: + case TIMEOUT: + return TERROR; + case HANGUP: + return HANGUP; + case ZRQINIT: + if (Rxhdr[ZF0] == ZCOMMAND) + continue; + default: + zshhdr(4, ZNAK, Txhdr); + continue; + } + } + return TERROR; +} + + + +/* + * Send send-init information + */ +int sendzsinit(void) +{ + int c; + + if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL))) + return OK; + errors = 0; + for (;;) { + stohdr(0L); + if (Zctlesc) { + Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr); + } + else + zsbhdr(4, ZSINIT, Txhdr); + zsdata(Myattn, ZATTNLEN, ZCRCW); + c = zgethdr(Rxhdr); + switch (c) { + case ZCAN: + return TERROR; + case HANGUP: + return HANGUP; + case ZACK: + return OK; + default: + if (++errors > 19) + return TERROR; + continue; + } + } +} + + + +/* + * Fill buffer with blklen chars + */ +int zfilbuf(void) +{ + int n; + + n = fread(txbuf, 1, blklen, in); + if (n < blklen) { + Eofseen = 1; + Syslog('z', "zfilbuf return %d", n); + } + + return n; +} + + + +/* + * Send file name and related info + */ +int zsendfile(char *buf, int blen) +{ + int c; + register unsigned long crc = -1; + long lastcrcrq = -1; + + Syslog('z', "zsendfile %s (%d)", buf, blen); + for (errors=0; ++errors<11;) { + Txhdr[ZF0] = Lzconv; /* file conversion request */ + Txhdr[ZF1] = Lzmanag; /* file management request */ + if (Lskipnocor) + Txhdr[ZF1] |= ZMSKNOLOC; + Txhdr[ZF2] = Lztrans; /* file transport request */ + Txhdr[ZF3] = 0; + zsbhdr(4, ZFILE, Txhdr); + zsdata(buf, blen, ZCRCW); +again: + c = zgethdr(Rxhdr); + switch (c) { + case ZRINIT: + while ((c = GETCHAR(5)) > 0) + if (c == ZPAD) { + goto again; + } + continue; + case ZCAN: + case TIMEOUT: + case ZABORT: + case ZFIN: + Syslog('+', "Zmodem: Got %s on pathname", frametypes[c+FTOFFSET]); + return TERROR; + default: + Syslog('+', "Zmodem: Got %d frame type on pathname", c); + continue; + case TERROR: + case ZNAK: + continue; + case ZCRC: + if (Rxpos != lastcrcrq) { + lastcrcrq = Rxpos; + crc = 0xFFFFFFFFL; + fseek(in, 0L, 0); + Syslog('Z', "bytcnt=%ld crc=%08lX", bytcnt, crc); + while (((c = getc(in)) != EOF) && --lastcrcrq) + crc = updcrc32(c, crc); + crc = ~crc; + clearerr(in); /* Clear possible EOF */ + lastcrcrq = Rxpos; + } + stohdr(crc); + zsbhdr(4, ZCRC, Txhdr); + goto again; + case ZFERR: + case ZSKIP: + Syslog('+', "Zmodem: File skipped by receiver request"); + fclose(in); return c; + case ZRPOS: + /* + * Suppress zcrcw request otherwise triggered by + * lastyunc==bytcnt + */ + if (Rxpos > 0) + skipsize = Rxpos; + if (fseek(in, Rxpos, 0)) + return TERROR; + Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1; + return zsendfdata(); + } + } + fclose(in); return TERROR; +} + + + +/* + * Send the data in the file + */ +int zsendfdata(void) +{ + int c=0, e, n; + int newcnt; + int tcount = 0; + int junkcount; /* Counts garbage chars received by TX */ + int maxblklen, goodblks = 0, goodneeded = 8; + + if (emsi_local_protos & PROT_ZAP) + maxblklen = MAXBLOCK; + else + maxblklen = 1024; + Syslog('z', "zsendfdata() maxblklen=%d", maxblklen); + + junkcount = 0; + Beenhereb4 = 0; +somemore: + if (0) { +waitack: + junkcount = 0; + c = getinsync(0); +gotack: + switch (c) { + default: + case ZCAN: + fclose(in); + return TERROR; + case ZRINIT: + fclose(in); + return ZSKIP; + case ZSKIP: + fclose(in); + return c; + case ZACK: + break; // Possible bug, added 23-08-99 + case ZRPOS: + blklen = ((blklen >> 2) > 64) ? (blklen >> 2) : 64; + goodblks = 0; + goodneeded = ((goodneeded << 1) > 16) ? 16 : goodneeded << 1; + Syslog('z', "zmsend: blocklen now %d", blklen); + break; + case TIMEOUT: /* Put back here 08-09-1999 mb */ + Syslog('z', "zmsend: zsendfdata TIMEOUT"); + goto to; + case HANGUP: /* New, added 08-09-1999 mb */ + Syslog('z', "zmsend: zsendfdata HANGUP"); + fclose(in); + return c; + } + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + if (TCHECK()) { + c = GETCHAR(1); + Syslog('z', "zsendfdata(): check getchar(1)=%d", c); + if (c < 0) { + return c; + } else switch (c) { + case CAN: + case ZPAD: + c = getinsync(1); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + GETCHAR(10); + } + } + } +to: + newcnt = Rxbuflen; + Txwcnt = 0; + stohdr(Txpos); + zsbhdr(4, ZDATA, Txhdr); + + do { + n = zfilbuf(); + if (Eofseen) + e = ZCRCE; + else if (junkcount > 3) + e = ZCRCW; + else if (bytcnt == Lastsync) + e = ZCRCW; + else if (Rxbuflen && (newcnt -= n) <= 0) + e = ZCRCW; + else if (Txwindow && (Txwcnt += n) >= Txwspac) { + Txwcnt = 0; e = ZCRCQ; + } else + e = ZCRCG; + Syslog('z', "%7ld ZMODEM%s ", + Txpos, Crc32t?" CRC-32":""); + Nopper(); + zsdata(txbuf, n, e); + bytcnt = Txpos += n; + + if ((blklen < maxblklen) && (++goodblks > goodneeded)) { + blklen = ((blklen << 1) < maxblklen) ? blklen << 1 : maxblklen; + goodblks = 0; + Syslog('z', "zmsend: blocklen now %d", blklen); + } + + if (e == ZCRCW) + goto waitack; + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fd) returns non 0 if a character is available + */ + if (TCHECK()) { + c = GETCHAR(1); + if (c < 0) { + return c; + } else switch (c) { + case CAN: + case ZPAD: + c = getinsync(1); + if (c == ZACK) + break; + /* zcrce - dinna wanna starta ping-pong game */ + zsdata(txbuf, 0, ZCRCE); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF|0200: + GETCHAR(10); + default: + ++junkcount; + } + } + if (Txwindow) { + while ((tcount = (Txpos - Lrxpos)) >= Txwindow) { + Syslog('z', "%ld window >= %u", tcount, Txwindow); + if (e != ZCRCQ) + zsdata(txbuf, 0, e = ZCRCQ); + c = getinsync(1); + if (c != ZACK) { + zsdata(txbuf, 0, ZCRCE); + goto gotack; + } + } + Syslog('z', "window = %ld", tcount); + } + } while (!Eofseen); + + for (;;) { + stohdr(Txpos); + zsbhdr(4, ZEOF, Txhdr); +egotack: + switch (getinsync(0)) { + case ZACK: + Syslog('z', "zsendfdata() ZACK"); + goto egotack; // continue in old source + case ZRPOS: + goto somemore; + case ZRINIT: + fclose(in); + return OK; + case ZSKIP: + fclose(in); + Syslog('+', "Zmodem: File skipped by receiver request"); + return ZSKIP; + default: + Syslog('+', "Zmodem: Got %d trying to send end of file", c); + case TERROR: + fclose(in); + return TERROR; + } + } +} + + + +/* + * Respond to receiver's complaint, get back in sync with receiver + */ +int getinsync(int flag) +{ + int c = 0; + + Syslog('z', "getinsync(%d)", flag); + + for (;;) { + c = zgethdr(Rxhdr); + switch (c) { + case HANGUP: + return HANGUP; + case ZCAN: + case ZABORT: + case ZFIN: + case TERROR: + case TIMEOUT: + Syslog('+', "Zmodem: Got %s sending data", frametypes[c+FTOFFSET]); + return TERROR; + case ZRPOS: + /* ************************************* */ + /* If sending to a buffered modem, you */ + /* might send a break at this point to */ + /* dump the modem's buffer. */ + clearerr(in); /* In case file EOF seen */ + if (fseek(in, Rxpos, 0)) { + Syslog('+', "Zmodem: Bad Seek to %ld", Rxpos); + return TERROR; + } + Eofseen = 0; + bytcnt = Lrxpos = Txpos = Rxpos; + if (Lastsync == Rxpos) { + if (++Beenhereb4 > 12) { + Syslog('+', "Zmodem: Can't send block"); + return TERROR; + } + if (Beenhereb4 > 4) + if (blklen > 32) { + blklen /= 2; + Syslog('z', "Zmodem: blocklen now %d", blklen); + } + } + else + Beenhereb4=0; + Lastsync = Rxpos; + return c; + case ZACK: + Lrxpos = Rxpos; + if (flag || Txpos == Rxpos) + return ZACK; + continue; + case ZRINIT: + return c; + case ZSKIP: + Syslog('+', "Zmodem: File skipped by receiver request"); + return c; + default: + zsbhdr(4, ZNAK, Txhdr); + continue; + } + } +} + + + +/* + * Set additional control chars to mask in Zsendmask + * according to bit array stored in char array at p + */ +void initzsendmsk(register char *p) +{ + int c; + + for (c = 0; c < 33; ++c) { + if (p[c>>3] & (1 << (c & 7))) { + Zsendmask[c] = 1; + Syslog('z', "Zmodem: Escaping %02o", c); + } + } +} + + diff --git a/mbfido/Makefile.am b/mbfido/Makefile.am new file mode 100644 index 00000000..0ef3c30a --- /dev/null +++ b/mbfido/Makefile.am @@ -0,0 +1,65 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = maptabs.tgz paths.h.in README + +noinst_PROGRAMS = mbfido mbmail mbseq mbaff mbindex mbdiff mbfile mbmsg + +mbfido_SOURCES = flock.c tosspkt.c mbfido.c hatch.c maketags.c \ +importmsg.c echoout.c tracker.c makestat.c scannews.c lhash.c \ +pack.c ulock.c tic.c ptic.c utic.c mover.c hash.c mkftnhdr.c \ +addbbs.c magic.c fsort.c toberep.c mkrfcmsg.c atoul.c ping.c \ +cookie.c forward.c sendmail.c scan.c addpkt.c importnet.c \ +areamgr.c filemgr.c notify.c mgrutil.c rollover.c bwrite.c \ +rnews.c newspost.c aliasdb.c postemail.c postnetmail.c backalias.c \ +flock.h tosspkt.h mbfido.h hatch.h maketags.h \ +importmsg.h echoout.h tracker.h makestat.h scannews.h lhash.h \ +pack.h ulock.h tic.h ptic.h utic.h mover.h hash.h mkftnhdr.h \ +addbbs.h magic.h fsort.h toberep.h mkrfcmsg.h atoul.h ping.h \ +cookie.h forward.h sendmail.h scan.h addpkt.h importnet.h \ +areamgr.h filemgr.h notify.h mgrutil.h rollover.h bwrite.h \ +rnews.h newspost.h aliasdb.h postemail.h postnetmail.h backalias.h + +mbmail_SOURCES = message.c hash.c lhash.c atoul.c \ +bread.c bwrite.c flock.c mkftnhdr.c mbmail.c tracker.c \ +viadate.c importnet.c aliasdb.c \ +message.h hash.h lhash.h atoul.h \ +bread.h bwrite.h flock.h mkftnhdr.h mbmail.h tracker.h \ +viadate.h importnet.h aliasdb.h + +mbseq_SOURCES = mbseq.c mbseq.h + +mbaff_SOURCES = announce.c fflist.c filefind.c grlist.c mbaff.c msgutil.c \ +announce.h fflist.h filefind.h grlist.h mbaff.h msgutil.h + +mbindex_SOURCES = mbindex.c mbindex.h + +mbdiff_SOURCES = mbdiff.c mbdiff.h + +mbfile_SOURCES = mbfile.c mbfile.h + +mbmsg_SOURCES = post.c mbmsg.c post.h mbmsg.h + +mbfido_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mbmail_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbseq_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbaff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbindex_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfile_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbmsg_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbfido $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbmail $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbseq $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbaff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbindex $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbdiff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfile $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmsg $(bindir) + rm -f $(bindir)/mbnews + ln -s $(bindir)/mbfido $(bindir)/mbnews + (cd ${exec_prefix}; tar xfz @PACKAGE@-@VERSION@/mbfido/maptabs.tgz; chown mbse.bbs etc/maptabs/*) + diff --git a/mbfido/Makefile.in b/mbfido/Makefile.in new file mode 100644 index 00000000..c05108f2 --- /dev/null +++ b/mbfido/Makefile.in @@ -0,0 +1,678 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = maptabs.tgz paths.h.in README + +noinst_PROGRAMS = mbfido mbmail mbseq mbaff mbindex mbdiff mbfile mbmsg + +mbfido_SOURCES = flock.c tosspkt.c mbfido.c hatch.c maketags.c importmsg.c echoout.c tracker.c makestat.c scannews.c lhash.c pack.c ulock.c tic.c ptic.c utic.c mover.c hash.c mkftnhdr.c addbbs.c magic.c fsort.c toberep.c mkrfcmsg.c atoul.c ping.c cookie.c forward.c sendmail.c scan.c addpkt.c importnet.c areamgr.c filemgr.c notify.c mgrutil.c rollover.c bwrite.c rnews.c newspost.c aliasdb.c postemail.c postnetmail.c backalias.c flock.h tosspkt.h mbfido.h hatch.h maketags.h importmsg.h echoout.h tracker.h makestat.h scannews.h lhash.h pack.h ulock.h tic.h ptic.h utic.h mover.h hash.h mkftnhdr.h addbbs.h magic.h fsort.h toberep.h mkrfcmsg.h atoul.h ping.h cookie.h forward.h sendmail.h scan.h addpkt.h importnet.h areamgr.h filemgr.h notify.h mgrutil.h rollover.h bwrite.h rnews.h newspost.h aliasdb.h postemail.h postnetmail.h backalias.h + + +mbmail_SOURCES = message.c hash.c lhash.c atoul.c bread.c bwrite.c flock.c mkftnhdr.c mbmail.c tracker.c viadate.c importnet.c aliasdb.c message.h hash.h lhash.h atoul.h bread.h bwrite.h flock.h mkftnhdr.h mbmail.h tracker.h viadate.h importnet.h aliasdb.h + + +mbseq_SOURCES = mbseq.c mbseq.h + +mbaff_SOURCES = announce.c fflist.c filefind.c grlist.c mbaff.c msgutil.c announce.h fflist.h filefind.h grlist.h mbaff.h msgutil.h + + +mbindex_SOURCES = mbindex.c mbindex.h + +mbdiff_SOURCES = mbdiff.c mbdiff.h + +mbfile_SOURCES = mbfile.c mbfile.h + +mbmsg_SOURCES = post.c mbmsg.c post.h mbmsg.h + +mbfido_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mbmail_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbseq_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbaff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbindex_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfile_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbmsg_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = paths.h +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbfido_OBJECTS = flock.o tosspkt.o mbfido.o hatch.o maketags.o \ +importmsg.o echoout.o tracker.o makestat.o scannews.o lhash.o pack.o \ +ulock.o tic.o ptic.o utic.o mover.o hash.o mkftnhdr.o addbbs.o magic.o \ +fsort.o toberep.o mkrfcmsg.o atoul.o ping.o cookie.o forward.o \ +sendmail.o scan.o addpkt.o importnet.o areamgr.o filemgr.o notify.o \ +mgrutil.o rollover.o bwrite.o rnews.o newspost.o aliasdb.o postemail.o \ +postnetmail.o backalias.o +mbfido_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a \ +../lib/libmbinet.a +mbfido_LDFLAGS = +mbmail_OBJECTS = message.o hash.o lhash.o atoul.o bread.o bwrite.o \ +flock.o mkftnhdr.o mbmail.o tracker.o viadate.o importnet.o aliasdb.o +mbmail_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbmail_LDFLAGS = +mbseq_OBJECTS = mbseq.o +mbseq_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbseq_LDFLAGS = +mbaff_OBJECTS = announce.o fflist.o filefind.o grlist.o mbaff.o \ +msgutil.o +mbaff_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbaff_LDFLAGS = +mbindex_OBJECTS = mbindex.o +mbindex_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbindex_LDFLAGS = +mbdiff_OBJECTS = mbdiff.o +mbdiff_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbdiff_LDFLAGS = +mbfile_OBJECTS = mbfile.o +mbfile_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbfile_LDFLAGS = +mbmsg_OBJECTS = post.o mbmsg.o +mbmsg_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbmsg_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = README Makefile.am Makefile.in paths.h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbfido_SOURCES) $(mbmail_SOURCES) $(mbseq_SOURCES) $(mbaff_SOURCES) $(mbindex_SOURCES) $(mbdiff_SOURCES) $(mbfile_SOURCES) $(mbmsg_SOURCES) +OBJECTS = $(mbfido_OBJECTS) $(mbmail_OBJECTS) $(mbseq_OBJECTS) $(mbaff_OBJECTS) $(mbindex_OBJECTS) $(mbdiff_OBJECTS) $(mbfile_OBJECTS) $(mbmsg_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbfido/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +paths.h: $(top_builddir)/config.status paths.h.in + cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbfido: $(mbfido_OBJECTS) $(mbfido_DEPENDENCIES) + @rm -f mbfido + $(LINK) $(mbfido_LDFLAGS) $(mbfido_OBJECTS) $(mbfido_LDADD) $(LIBS) + +mbmail: $(mbmail_OBJECTS) $(mbmail_DEPENDENCIES) + @rm -f mbmail + $(LINK) $(mbmail_LDFLAGS) $(mbmail_OBJECTS) $(mbmail_LDADD) $(LIBS) + +mbseq: $(mbseq_OBJECTS) $(mbseq_DEPENDENCIES) + @rm -f mbseq + $(LINK) $(mbseq_LDFLAGS) $(mbseq_OBJECTS) $(mbseq_LDADD) $(LIBS) + +mbaff: $(mbaff_OBJECTS) $(mbaff_DEPENDENCIES) + @rm -f mbaff + $(LINK) $(mbaff_LDFLAGS) $(mbaff_OBJECTS) $(mbaff_LDADD) $(LIBS) + +mbindex: $(mbindex_OBJECTS) $(mbindex_DEPENDENCIES) + @rm -f mbindex + $(LINK) $(mbindex_LDFLAGS) $(mbindex_OBJECTS) $(mbindex_LDADD) $(LIBS) + +mbdiff: $(mbdiff_OBJECTS) $(mbdiff_DEPENDENCIES) + @rm -f mbdiff + $(LINK) $(mbdiff_LDFLAGS) $(mbdiff_OBJECTS) $(mbdiff_LDADD) $(LIBS) + +mbfile: $(mbfile_OBJECTS) $(mbfile_DEPENDENCIES) + @rm -f mbfile + $(LINK) $(mbfile_LDFLAGS) $(mbfile_OBJECTS) $(mbfile_LDADD) $(LIBS) + +mbmsg: $(mbmsg_OBJECTS) $(mbmsg_DEPENDENCIES) + @rm -f mbmsg + $(LINK) $(mbmsg_LDFLAGS) $(mbmsg_OBJECTS) $(mbmsg_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbfido + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +addbbs.o: addbbs.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h fsort.h addbbs.h +addpkt.o: addpkt.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h ../lib/dbnode.h ../lib/dbmsgs.h \ + pack.h addpkt.h +aliasdb.o: aliasdb.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h aliasdb.h +announce.o: announce.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h grlist.h msgutil.h announce.h +areamgr.o: areamgr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h scan.h \ + areamgr.h +atoul.o: atoul.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h atoul.h +backalias.o: backalias.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbcfg.h backalias.h +bread.o: bread.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h bread.h +bwrite.o: bwrite.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h bwrite.h +cookie.o: cookie.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h cookie.h +echoout.o: echoout.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h ../lib/dbnode.h ../lib/dbmsgs.h addpkt.h \ + echoout.h +fflist.o: fflist.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h ../lib/msg.h fflist.h +filefind.o: filefind.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h fflist.h filefind.h msgutil.h +filemgr.o: filemgr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbtic.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h filemgr.h +flock.o: flock.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h flock.h +forward.o: forward.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h ../lib/dbtic.h \ + tic.h cookie.h sendmail.h rollover.h forward.h +fsort.o: fsort.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h fsort.h +grlist.o: grlist.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h grlist.h +hash.o: hash.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h hash.h lhash.h +hatch.o: hatch.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbtic.h utic.h \ + rollover.h hatch.h +importmsg.o: importmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h echoout.h mkrfcmsg.h importmsg.h \ + postnetmail.h rollover.h +importnet.o: importnet.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbmsgs.h ../lib/dbuser.h rollover.h importnet.h +lhash.o: lhash.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/clcomm.h lhash.h +magic.o: magic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbtic.h tic.h utic.h \ + magic.h +makestat.o: makestat.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h makestat.h +maketags.o: maketags.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h maketags.h +mbaff.o: mbaff.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + announce.h filefind.h mbaff.h +mbdiff.o: mbdiff.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbdiff.h +mbfido.o: mbfido.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h \ + ../lib/dbdupe.h ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbmsgs.h \ + ../lib/dbuser.h ../lib/dbftn.h ../lib/dbtic.h ../lib/msg.h \ + flock.h tosspkt.h pack.h ulock.h tic.h fsort.h scan.h mbfido.h \ + tracker.h notify.h rollover.h hatch.h scannews.h maketags.h \ + makestat.h newspost.h rnews.h backalias.h +mbfile.o: mbfile.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbfile.h +mbindex.o: mbindex.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbftn.h \ + mbindex.h +mbmail.o: mbmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbftn.h ../lib/dbcfg.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/dbuser.h hash.h \ + mkftnhdr.h message.h +mbmsg.o: mbmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/dbcfg.h \ + post.h mbmsg.h +mbseq.o: mbseq.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbseq.h +message.o: message.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/dbuser.h \ + bread.h bwrite.h hash.h mkftnhdr.h tracker.h viadate.h \ + importnet.h +mgrutil.o: mgrutil.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h sendmail.h \ + mgrutil.h +mkftnhdr.o: mkftnhdr.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h atoul.h hash.h \ + aliasdb.h mkftnhdr.h +mkrfcmsg.o: mkrfcmsg.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbftn.h ../lib/dbdupe.h ../lib/dbuser.h ../lib/common.h \ + ../lib/clcomm.h rollover.h aliasdb.h postemail.h backalias.h \ + mkrfcmsg.h +mover.o: mover.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h mover.h +msgutil.o: msgutil.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h msgutil.h +newspost.o: newspost.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h newspost.h +notify.o: notify.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbnode.h filemgr.h areamgr.h sendmail.h notify.h +pack.o: pack.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbftn.h ../lib/clcomm.h ../lib/dbnode.h \ + pack.h +ping.o: ping.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h ../lib/msgtext.h \ + ../lib/dbcfg.h ../lib/dbnode.h ../lib/dbtic.h ../lib/dbdupe.h \ + ../lib/dbuser.h ../lib/dbftn.h sendmail.h mgrutil.h \ + postnetmail.h ping.h +post.o: post.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h ../lib/msg.h \ + ../lib/msgtext.h post.h +postemail.o: postemail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbuser.h ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h \ + postemail.h +postnetmail.o: postnetmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/dbcfg.h ../lib/dbuser.h ../lib/dbnode.h ../lib/dbftn.h \ + ../lib/common.h ../lib/clcomm.h tracker.h addpkt.h importnet.h \ + mkrfcmsg.h areamgr.h filemgr.h ping.h postemail.h +ptic.o: ptic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbtic.h ../lib/clcomm.h ../lib/dbnode.h \ + ../lib/dbdupe.h ulock.h mover.h toberep.h tic.h utic.h addbbs.h \ + magic.h forward.h rollover.h ptic.h +rnews.o: rnews.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h ../lib/dbdupe.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/msg.h ../lib/msgtext.h \ + pack.h scannews.h mbfido.h rnews.h +rollover.o: rollover.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h rollover.h +scan.o: scan.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/msg.h ../lib/clcomm.h ../lib/msgtext.h \ + ../lib/dbnode.h ../lib/dbmsgs.h addpkt.h pack.h tracker.h \ + mkrfcmsg.h postemail.h scan.h +scannews.o: scannews.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/mbinet.h ../lib/dbdupe.h \ + ../lib/dbnode.h ../lib/dbmsgs.h ../lib/msg.h ../lib/msgtext.h \ + mkftnhdr.h hash.h echoout.h rollover.h pack.h scannews.h +sendmail.o: sendmail.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbnode.h ../lib/clcomm.h ../lib/dbmsgs.h \ + addpkt.h rollover.h sendmail.h +tic.o: tic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/dbftn.h ../lib/clcomm.h ulock.h ptic.h \ + fsort.h pack.h tic.h +toberep.o: toberep.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h toberep.h +tosspkt.o: tosspkt.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h importmsg.h \ + tosspkt.h +tracker.o: tracker.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbnode.h ../lib/dbftn.h \ + tracker.h +ulock.o: ulock.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h flock.h ulock.h +utic.o: utic.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h tic.h mover.h utic.h +viadate.o: viadate.c ../lib/libs.h ../lib/../config.h paths.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + viadate.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbfido $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 4751 mbmail $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbseq $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbaff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbindex $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbdiff $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfile $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmsg $(bindir) + rm -f $(bindir)/mbnews + ln -s $(bindir)/mbfido $(bindir)/mbnews + (cd ${exec_prefix}; tar xfz @PACKAGE@-@VERSION@/mbfido/maptabs.tgz; chown mbse.bbs etc/maptabs/*) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbfido/README b/mbfido/README new file mode 100644 index 00000000..35615030 --- /dev/null +++ b/mbfido/README @@ -0,0 +1,16 @@ + Mailflow roadmap (in progress)! + + + + + RFC +---------------+ + ------->| postemail |--> SMTP + +---------------+ + + +---------------+ + FTN | |--> Outbound + ------->| postnetmail |--> MsgBase + | |--> mkrfcmsg --> postemail + +---------------+ + + diff --git a/mbfido/addbbs.c b/mbfido/addbbs.c new file mode 100644 index 00000000..3f115ea6 --- /dev/null +++ b/mbfido/addbbs.c @@ -0,0 +1,341 @@ +/***************************************************************************** + * + * File ..................: mbfido/addbbs.c + * Purpose ...............: Add TIC file to the BBS + * Last modification date : 21-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "fsort.h" +#include "addbbs.h" + + +extern int tic_imp; + + +/* + * Add file to the BBS file database and place it in the download + * directory. If it is replacing a file, a file with a matching name + * will be deleted. If there is a limit on the number of files with + * the same name pattern, the oldest files will be deleted. The + * files database will be packed if necessary. All modifications are + * done on temp files first. + */ +int Add_BBS() +{ + struct FILERecord frec; + int i, Insert, Done = FALSE, Found = FALSE; + char fdbname[128], fdbtemp[128]; + char temp1[128], temp2[128], *fname; + FILE *fdb, *fdt; + int Keep = 0, DidDelete = FALSE; + fd_list *fdl = NULL; + + /* + * Create filedatabase record. + */ + memset(&frec, 0, sizeof(frec)); + strcpy(frec.Name, TIC.NewName); + strcpy(frec.LName, TIC.NewName); +// strcpy(frec.TicArea, TIC.TicIn.Area); /* TIJDELIJK IVM VELDLENGTE */ + frec.Size = TIC.FileSize; + frec.Crc32 = TIC.Crc_Int; + frec.Announced = TRUE; + sprintf(frec.Uploader, "Filemgr"); + frec.UploadDate = time(NULL); + frec.FileDate = TIC.FileDate; + for (i = 0; i <= TIC.File_Id_Ct; i++) { + strcpy(frec.Desc[i], TIC.File_Id[i]); + if (i == 24) + break; + } + if (strlen(TIC.TicIn.Magic)) + sprintf(frec.Desc[i], "Magic Request: %s", TIC.TicIn.Magic); + + sprintf(temp1, "%s%s", TIC.FilePath, TIC.NewName); + sprintf(temp2, "%s/%s", TIC.BBSpath, TIC.NewName); + mkdirs(temp2); + + if (file_cp(temp1, temp2) != 0) { + WriteError("$Copy to %s failed", temp2); + return FALSE; + } + chmod(temp2, 0644); + + sprintf(fdbname, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), tic.FileArea); + sprintf(fdbtemp, "%s/fdb/fdb%ld.temp", getenv("MBSE_ROOT"), tic.FileArea); + + if ((fdb = fopen(fdbname, "r+")) == NULL) { + Syslog('+', "Fdb %s doesn't exist, creating", fdbname); + if ((fdb = fopen(fdbname, "a+")) == NULL) { + WriteError("$Can't create %s", fdbname); + return FALSE; + } + } + + /* + * If there are no files in this area, we append the first + * one and leave immediatly, keepnum and replace have no + * use at this point. + */ + fseek(fdb, 0, SEEK_END); + if (ftell(fdb) == 0) { + fwrite(&frec, sizeof(frec), 1, fdb); + fclose(fdb); + if (!TIC.NoMove) + file_rm(temp1); + tic_imp++; + return TRUE; + } + + /* + * There are already files in the area. We must now see at + * which position to insert the new file, replace or + * remove the old entry. + */ + fseek(fdb, 0, SEEK_SET); + + Insert = 0; + do { + if (fread(&file, sizeof(file), 1, fdb) != 1) + Done = TRUE; + if (!Done) { + if (strcmp(frec.Name, file.Name) == 0) { + Found = TRUE; + Insert++; + } else + if (strcmp(frec.Name, file.Name) < 0) + Found = TRUE; + else + Insert++; + } + } while ((!Found) && (!Done)); + + if (Found) { + if ((fdt = fopen(fdbtemp, "a+")) == NULL) { + WriteError("$Can't create %s", fdbtemp); + fclose(fdb); + return FALSE; + } + + fseek(fdb, 0, SEEK_SET); + /* + * Copy entries till the insert point. + */ + for (i = 0; i < Insert; i++) { + fread(&file, sizeof(file), 1, fdb); + /* + * Check if we are importing a file with the same + * name, if so, don't copy the original database + * record. The file is also overwritten. + */ + if (strcmp(file.Name, frec.Name) != 0) + fwrite(&file, sizeof(file), 1, fdt); + } + + if (area.AddAlpha) { + /* + * Insert the new entry + */ + fwrite(&frec, sizeof(frec), 1, fdt); + } + + /* + * Append the rest of the entries. + */ + while (fread(&file, sizeof(file), 1, fdb) == 1) { + /* + * Check if we find a file with the same name, + * then we skip the record what was origionaly + * in the database record. + */ + if (strcmp(file.Name, frec.Name) != 0) + fwrite(&file, sizeof(file), 1, fdt); + } + + if (!area.AddAlpha) { + /* + * Append the new entry + */ + fwrite(&frec, sizeof(frec), 1, fdt); + } + fclose(fdt); + fclose(fdb); + + /* + * Now make the changes for real. + */ + if (unlink(fdbname) == 0) { + rename(fdbtemp, fdbname); + } else { + WriteError("$Can't unlink %s", fdbname); + unlink(fdbtemp); + return FALSE; + } + + } else { + /* + * Append the new entry + */ + fseek(fdb, 0, SEEK_END); + fwrite(&frec, sizeof(frec), 1, fdb); + fclose(fdb); + } + + /* + * Delete file from the inbound + */ + if (!TIC.NoMove) { + if ((i = file_rm(temp1))) + WriteError("$ %d = file_rm(%s)", i, temp1); + } + + /* + * Handle the replace option. + */ + if ((strlen(TIC.TicIn.Replace)) && (tic.Replace)) { + Syslog('f', "Must Replace: %s", TIC.TicIn.Replace); + + if ((fdb = fopen(fdbname, "r+")) != NULL) { + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + if (strlen(file.Name) == strlen(TIC.NewName)) { + if (strcasecmp(file.Name, TIC.NewName) != 0) { + Found = TRUE; + for (i = 0; i < strlen(TIC.NewName); i++) { + if ((TIC.TicIn.Replace[i] != '?') && + (toupper(TIC.TicIn.Replace[i]) != toupper(file.Name[i]))) + Found = FALSE; + } + if (Found) { + Syslog('+', "Replace: Deleting: %s", file.Name); + file.Deleted = TRUE; + fseek(fdb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fdb); + DidDelete = TRUE; + } + } + } + } + fclose(fdb); + } + } + + /* + * Handle the Keep number of files option + */ + if (TIC.KeepNum) { + if ((fdb = fopen(fdbname, "r")) != NULL) { + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + + if ((strlen(file.Name) == strlen(TIC.NewName)) && (!file.Deleted)) { + Found = TRUE; + + for (i = 0; i < strlen(file.Name); i++) { + if ((TIC.NewName[i] < '0') || (TIC.NewName[i] > '9')) { + if (TIC.NewName[i] != file.Name[i]) { + Found = FALSE; + } + } + } + if (Found) { + Keep++; + fill_fdlist(&fdl, file.Name, file.UploadDate); + } + } + } + fclose(fdb); + } + + /* + * If there are files to delete, mark them. + */ + if (Keep > TIC.KeepNum) { + sort_fdlist(&fdl); + + if ((fdb = fopen(fdbname, "r+")) != NULL) { + for (i = 0; i < (Keep - TIC.KeepNum); i++) { + fname = pull_fdlist(&fdl); + fseek(fdb, 0, SEEK_SET); + + while (fread(&file, sizeof(file), 1, fdb) == 1) { + if (strcmp(file.Name, fname) == 0) { + Syslog('+', "Keep %d files, deleting: %s", TIC.KeepNum, file.Name); + file.Deleted = TRUE; + fseek(fdb, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fdb); + DidDelete = TRUE; + } + } + } + fclose(fdb); + } + } + tidy_fdlist(&fdl); + } + + /* + * Now realy delete the marked files and clean the file + * database. + */ + if (DidDelete) { + if ((fdb = fopen(fdbname, "r")) != NULL) { + if ((fdt = fopen(fdbtemp, "a+")) != NULL) { + while (fread(&file, sizeof(file), 1, fdb) == 1) + if (!file.Deleted) + fwrite(&file, sizeof(file), 1, fdt); + else { + sprintf(temp2, "%s/%s", area.Path, file.Name); + if (unlink(temp2) != 0) + WriteError("$Can't unlink file %s", temp2); + } + fclose(fdb); + fclose(fdt); + if (unlink(fdbname) == 0) { + rename(fdbtemp, fdbname); + } else { + WriteError("$Can't unlink %s", fdbname); + unlink(fdbtemp); + } + } else { + fclose(fdb); + } + DidDelete = FALSE; + } + } + + tic_imp++; + return TRUE; +} + + diff --git a/mbfido/addbbs.h b/mbfido/addbbs.h new file mode 100644 index 00000000..aefb025c --- /dev/null +++ b/mbfido/addbbs.h @@ -0,0 +1,9 @@ +#ifndef _ADDBBS_H +#define _ADDBBS_H + + +int Add_BBS(void); + + +#endif + diff --git a/mbfido/addpkt.c b/mbfido/addpkt.c new file mode 100644 index 00000000..e02e7f15 --- /dev/null +++ b/mbfido/addpkt.c @@ -0,0 +1,244 @@ +/***************************************************************************** + * + * File ..................: mbfido/addpkt.c + * Purpose ...............: Add mail to .pkt + * Last modification date : 02-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "pack.h" +#include "addpkt.h" + + + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + +extern int do_unprot; + + +FILE *CreatePkt(char *, fidoaddr, fidoaddr, char *); +FILE *CreatePkt(char *Queue, fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + FILE *qp; + unsigned char buffer[0x3a]; + time_t Now; + int i; + struct tm *Tm; + char str[81]; + + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't create Queue %s", Queue); + return NULL; + } + + /* + * Write .PKT header, see FSC-0039 rev. 4 + */ + memset(&buffer, 0, sizeof(buffer)); + time(&Now); + Tm = localtime(&Now); + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + buffer[0x00] = (Orig.node & 0x00ff); + buffer[0x01] = (Orig.node & 0xff00) >> 8; + buffer[0x02] = (Dest.node & 0x00ff); + buffer[0x03] = (Dest.node & 0xff00) >> 8; + buffer[0x04] = ((Tm->tm_year + 1900) & 0x00ff); + buffer[0x05] = ((Tm->tm_year + 1900) & 0xff00) >> 8; + buffer[0x06] = Tm->tm_mon; + buffer[0x08] = Tm->tm_mday; + buffer[0x0a] = Tm->tm_hour; + buffer[0x0c] = Tm->tm_min; + buffer[0x0e] = Tm->tm_sec; + buffer[0x12] = 2; + buffer[0x14] = (Orig.net & 0x00ff); + buffer[0x15] = (Orig.net & 0xff00) >> 8; + buffer[0x16] = (Dest.net & 0x00ff); + buffer[0x17] = (Dest.net & 0xff00) >> 8; + buffer[0x18] = 0xfe; + + memset(&str, 0, 8); /* Packet password */ + if (SearchNode(Dest)) { + if (strlen(nodes.Epasswd)) { + sprintf(str, "%s", nodes.Epasswd); + } + } + + for (i = 0; i < 8; i++) + buffer[0x1a + i] = str[i]; + + buffer[0x22] = (Orig.zone & 0x00ff); + buffer[0x23] = (Orig.zone & 0xff00) >> 8; + buffer[0x24] = (Dest.zone & 0x00ff); + buffer[0x25] = (Dest.zone & 0xff00) >> 8; + buffer[0x29] = 1; + buffer[0x2c] = 1; + buffer[0x2e] = buffer[0x22]; + buffer[0x2f] = buffer[0x23]; + buffer[0x30] = buffer[0x24]; + buffer[0x31] = buffer[0x25]; + buffer[0x32] = (Orig.point & 0x00ff); + buffer[0x33] = (Orig.point & 0xff00) >> 8; + buffer[0x34] = (Dest.point & 0x00ff); + buffer[0x35] = (Dest.point & 0xff00) >> 8; + buffer[0x36] = 'm'; + buffer[0x37] = 'b'; + buffer[0x38] = 's'; + buffer[0x39] = 'e'; + fwrite(buffer, 1, 0x3a, qp); + + fsync(fileno(qp)); + return qp; +} + + + +/* + * Open a .pkt file on the queue, create a fresh one if needed. + * If CFG.maxpktsize is set then it will add the .pkt to the + * ARCmail archive when possible. + */ +FILE *OpenPkt(fidoaddr Orig, fidoaddr Dest, char *Extension) +{ + char Queue[128], qname[128]; + FILE *qp; + + sprintf(Queue, "%s/tmp/%d.%d.%d.%d.%s", getenv("MBSE_ROOT"), + Dest.zone, Dest.net, Dest.node, Dest.point, Extension); + + if (file_exist(Queue, R_OK)) + qp = CreatePkt(Queue, Orig, Dest, Extension); + else { + if ((qp = fopen(Queue, "a")) == NULL) { + WriteError("$Can't reopen Queue %s", Queue); + return NULL; + } + + if (CFG.maxpktsize && (ftell(qp) >= (CFG.maxpktsize * 1024)) && + (strncmp(Extension, "qqq", 3) == 0)) { + /* + * It's a pkt that's meant to be send archived and it's + * bigger then maxpktsize. Try to add this pkt to the + * outbound archive for this node. + */ + sprintf(qname, "%s/tmp", getenv("MBSE_ROOT")); + chdir(qname); + sprintf(qname, "%d.%d.%d.%d.qqq", Dest.zone, Dest.net, Dest.node, Dest.point); + fsync(fileno(qp)); + fclose(qp); + if (pack_queue(qname) == TRUE) { + /* + * If the pack succeeded create a fresh packet. + */ + qp = CreatePkt(Queue, Orig, Dest, Extension); + } else { + /* + * If the pack failed the existing queue is + * reopened and we continue adding to that + * existing packet. This is the case when the + * node is locked. + */ + Syslog('s', "pack_queue failed"); + qp = fopen(Queue, "a"); + } + + /* + * Go back to the original inbound directory. + */ + if (do_unprot) + chdir(CFG.inbound); + else + chdir(CFG.pinbound); + } + } + + return qp; +} + + + +int AddMsgHdr(FILE *fp, faddr *f, faddr *t, int flags, int cost, time_t date, char *tname, char *fname, char *subj) +{ + unsigned char buffer[0x0e]; + struct tm *Tm; + + if ((tname == NULL) || (strlen(tname) > 36) || + (fname == NULL) || (strlen(fname) > 36) || + (subj == NULL) || (strlen(subj) > 72)) + return 1; + + buffer[0x00] = 2; + buffer[0x01] = 0; + buffer[0x02] = (f->node & 0x00ff); + buffer[0x03] = (f->node & 0xff00) >> 8; + buffer[0x04] = (t->node & 0x00ff); + buffer[0x05] = (t->node & 0xff00) >> 8; + buffer[0x06] = (f->net & 0x00ff); + buffer[0x07] = (f->net & 0xff00) >> 8; + buffer[0x08] = (t->net & 0x00ff); + buffer[0x09] = (t->net & 0xff00) >> 8; + buffer[0x0a] = (flags & 0x00ff); + buffer[0x0b] = (flags & 0xff00) >> 8; + buffer[0x0c] = (cost & 0x00ff); + buffer[0x0d] = (cost & 0xff00) >> 8; + fwrite(buffer, 1, sizeof(buffer), fp); + + if (date == (time_t)0) { + date = time(NULL); + Tm = localtime(&date); + } else + Tm = gmtime(&date); + + /* + * According to the manpage the tm_sec value is in the range 0..61 + * to allow leap seconds. FTN networks don't allow this, so if this + * happens we reset the leap seconds. + */ + if (Tm->tm_sec > 59) + Tm->tm_sec = 59; + + fprintf(fp, "%02d %-3.3s %02d %02d:%02d:%02d%c", + Tm->tm_mday % 100, months[Tm->tm_mon], Tm->tm_year % 100, + Tm->tm_hour % 100, Tm->tm_min % 100, Tm->tm_sec % 100, '\0'); + + fprintf(fp, "%s%c", tname, '\0'); + fprintf(fp, "%s%c", fname, '\0'); + fprintf(fp, "%s%c", subj, '\0'); + fsync(fileno(fp)); + return 0; +} + diff --git a/mbfido/addpkt.h b/mbfido/addpkt.h new file mode 100644 index 00000000..c47b53c7 --- /dev/null +++ b/mbfido/addpkt.h @@ -0,0 +1,10 @@ +#ifndef _ADDPKT_H +#define _ADDPKT_H + + +FILE *OpenPkt(fidoaddr, fidoaddr, char *); +int AddMsgHdr(FILE *, faddr *, faddr *, int, int, time_t, char *, char *, char *); + + +#endif + diff --git a/mbfido/aliasdb.c b/mbfido/aliasdb.c new file mode 100644 index 00000000..935ead89 --- /dev/null +++ b/mbfido/aliasdb.c @@ -0,0 +1,217 @@ +/***************************************************************************** + * + * File ..................: mbfido/aliasdb.c + * Purpose ...............: Alias Database + * Last modification date : 11-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "aliasdb.h" + + + +typedef struct _aliasrec { + char freename[MAXNAME]; /* Internet address */ + char address[128]; /* Fidonet address */ + time_t dtime; /* Time the record is added/updated */ +} aliasrec; + + +static int opened = 0; +FILE *afp = NULL; + + +static int alias_db_init(void); +void close_alias_db(void); + + +static int alias_db_init(void) +{ + char buf[PATH_MAX]; + struct stat stbuf; + int tries = 0; + struct flock txflock; + + txflock.l_type = F_WRLCK; + txflock.l_whence = SEEK_SET; + txflock.l_start = 0L; + txflock.l_len = 0L; + + if (opened == -1) + return -1; + if (opened) + return 0; + + sprintf(buf, "%s/var/aliases.data", getenv("MBSE_ROOT")); + if (stat(buf, &stbuf) != 0) { + afp = fopen(buf,"a"); + if (afp) + fclose(afp); + } + + if ((afp = fopen(buf, "r+")) == NULL) { + WriteError("$Can't open %s", buf); + return -1; + } + + /* + * Now lock it. + */ + while (fcntl(fileno(afp), F_SETLK, &txflock) != 0) { + if (tries > 4) + Syslog('+', "Alias database locked %d errno=%d %s", tries +1, errno, strerror(errno)); + usleep(250000); + if (++tries >= 60) { + fclose(afp); + afp = NULL; + WriteError("$Error locking alias database"); + return -1; + } + } + + opened = 1; + return 0; +} + + + +int registrate(char *freename, char *address) +{ + char buf[128], *p, *q; + int first; + aliasrec key; + + if (alias_db_init()) + return 1; + + if (strlen(freename) > MAXNAME) + freename[MAXNAME] = '\0'; + strncpy(buf, freename, sizeof(buf)-1); + first = TRUE; + for (p = buf, q = buf; *p; p++) + switch (*p) { + case '.': *p=' '; /* fallthrough */ + case ' ': if (first) { + *(q++) = *p; + first = FALSE; + } + break; + default: *(q++) = *p; + first = 1; + break; + } + + *q = '\0'; + Syslog('m', "Registrate \"%s\" \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + + while (fread(&key, sizeof(key), 1, afp)) { + if (!strcmp(key.freename, buf)) { + /* + * Already present, update date/time. + */ + time(&key.dtime); + fseek(afp, - sizeof(key), SEEK_CUR); + fwrite(&key, sizeof(key), 1, afp); + close_alias_db(); + return 1; + } + } + + sprintf(key.freename, "%s", buf); + sprintf(key.address, "%s", address); + time(&key.dtime); + + if (fwrite(&key, sizeof(key), 1, afp) != 1) { + WriteError("$Cannot store: \"%s\" \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + } else { + Syslog('m', "Registered \"%s\" as \"%s\"", MBSE_SS(buf), MBSE_SS(address)); + } + close_alias_db(); + return 1; +} + + + +char *lookup(char *freename) +{ + static char buf[128], *p, *q; + int first; + aliasrec key; + + if (alias_db_init()) + return NULL; + + strncpy(buf, freename, sizeof(buf) -1); + first = TRUE; + for (p = buf, q = buf; *p; p++) + switch (*p) { + case '.': *p=' '; /* fallthrough */ + case ' ': if (first) { + *(q++) = *p; + first = FALSE; + } + break; + default: *(q++) = *p; + first = TRUE; + break; + } + + *q = '\0'; + Syslog('m', "Lookup \"%s\"", MBSE_SS(freename)); + + while (fread(&key, sizeof(key), 1, afp)) { + if (!strcmp(key.freename, buf)) { + /* + * Already present + */ + close_alias_db(); + Syslog('m',"Found: \"%s\"",buf); + return buf; + } + } + + Syslog('m',"Not found: \"%s\"",buf); + close_alias_db(); + return NULL; +} + + + +void close_alias_db(void) +{ + if (opened != 1) + return; + fclose(afp); + afp = NULL; + opened = 0; +} + + diff --git a/mbfido/aliasdb.h b/mbfido/aliasdb.h new file mode 100644 index 00000000..951d21b3 --- /dev/null +++ b/mbfido/aliasdb.h @@ -0,0 +1,12 @@ +#ifndef _ALIASDB_H +#define _ALIASDB_H + + +#define MAXNAME 35 + +int registrate(char *, char *); +char *lookup(char *); + + +#endif + diff --git a/mbfido/announce.c b/mbfido/announce.c new file mode 100644 index 00000000..f45b49e4 --- /dev/null +++ b/mbfido/announce.c @@ -0,0 +1,470 @@ +/***************************************************************************** + * + * File ..................: mbaff/announce.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "grlist.h" +#include "msgutil.h" +#include "announce.h" + + +extern int do_quiet; /* Supress screen output */ +struct _filerecord T_File; /* Internal announce record */ +int TotalFiles; /* Total announced files */ +unsigned long TotalSize; /* Total size in KBytes. */ +int MsgCount; /* Message counter */ + + + +/* + * Add a file whos data is in T_File to the toberep.data file. + */ +int Add_ToBeRep(void); +int Add_ToBeRep() +{ + char *fname; + struct _filerecord Temp; + FILE *tbr; + int Found = FALSE; + + fname = calloc(PATH_MAX, sizeof(char)); + sprintf(fname, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((tbr = fopen(fname, "a+")) == NULL) { + WriteError("$Can't create %s", fname); + free(fname); + return FALSE; + } + free(fname); + + fseek(tbr, 0, SEEK_SET); + while (fread(&Temp, sizeof(Temp), 1, tbr) == 1) { + if ((strcmp(Temp.Name, T_File.Name) == 0) && + (Temp.Fdate = T_File.Fdate)) + Found = TRUE; + } + + if (Found) { + Syslog('!', "File %s already in toberep.data", T_File.Name); + fclose(tbr); + return FALSE; + } + + fwrite(&T_File, sizeof(T_File), 1, tbr); + fclose(tbr); + return TRUE; +} + + + +/* + * Check for uploads, these are files in the files database with + * the announced flag not yet set. + */ +void Uploads(void); +void Uploads() +{ + FILE *pAreas, *pFile; + char *sAreas, *fAreas; + int Count = 0, i = 0, j, k; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + + Syslog('+', "Checking for uploads"); + IsDoing("Check uploads"); + + if (!do_quiet) { + colour(3, 0); + printf(" Checking uploads...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + free(sAreas); + free(fAreas); + return; + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + i++; + + if (CFG.slow_util && do_quiet) + usleep(1); + + if ((area.Available) && strlen(area.NewGroup)) { + + if (!do_quiet) { + printf("\r %4d => %-44s", i, area.Name); + fflush(stdout); + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + if ((pFile = fopen(fAreas, "r+")) != NULL) { + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if (!file.Announced) { + Syslog('m', " %d %s", i, file.Name); + memset(&T_File, 0, sizeof(T_File)); + sprintf(T_File.Echo, "AREA %d", i); + sprintf(T_File.Group, "%s", area.NewGroup); + sprintf(T_File.Comment, "%s", area.Name); + sprintf(T_File.Name, "%s", file.Name); + T_File.Size = file.Size; + T_File.SizeKb = file.Size / 1024; + T_File.Fdate = file.FileDate; + sprintf(T_File.Crc, "%08lx", file.Crc32); + sprintf(T_File.Desc, "%s %s %s %s", file.Desc[0], file.Desc[1], file.Desc[2], file.Desc[3]); + k = 0; + for (j = 0; j < 25; j++) { + if (strlen(file.Desc[j])) { + sprintf(T_File.LDesc[k], "%s", file.Desc[j]); + T_File.LDesc[k][49] = '\0'; + k++; + } + } + T_File.TotLdesc = k; + T_File.Cost = file.Cost; + T_File.Announce = TRUE; + if (Add_ToBeRep()) + Count++; + /* + * Mark file is announced. + */ + file.Announced = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } + } + + fclose(pFile); + } + } + } + + if (!do_quiet) { + printf("\r \r"); + if (Count) + printf(" %d new uploads\n", Count); + fflush(stdout); + } + + if (Count) + Syslog('+', "%d new uploads", Count); + + fclose(pAreas); + free(sAreas); + free(fAreas); +} + + + +int StartMsg(void); +int StartMsg(void) +{ + if (!Msg_Open(newfiles.Area)) + return FALSE; + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + Msg_New(); + + CountPosted(newfiles.Area); + + sprintf(Msg.From, "%s", newfiles.From); + sprintf(Msg.To, "%s", newfiles.Too); + if (MsgCount == 1) { + sprintf(Msg.Subject, "%s", newfiles.Subject); + TotalSize = TotalFiles = 0; + } else + sprintf(Msg.Subject, "%s #%d", newfiles.Subject, MsgCount); + sprintf(Msg.FromAddress, "%s", aka2str(newfiles.UseAka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + Msg.Echomail = TRUE; + + /* + * Start message text including kludges + */ + Msg_Id(newfiles.UseAka); + Msg_Pid(); + Msg_Top(); + return TRUE; +} + + + +void FinishMsg(int); +void FinishMsg(int Final) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + + if (Final) { + MsgText_Add2((char *)""); + sprintf(temp, "This is a total of %d files, %lu Kbytes", TotalFiles, TotalSize); + MsgText_Add2(temp); + } else { + MsgText_Add2((char *)""); + MsgText_Add2((char *)"to be continued..."); + MsgCount++; + } + + if (strlen(newfiles.Origin)) + Msg_Bot(newfiles.UseAka, newfiles.Origin); + else + Msg_Bot(newfiles.UseAka, CFG.origin); + + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld, %d bytes", Msg.Id, Msg.Size); + + sprintf(temp, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", newfiles.Area, Msg.Id); + fclose(fp); + } + Msg_Close(); + + free(temp); +} + + + +void Report(gr_list *); +void Report(gr_list *ta) +{ + FILE *fp; + char *temp; + int i, Total = 0; + unsigned long Size = 0; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if ((!strcmp(T_File.Echo, ta->echo)) && + (!strcmp(T_File.Group, ta->group))) + break; + } + + sprintf(temp, "Area %s - %s", T_File.Echo, T_File.Comment); + MsgText_Add2(temp); + + fseek(fp, 0, SEEK_SET); + MsgText_Add2((char *)"------------------------------------------------------------------------"); + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if ((!strcmp(T_File.Echo, ta->echo)) && + (!strcmp(T_File.Group, ta->group))) { + + if (CFG.slow_util && do_quiet) + usleep(1); + + sprintf(temp, "%-12s %5lu Kb. %s", tu(T_File.Name), T_File.SizeKb, To_Low(T_File.LDesc[0],newfiles.HiAscii)); + MsgText_Add2(temp); + if (T_File.TotLdesc > 0) + for (i = 1; i < T_File.TotLdesc; i++) { + sprintf(temp, " %s", To_Low(T_File.LDesc[i],newfiles.HiAscii)); + MsgText_Add2(temp); + } + Total++; + Size += T_File.SizeKb; + + /* + * Split message the hard way. + */ + if (Msg.Size > (CFG.new_force * 1024)) { + FinishMsg(FALSE); + StartMsg(); + } + } + } + MsgText_Add2((char *)"------------------------------------------------------------------------"); + + sprintf(temp, "%d files, %lu Kb", Total, Size); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + fclose(fp); + free(temp); + + /* + * Split messages the gently way. + */ + if (Msg.Size > (CFG.new_split * 1024)) { + FinishMsg(FALSE); + StartMsg(); + } + + TotalFiles += Total; + TotalSize += Size; +} + + + +int Announce() +{ + gr_list *fgr = NULL, *tmp; + char *temp; + FILE *fp; + int Count = 0, rc = FALSE; + long filepos; + char group[13]; + int i, groups, any; + + if (!do_quiet) { + colour(3, 0); + printf("Announce new files\n"); + } + + Uploads(); + + IsDoing("Announce files"); + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + Syslog('+', "No new files to announce"); + free(temp); + if (!do_quiet) { + printf(" No new files.\n"); + } + return FALSE; + } + + if (!do_quiet) + printf(" Preparing reports...\n"); + + while (fread(&T_File, sizeof(T_File), 1, fp) == 1) { + if (T_File.Announce) { + fill_grlist(&fgr, T_File.Group, T_File.Echo); + Count++; + } + } + + fclose(fp); + + if (Count == 0) { + unlink(temp); + if (!do_quiet) + printf(" No new files.\n"); + Syslog('+', "No new files to announce"); + free(temp); + return FALSE; + } + + if (!do_quiet) + printf(" %d new files found\n", Count); + + sort_grlist(&fgr); + + /* + * At this point we have a sorted list of groups with a counter + * indicating howmany files to report in each group. + */ + sprintf(temp, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + if (!do_quiet) + printf(" No newfile reports defined\n"); + free(temp); + return FALSE; + } + fread(&newfileshdr, sizeof(newfileshdr), 1, fp); + groups = newfileshdr.grpsize / 13; + + while (fread(&newfiles, newfileshdr.recsize, 1, fp) == 1) { + if (newfiles.Active) { + filepos = ftell(fp); + if (!do_quiet) { + printf(" %s\n", newfiles.Comment); + } + any = FALSE; + + for (i = 0; i < groups; i++) { + fread(&group, 13, 1, fp); + for (tmp = fgr; tmp; tmp = tmp->next) + if (strcmp(tmp->group, group) == 0) + any = TRUE; + } + if (any) { + fseek(fp, filepos, SEEK_SET); + rc = TRUE; + Syslog('+', "Create report: %s", newfiles.Comment); + MsgCount = 1; + if (StartMsg()) { + while (fread(&group, 13, 1, fp) == 1) { + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) { + Report(tmp); + } + } + } + FinishMsg(TRUE); + } + + fseek(fp, filepos, SEEK_SET); + } + + fseek(fp, newfileshdr.grpsize, SEEK_CUR); + } + fclose(fp); + + tidy_grlist(&fgr); + + if (rc) { + sprintf(temp, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + unlink(temp); + } + + free(temp); + return rc; +} + + diff --git a/mbfido/announce.h b/mbfido/announce.h new file mode 100644 index 00000000..70fbbf7d --- /dev/null +++ b/mbfido/announce.h @@ -0,0 +1,9 @@ +#ifndef _MBAFF_H_ +#define _MBAFF_H + + +int Announce(void); /* Announce files */ + + +#endif + diff --git a/mbfido/areamgr.c b/mbfido/areamgr.c new file mode 100644 index 00000000..e7be7e70 --- /dev/null +++ b/mbfido/areamgr.c @@ -0,0 +1,1105 @@ +/***************************************************************************** + * + * File ..................: mbfido/areamgr.c + * Purpose ...............: AreaMgr + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "scan.h" +#include "areamgr.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad echomail */ +extern int echo_dupe; /* Dupe echomail */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + +int areamgr = 0; /* Nr of AreaMgr messages */ +int a_help = FALSE; +int a_list = FALSE; +int a_query = FALSE; +int a_stat = FALSE; +int a_unlnk = FALSE; +int a_flow = FALSE; +unsigned long a_msgs = 0; + + + +void A_Help(faddr *); +void A_Help(faddr *t) +{ + FILE *fp; + + Syslog('+', "AreaMgr: Help"); + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr help", msgid)) != NULL) { + fprintf(fp, "Address all requests to '%s' (without quotes)\r", (char *)"Areamgr"); + fprintf(fp, "Youre AreaMgr password goes on the subject line.\r\r"); + + fprintf(fp, "In the body of the message to AreaMgr:\r\r"); + + fprintf(fp, "+ To connect to an echomail area\r"); + fprintf(fp, "- To disconnect from an echomail area\r"); + fprintf(fp, "%%+ALL To connect to all echomail areas\r"); + fprintf(fp, "%%-ALL To disconnect from all echomail areas\r"); + fprintf(fp, "%%+ To connect all echomail areas of a group\r"); + fprintf(fp, "%%- To disconnect from all echomail areas of a group\r"); + fprintf(fp, "%%HELP To request this help message\r"); + fprintf(fp, "%%LIST To request a list of echomail areas available to you\r"); + fprintf(fp, "%%QUERY To request a list of echomail areas for which you are active\r"); + fprintf(fp, "%%UNLINKED To request a list of echomail areas available to you\r"); + fprintf(fp, " to which you are not already connected\r"); + fprintf(fp, "%%FLOW To request a flow report of available areas\r"); + fprintf(fp, "%%STATUS To request a status report for your system\r"); +// fprintf(fp, "%%PAUSE To temporary disconnect from the connected echomail areas\r"); +// fprintf(fp, "%%RESUME To reconnect the temporary disconnected echomail areas\r"); + fprintf(fp, "%%PWD=newpwd To set a new AreaMgr and FileMgr password\r"); + fprintf(fp, "%%MSGS To set max. number of messages to be rescanned\r"); + fprintf(fp, "%%RESCAN To request messages from 'area' again\r"); + fprintf(fp, "%%NOTIFY=On/Off To switch the notify function on or off\r"); + fprintf(fp, "[---] Everything below the tearline is ignored\r\r"); + + fprintf(fp, "Example:\r\r"); + + fprintf(fp, " By: %s\r", nodes.Sysop); + fprintf(fp, " To: %s, %s\r", (char *)"Areamgr", ascfnode(bestaka_s(t), 0xf)); + fprintf(fp, " Re: %s\r", nodes.Apasswd); + fprintf(fp, " St: Pvt Local Kill\r"); + fprintf(fp, " ----------------------------------------------------------\r"); + fprintf(fp, " +SYSOPS\r"); + fprintf(fp, " -GENERAL\r"); + fprintf(fp, " %%QUERY\r"); + fprintf(fp, " %%LIST\r\r"); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void A_Query(faddr *); +void A_Query(faddr *t) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + Syslog('+', "AreaMgr: Query"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your query request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all connected message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + + if (Stat[0] == 'S' || Stat[1] == 'R') { + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d connected area(s)\r\r\r", SubTot); + } + } + } + fprintf(qp, "Total: %d connected area(s)\r\r\r", Total); + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_List(faddr *t, int Notify) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + if (Notify) + Syslog('+', "AreaMgr: Notify to %s", ascfnode(t, 0xff)); + else + Syslog('+', "AreaMgr: List"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr List", msgid)) != NULL) { + + WriteMailGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + fprintf(qp, "Total: %d available area(s)\r\r\r", Total); + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Flow(faddr *t, int Notify) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, Cons; + char Stat[2]; + faddr *f; + sysconnect System; + time_t Now; + struct tm *tt; + int lmonth; + long lw, lm; + + Now = time(NULL); + tt = localtime(&Now); + lmonth = tt->tm_mon; + if (lmonth) + lmonth--; + else + lmonth = 11; + + if (Notify) + Syslog('+', "AreaMgr: Flow report to %s", ascfnode(t, 0xff)); + else + Syslog('+', "AreaMgr: Flow report"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr Flow report", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a flow report of all message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + lm = lw = 0; + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); +// 1 2 3 4 5 6 7 +// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + fprintf(qp, "Con Message area Last week Last Month\r"); + fprintf(qp, "---------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if ((System.receivefrom || System.sendto) && + (!System.pause) && (!System.cutoff)) + Stat[0] = 'C'; + } + } + fprintf(qp, "%s %s %9lu %10lu\r", + Stat, padleft(msgs.Tag, 50, ' '), + msgs.Received.lweek, + msgs.Received.month[lmonth]); + lm += msgs.Received.month[lmonth]; + lw += msgs.Received.lweek; + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "---------------------------------------------------------------------------\r"); + fprintf(qp, "Total %58lu %10lu\r\r\r", lw, lm); + } + } + } + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " C - You connected to this area\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Status(faddr *); +void A_Status(faddr *t) +{ + FILE *fp; + int i; + + Syslog('+', "AreaMgr: Status"); + if (Miy == 0) + i = 11; + else + i = Miy - 1; + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"AreaMgr status", msgid)) != NULL) { + + fprintf(fp, "Here is your (echo)mail status:\r\r"); + + fprintf(fp, "Netmail direct %s\r", GetBool(nodes.Direct)); + fprintf(fp, "Netmail crash %s\r", GetBool(nodes.Crash)); + fprintf(fp, "Netmail hold %s\r", GetBool(nodes.Hold)); + if (nodes.RouteVia.zone) + fprintf(fp, "Route via %s\r", aka2str(nodes.RouteVia)); + + fprintf(fp, "\r\rMailflow:\r\r"); + + fprintf(fp, " Last week Last month Total ever\r"); + fprintf(fp, " ---------- ---------- ----------\r"); + fprintf(fp, "Messages to you %-10ld %-10ld %-10ld\r", nodes.MailSent.lweek, nodes.MailSent.month[i], nodes.MailSent.total); + fprintf(fp, "Messages from you %-10ld %-10ld %-10ld\r", nodes.MailRcvd.lweek, nodes.MailRcvd.month[i], nodes.MailRcvd.total); + + fprintf(fp, "\rWith regards, %s\r\r", CFG.sysop_name); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void A_Unlinked(faddr *); +void A_Unlinked(faddr *t) +{ + FILE *qp, *gp, *mp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[5]; + faddr *f; + sysconnect System; + + Syslog('+', "AreaMgr: Unlinked"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your unlinked request", msgid)) != NULL) { + + WriteMailGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all available message areas\r\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", mgroup.Name, mgroup.Comment); + fprintf(qp, "Con Message area Description\r"); + fprintf(qp, "----------------------------------------------------------------------------\r"); + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if (!strcmp(Group, msgs.Group) && msgs.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, mp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + if (System.cutoff) + Stat[3] = 'C'; + } + } + + if ((!System.sendto) && (!System.receivefrom)) { + fprintf(qp, "%s %-25s %s\r", Stat, msgs.Tag, msgs.Name); + SubTot++; + Total++; + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + + fprintf(qp, "----------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(mp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive mail from my system\r"); + fprintf(qp, " S - You may send mail to my system\r"); + fprintf(qp, " P - The message area is temporary paused\r"); + fprintf(qp, " C - You are cutoff from this area\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void A_Global(faddr *, char *, FILE *); +void A_Global(faddr *t, char *Cmd, FILE *tmp) +{ + ShiftBuf(Cmd, 1); + Syslog('m', " AreaMgr node %s global %s", ascfnode(t, 0x1f), Cmd); +} + + + +void A_Disconnect(faddr *, char *, FILE *); +void A_Disconnect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "AreaMgr: \"%s\"", Area); + ShiftBuf(Area, 1); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + + if (!SearchMsgs(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + return; + } + + Syslog('m', " Found %s group %s", msgs.Tag, mgroup.Name); + + First = TRUE; + while ((Group = GetNodeMailGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, mgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not disconnect from area %s\n", Area); + Syslog('m', " Group %s not available for node", mgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(mgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not disconnect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not disconnect from group %s", mgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = FALSE; + Sys.receivefrom = FALSE; + + if (!MsgSystemConnected(Sys)) { + fprintf(tmp, "You are not connected to %s\n", Area); + Syslog('m', " Node is not connected to %s", Area); + return; + } + + if (MsgSystemConnect(&Sys, FALSE)) { + + /* + * Make sure to write an overview afterwards. + */ + a_list = TRUE; + Syslog('+', "Disconnected echo area %s", Area); + fprintf(tmp, "Disconnected from area %s\n", Area); + return; + } + + fprintf(tmp, "You may not disconnect area %s\n", Area); + Syslog('+', "Didn't disconnect %s from mandatory or cutoff echo area %s", ascfnode(t, 0x1f), Area); +} + + + +void A_Connect(faddr *, char *, FILE *); +void A_Connect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "AreaMgr: \"%s\"", printable(Area, 0)); + + if (Area[0] == '+') + ShiftBuf(Area, 1); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + + if (!SearchMsgs(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + /* SHOULD CHECK FOR AREAS FILE AND ASK UPLINK + CHECK ALL GROUPRECORDS FOR AKA MATCH + IF MATCH CHECK FOR UPLINK AND AREAS FILE + IF FOUND, CREATE MSG AREA, CONNECT UPLINK + RESTORE NODERECORD (IS GONE!) + FALLTHRU TO CONNECT DOWNLINK + */ + return; + } + + Syslog('m', " Found %s group %s", msgs.Tag, mgroup.Name); + + First = TRUE; + while ((Group = GetNodeMailGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, mgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not connect to area %s\n", Area); + Syslog('m', " Group %s not available for node %s", mgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(mgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not connect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not connect to group %s", mgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + Sys.receivefrom = TRUE; + + if (MsgSystemConnected(Sys)) { + fprintf(tmp, "You are already connected to %s\n", Area); + Syslog('m', " Node is already connected to %s", Area); + return; + } + + if (MsgSystemConnect(&Sys, TRUE)) { + + /* + * Make sure to write an overview afterwards. + */ + a_list = TRUE; + Syslog('+', "Connected echo area %s", Area); + fprintf(tmp, "Connected to area %s\n", Area); + return; + } + + fprintf(tmp, "Not connected to %s, this is not allowed\n", Area); + WriteError("Can't connect node %s to echo area %s", ascfnode(t, 0x1f), Area); +} + + + +void A_All(faddr *, int, FILE *, char *); +void A_All(faddr *t, int Connect, FILE *tmp, char *Grp) +{ + FILE *mp, *gp; + char *Group, temp[81]; + faddr *f; + int i, Link, First = TRUE, Cons; + sysconnect Sys; + long Pos; + + if (Grp == NULL) { + if (Connect) + Syslog('+', "AreaMgr: Connect All"); + else + Syslog('+', "AreaMgr: Disconnect All"); + } else { + if (Connect) + Syslog('+', "AreaMgr: Connect group %s", Grp); + else + Syslog('+', "AreaMgr: Disconnect group %s", Grp); + } + + f = bestaka_s(t); + Syslog('m', "Bestaka for %s is %s", ascfnode(t, 0x1f), ascfnode(f, 0x1f)); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mp = fopen(temp, "r+"); + fread(&msgshdr, sizeof(msgshdr), 1, mp); + Cons = msgshdr.syssize / sizeof(Sys); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + ((Grp == NULL) || (!strcmp(Group, Grp)))) { + + fseek(mp, msgshdr.hdrsize, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mp) == 1) { + if ((!strcmp(Group, msgs.Group)) && + (msgs.Active) && (!msgs.Mandatory) && + (metric(fido2faddr(mgroup.UseAka), f) == METRIC_EQUAL)) { + + if (Connect) { + Link = FALSE; + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) + Link = TRUE; + } + if (!Link) { + Pos = ftell(mp); + fseek(mp, - msgshdr.syssize, SEEK_CUR); + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if (!Sys.aka.zone) { + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + Sys.receivefrom = TRUE; + fseek(mp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, mp); + Syslog('+', "AreaMgr: Connected %s", msgs.Tag); + fprintf(tmp, "Connected area %s\n", msgs.Tag); + a_list = TRUE; + break; + } + } + fseek(mp, Pos, SEEK_SET); + } + } else { + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, mp); + if ((metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) && + (!Sys.cutoff)) { + memset(&Sys, 0, sizeof(Sys)); + fseek(mp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, mp); + Syslog('+', "AreaMgr: Disconnected %s", msgs.Tag); + fprintf(tmp, "Disconnected area %s\n", msgs.Tag); + a_list = TRUE; + } + } + } + } else + fseek(mp, msgshdr.syssize, SEEK_CUR); + } + } + } + } + fclose(gp); + fclose(mp); +} + + + +void A_Group(faddr *, char *, int, FILE *); +void A_Group(faddr *t, char *Area, int Connect, FILE *tmp) +{ + int i; + + ShiftBuf(Area, 2); + CleanBuf(Area); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + A_All(t, Connect, tmp, Area); +} + + + +void A_Pause(faddr *, int, FILE *); +void A_Pause(faddr *t, int Pause, FILE *tmp) +{ + return; + if (Pause) + Syslog('+', "AreaMgr: Pause"); + else + Syslog('+', "AreaMgr: Resume"); +} + + + +void A_Rescan(faddr *, char *, FILE *); +void A_Rescan(faddr *t, char *Area, FILE *tmp) +{ + int i,result; + + /* + * First strip leading garbage + */ + ShiftBuf(Area, 7); + CleanBuf(Area); + for (i=0; i < strlen(Area); i++ ) + Area[i]=toupper(Area[i]); + Syslog('+', "AreaMgr: Rescan %s, MSGS=%lu", Area, a_msgs); + result=RescanOne(t, Area, a_msgs); + if (result==0){ + if (a_msgs>0) + fprintf(tmp, "Rescan area %s, %lu last msgs.\n", Area, a_msgs); + else + fprintf(tmp, "Rescan area %s \n", Area); + } else if (result==1) + fprintf(tmp, "Can't rescan unknown area %s\n", Area); + else if (result==2) + fprintf(tmp, "%s can't rescan area %s\n", ascfnode(t, 0x1f), Area); + else + fprintf(tmp, "Fatal Error Rescanning area %s\n", Area); +} + + + +void A_Msgs(char *, int); +void A_Msgs(char *Buf, int skip) +{ + /* + * First strip leading garbage + */ + ShiftBuf(Buf, skip); + CleanBuf(Buf); + a_msgs = strtoul( Buf, (char **)NULL, 10 ); + Syslog('+', "AreaMgr: msgs %s ", Buf ); +} + + + +int AreaMgr(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + int i, rc = 0, spaces; + char *Buf; + FILE *tmp, *np; + fidoaddr Node; + + a_help = a_stat = a_unlnk = a_list = a_query = FALSE; + areamgr++; + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "AreaMgr msg from %s", ascfnode(f, 0xff)); + + /* + * If the password failed, we return silently and don't respond. + */ + if ((!strlen(subj)) || (strcasecmp(subj, nodes.Apasswd))) { + WriteError("AreaMgr: password expected \"%s\", got \"%s\"", nodes.Apasswd, subj); + net_bad++; + return FALSE; + } + + if ((tmp = tmpfile()) == NULL) { + WriteError("$AreaMgr: Can't open tmpfile()"); + net_bad++; + return FALSE; + } + + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + while ((fgets(Buf, 2048, fp)) != NULL) { + + /* + * Make sure we have the nodes record loaded + */ + memcpy(&Node, faddr2fido(f), sizeof(fidoaddr)); + SearchNode(Node); + + spaces = 0; + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == ' ') + spaces++; + if (*(Buf + i) == '\t') + spaces++; + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + if (!strncmp(Buf, "---", 3)) + break; + + if (strlen(Buf) && (*(Buf) != '\001') && (spaces <= 1)) { + + if (!strncasecmp(Buf, "%help", 5)) + a_help = TRUE; + else if (!strncasecmp(Buf, "%query", 6)) + a_query = TRUE; + else if (!strncasecmp(Buf, "%linked", 7)) + a_query = TRUE; + else if (!strncasecmp(Buf, "%list", 5)) + a_list = TRUE; + else if (!strncasecmp(Buf, "%status", 7)) + a_stat = TRUE; + else if (!strncasecmp(Buf, "%unlinked", 9)) + a_unlnk = TRUE; + else if (!strncasecmp(Buf, "%flow", 5)) + a_flow = TRUE; + else if (!strncasecmp(Buf, "%msgs", 5)) + A_Msgs(Buf, 5); + else if (!strncasecmp(Buf, "%rescan", 7)) + A_Rescan(f, Buf, tmp); + else if (!strncasecmp(Buf, "%+all", 5)) + A_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-all", 5)) + A_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+*", 3)) + A_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-*", 3)) + A_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+", 2)) + A_Group(f, Buf, TRUE, tmp); + else if (!strncasecmp(Buf, "%-", 2)) + A_Group(f, Buf, FALSE, tmp); + else if (!strncasecmp(Buf, "%pause", 6)) + A_Pause(f, TRUE, tmp); + else if (!strncasecmp(Buf, "%resume", 7)) + A_Pause(f, FALSE, tmp); + else if (!strncasecmp(Buf, "%password", 9)) + MgrPasswd(f, Buf, tmp, 9); + else if (!strncasecmp(Buf, "%pwd", 4)) + MgrPasswd(f, Buf, tmp, 4); + else if (!strncasecmp(Buf, "%notify", 7)) + MgrNotify(f, Buf, tmp); + else if (*(Buf) == '%') + A_Global(f, Buf, tmp); + else if (*(Buf) == '-') + A_Disconnect(f, Buf, tmp); + else + A_Connect(f, Buf, tmp); + } + } + + /* + * If the temporary response file isn't empty, + * create a response netmail about what we did. + */ + if (ftell(tmp)) { + if ((np = SendMgrMail(f, CFG.ct_KeepMgr, FALSE, (char *)"Areamgr", (char *)"Your AreaMgr request", msgid)) != NULL) { + + fprintf(np, " Dear %s\r\r", nodes.Sysop); + fprintf(np, "Here is the result of your AreaMgr request:\r\r"); + fseek(tmp, 0, SEEK_SET); + + while ((fgets(Buf, 2048, tmp)) != NULL) { + Buf[strlen(Buf)-1] = '\0'; + fprintf(np, "%s\r", Buf); + Syslog('m', "Rep: %s", Buf); + } + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(np, t); + net_out++; + } else + WriteError("Can't create netmail"); + } + + free(Buf); + fclose(tmp); + + if (a_stat) + A_Status(f); + + if (a_query) + A_Query(f); + + if (a_list) + A_List(f, FALSE); + + if (a_flow) + A_Flow(f, FALSE); + + if (a_unlnk) + A_Unlinked(f); + + if (a_help) + A_Help(f); + + return rc; +} + + + diff --git a/mbfido/areamgr.h b/mbfido/areamgr.h new file mode 100644 index 00000000..caef8df0 --- /dev/null +++ b/mbfido/areamgr.h @@ -0,0 +1,12 @@ +#ifndef _AREAMGR_H +#define _AREAMGR_H + + +void A_Status(faddr *); +void A_List(faddr *, int); +void A_Flow(faddr *, int); +int AreaMgr(faddr *, faddr *, time_t, int, FILE *); + + +#endif + diff --git a/mbfido/atoul.c b/mbfido/atoul.c new file mode 100644 index 00000000..71a6054d --- /dev/null +++ b/mbfido/atoul.c @@ -0,0 +1,46 @@ +/***************************************************************************** + * + * File ..................: mbmail/atoul.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "atoul.h" + + +unsigned long atoul(char *str) +{ + unsigned long x; + + if (sscanf(str,"%lu",&x) == 1) + return x; + else + return 0xffffffff; +} + diff --git a/mbfido/atoul.h b/mbfido/atoul.h new file mode 100644 index 00000000..87bd34c7 --- /dev/null +++ b/mbfido/atoul.h @@ -0,0 +1,8 @@ +#ifndef _ATOUL_H +#define _ATOUL_H + + +unsigned long atoul(char*); + +#endif + diff --git a/mbfido/backalias.c b/mbfido/backalias.c new file mode 100644 index 00000000..f563357a --- /dev/null +++ b/mbfido/backalias.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: mbfido/backalias.c + * Purpose ...............: Alias functions. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "backalias.h" + + + +static struct aliaslist { + struct aliaslist *next; + faddr *addr; + char *alias; +} *alist = NULL; + + + +char *backalias(faddr *fa) +{ + struct aliaslist *tmp; + + for (tmp = alist; tmp; tmp = tmp->next) + if ((!fa->domain || !tmp->addr->domain || !strcasecmp(fa->domain,tmp->addr->domain)) && + (!fa->zone || (fa->zone == tmp->addr->zone)) && (fa->net == tmp->addr->net) && + (fa->node == tmp->addr->node) && (fa->point == tmp->addr->point) && (fa->name) && + (tmp->addr->name) && (strcasecmp(fa->name,tmp->addr->name) == 0)) { + Syslog('m', "Address \"%s\" has local alias \"%s\"", ascinode(fa,0x7f), MBSE_SS(tmp->alias)); + return tmp->alias; + } + return NULL; +} + + + +void readalias(char *fn) +{ + FILE *fp; + char buf[256], *k, *v; + struct aliaslist *tmp = NULL; + faddr *ta = NULL; + + if ((fp = fopen(fn,"r")) == NULL) { + WriteError("$cannot open system alias file %s", MBSE_SS(fn)); + return; + } + + while (fgets(buf, sizeof(buf)-1, fp)) { + k = strtok(buf, " \t:"); + v = strtok(NULL, " \t\n\r\0:"); + if (k && v) + if ((ta = parsefaddr(v))) { + if (alist) { + tmp->next = (struct aliaslist *) xmalloc(sizeof(struct aliaslist)); + tmp = tmp->next; + } else { + alist = (struct aliaslist *) xmalloc(sizeof(struct aliaslist)); + tmp = alist; + } + tmp->next = NULL; + tmp->addr = ta; + ta = NULL; + tmp->alias = xstrcpy(k); + } + } + fclose(fp); +} + diff --git a/mbfido/backalias.h b/mbfido/backalias.h new file mode 100644 index 00000000..ea82bfef --- /dev/null +++ b/mbfido/backalias.h @@ -0,0 +1,8 @@ +#ifndef _BACKALIAS_H +#define _BACKALIAS_H + +char *backalias(faddr *); +void readalias(char *); + +#endif + diff --git a/mbfido/bread.c b/mbfido/bread.c new file mode 100644 index 00000000..cb9657a6 --- /dev/null +++ b/mbfido/bread.c @@ -0,0 +1,111 @@ +/***************************************************************************** + * + * File ..................: mbmail/bread.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "bread.h" + + +extern int pgpsigned; + + + +/* + * read short (16bit) integer in "standart" byte order + */ +int iread(FILE *fp) +{ + unsigned char lo,hi; + + fread(&lo,1,1,fp); + fread(&hi,1,1,fp); + return (hi<<8) | lo; +} + + + +/* + * read long (32bit) integer in "standart" byte order + */ +long lread(FILE *fp) +{ + int c; + unsigned char buf; + long ret = 0L; + + for (c = 0; c < 32; c += 8) { + fread(&buf, 1, 1, fp); + ret |= ((unsigned long)buf << c); + } + return ret; +} + + + +static int at_zero=0; + +char *aread(char *s, int count, FILE *fp) +{ + int i,c,next; + + if (feof(fp)) + return(NULL); + if (s == NULL) + return NULL; + if (at_zero) { + at_zero=0; + return NULL; + } + + for (i = 0, next = 1; (i> 8) & 0xff,fp); + return 0; +} + + +/* + * write long (32bit) integer in "standart" byte order + */ +int lwrite(long i, FILE *fp) +{ + int c; + + for (c = 0; c < 32; c += 8) + putc((i >> c) & 0xff,fp); + return 0; +} + + +int awrite(char *s, FILE *fp) +{ + if (s) + while (*s) + putc(*(s++), fp); + putc(0,fp); + return 0; +} + + + +/* + * write an arbitrary line to message body: change \n to \r, + */ +int cwrite(char *s, FILE *fp, int postlocal) +{ + while (*s) { + if ((*s == '\n') && !postlocal) + putc('\r',fp); + else if ((*s == '\r') && postlocal) + putc('\n',fp); + else + putc(*s, fp); + s++; + } + return 0; +} + + + +/* + * write (multiline) header to kluge: change \n to ' ' and end line with \r + */ +int kwrite(char *s, FILE *fp, int postlocal) +{ + while (*s) { + if (*s != '\n') + putc(*s, fp); + else if (*(s+1)) + putc(' ',fp); + s++; + } + if (postlocal) + putc('\n',fp); + else + putc('\r',fp); + return 0; +} + diff --git a/mbfido/bwrite.h b/mbfido/bwrite.h new file mode 100644 index 00000000..0a3b729f --- /dev/null +++ b/mbfido/bwrite.h @@ -0,0 +1,11 @@ +#ifndef _BWRITE_H +#define _BWRITE_H + +int iwrite(int,FILE *); +int lwrite(long,FILE *); +int awrite(char *,FILE *); +int cwrite(char *,FILE *, int); +int kwrite(char *,FILE *, int); + +#endif + diff --git a/mbfido/cookie.c b/mbfido/cookie.c new file mode 100644 index 00000000..fd036cb7 --- /dev/null +++ b/mbfido/cookie.c @@ -0,0 +1,90 @@ +/***************************************************************************** + * + * File ..................: mbfido/cookie.h + * Purpose ...............: Create a cookie + * Last modification date : 19-Mar-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "cookie.h" + + + +char *Cookie() +{ + FILE *olf; + char fname[81]; + int i, j, in, id; + int recno = 0; + long offset; + int nrecno; + static char temp[81]; + + sprintf(fname, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((olf = fopen(fname, "r")) == NULL) { + WriteError("$Can't open %s", fname); + return '\0'; + } + + fread(&olhdr, sizeof(olhdr), 1, olf); + while (fread(&ol, olhdr.recsize, 1, olf) == 1) { + recno++; + } + nrecno = recno; + + /* + * Generate random record number + */ + while (TRUE) { + in = nrecno; + id = getpid(); + + i = rand(); + j = i % id; + if ((j <= in)) + break; + } + + offset = olhdr.hdrsize + (j * olhdr.recsize); + if (fseek(olf, offset, SEEK_SET) != 0) { + WriteError("$Can't move pointer in %s", fname); + return '\0'; + } + fread(&ol, olhdr.recsize, 1, olf); + fclose(olf); + + memset(&temp, 0, sizeof(temp)); + strcpy(temp, ol.Oneline); + return temp; +} + + diff --git a/mbfido/cookie.h b/mbfido/cookie.h new file mode 100644 index 00000000..e2ff1462 --- /dev/null +++ b/mbfido/cookie.h @@ -0,0 +1,8 @@ +#ifndef _COOKIE_H +#define _COOKIE_H + + +char *Cookie(void); + +#endif + diff --git a/mbfido/echoout.c b/mbfido/echoout.c new file mode 100644 index 00000000..4304c6f4 --- /dev/null +++ b/mbfido/echoout.c @@ -0,0 +1,85 @@ +/***************************************************************************** + * + * File ..................: tosser/echoout.c + * Purpose ...............: Forward echomail packets + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "echoout.h" + + + +/* + * External declarations + */ +extern char *toname; /* To user */ +extern char *fromname; /* From user */ +extern char *subj; /* Message subject */ + + + + +void EchoOut(faddr *fa, fidoaddr aka, FILE *fp, int flags, int cost, time_t date) +{ + char *buf; + FILE *qp; + faddr *From, *To; + + if ((qp = OpenPkt(msgs.Aka, aka, (char *)"qqq")) == NULL) + return; + + From = fido2faddr(msgs.Aka); + To = fido2faddr(aka); + if (AddMsgHdr(qp, From, To, flags, cost, date, toname, fromname, subj)) { + tidy_faddr(From); + tidy_faddr(To); + return; + } + + rewind(fp); + buf = calloc(2048, sizeof(char)); + + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + fprintf(qp, "%s\r", buf); + } + + free(buf); + putc(0, qp); + fsync(fileno(qp)); + fclose(qp); +} + + + diff --git a/mbfido/echoout.h b/mbfido/echoout.h new file mode 100644 index 00000000..a31d7193 --- /dev/null +++ b/mbfido/echoout.h @@ -0,0 +1,8 @@ +#ifndef _ECHOOUT_H +#define _ECHOOUT_H + + +void EchoOut(faddr *, fidoaddr, FILE *, int, int, time_t); + +#endif + diff --git a/mbfido/fflist.c b/mbfido/fflist.c new file mode 100644 index 00000000..f5b0f6cf --- /dev/null +++ b/mbfido/fflist.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbaff/fflist.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "fflist.h" + + +/* + * Tidy the filefind array + */ +void tidy_fflist(ff_list ** fdp) +{ + ff_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a search record to the array + */ +void fill_fflist(ff_list **fdp) +{ + char *b; + ff_list *tmp, *ta; + + b = calloc(44, sizeof(char)); + sprintf(b, "%s~", Msg.FromAddress); + + /* + * Add a new record + */ + tmp = (ff_list *)malloc(sizeof(ff_list)); + tmp->next = NULL; + sprintf(tmp->from, "%s", Msg.From); + sprintf(tmp->subject, "%s", Msg.Subject); + if (strchr(b, '.') == NULL) { + tmp->zone = atoi(strtok(b, ":")); + tmp->net = atoi(strtok(NULL, "/")); + tmp->node = atoi(strtok(NULL, "~")); + } else { + tmp->zone = atoi(strtok(b, ":")); + tmp->net = atoi(strtok(NULL, "/")); + tmp->node = atoi(strtok(NULL, ".")); + tmp->point = atoi(strtok(NULL, "~")); + } + sprintf(tmp->msgid, "%s", Msg.Msgid); + tmp->msgnr = Msg.Id; + tmp->done = FALSE; + + /* + * New record goes at the end. + */ + if (*fdp == NULL) + *fdp = tmp; + else + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (ff_list *)tmp; + break; + } + + free(b); +} + + + +/* + * Tidy the reply files array + */ +void tidy_rflist(rf_list ** fdp) +{ + rf_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a reply file to the array + */ +void fill_rflist(rf_list **fdp, char *fname, unsigned long area) +{ + rf_list *tmp, *ta; + + /* + * Add a new record + */ + tmp = (rf_list *)malloc(sizeof(rf_list)); + tmp->next = NULL; + sprintf(tmp->filename, "%s", fname); + tmp->area = area; + + /* + * New record goes at the end. + */ + if (*fdp == NULL) + *fdp = tmp; + else + for (ta = *fdp; ta; ta = ta->next) + if (ta->next == NULL) { + ta->next = (rf_list *)tmp; + break; + } +} + + + diff --git a/mbfido/fflist.h b/mbfido/fflist.h new file mode 100644 index 00000000..c7765894 --- /dev/null +++ b/mbfido/fflist.h @@ -0,0 +1,34 @@ +#ifndef _FFLIST_H_ +#define _FFLIST_H + + +typedef struct _ff_list { /* Filefind array */ + struct _ff_list *next; + char from[36]; /* From username */ + char subject[72]; /* Search parameters */ + unsigned short zone; /* Original zone */ + unsigned short net; /* Original net */ + unsigned short node; /* Original node */ + unsigned short point; /* Original point */ + char msgid[81]; /* Original msgid */ + unsigned long msgnr; /* Original message number */ + unsigned done : 1; /* True if processed with success */ +} ff_list; + + + +typedef struct _rf_list { /* Reply filenames array */ + struct _rf_list *next; + char filename[15]; /* Filename found */ + unsigned long area; /* BBS file area number */ +} rf_list; + + +void tidy_fflist(ff_list **); +void fill_fflist(ff_list **); +void tidy_rflist(rf_list **); +void fill_rflist(rf_list **, char *, unsigned long); + + +#endif + diff --git a/mbfido/filefind.c b/mbfido/filefind.c new file mode 100644 index 00000000..6c4183a3 --- /dev/null +++ b/mbfido/filefind.c @@ -0,0 +1,523 @@ +/***************************************************************************** + * + * File ..................: mbaff/filefind.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "fflist.h" +#include "filefind.h" +#include "msgutil.h" + +/* + * The next constants are to prevent overflowing the echomail areas + * with huge replies. MAX_DESC_LINES limits the number of file description + * lines, 5 should be enough. The other two are the maximum files to report + * if in the same area or different area. + * For netmail replies there is a different limit. + */ +#define MAX_DESC_LINES 5 +#define MAX_FILES_SAMEBOARD 15 +#define MAX_FILES_OTHERBOARD 50 +#define MAX_FILES_NETMAIL 100 + + +extern int do_quiet; /* Supress screen output */ +struct _filerecord T_File; /* Internal announce record */ +int Requests = 0; /* Total found request */ +int Replies = 0; /* Total generated replies */ + + +void Back(int); +void Back(int count) +{ + int i; + + if (do_quiet) + return; + + for (i = 0; i < count; i++) + printf("\b"); + fflush(stdout); +} + + + +void Clean(int); +void Clean(int count) +{ + int i; + + if (do_quiet) + return; + + for (i = 0; i < count; i++) + printf(" "); + Back(count); +} + + + +void ScanArea(ff_list **); +void ScanArea(ff_list **ffl) +{ + unsigned long Number, Highest; + + if (!do_quiet) { + colour(3, 0); + printf("\r %-40s", scanmgr.Comment); + colour(12, 0); + printf(" (Scanning) "); + colour(13, 0); + fflush(stdout); + } + Syslog('+', "Scanning %s", scanmgr.Comment); + if (Msg_Open(scanmgr.ScanBoard)) { + Number = Msg_Lowest(); + Highest = Msg_Highest(); + + do { + if (!do_quiet) { + printf("%6lu / %6lu", Number, Highest); + Back(15); + } + + if (CFG.slow_util && do_quiet) + usleep(1); + + if (Msg_ReadHeader(Number) == TRUE) { + if (((!strcasecmp(Msg.To, "allfix")) || + (!strcasecmp(Msg.To, "filefind"))) && + (!Msg.Received)) { + Syslog('m', "Msg: %s (%lu) [%s]", Msg.From, Number, Msg.Subject); + Msg.Received = TRUE; + Msg.Read = time(NULL); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Number); + Msg_UnLock(); + Syslog('m', "Marked message received"); + } + if (strlen(Msg.Subject) && strlen(Msg.FromAddress)) { + fill_fflist(ffl); + Requests++; + } + } + } + + } while (Msg_Next(&Number) == TRUE); + + Msg_Close(); + Clean(15); + } else + WriteError("$Can't open %s", scanmgr.ScanBoard); + + Back(54); + Clean(54); +} + + + +int StartReply(ff_list *); +int StartReply(ff_list *ffl) +{ + char *temp; + unsigned long crc = -1; + + if (strlen(scanmgr.ReplBoard)) { + if (!Msg_Open(scanmgr.ReplBoard)) + return FALSE; + else + CountPosted(scanmgr.ReplBoard); + } else { + if (!Msg_Open(scanmgr.ScanBoard)) + return FALSE; + else + CountPosted(scanmgr.ScanBoard); + } + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + Msg_New(); + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(Msg.From, "%s", CFG.sysop_name); + sprintf(Msg.To, "%s", ffl->from); + sprintf(Msg.Subject, "Re: %s", ffl->subject); + sprintf(Msg.FromAddress, "%s", aka2str(scanmgr.Aka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + if (scanmgr.NetReply) + Msg.Netmail = TRUE; + else + Msg.Echomail = TRUE; + + /* + * Start message text including kludges + */ + Msg_Id(scanmgr.Aka); + sprintf(temp, "\001REPLYID: %s", ffl->msgid); + MsgText_Add2(temp); + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + Msg_Pid(); + Msg_Top(); + + return TRUE; +} + + + +void FinishReply(int, int); +void FinishReply(int Reported, int Total) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + + MsgText_Add2((char *)""); + if (Reported < Total) { + sprintf(temp, "Listed %d out of %d files matching your search request", Reported, Total); + MsgText_Add2(temp); + MsgText_Add2((char *)"For more information, visit our BBS"); + } else { + sprintf(temp, "Found %d files matching your search request", Reported); + MsgText_Add2(temp); + } + + if (strlen(scanmgr.Origin)) + Msg_Bot(scanmgr.Aka, scanmgr.Origin); + else + Msg_Bot(scanmgr.Aka, CFG.origin); + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld", Msg.Id); + + sprintf(temp, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + if (strlen(scanmgr.ReplBoard)) + fprintf(fp, "%s %lu\n", scanmgr.ReplBoard, Msg.Id); + else + fprintf(fp, "%s %lu\n", scanmgr.ScanBoard, Msg.Id); + fclose(fp); + } + + Msg_Close(); + free(temp); +} + + + +/* + * Scan for files for one request. + */ +void ScanFiles(ff_list *); +void ScanFiles(ff_list *tmp) +{ + char *temp, *kwd, *BigDesc; + FILE *pAreas, *pFile; + unsigned long areanr = 0, found = 0; + int i, j, k, keywrd, Found; + rf_list *rfl = NULL, *rft; + int Rep = 0, Sub = 0, Stop = FALSE; + + /* + * Check for local generated requests. + */ + if (!CFG.ct_LocalRep) { + } + + kwd = calloc(81, sizeof(char)); + temp = calloc(1024, sizeof(char)); + BigDesc = calloc(1230, sizeof(char)); + + sprintf(temp, "%s (%d:%d/%d.%d)", tmp->from, tmp->zone, tmp->net, tmp->node, tmp->point); + Syslog('+', "ff: %s [%s]", temp, tmp->subject); + + if (!do_quiet) { + colour(3, 0); + temp[40] = '\0'; + printf("\r %-40s", temp); + colour(12, 0); + printf(" (Searching)"); + colour(13, 0); + fflush(stdout); + } + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + areanr++; + + if (CFG.slow_util && do_quiet) + usleep(1); + + if (!do_quiet) { + printf("%6lu / %6lu", areanr, found); + Back(15); + } + if (area.Available && area.FileFind) { + sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), areanr); + if ((pFile = fopen(temp, "r")) != NULL) { + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + for (i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + sprintf(temp, "%s", tmp->subject); + + Found = FALSE; + while (strlen(temp) && (!Found)) { + /* + * Split the search request in + * separate words. + */ + k = strlen(temp); + for (i = 0; i < k; i++) + if (temp[i] == ' ') + break; + if (i < k) { + strncpy(kwd, temp, i); + kwd[i] = '\0'; + for (j = 0; j < (k - i -1); j++) + temp[j] = temp[j+i+1]; + temp[j] = '\0'; + } else { + sprintf(kwd, "%s", temp); + temp[0] = '\0'; + } + + /* + * Check if it's a filename search + * or a keyword search. + */ + keywrd = FALSE; + if ((kwd[0] == '/') || (kwd[0] == '\\')) { + keywrd = TRUE; + for (i = 1; i < strlen(kwd); i++) + kwd[i-1] = kwd[i]; + kwd[i-1] = '\0'; + } + tl(kwd); + + if (strlen(kwd) > 3) { + if (strstr(file.Name, kwd) != NULL) { + Found = TRUE; + Syslog('m', "Found %s in %s in filename", kwd, file.Name); + } + if (keywrd && (strstr(tl(BigDesc), kwd) != NULL)) { + Found = TRUE; + Syslog('m', "Found %s in %s in description", kwd, file.Name); + } + } + } + if (Found) { + found++; + Syslog('m', "Found %s area %d", file.Name, areanr); + fill_rflist(&rfl, file.Name, areanr); + } + strcpy(BigDesc, ""); + } + + fclose(pFile); + } else + WriteError("$Can't open %s", temp); + } + } + fclose(pAreas); + Clean(15); + } else + WriteError("$Can't open %s", temp); + + Back(12); + Clean(12); + + if (found) { + if (!do_quiet) { + colour(14, 0); + printf(" (Replying)"); + fflush(stdout); + } + + if (StartReply(tmp)) { + areanr = 0; + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + for (rft = rfl; rft; rft = rft->next) { + + if ((areanr != rft->area) && (Sub)) { + MsgText_Add2((char *)"------------------------------------------------------------------------"); + sprintf(temp, "Found %d file(s)", Sub); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + Sub = 0; + } + + if (areanr != rft->area) { + fseek(pAreas, ((rft->area - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + sprintf(temp, "Area %lu - %s", rft->area, area.Name); + MsgText_Add2(temp); + MsgText_Add2((char *)"------------------------------------------------------------------------"); + areanr = rft->area; + } + + sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), rft->area); + if ((pFile = fopen(temp, "r")) != NULL) { + while (fread(&file, sizeof(file), 1, pFile) == 1) + if (!strcmp(rft->filename, file.Name)) + break; + fclose(pFile); + sprintf(temp, "%-12s %5lu Kb. %s", tu(file.Name), file.Size / 1024, To_Low(file.Desc[0],scanmgr.HiAscii)); + MsgText_Add2(temp); + + /* + * We add no more then 5 description lines + * to prevent unnecesary long messages. + */ + for (i = 1; i < MAX_DESC_LINES; i++) + if (strlen(file.Desc[i])) { + sprintf(temp, " %s", To_Low(file.Desc[i],scanmgr.HiAscii)); + MsgText_Add2(temp); + } + } + Rep++; + Sub++; + + if (!scanmgr.NetReply) { + if (strlen(scanmgr.ReplBoard)) { + if (Rep >= MAX_FILES_OTHERBOARD) + Stop = TRUE; + } else { + if (Rep >= MAX_FILES_SAMEBOARD) + Stop = TRUE; + } + } else { + if (Rep >= MAX_FILES_NETMAIL) + Stop = TRUE; + } + if (Stop) + break; + } + + if (Sub) { + MsgText_Add2((char *)"------------------------------------------------------------------------"); + sprintf(temp, "Found %d file(s)", Sub); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + } + + fclose(pAreas); + } + FinishReply(Rep, found); + Replies++; + } + + Back(11); + Clean(11); + } + + Back(42); + Clean(42); + + tidy_rflist(&rfl); + free(BigDesc); + free(temp); + free(kwd); +} + + + +int Filefind() +{ + char *temp; + int rc = FALSE; + FILE *fp; + ff_list *ffl = NULL, *tmp; + + IsDoing("FileFind"); + + if (!do_quiet) { + colour(3, 0); + printf("Processing FileFind requests\n"); + } + Syslog('+', "Processing FileFind requests"); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return FALSE; + } + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fp); + + while (fread(&scanmgr, scanmgrhdr.recsize, 1, fp) == 1) { + if (scanmgr.Active) { + ScanArea(&ffl); + + for (tmp = ffl; tmp; tmp = tmp->next) { + ScanFiles(tmp); + } + tidy_fflist(&ffl); + } + } + fclose(fp); + + free(temp); + + if (Requests) { + Syslog('+', "Processed %d requests, created %d replies", Requests, Replies); + if (Replies) + rc = TRUE; + if (!do_quiet) { + colour(3, 0); + printf("Processed %d requests, created %d replies\n", Requests, Replies); + } + } + + return rc; +} + + diff --git a/mbfido/filefind.h b/mbfido/filefind.h new file mode 100644 index 00000000..3c6330ef --- /dev/null +++ b/mbfido/filefind.h @@ -0,0 +1,9 @@ +#ifndef _FILEFIND_H +#define _FILEFIND_H + + +int Filefind(void); + + +#endif + diff --git a/mbfido/filemgr.c b/mbfido/filemgr.c new file mode 100644 index 00000000..5c33e4b5 --- /dev/null +++ b/mbfido/filemgr.c @@ -0,0 +1,974 @@ +/***************************************************************************** + * + * File ..................: mbfido/filemgr.c + * Purpose ...............: FileMgr + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "filemgr.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad fileecho */ +extern int echo_dupe; /* Dupe fileecho */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + +int filemgr = 0; /* Nr of FileMgr messages */ +int f_help = FALSE; +int f_list = FALSE; +int f_query = FALSE; +int f_stat = FALSE; +int f_unlnk = FALSE; + + + +void F_Help(faddr *); +void F_Help(faddr *t) +{ + FILE *fp; + + Syslog('+', "FileMgr: Help"); + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr help", msgid)) != NULL) { + fprintf(fp, "Address all requests to '%s' (without quotes)\r", (char *)"Filemgr"); + fprintf(fp, "Youre FileMgr password goes on the subject line.\r\r"); + + fprintf(fp, "In the body of the message to FileMgr:\r\r"); + + fprintf(fp, "+ To connect to an fileecho area\r"); + fprintf(fp, "- To disconnect from an fileecho area\r"); + fprintf(fp, "%%+ALL To connect to all fileecho areas\r"); + fprintf(fp, "%%-ALL To disconnect from all fileecho areas\r"); + fprintf(fp, "%%+ To connect all fileecho areas of a group\r"); + fprintf(fp, "%%- To disconnect from all fileecho areas of a group\r"); + fprintf(fp, "%%HELP To request this help message\r"); + fprintf(fp, "%%LIST To request a list of available fileecho areas\r"); + fprintf(fp, "%%QUERY To request a list of active fileecho areas\r"); + fprintf(fp, "%%UNLINKED To request a list of available fileecho areas\r"); + fprintf(fp, " to which you are not already connected\r"); + fprintf(fp, "%%STATUS To request a status report for your system\r"); +// fprintf(fp, "%%PAUSE To temporary disconnect from the connected areas\r"); +// fprintf(fp, "%%RESUME To reconnect the temporary disconnected areas\r); + fprintf(fp, "%%PWD=newpwd To set a new AreaMgr and FileMgr password\r"); +// fprintf(fp, "%%RESCAN To request all files from 'area' again\r"); + fprintf(fp, "%%MESSGAE=On/Off To switch the message function on or off\r"); + fprintf(fp, "%%TICK=On/Off/Advanced To set the tic file mode off, normal or advanced\r"); + fprintf(fp, "%%NOTIFY=On/Off To switch the notify function on or off\r"); +// fprintf(fp, "%%RESEND To resend file 'name' with tic file\r"); + fprintf(fp, "[---] Everything below the tearline is ignored\r\r"); + + fprintf(fp, "Example:\r\r"); + + fprintf(fp, " By: %s\r", nodes.Sysop); + fprintf(fp, " To: %s, %s\r", (char *)"Filemgr", ascfnode(bestaka_s(t), 0xf)); + fprintf(fp, " Re: %s\r", nodes.Fpasswd); + fprintf(fp, " St: Pvt Local Kill\r"); + fprintf(fp, " ----------------------------------------------------------\r"); + fprintf(fp, " +MBSE_BBS\r"); + fprintf(fp, " -NODELIST\r"); + fprintf(fp, " %%QUERY\r"); + fprintf(fp, " %%LIST\r\r"); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void F_Query(faddr *); +void F_Query(faddr *t) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + Syslog('+', "FileMgr: Query"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your query request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all connected file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + + if (System.sendto || System.receivefrom) { + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } + } + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_List(faddr *t, int Notify) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + if (Notify) + Syslog('+', "FileMgr: Notify to %s", ascfnode(t, 0xff)); + else + Syslog('+', "FileMgr: List"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr List", msgid)) != NULL) { + + WriteFileGroups(qp, f); + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + } + } + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_Status(faddr *); +void F_Status(faddr *t) +{ + FILE *fp; + int i; + + Syslog('+', "FileMgr: Status"); + if (Miy == 0) + i = 11; + else + i = Miy - 1; + + if ((fp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"FileMgr Status", msgid)) != NULL) { + + fprintf(fp, "Here is your fileecho status:\r\r"); + + fprintf(fp, "Netmail message %s\r", GetBool(nodes.Message)); + fprintf(fp, "TIC files %s\r", GetBool(nodes.Tic)); + if (nodes.Tic) + fprintf(fp, "Andvanced TIC files %s\r", GetBool(nodes.AdvTic)); + fprintf(fp, "Notify messages %s\r", GetBool(nodes.Notify)); + fprintf(fp, "Cost sharing %s\r", GetBool(nodes.Billing)); + if (nodes.Billing) { + fprintf(fp, "Send bill direct %s\r", GetBool(nodes.BillDirect)); + fprintf(fp, "Units debet %ld\r", nodes.Debet); + fprintf(fp, "Units credit %ld\r", nodes.Credit); + fprintf(fp, "Warning level %ld\r", nodes.WarnLevel); + } + + fprintf(fp, "\r\rRecent flow:\r\r"); + + fprintf(fp, " Last week Last month Total ever\r"); + fprintf(fp, " ---------- ---------- ----------\r"); + fprintf(fp, "Files sent %-10ld %-10ld %-10ld\r", nodes.FilesSent.lweek, nodes.FilesSent.month[i], nodes.FilesSent.total); + fprintf(fp, "KBytes sent %-10ld %-10ld %-10ld\r", nodes.F_KbSent.lweek, nodes.F_KbSent.month[i], nodes.F_KbSent.total); + fprintf(fp, "Files received %-10ld %-10ld %-10ld\r", nodes.FilesRcvd.lweek, nodes.FilesRcvd.month[i], nodes.FilesRcvd.total); + fprintf(fp, "KBytes received %-10ld %-10ld %-10ld\r", nodes.F_KbRcvd.lweek, nodes.F_KbRcvd.month[i], nodes.F_KbRcvd.total); + + fprintf(fp, "\rWith regards, %s\r\r", CFG.sysop_name); + + fprintf(fp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(fp, t); + net_out++; + } else + WriteError("Can't create netmail"); +} + + + +void F_Unlinked(faddr *); +void F_Unlinked(faddr *t) +{ + FILE *qp, *gp, *fp; + char *temp, *Group; + int i, First = TRUE, SubTot, Total = 0, Cons; + char Stat[4]; + faddr *f; + sysconnect System; + + Syslog('+', "FileMgr: Unlinked"); + f = bestaka_s(t); + + if ((qp = SendMgrMail(t, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your unlinked request", msgid)) != NULL) { + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(System); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + fprintf(qp, "The following is a list of all available file areas\r\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + SubTot = 0; + fprintf(qp, "Group %s - %s\r\r", fgroup.Name, fgroup.Comment); + fprintf(qp, "Con File tic Description\r"); + fprintf(qp, "------------------------------------------------------------------------\r"); + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (!strcmp(Group, tic.Group) && tic.Active) { + memset(&Stat, ' ', sizeof(Stat)); + Stat[sizeof(Stat)-1] = '\0'; + + /* + * Now check if this node is connected, + * if so, set the Stat bits. + */ + for (i = 0; i < Cons; i++) { + fread(&System, sizeof(System), 1, fp); + if ((t->zone == System.aka.zone) && + (t->net == System.aka.net) && + (t->node == System.aka.node) && + (t->point == System.aka.point)) { + if (System.receivefrom) + Stat[0] = 'S'; + if (System.sendto) + Stat[1] = 'R'; + if (System.pause) + Stat[2] = 'P'; + } + } + + if ((!System.sendto) && (!System.receivefrom)) { + fprintf(qp, "%s %-20s %s\r", Stat, tic.Name, tic.Comment); + SubTot++; + Total++; + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + fprintf(qp, "------------------------------------------------------------------------\r"); + fprintf(qp, "%d available area(s)\r\r\r", SubTot); + } + } + } + + fclose(fp); + fclose(gp); + + fprintf(qp, "Con means:\r"); + fprintf(qp, " R - You receive files from my system\r"); + fprintf(qp, " S - You may send files in this area\r"); + fprintf(qp, " P - The file area is temporary paused\r\r"); + fprintf(qp, "With regards, %s\r\r", CFG.sysop_name); + fprintf(qp, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(qp, t); + net_out++; + free(temp); + } else + WriteError("Can't create netmail"); +} + + + +void F_Global(faddr *, char *, FILE *); +void F_Global(faddr *t, char *Cmd, FILE *tmp) +{ + ShiftBuf(Cmd, 1); + Syslog('m', " FileMgr node %s global %s", ascfnode(t, 0x1f), Cmd); +} + + + +void F_Disconnect(faddr *, char *, FILE *); +void F_Disconnect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "FileMgr: %s", Area); + ShiftBuf(Area, 1); + + if (!SearchTic(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + return; + } + + Syslog('m', " Found %s group %s", tic.Name, fgroup.Name); + + First = TRUE; + while ((Group = GetNodeFileGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, fgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not disconnect from area %s\n", Area); + Syslog('m', " Group %s not available for node", fgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(fgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not disconnect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not disconnect from group %s", fgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = FALSE; + Sys.receivefrom = FALSE; + + if (!TicSystemConnected(Sys)) { + fprintf(tmp, "You are not connected to %s\n", Area); + Syslog('m', " Node is not connected to %s", Area); + return; + } + + if (!TicSystemConnect(&Sys, FALSE)) { + + /* + * Make sure to write an overview afterwards + */ + f_list = TRUE; + Syslog('+', "Disconnected file area %s", Area); + fprintf(tmp, "Disconnected from area %s\n", Area); + return; + } + + fprintf(tmp, "You may not disconnect area %s, area is mandatory\n", Area); + Syslog('+', "Didn't disconnect %s from mandatory file area %s", ascfnode(t, 0x1f), Area); +} + + + +void F_Connect(faddr *, char *, FILE *); +void F_Connect(faddr *t, char *Area, FILE *tmp) +{ + int i, First; + char *Group; + faddr *b; + sysconnect Sys; + + Syslog('+', "FileMgr: %s", Area); + + if (Area[0] == '+') + ShiftBuf(Area, 1); + + if (!SearchTic(Area)) { + fprintf(tmp, "Area %s not found\n", Area); + Syslog('m', " Area not found"); + /* SHOULD CHECK FOR AREAS FILE AND ASK UPLINK + CHECK ALL GROUPRECORDS FOR AKA MATCH + IF MATCH CHECK FOR UPLINK AND AREAS FILE + IF FOUND, CREATE TIC AREA, CONNECT UPLINK + RESTORE NODERECORD (IS GONE!) + FALLTHRU TO CONNECT DOWNLINK + */ + return; + } + + Syslog('m', " Found %s group %s", tic.Name, fgroup.Name); + + First = TRUE; + while ((Group = GetNodeFileGrp(First)) != NULL) { + First = FALSE; + if (strcmp(Group, fgroup.Name) == 0) + break; + } + if (Group == NULL) { + fprintf(tmp, "You may not connect to area %s\n", Area); + Syslog('m', " Group %s not available for node %s", fgroup.Name); + return; + } + + b = bestaka_s(t); + i = metric(b, fido2faddr(fgroup.UseAka)); + Syslog('m', "Aka match level is %d", i); + + if (i > METRIC_POINT) { + fprintf(tmp, "You may not connect area %s with nodenumber %s\n", Area, ascfnode(t, 0x1f)); + Syslog('m', " Node may not connect to group %s", fgroup.Name); + return; + } + + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + + if (TicSystemConnected(Sys)) { + fprintf(tmp, "You are already connected to %s\n", Area); + Syslog('m', " Node is already connected to %s", Area); + return; + } + + if (TicSystemConnect(&Sys, TRUE)) { + + /* + * Make sure to write an overview afterwards + */ + f_list = TRUE; + Syslog('+', "Connected to file area %s", Area); + fprintf(tmp, "Connected to area %s\n", Area); + return; + } + + fprintf(tmp, "Not connected to %s, internal error, sysop is notified\n", Area); + WriteError("Can't connect node %s to file area %s", ascfnode(t, 0x1f), Area); +} + + + +void F_All(faddr *, int, FILE *, char *); +void F_All(faddr *t, int Connect, FILE *tmp, char *Grp) +{ + FILE *fp, *gp; + char *Group, temp[81]; + faddr *f; + int i, Link, First = TRUE, Cons; + sysconnect Sys; + long Pos; + + if (Grp == NULL) { + if (Connect) + Syslog('+', "FileMgr: Connect All"); + else + Syslog('+', "FileMgr: Disconnect All"); + } else { + if (Connect) + Syslog('+', "FileMgr: Connect group %s", Grp); + else + Syslog('+', "FileMgr: Disconnect group %s", Grp); + } + + f = bestaka_s(t); + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + fp = fopen(temp, "r+"); + fread(&tichdr, sizeof(tichdr), 1, fp); + Cons = tichdr.syssize / sizeof(Sys); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + gp = fopen(temp, "r"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + ((Grp == NULL) || (!strcmp(Group, Grp)))) { + + fseek(fp, tichdr.hdrsize, SEEK_SET); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + + if ((!strcmp(Group, tic.Group)) && tic.Active && + (metric(fido2faddr(fgroup.UseAka), f) == METRIC_EQUAL)) { + + if (Connect) { + Link = FALSE; + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) + Link = TRUE; + } + if (!Link) { + Pos = ftell(fp); + fseek(fp, - tichdr.syssize, SEEK_CUR); + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (!Sys.aka.zone) { + memset(&Sys, 0, sizeof(Sys)); + memcpy(&Sys.aka, faddr2fido(t), sizeof(fidoaddr)); + Sys.sendto = TRUE; + fseek(fp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, fp); + Syslog('+', "FileMgr: Connected %s", tic.Name); + fprintf(tmp, "Connected area %s\n", tic.Name); + f_list = TRUE; + break; + } + } + fseek(fp, Pos, SEEK_SET); + } + } else { + for (i = 0; i < Cons; i++) { + fread(&Sys, sizeof(Sys), 1, fp); + if (metric(fido2faddr(Sys.aka), t) == METRIC_EQUAL) { + memset(&Sys, 0, sizeof(Sys)); + fseek(fp, - sizeof(Sys), SEEK_CUR); + fwrite(&Sys, sizeof(Sys), 1, fp); + Syslog('+', "FileMgr: Disconnected %s", tic.Name); + fprintf(tmp, "Disconnected area %s\n", tic.Name); + f_list = TRUE; + } + } + } + } else + fseek(fp, tichdr.syssize, SEEK_CUR); + } + } + } + } + fclose(gp); + fclose(fp); +} + + + +void F_Group(faddr *, char *, int, FILE *); +void F_Group(faddr *t, char *Area, int Connect, FILE *tmp) +{ + ShiftBuf(Area, 2); + CleanBuf(Area); + F_All(t, Connect, tmp, Area); +} + + + +void F_Pause(faddr *, int, FILE *); +void F_Pause(faddr *t, int Pause, FILE *tmp) +{ + if (Pause) + Syslog('+', "FileMgr: Pause"); + else + Syslog('+', "FileMgr: Resume"); +} + + + +void F_Message(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + ShiftBuf(Buf, 8); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) + nodes.Message = TRUE; + else if (!strncasecmp(Buf, "off", 3)) + nodes.Message = FALSE; + else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "FileMgr: Message %s", GetBool(nodes.Message)); + fprintf(tmp, "FileMgr Message file is %s\n", GetBool(nodes.Message)); +} + + + +void F_Tick(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + ShiftBuf(Buf, 5); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) { + nodes.Tic = TRUE; + nodes.AdvTic = FALSE; + } else if (!strncasecmp(Buf, "off", 3)) { + nodes.Tic = nodes.AdvTic = FALSE; + } else if (!strncasecmp(Buf, "advanced", 8)) { + nodes.Tic = nodes.AdvTic = TRUE; + } else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "FileMgr: Tick %s, Advanced %s", nodes.Tic, nodes.AdvTic); + if (nodes.Tic) + if (nodes.AdvTic) + fprintf(tmp, "Tick mode is advanced"); + else + fprintf(tmp, "Tick mode is normal"); + else + fprintf(tmp, "Tick mode is off"); +} + + + +int FileMgr(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + int i, rc = 0, spaces; + char *Buf; + FILE *tmp, *np; + fidoaddr Node; + + f_help = f_stat = f_unlnk = f_list = f_query = FALSE; + filemgr++; + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "FileMgr msg from %s", ascfnode(f, 0xff)); + + /* + * If the password failed, we return silently and don't respond. + */ + if ((!strlen(subj)) || (strcasecmp(subj, nodes.Fpasswd))) { + WriteError("FileMgr: password expected \"%s\", got \"%s\"", nodes.Fpasswd, subj); + net_bad++; + return FALSE; + } + + if ((tmp = tmpfile()) == NULL) { + WriteError("$FileMsr: Can't open tmpfile()"); + net_bad++; + return FALSE; + } + + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + while ((fgets(Buf, 2048, fp)) != NULL) { + + /* + * Make sure we refresh the nodes record. + */ + memcpy(&Node, faddr2fido(f), sizeof(fidoaddr)); + SearchNode(Node); + + spaces = 0; + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == ' ') + spaces++; + if (*(Buf + i) == '\t') + spaces++; + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + + if (!strncmp(Buf, "---", 3)) + break; + + if (strlen(Buf) && (*(Buf) != '\001') && (spaces <= 1)) { + + if (!strncasecmp(Buf, "%help", 5)) + f_help = TRUE; + else if (!strncasecmp(Buf, "%query", 6)) + f_query = TRUE; + else if (!strncasecmp(Buf, "%linked", 7)) + f_query = TRUE; + else if (!strncasecmp(Buf, "%list", 5)) + f_list = TRUE; + else if (!strncasecmp(Buf, "%status", 7)) + f_stat = TRUE; + else if (!strncasecmp(Buf, "%unlinked", 9)) + f_unlnk = TRUE; + else if (!strncasecmp(Buf, "%+all", 5)) + F_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-all", 5)) + F_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+*", 3)) + F_All(f, TRUE, tmp, NULL); + else if (!strncasecmp(Buf, "%-*", 3)) + F_All(f, FALSE, tmp, NULL); + else if (!strncasecmp(Buf, "%+", 2)) + F_Group(f, Buf, TRUE, tmp); + else if (!strncasecmp(Buf, "%-", 2)) + F_Group(f, Buf, FALSE, tmp); + else if (!strncasecmp(Buf, "%pause", 6)) + F_Pause(f, TRUE, tmp); + else if (!strncasecmp(Buf, "%resume", 7)) + F_Pause(f, FALSE, tmp); + else if (!strncasecmp(Buf, "%password", 9)) + MgrPasswd(f, Buf, tmp, 9); + else if (!strncasecmp(Buf, "%pwd", 4)) + MgrPasswd(f, Buf, tmp, 4); + else if (!strncasecmp(Buf, "%notify", 7)) + MgrNotify(f, Buf, tmp); + else if (!strncasecmp(Buf, "%message", 8)) + F_Message(f, Buf, tmp); + else if (!strncasecmp(Buf, "%tick", 5)) + F_Tick(f, Buf, tmp); + else if (*(Buf) == '%') + F_Global(f, Buf, tmp); + else if (*(Buf) == '-') + F_Disconnect(f, Buf, tmp); + else + F_Connect(f, Buf, tmp); + } + } + + if (ftell(tmp)) { + if ((np = SendMgrMail(f, CFG.ct_KeepMgr, FALSE, (char *)"Filemgr", (char *)"Your FileMgr request", msgid)) != NULL) { + + fprintf(np, " Dear %s\r\r", nodes.Sysop); + fprintf(np, "Here is the result of your FileMgr request:\r\r"); + fseek(tmp, 0, SEEK_SET); + + while ((fgets(Buf, 2048, tmp)) != NULL) { + Buf[strlen(Buf)-1] = '\0'; + fprintf(np, "%s\r", Buf); + Syslog('m', "Rep: %s", Buf); + } + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + CloseMail(np, t); + net_out++; + } else + WriteError("Can't create netmail"); + } + + free(Buf); + fclose(tmp); + + if (f_stat) + F_Status(f); + + if (f_query) + F_Query(f); + + if (f_list) + F_List(f, FALSE); + + if (f_unlnk) + F_Unlinked(f); + + if (f_help) + F_Help(f); + + return rc; +} + + diff --git a/mbfido/filemgr.h b/mbfido/filemgr.h new file mode 100644 index 00000000..306c2079 --- /dev/null +++ b/mbfido/filemgr.h @@ -0,0 +1,11 @@ +#ifndef _FILEMGR_H +#define _FILEMGR_H + + +void F_Status(faddr *); +void F_List(faddr *, int); +int FileMgr(faddr *, faddr *, time_t, int, FILE *); + + +#endif + diff --git a/mbfido/flock.c b/mbfido/flock.c new file mode 100644 index 00000000..cad5fbed --- /dev/null +++ b/mbfido/flock.c @@ -0,0 +1,82 @@ +/***************************************************************************** + * + * File ..................: tosser/flock.c + * Purpose ...............: File locker + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "flock.h" + + +int f_lock(char *fn) +{ + int lfd=-1; + struct flock fl; + struct stat st; + + if (fn) { + if ((lfd = open(fn,O_RDWR | O_CREAT)) < 0) { + perror(""); + WriteError("Error opening file %s", fn); + return -1; + } + + fl.l_type=F_WRLCK; + fl.l_whence=0; + fl.l_start=0L; + fl.l_len=0L; + fl.l_pid=getpid(); + + if (fcntl(lfd,F_SETLK,&fl) != 0) { + if (errno != EAGAIN) + Syslog('+', "Error locking file %s",fn); + close(lfd); + return -1; + } + + if (stat(fn,&st) != 0) { + perror(""); + WriteError("Error accessing file %s",fn); + close(lfd); + return -1; + } + } + return lfd; +} + + + +void funlock(int fd) +{ + close(fd); + return; +} + + + diff --git a/mbfido/flock.h b/mbfido/flock.h new file mode 100644 index 00000000..b13a1749 --- /dev/null +++ b/mbfido/flock.h @@ -0,0 +1,10 @@ +/* flock.h */ + +#ifndef _FLOCK_H +#define _FLOCK_H + +int f_lock(char *); +void funlock(int); + +#endif + diff --git a/mbfido/forward.c b/mbfido/forward.c new file mode 100644 index 00000000..8e8a6376 --- /dev/null +++ b/mbfido/forward.c @@ -0,0 +1,300 @@ +/***************************************************************************** + * + * File ..................: mbfido/forward.c + * Purpose ...............: File forward to a node + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "tic.h" +#include "cookie.h" +#include "sendmail.h" +#include "rollover.h" +#include "forward.h" + + + +void ForwardFile(fidoaddr Node, fa_list *sbl) +{ + char *subject = NULL, *fwdfile = NULL, *ticfile = NULL, fname[128]; + FILE *fp, *net; + char flavor; + faddr *dest, *route, *Fa; + int i, z, n; + time_t now; + fa_list *tmp; + + Syslog('+', "Forward file to %s", aka2str(Node)); + + if (!SearchNode(Node)) { + WriteError("No forward, node %s not known", Node); + return; + } + + /* + * Hier moet een nieuwe SEEN-BY check komen, maar dan wel zo dat + * de net toegevoegde seenby niet getest wordt. + */ + + /* + * Check if this node has enough credits for this file. + */ + T_File.Cost = TIC.FileCost + (TIC.FileCost * nodes.AddPerc / 1000); + if ((nodes.Credit < (nodes.StopLevel + T_File.Cost)) && (!TIC.Charge)) { + Syslog('!', "No forward to %s, not enough credit left", aka2str(Node)); + exit; + } + + /* + * Check if we are passing the warning level + */ + if ((nodes.Credit > nodes.WarnLevel) && + ((nodes.Credit - T_File.Cost) <= nodes.WarnLevel)) { + Syslog('+', "Low credit warning to %s", aka2str(Node)); + /* CREATE NETMAIL */ + } + + fwdfile = calloc(128, sizeof(char)); + /* + * Create the full filename + */ + if (TIC.SendOrg) + sprintf(fwdfile, "%s/%s", TIC.FilePath, TIC.TicIn.OrgName); + else + sprintf(fwdfile, "%s/%s", TIC.BBSpath, TIC.NewName); + + flavor = 'f'; + if (nodes.Crash) + flavor = 'c'; + if (nodes.Hold) + flavor = 'h'; + + if (nodes.RouteVia.zone) + route = fido2faddr(nodes.RouteVia); + else + route = fido2faddr(Node); + dest = fido2faddr(Node); + attach(*route, fwdfile, LEAVE, flavor); + + if (strlen(CFG.dospath)) + subject = xstrcpy(Unix2Dos(fwdfile)); + else + subject = xstrcpy(fwdfile); + + ticfile = calloc(128, sizeof(char)); + if (nodes.Tic) { + sprintf(ticfile, "%s/%08lx.tic", CFG.ticout, sequencer()); + subject = xstrcat(subject, (char *)" "); + if (strlen(CFG.dospath)) + subject = xstrcat(subject, Unix2Dos(ticfile)); + else + subject = xstrcat(subject, ticfile); + } + + /* + * Send netmail message if the node has it turned on. + */ + if (nodes.Message) { + if ((net = SendMgrMail(fido2faddr(Node), CFG.ct_KeepMgr, TRUE, (char *)"Filemgr", subject, NULL)) != NULL) { + fprintf(net, " Dear %s\r", nodes.Sysop); + fprintf(net, "\r"); + fprintf(net, "I sent the following file to your system:\r"); + fprintf(net, "\r"); + fprintf(net, "File : %s\r", TIC.TicIn.OrgName); + fprintf(net, "Description : %s\r", TIC.TicIn.Desc); + fprintf(net, "Area : %s %s\r", TIC.TicIn.Area, TIC.TicIn.AreaDesc); + fprintf(net, "Size : %ld\r", TIC.FileSize); + fprintf(net, "CRC : %s\r", TIC.TicIn.Crc); + fprintf(net, "Origin : %s\r", TIC.TicIn.Origin); + if (strlen(TIC.TicIn.Magic)) + fprintf(net, "Magic : %s\r", TIC.TicIn.Magic); + if (strlen(TIC.TicIn.Replace)) + fprintf(net, "Replaces : %s\r", TIC.TicIn.Replace); + fprintf(net, "\r\r"); + fprintf(net, "With regards, %s\r\r", CFG.sysop_name); + fprintf(net, "... %s\r\r", Cookie()); + fprintf(net, "--- MBSE BBS %s\r", VERSION); + CloseMail(net, fido2faddr(Node)); + } else { + WriteError("$Can't create netmail"); + } + } + free(subject); + + /* + * If we need a .TIC file, start creating it. + */ + if (nodes.Tic) { + mkdirs(ticfile); + if ((fp = fopen(ticfile, "a+")) != NULL) { +// subject = calloc(128, sizeof(char)); + fprintf(fp, "Area %s\r\n", TIC.TicIn.Area); + fprintf(fp, "Origin %s\r\n", TIC.TicIn.Origin); + Fa = fido2faddr(tic.Aka); + fprintf(fp, "From %s\r\n", ascfnode(Fa, 0x0f)); + free(Fa); + if (strlen(TIC.TicIn.Replace)) + fprintf(fp, "Replaces %s\r\n", TIC.TicIn.Replace); + if (strlen(TIC.TicIn.Magic)) + fprintf(fp, "Magic %s\r\n", TIC.TicIn.Magic); + if ((TIC.PassThru) || (TIC.SendOrg)) + subject = xstrcpy(TIC.TicIn.OrgName); + else + subject = xstrcpy(TIC.NewName); + fprintf(fp, "File %s\r\n", tu(subject)); + free(subject); + fprintf(fp, "Desc %s\r\n", TIC.TicIn.Desc); + fprintf(fp, "Crc %s\r\n", TIC.TicIn.Crc); + if (nodes.AdvTic) { + fprintf(fp, "To %s %s\r\n", nodes.Sysop, ascfnode(dest, 0x1f)); + fprintf(fp, "Areadesc %s\r\n", tic.Comment); + fprintf(fp, "Fdn %s\r\n", fgroup.Comment); + /* + * According to Harald Harms this field must + * be multiplied with 100. + */ + if (TIC.FileCost) + fprintf(fp, "Cost %ld.00\r\n", T_File.Cost); + if (TIC.TicIn.TotLDesc) + for (i = 0; i < TIC.TicIn.TotLDesc; i++) + fprintf(fp, "LDesc %s\r\n", TIC.TicIn.LDesc[i]); + } + fprintf(fp, "Created by MBSE BBS %s %s\r\n", VERSION, ShortRight); + if (TIC.TicIn.TotPath) + for (i = 0; i < TIC.TicIn.TotPath; i++) + fprintf(fp, "Path %s\r\n", TIC.TicIn.Path[i]); + /* + * Add our system to the path + */ + now = time(NULL); + subject = ctime(&now); + Striplf(subject); + fprintf(fp, "Path %s %lu %s %s\r\n", ascfnode(bestaka_s(dest), 0x1f), + mktime(localtime(&now)), subject, tzname[0]); + + if (nodes.AdvTic) { + /* + * In advanced TIC mode we send multiple seenby + * addresses on one line in stead of one line + * per system. + */ + z = 0; + n = 0; + subject = xstrcpy((char *)"Seenby"); + for (tmp = sbl; tmp; tmp = tmp->next) { + if (strlen(subject) > 70) { + fprintf(fp, "%s\r\n", subject); + z = 0; + n = 0; + free(subject); + subject = xstrcpy((char *)"Seenby "); + } else { + subject = xstrcat(subject, (char *)" "); + } + + if (z != tmp->addr->zone) { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x0e)); + z = tmp->addr->zone; + } else { + if (n != tmp->addr->net) { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x06)); + n = tmp->addr->net; + } else { + subject = xstrcat(subject, ascfnode(tmp->addr, 0x02)); + } + } + } + if (strlen(subject) > 7) { + fprintf(fp, "%s\r\n", subject); + free(subject); + } + } else { + /* + * Old style seenby lines + */ + for (tmp = sbl; tmp; tmp = tmp->next) { + fprintf(fp, "Seenby %s\r\n", ascfnode(tmp->addr, 0x0f)); + } + } + + /* + * Now append all passthru ticlines + */ + if (TIC.TicIn.Unknowns) + for (i = 0; i < TIC.TicIn.Unknowns; i++) + fprintf(fp, "%s\r\n", TIC.TicIn.Unknown[i]); + + fprintf(fp, "Pw %s\r\n", nodes.Fpasswd); + fclose(fp); + attach(*route, ticfile, KFS, flavor); + } else { + WriteError("$Can't create %s", ticfile); + } + } + + if (TIC.Charge) { + nodes.Credit -= TIC.FileCost; + Syslog('-', "Cost: %d Left: %d", TIC.FileCost, nodes.Credit); + + /* + * Add an entry to the billing file, each node has his own + * billing file. + */ + sprintf(fname, "%s/tmp/%d.%d.%d.%d.bill", getenv("MBSE_ROOT"), + nodes.Aka[0].zone, nodes.Aka[0].net, nodes.Aka[0].node, nodes.Aka[0].point); + if ((fp = fopen(fname, "a+")) != NULL) { + memset(&bill, 0, sizeof(bill)); + bill.Node = nodes.Aka[0]; + strcpy(bill.FileName, TIC.NewName); + strcpy(bill.FileEcho, TIC.TicIn.Area); + bill.Size = TIC.FileSize; + bill.Cost = TIC.FileCost; + fwrite(&bill, sizeof(bill), 1, fp); + fclose(fp); + } else { + WriteError("$Can't create %s", fname); + } + } + + /* + * Update the nodes statistic counters + */ + StatAdd(&nodes.FilesSent, 1L); + StatAdd(&nodes.F_KbSent, T_File.SizeKb); + UpdateNode(); + SearchNode(Node); + free(ticfile); + free(fwdfile); +} + + diff --git a/mbfido/forward.h b/mbfido/forward.h new file mode 100644 index 00000000..c8f5fed9 --- /dev/null +++ b/mbfido/forward.h @@ -0,0 +1,9 @@ +#ifndef _FORWARD_H +#define _FORWARD_H + + +void ForwardFile(fidoaddr, fa_list *); + + +#endif + diff --git a/mbfido/fsort.c b/mbfido/fsort.c new file mode 100644 index 00000000..d130b773 --- /dev/null +++ b/mbfido/fsort.c @@ -0,0 +1,145 @@ +/***************************************************************************** + * + * File ..................: mbfido/fsort.c + * Purpose ...............: File sort + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "fsort.h" + + + +/* + * Tidy the filearray + */ +void tidy_fdlist(fd_list **fdp) +{ + fd_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a file on the array. + */ +void fill_fdlist(fd_list **fdp, char *filename, time_t filedate) +{ + fd_list *tmp; + + tmp = (fd_list *)malloc(sizeof(fd_list)); + tmp->next = *fdp; + sprintf(tmp->fname, "%s", filename); + tmp->fdate = filedate; + *fdp = tmp; +} + + + +int compfdate(fd_list **, fd_list **); + + +/* + * Sort the array of files by filedate + */ +void sort_fdlist(fd_list **fdp) +{ + fd_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) { + return; + } + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (fd_list **)malloc(n * sizeof(fd_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(fd_list*), (int(*)(const void*, const void*))compfdate); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compfdate(fd_list **fdp1, fd_list **fdp2) +{ + return ((*fdp1)->fdate - (*fdp2)->fdate); +} + + + +/* + * Return the name of the oldest file in the array + */ +char *pull_fdlist(fd_list **fdp) +{ + static char buf[65]; + fd_list *ta; + + if (*fdp == NULL) + return NULL; + + ta = *fdp; + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "%s", ta->fname); + + if (ta->next != NULL) + *fdp = ta->next; + else + *fdp = NULL; + + free(ta); + return buf; +} + + diff --git a/mbfido/fsort.h b/mbfido/fsort.h new file mode 100644 index 00000000..ea401f36 --- /dev/null +++ b/mbfido/fsort.h @@ -0,0 +1,20 @@ +#ifndef _FSORT_H +#define _FSORT_H + + + +typedef struct _fd_list { + struct _fd_list *next; + char fname[65]; + time_t fdate; +} fd_list; + + +void tidy_fdlist(fd_list **); +void fill_fdlist(fd_list **, char *, time_t); +void sort_fdlist(fd_list **); +char *pull_fdlist(fd_list **); + + +#endif + diff --git a/mbfido/grlist.c b/mbfido/grlist.c new file mode 100644 index 00000000..56886bf6 --- /dev/null +++ b/mbfido/grlist.c @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * File ..................: mbaff/grlist.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 27-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "grlist.h" + + + + +/* + * Tidy the groupnames array + */ +void tidy_grlist(gr_list ** fdp) +{ + gr_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a group to the array + */ +void fill_grlist(gr_list **fdp, char *groupname, char *echoname) +{ + gr_list *tmp; + + /* + * Count files in group if the group already exists. + */ + if (*fdp != NULL) { + for (tmp = *fdp; tmp; tmp = tmp->next) + if ((strcmp(groupname, tmp->group) == 0) && + (strcmp(echoname, tmp->echo) == 0)) { + tmp->count++; + return; + } + } + + /* + * Add a new group + */ + tmp = (gr_list *)malloc(sizeof(gr_list)); + tmp->next = *fdp; + sprintf(tmp->group, "%s", groupname); + sprintf(tmp->echo, "%s", echoname); + tmp->count = 1; + *fdp = tmp; +} + + + +int compgroup(gr_list **, gr_list **); + +/* + * Sort the array of groups + */ +void sort_grlist(gr_list **fdp) +{ + gr_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (gr_list **)malloc(n * sizeof(gr_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(gr_list*), (int(*)(const void*, const void*))compgroup); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compgroup(gr_list **fdp1, gr_list **fdp2) +{ + int rc; + + rc = strcmp((*fdp1)->group, (*fdp2)->group); + if (rc != 0) + return rc; + return strcmp((*fdp1)->echo, (*fdp2)->echo); +} + + + diff --git a/mbfido/grlist.h b/mbfido/grlist.h new file mode 100644 index 00000000..d575c3ed --- /dev/null +++ b/mbfido/grlist.h @@ -0,0 +1,19 @@ +#ifndef _GRLIST_H_ +#define _GRLIST_H + + +typedef struct _gr_list { /* Announce array */ + struct _gr_list *next; + char group[13]; /* Group name */ + char echo[21]; /* Fileecho name */ + int count; /* Number of new files */ +} gr_list; + + +void tidy_grlist(gr_list **); +void fill_grlist(gr_list **, char *, char *); +void sort_grlist(gr_list **); + + +#endif + diff --git a/mbfido/hash.c b/mbfido/hash.c new file mode 100644 index 00000000..6e32f048 --- /dev/null +++ b/mbfido/hash.c @@ -0,0 +1,52 @@ +/***************************************************************************** + * + * File ..................: mbmail/hash.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "hash.h" +#include "lhash.h" + + +void hash_update_s(unsigned long *id, char *mod) +{ + *id ^= lh_strhash(mod); +} + + + +void hash_update_n(unsigned long *id, unsigned long mod) +{ + char buf[32]; + + sprintf(buf,"%030lu",mod); + *id ^= lh_strhash(buf); +} + + diff --git a/mbfido/hash.h b/mbfido/hash.h new file mode 100644 index 00000000..511bcdd9 --- /dev/null +++ b/mbfido/hash.h @@ -0,0 +1,8 @@ +#ifndef HASH_H +#define HASH_H + +void hash_update_s(unsigned long *, char *); +void hash_update_n(unsigned long *, unsigned long); + + +#endif diff --git a/mbfido/hatch.c b/mbfido/hatch.c new file mode 100644 index 00000000..3e121136 --- /dev/null +++ b/mbfido/hatch.c @@ -0,0 +1,201 @@ +/***************************************************************************** + * + * File ..................: mbfido/hatch.c + * Purpose ...............: Hatch files + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbtic.h" +#include "utic.h" +#include "rollover.h" +#include "hatch.h" + + +extern int do_quiet; + +int Days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; +int Hatched = 0; + +int CheckHatch(char *); + + +void Hatch() +{ + char *temp; + FILE *fp; + struct tm *Tm; + time_t Now; + int LastDay; + int HatchToday; + + temp = calloc(128, sizeof(char)); + Syslog('+', "Pass: hatch files"); + Now = time(NULL); + Tm = localtime(&Now); + + LastDay = Days[Tm->tm_mon]; + if (Tm->tm_mon == 1) { + /* + * Note that with this method each century change is a leapyear, + * but take in mind that fidonet will no longer exist in 2100. + */ + if (!(Tm->tm_year % 4)) + LastDay++; + } + + sprintf(temp, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fp); + + while (fread(&hatch, hatchhdr.recsize, 1, fp) == 1) { + if (hatch.Active) { + HatchToday = FALSE; + if (hatch.Days[Diw]) + HatchToday = TRUE; + if ((hatch.Month[Tm->tm_mday -1]) || + (hatch.Month[31] && (LastDay == Tm->tm_mday))) + HatchToday = TRUE; + sprintf(temp, "%s", hatch.Spec); + + if (HatchToday) + CheckHatch(temp); + } + } + + fclose(fp); + free(temp); +} + + + +int CheckHatch(char *temp) +{ + DIR *dp; + struct dirent *de; + char *fn, tf[81], tmp[4]; + int i, Match, hatched = FALSE; + FILE *Tf; + + fn = xstrcpy(strrchr(temp, '/') + 1); + + while (temp[strlen(temp) -1] != '/') + temp[strlen(temp) -1] = '\0'; + temp[strlen(temp) -1] = '\0'; + + if (chdir(temp)) { + WriteError("$Can't chdir(%s)", temp); + return FALSE; + } + + if ((dp = opendir(temp)) == NULL) { + WriteError("$Can't opendir(%s)", temp); + return FALSE; + } + + while ((de = readdir(dp))) { + Match = FALSE; + if (strlen(fn) == strlen(de->d_name)) { + Match = TRUE; + for (i = 0; i < strlen(fn); i++) { + switch(fn[i]) { + case '?' : break; + case '#' : if (!isdigit(de->d_name[i])) + Match = FALSE; + break; + case '@' : if (!isalpha(de->d_name[i])) + Match = FALSE; + break; + default : if (fn[i] != de->d_name[i]) + Match = FALSE; + } + } + } + if (Match) { + hatched = TRUE; + Syslog('+', "Hatch %s in area %s", de->d_name, hatch.Name); + sprintf(tf, "%s/%s", CFG.pinbound, MakeTicName()); + if ((Tf = fopen(tf, "a+")) == NULL) + WriteError("Can't create %s", tf); + else { + fprintf(Tf, "Hatch\r\n"); + fprintf(Tf, "Created MBSE BBS v%s, %s\r\n", VERSION, ShortRight); + fprintf(Tf, "Area %s\r\n", hatch.Name); + if (SearchTic(hatch.Name)) { + fprintf(Tf, "Origin %s\r\n", aka2str(tic.Aka)); + fprintf(Tf, "From %s\r\n", aka2str(tic.Aka)); + } else { + fprintf(Tf, "Origin %s\r\n", aka2str(CFG.aka[0])); + fprintf(Tf, "From %s\r\n", aka2str(CFG.aka[0])); + Syslog('?', "Warning: TIC group not found"); + } + if (strlen(hatch.Replace)) + fprintf(Tf, "Replaces %s\r\n", hatch.Replace); + if (strlen(hatch.Magic)) + fprintf(Tf, "Magic %s\r\n", hatch.Magic); + fprintf(Tf, "File %s\r\n", de->d_name); + fprintf(Tf, "Pth %s\r\n", temp); + fprintf(Tf, "Desc "); + for (i = 0; i < strlen(hatch.Desc); i++) { + if (hatch.Desc[i] != '%') { + fprintf(Tf, "%c", hatch.Desc[i]); + } else { + i++; + memset(&tmp, 0, sizeof(tmp)); + if (isdigit(hatch.Desc[i])) + tmp[0] = hatch.Desc[i]; + if (isdigit(hatch.Desc[i+1])) { + tmp[1] = hatch.Desc[i+1]; + i++; + } + fprintf(Tf, "%c", de->d_name[atoi(tmp) -1]); + } + } + fprintf(Tf, "\r\n"); + fprintf(Tf, "Crc %08lx\r\n", file_crc(de->d_name, CFG.slow_util && do_quiet)); + fprintf(Tf, "Pw %s\r\n", CFG.hatchpasswd); + fclose(Tf); + Hatched++; + StatAdd(&hatch.Hatched , 1); + } + } + } + closedir(dp); + free(fn); + return hatched; +} + + diff --git a/mbfido/hatch.h b/mbfido/hatch.h new file mode 100644 index 00000000..f7ec4748 --- /dev/null +++ b/mbfido/hatch.h @@ -0,0 +1,9 @@ +#ifndef _HATCH_H +#define _HATCH_H + + +void Hatch(void); + + +#endif + diff --git a/mbfido/importmsg.c b/mbfido/importmsg.c new file mode 100644 index 00000000..46bb3159 --- /dev/null +++ b/mbfido/importmsg.c @@ -0,0 +1,908 @@ +/***************************************************************************** + * + * File ..................: tosser/importmsg.c + * Purpose ...............: Import a message + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "echoout.h" +#include "mkrfcmsg.h" +#include "importmsg.h" +#include "postnetmail.h" +#include "rollover.h" + + + +/* + * External declarations + */ +extern int do_quiet; +extern int do_unsec; +extern int check_dupe; +extern int autocrea; +extern time_t t_start; +extern int most_debug; + + +/* + * Global variables + */ +extern int echo_in; /* Echomail received */ +extern int echo_imp; /* Echomail imported */ +extern int echo_out; /* Echomail forwarded */ +extern int echo_bad; /* Bad echomail */ +extern int echo_dupe; /* Dupe echomail */ +extern char *subj; /* Message subject */ +char *msgid = NULL; /* Message id string */ + +#define MAXPATH 73 +#define MAXSEEN 70 + + +void tidy_qualify(qualify **); +void fill_qualify(qualify **, fidoaddr, int, int); +void dlog_qualify(qualify **, char *); + + +void tidy_qualify(qualify **qal) +{ + qualify *tmp, *old; + + for (tmp = *qal; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *qal = NULL; +} + + + +void fill_qualify(qualify **qal, fidoaddr aka, int orig, int insb) +{ + qualify *tmp; + + tmp = (qualify *)malloc(sizeof(qualify)); + tmp->next = *qal; + tmp->aka = aka; + tmp->inseenby = insb; + tmp->send = ((!insb) && (!orig)); + tmp->orig = orig; + *qal = tmp; +} + + + +void dlog_qualify(qualify **qal, char *msg) +{ + qualify *tmpl; + + for (tmpl = *qal; tmpl; tmpl = tmpl->next) { + Syslog('m', "%s InSB=%s Snd=%s Org=%s", + aka2str(tmpl->aka), tmpl->inseenby ? "True":"False", + tmpl->send ? "True":"False", + tmpl->orig ? "True":"False"); + } +} + + + +/* + * Import 1 message, forward if needed. + * pkt_from, from, to, subj, orig, mdate, flags, cost, file + * + * 1 - Cannot open message base. + * 2 - Cannot open mareas.data + * 3 - Echomail without Origin line. + * 4 - Echomail from unknown node, disconnected node. + * 5 - Locking error. + * + * For echomail, the crc32 is calculated over the ^AREA kludge, subject, + * message date, origin line, message id. + */ +int importmsg(faddr *p_from, faddr *f, faddr *t, char *orig, time_t mdate, int flags, int cost, FILE *fp, off_t orig_off) +{ + char *buf, *marea = NULL, *reply = NULL; + char *p, *q, *l, *r; + int echomail = FALSE, First = FALSE, email = FALSE; + int rc = 0, i, topt = 0, fmpt = 0, kludges = TRUE; + faddr *ta, *Faddr; + int result, dupe = FALSE, bad = FALSE; + unsigned long crc, crc2; + char sbe[16]; + sysconnect Link; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + qualify *qal = NULL, *tmpq; + FILE *nfp, *qp; + int Known = FALSE, seenlen, oldnet; + int FirstLine; + + if (CFG.slow_util && do_quiet) + usleep(1); + + memset(&Link, 0, sizeof(Link)); + msgid = NULL; + + /* + * Increase uplink's statistic counter. + */ + Link.aka.zone = p_from->zone; + Link.aka.net = p_from->net; + Link.aka.node = p_from->node; + Link.aka.point = p_from->point; + if (SearchNode(Link.aka)) { + StatAdd(&nodes.MailRcvd, 1); + UpdateNode(); + SearchNode(Link.aka); + Known = TRUE; + } + + crc = 0xffffffff; + buf = calloc(2048, sizeof(char)); + marea = NULL; + + /* + * First read the message for kludges we need. + */ + rewind(fp); + + FirstLine = TRUE; + while ((fgets(buf, 2048, fp)) != NULL) { + + Striplf(buf); + + /* + * Check all sort of relevant kludges. + */ + if (FirstLine && (!strncmp(buf, "AREA:", 5))) { + + echo_in++; + marea = xstrcpy(tu(buf + 5)); + + if (orig == NULL) { + Syslog('!', "Echomail without Origin line"); + echo_bad++; + bad = TRUE; + free(buf); + free(marea); + return 3; + } + + if (!SearchMsgs(marea)) { + WriteError("Unknown echo area %s", marea); + if (autocrea) { + autocreate(marea, p_from); + if (!SearchMsgs(marea)) { + WriteError("Autocreate of area %s failed.", area); + echo_bad++; + bad = TRUE; + free(marea); + free(buf); + return 4; + } + } else { + echo_bad++; + bad = TRUE; + free(buf); + free(marea); + return 4; + } + } + crc = upd_crc32(buf, crc, strlen(buf)); + echomail = TRUE; + free(marea); + + /* + * Check if node is allowed to enter echomail in this area. + */ + if (!bad) { + bad = TRUE; + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((p_from->zone == Link.aka.zone) && + (p_from->net == Link.aka.net) && + (p_from->node == Link.aka.node)) { + bad = FALSE; + break; + } + } + if (bad && (msgs.UnSecure || do_unsec)) { + bad = FALSE; + memset(&Link, 0, sizeof(Link)); + } + if (bad) { + Syslog('+', "Node %s not connected to area %s", ascfnode(p_from, 0x1f), msgs.Tag); + free(buf); + echo_bad++; + return 4; + } + + if (Link.cutoff && !bad) { + Syslog('+', "Echomail from %s in %s refused, cutoff", ascfnode(p_from, 0x1f), msgs.Tag); + free(buf); + bad = TRUE; + echo_bad++; + return 4; + } + if (!Link.receivefrom && !bad) { + Syslog('+', "Echomail from %s in %s refused, read only", ascfnode(p_from, 0x1f), msgs.Tag); + bad = TRUE; + free(buf); + echo_bad++; + return 4; + } + + if (CFG.toss_old) { + if (((t_start - mdate) / 86400) > CFG.toss_old) { + Syslog('+', "Rejecting msg: too old, %s", rfcdate(mdate)); + bad = TRUE; + free(buf); + echo_bad++; + return 4; + } + } + } + + StatAdd(&msgs.Received, 1); + time(&msgs.LastRcvd); + StatAdd(&mgroup.MsgsRcvd, 1); + time(&mgroup.LastDate); + UpdateMsgs(); + } + + if (*buf != '\001') + FirstLine = FALSE; + + if (!echomail) { + + /* + * Check for X-FTN- kludges, this could be gated email. + * This should be impossible. + */ + if (!strncmp(buf, "\001X-FTN-", 7)) { + email = TRUE; + Syslog('?', "Warning: detected ^aX-FTN- kludge in netmail"); + } + + /* + * Check DOMAIN and INTL kludges + */ + if (!strncmp(buf, "\001DOMAIN", 7)) { + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + p = strtok(NULL," \n"); + r = strtok(NULL," \n"); + q = strtok(NULL," \n"); + if ((ta = parsefnode(p))) { + t->point = ta->point; + t->node = ta->node; + t->net = ta->net; + t->zone = ta->zone; + tidy_faddr(ta); + } + t->domain = xstrcpy(l); + if ((ta = parsefnode(q))) { + f->point = ta->point; + f->node = ta->node; + f->net = ta->net; + f->zone = ta->zone; + tidy_faddr(ta); + } + f->domain = xstrcpy(r); + } else { + if (!strncmp(buf, "\001INTL", 5)) { + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + r = strtok(NULL," \n"); + if ((ta = parsefnode(l))) { + t->point = ta->point; + t->node = ta->node; + t->net = ta->net; + t->zone = ta->zone; + if (ta->domain) { + if (t->domain) + free(t->domain); + t->domain = ta->domain; + ta->domain = NULL; + } + tidy_faddr(ta); + } + if ((ta = parsefnode(r))) { + f->point = ta->point; + f->node = ta->node; + f->net = ta->net; + f->zone = ta->zone; + if (ta->domain) { + if (f->domain) + free(f->domain); + f->domain = ta->domain; + ta->domain = NULL; + } + tidy_faddr(ta); + } + } + } + /* + * Now check FMPT and TOPT kludges + */ + if (!strncmp(buf, "\001FMPT", 5)) { + p = strtok(buf, " \n"); + p = strtok(NULL, " \n"); + fmpt = atoi(p); + } + if (!strncmp(buf, "\001TOPT", 5)) { + p = strtok(buf, " \n"); + p = strtok(NULL, " \n"); + topt = atoi(p); + } + + if (!strncmp(buf, "\001MSGID: ", 8)) { + msgid = xstrcpy(buf + 8); + /* + * Extra test to see if the mail comes from a pointaddress. + */ + l = strtok(buf," \n"); + l = strtok(NULL," \n"); + if ((ta = parsefnode(l))) { + if (ta->zone == f->zone && ta->net == f->net && ta->node == f->node && !fmpt && ta->point) { + Syslog('m', "Setting pointinfo (%d) from MSGID", ta->point); + fmpt = f->point = ta->point; + } + tidy_faddr(ta); + } + } + } /* if netmail */ + + if (!strncmp(buf, "\001REPLYTO: ", 10)) + reply = xstrcpy(buf + 10); + if (!strncmp(buf, "SEEN-BY:", 8)) { + if (Link.aka.zone == msgs.Aka.zone) { + p = xstrcpy(buf + 9); + fill_list(&sbl, p, NULL, FALSE); + free(p); + } else + Syslog('m', "Strip zone SB lines"); + } + if (!strncmp(buf, "\001PATH:", 6)) { + p = xstrcpy(buf + 7); + fill_path(&ptl, p); + free(p); + } + + } /* end of checking kludges */ + + /* + * Handle netmail + */ + if (!echomail) { + /* + * Only set point info if there was any info. + * GoldED doesn't set FMPT and TOPT kludges. + */ + if (fmpt) + f->point = fmpt; + if (topt) + t->point = topt; + rc = postnetmail(fp, f, t, orig, subj, mdate, flags, TRUE); + free(buf); + return rc; + } /* if !echomail */ + + /* + * Handle echomail + */ + if (echomail && (!bad)) { + /* + * First, further dupe checking. + */ + crc = upd_crc32(subj, crc, strlen(subj)); + + if (orig == NULL) + Syslog('!', "No origin line found"); + else + crc = upd_crc32(orig, crc, strlen(orig)); + + crc = upd_crc32((char *)&mdate, crc, sizeof(mdate)); + + if (msgid != NULL) { + crc = upd_crc32(msgid, crc, strlen(msgid)); + } else { + if (check_dupe) { + /* + * If a MSGID is missing it is possible that dupes from some offline + * readers slip through because these readers use the same date for + * each message. In this case the message text is included in the + * dupecheck. Redy Rodriguez. + */ + rewind(fp); + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + if (strncmp(buf, "---", 3) == 0) + break; + if ((strncmp(buf, "\001", 1) != 0 ) && (strncmp(buf,"AREA:",5) != 0 )) + crc = upd_crc32(buf, crc , strlen(buf)); + } + } + } + + if (check_dupe) + dupe = CheckDupe(crc, D_ECHOMAIL, CFG.toss_dupes); + else + dupe = FALSE; + if (dupe) + echo_dupe++; + } + + if ((echomail) && (!bad) && (!dupe) && (!msgs.UnSecure) && (!do_unsec)) { + + /* + * Check if the message is for us. Don't check point address, + * echomail messages don't have point destination set. + */ + if ((msgs.Aka.zone != t->zone) || (msgs.Aka.net != t->net) || (msgs.Aka.node != t->node)) { + bad = TRUE; + /* + * If we are a hub or host and have all our echomail + * connected to the hub/host aka, echomail from points + * under a nodenumber aka isn't accepted. The match + * must be further tested. + */ + if ((msgs.Aka.zone == t->zone) && (msgs.Aka.net == t->net)) { + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && + (CFG.aka[i].zone == t->zone) && + (CFG.aka[i].net == t->net) && + (CFG.aka[i].node == t->node)) + bad = FALSE; /* Undo the result */ + } + } + } + if (bad) { + echo_bad++; + WriteError("Msg in %s not for us (%s) but for %s", msgs.Tag, aka2str(msgs.Aka), ascfnode(t,0x1f)); + } + } + + if ((echomail) && (!bad) && (!dupe)) { + + if (msgs.Aka.zone != Link.aka.zone) { + /* + * If it is a zonegated echomailmessage the SEEN-BY lines + * are stripped off including that of the other zone's + * gate. Add the gate's aka to the SEEN-BY + */ + Syslog('m', "Gated echomail, clean SB"); + tidy_falist(&sbl); + sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node); + Syslog('m', "Add gate SB %s", sbe); + fill_list(&sbl, sbe, NULL, FALSE); + } + + /* + * Add more aka's to SEENBY if in the same zone as our system. + * When ready filter dupe's, there is at least one. + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + uniq_list(&sbl); + } + + /* + * Add our system to the path for later export. + */ + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl, sbe); + + if (echomail) { + /* + * Build a list of qualified systems to receive this message. + * Complete the SEEN-BY lines. + */ + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + Faddr = fido2faddr(Link.aka); + fill_qualify(&qal, Link.aka, ((p_from->zone == Link.aka.zone) && + (p_from->net == Link.aka.net) && (p_from->node == Link.aka.node) && + (p_from->point == Link.aka.point)), in_list(Faddr, &sbl, FALSE)); + tidy_faddr(Faddr); + } + } + + /* + * Add SEEN-BY for nodes qualified to receive this message. + * When ready, filter the dupes and sort the SEEN-BY entries. + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + sprintf(sbe, "%u/%u", tmpq->aka.net, tmpq->aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + /* + * Create a new tmpfile with a copy of the message + * without original PATH and SEENBY lines, add the + * new PATH and SEENBY lines. + */ + rewind(fp); + if ((nfp = tmpfile()) == NULL) { + WriteError("$Unable to open tmpfile"); + } + while ((fgets(buf, 2048, fp)) != NULL) { + Striplf(buf); + fprintf(nfp, "%s", buf); + /* + * Don't write SEEN-BY and PATH lines + */ + if (strncmp(buf, " * Origin:", 10) == 0) + break; + fprintf(nfp, "\n"); + } + + /* + * Now add new SEEN-BY and PATH lines + */ + seenlen = MAXSEEN + 1; + /* + * Ensure that it will not match for + * the first entry. + */ + oldnet = sbl->addr->net - 1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(nfp, "\nSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + + seenlen = MAXPATH + 1; + /* + * Ensure it will not match for the first entry + */ + oldnet = ptl->addr->net - 1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(nfp, "\n\001PATH:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(nfp, "%s", sbe); + } + fprintf(nfp, "\n"); + fflush(nfp); + rewind(nfp); + + /* + * Import this message. + */ + if (bad) { + if (strlen(CFG.badboard) == 0) { + Syslog('+', "Killing bad message"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 0; + } else { + if ((result = Msg_Open(CFG.badboard))) + Syslog('+', "Tossing in bad board"); + } + } else if (dupe) { + if (strlen(CFG.dupboard) == 0) { + Syslog('+', "Killing dupe message"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 0; + } else { + if ((result = Msg_Open(CFG.dupboard))) + Syslog('+', "Tossing in dupe board"); + } + } else { + result = Msg_Open(msgs.Base); + } + if (!result) { + WriteError("Can't open JAMmb %s", msgs.Base); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 1; + } + + if (Msg_Lock(30L)) { + if ((!dupe) && (!bad)) + echo_imp++; + + if (!do_quiet) { + colour(3, 0); + printf("\r%6u => %-40s\r", echo_in, msgs.Name); + fflush(stdout); + } + + Msg_New(); + + /* + * Fill subfields + */ + strcpy(Msg.From, f->name); + strcpy(Msg.To, t->name); + strcpy(Msg.FromAddress, ascfnode(f,0x1f)); + strcpy(Msg.Subject, subj); + Msg.Written = mdate; + Msg.Arrived = time(NULL); + Msg.Echomail = TRUE; + + /* + * These are the only usefull flags in echomail + */ + if ((flags & M_PVT) && ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE))) + Msg.Private = TRUE; + if (flags & M_FILE) + Msg.FileAttach = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (msgid != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(msgid, crc2, strlen(msgid)); + } + if (reply != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(reply, crc2, strlen(reply)); + } + + /* + * Start write the message + * If not a bad or dupe message, eat the first + * line (AREA:tag). + */ + rewind(nfp); + if (!dupe && !bad) + fgets(buf , 256, nfp); + Msg_Write(nfp); + Msg_AddMsg(); + Msg_UnLock(); + Msg_Close(); + } else { + Syslog('+', "Can't lock msgbase %s", msgs.Base); + Msg_UnLock(); + Msg_Close(); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + free(buf); + return 5; + } + + /* + * Forward to other links + */ + if ((!dupe) && (!bad)) { + /* + * Now start exporting this echomail. + */ + for (tmpq = qal; tmpq; tmpq = tmpq->next) { + if (tmpq->send) { + if (SearchNode(tmpq->aka)) { + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(tmpq->aka); + } + echo_out++; + EchoOut(p_from, tmpq->aka, nfp, flags, cost, mdate); + } + } + + /* + * Gate to newsserver + */ + if (strlen(msgs.Newsgroup)) { + rewind(nfp); + qp = tmpfile(); + while ((fgets(buf, 2048, nfp)) != NULL) { + Striplf(buf); + if (kludges && (buf[0] != '\001') && strncmp(buf, "AREA:", 5)) { + kludges = FALSE; + q = xstrcpy(Msg.From); + for (i = 0; i < strlen(q); i++) + if (q[i] == ' ') + q[i] = '_'; + fprintf(qp, "From: %s@%s\n", q, ascinode(f, 0x1f)); + fprintf(qp, "Subject: %s\n", Msg.Subject); + fprintf(qp, "To: %s\n", Msg.To); + fprintf(qp, "\n"); + } + fprintf(qp, "%s\n", buf); + } + rewind(qp); + most_debug = TRUE; + mkrfcmsg(f, t, subj, orig, mdate, flags, qp, orig_off, FALSE); + most_debug = FALSE; + fclose(qp); + } + } + fclose(nfp); + } + + /* + * Free memory used by SEEN-BY, ^APATH and Qualified lines. + */ + tidy_falist(&sbl); + tidy_falist(&ptl); + tidy_qualify(&qal); + + if (rc < 0) + rc =-rc; + free(buf); + if (reply) + free(reply); + return rc; +} + + + +void autocreate(char *marea, faddr *p_from) +{ + FILE *pMsgs; + char temp[250]; + int i; + struct _sysconnect syscon; + + if (!SearchMsgs((char *)"DEFAULT")){ + WriteError("Can't find DEFAULT area, can't autocreate:"); + autocrea = FALSE; + return; + } + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pMsgs = fopen(temp, "r+")) == NULL) { + WriteError("$Database error: Can't create %s", temp); + return; + } + strncat(msgs.Name,marea,40-strlen(msgs.Name)); + strncpy(msgs.Tag,marea,50); + strncpy(msgs.QWKname,marea,20); + strncat(msgs.Base,marea,64-strlen(msgs.Base)); + fseek(pMsgs, 0, SEEK_END); + Syslog('+', "Autocreate area %s", marea); + + memset(&syscon, 0, sizeof(syscon)); + syscon.aka.zone = p_from->zone; + syscon.aka.node = p_from->node; + syscon.aka.net = p_from->net; + if (SearchFidonet(p_from->zone)) + strcpy(syscon.aka.domain,fidonet.domain); + else { + WriteError("New area %s from node of unknown zone %d not created.", marea,p_from->zone); + fclose(pMsgs); + return; + } + syscon.sendto = TRUE; + syscon.receivefrom = TRUE; + if (msgs.Aka.zone == 0) { + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i]) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (strcmp(CFG.aka[i].domain,msgs.Aka.domain)==0)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && (CFG.aka[i].net == p_from->net)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + for (i = 0; i < 40; i++) { + if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && + (CFG.aka[i].net == p_from->net) && (CFG.aka[i].node == p_from->node)) { + msgs.Aka.zone=CFG.aka[i].zone; + msgs.Aka.net=CFG.aka[i].net; + msgs.Aka.node=CFG.aka[i].node; + msgs.Aka.point=CFG.aka[i].point; + strcpy(msgs.Aka.domain,CFG.aka[i].domain); + i=40; + } + } + } + fwrite(&msgs, msgshdr.recsize, 1, pMsgs); + fwrite(&syscon, sizeof(syscon), 1, pMsgs); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1 ; i < CFG.toss_systems; i++ ) + fwrite(&syscon, sizeof(syscon), 1, pMsgs); + fclose(pMsgs); + return; +} + + diff --git a/mbfido/importmsg.h b/mbfido/importmsg.h new file mode 100644 index 00000000..71fb6399 --- /dev/null +++ b/mbfido/importmsg.h @@ -0,0 +1,22 @@ +#ifndef _IMPORTMSG_H +#define _IMPORTMSG_H + + +/* + * Structure for qualified systems to receive a echomail message + */ +typedef struct _qualify { + struct _qualify *next; /* Linked list */ + fidoaddr aka; /* AKA of the linked system */ + unsigned inseenby : 1; /* System is in SEEN-BY */ + unsigned send : 1; /* Send message to link */ + unsigned orig : 1; /* Is originator of message */ +} qualify; + + +int importmsg(faddr *, faddr *, faddr *, char *, time_t, int, int, FILE *, off_t); +void autocreate(char *, faddr *); + + +#endif + diff --git a/mbfido/importnet.c b/mbfido/importnet.c new file mode 100644 index 00000000..21bf780e --- /dev/null +++ b/mbfido/importnet.c @@ -0,0 +1,173 @@ +/***************************************************************************** + * + * File ..................: tosser/importnet.c + * Purpose ...............: Import a netmail message + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "rollover.h" +#include "importnet.h" + + + +/* + * Global variables + */ +extern int net_imp; /* Netmails imported */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern char *subj; /* Message subject */ + + + +/* + * Import netmail into the BBS. + * + * 0 - All seems well. + * 1 - Something went wrong. + * + */ +int importnet(faddr *f, faddr *t, time_t mdate, int flags, FILE *fp) +{ + char *msgid = NULL, *reply = NULL; + int result, i, empty = TRUE; + unsigned long crc2; + char *Buf; + + if (SearchNetBoard(t->zone, t->net)) { + StatAdd(&msgs.Received, 1L); + time(&msgs.LastRcvd); + UpdateMsgs(); + + result = Msg_Open(msgs.Base); + if (!result) { + WriteError("Can't open msgbase %s", msgs.Base); + net_bad++; + return 1; + } + + if (Msg_Lock(30L)) { + Msg_New(); + + Syslog('m', "Flagfield 0x%04x", flags); + strcpy(Msg.From, f->name); + strcpy(Msg.To, usr.sUserName); + strcpy(Msg.FromAddress, ascfnode(f,0x1f)); + strcpy(Msg.ToAddress, ascfnode(t,0x1f)); + strcpy(Msg.Subject, subj); + Msg.Written = mdate; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Netmail = TRUE; + + /* + * These are the only usefull flags in netmail + */ + if ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE)) { + if (flags & M_PVT) + Msg.Private = TRUE; + else + Msg.Private = FALSE; + } else + Msg.Private = TRUE; /* Allways */ + if (flags & M_CRASH) + Msg.Crash = TRUE; + if (flags & M_FILE) + Msg.FileAttach = TRUE; + if (flags & M_REQ) + Msg.FileRequest = TRUE; + if (flags & M_RRQ) + Msg.ReceiptRequest = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (msgid != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(msgid, crc2, strlen(msgid)); + } + if (reply != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(reply, crc2, strlen(reply)); + } + + /* + * Check if this is an empty netmail + */ + rewind(fp); + Buf = calloc(2049, sizeof(char)); + while ((fgets(Buf, 2048, fp)) != NULL) { + + for (i = 0; i < strlen(Buf); i++) { + if (*(Buf + i) == '\0') + break; + if (*(Buf + i) == '\n') + *(Buf + i) = '\0'; + if (*(Buf + i) == '\r') + *(Buf + i) = '\0'; + } + if (*(Buf) != '\0') { + if ((*(Buf) != '\001') && + (strcmp(Buf, (char *)"--- "))) + empty = FALSE; + } + } + free(Buf); + + if (!empty) { + Syslog('+', "Import netmail to %s", usr.sUserName); + rewind(fp); + Msg_Write(fp); + Msg_AddMsg(); + net_imp++; + } else { + Syslog('+', "Empty netmail for %s dropped", usr.sUserName); + } + Msg_UnLock(); + Msg_Close(); + + return 0; + } else { + WriteError("Can't lock msgbase %s", msgs.Base); + Msg_Close(); + return 1; + } + } else { + WriteError("Can't find a netmail board"); + net_bad++; + return 1; + } /* if SearchNetBoard() */ +} + + diff --git a/mbfido/importnet.h b/mbfido/importnet.h new file mode 100644 index 00000000..a01f9d66 --- /dev/null +++ b/mbfido/importnet.h @@ -0,0 +1,8 @@ +#ifndef _IMPORTNET_H +#define _IMPORTNET_H + + +int importnet(faddr *, faddr *, time_t, int, FILE *); + +#endif + diff --git a/mbfido/lhash.c b/mbfido/lhash.c new file mode 100644 index 00000000..0b020f9a --- /dev/null +++ b/mbfido/lhash.c @@ -0,0 +1,515 @@ +/***************************************************************************** + * + * File ..................: mbmail/lhash.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/clcomm.h" +#include "lhash.h" + +/* crypto/lhash/lhash.c */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +char *lh_version=(char *)"lhash part of SSLeay 0.6.4 30-Aug-1996"; + +/* Code for dynamic hash table routines + * Author - Eric Young v 2.0 + * + * 2.0 eay - Fixed a bug that occured when using lh_delete + * from inside lh_doall(). As entries were deleted, + * the 'table' was 'contract()ed', making some entries + * jump from the end of the table to the start, there by + * skiping the lh_doall() processing. eay - 4/12/95 + * + * 1.9 eay - Fixed a memory leak in lh_free, the LHASH_NODEs + * were not being free()ed. 21/11/95 + * + * 1.8 eay - Put the stats routines into a seperate file, lh_stats.c + * 19/09/95 + * + * 1.7 eay - Removed the fputs() for realloc failures - the code + * should silently tolerate them. I have also fixed things + * lint complained about 04/05/95 + * + * 1.6 eay - Fixed an invalid pointers in contract/expand 27/07/92 + * + * 1.5 eay - Fixed a misuse of realloc in expand 02/03/1992 + * + * 1.4 eay - Fixed lh_doall so the function can call lh_delete 28/05/91 + * + * 1.3 eay - Fixed a few lint problems 19/3/1991 + * + * 1.2 eay - Fixed lh_doall problem 13/3/1991 + * + * 1.1 eay - Added lh_doall + * + * 1.0 eay - First version + */ + + +#undef MIN_NODES +#define MIN_NODES 16 +#define UP_LOAD (2*LH_LOAD_MULT) /* load times 256 (default 2) */ +#define DOWN_LOAD (LH_LOAD_MULT) /* load times 256 (default 1) */ + +#ifndef NOPROTO + +#define P_CP char * +#define P_CPP char *,char * +static void expand(LHASH *lh); +static void contract(LHASH *lh); +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash); + +#else + +#define P_CP +#define P_CPP +static void expand(); +static void contract(); +static LHASH_NODE **getrn(); + +#endif + +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)) +{ + LHASH *ret; + int i; + + if ((ret=(LHASH *)malloc(sizeof(LHASH))) == NULL) + goto err0; + if ((ret->b=(LHASH_NODE **)malloc(sizeof(LHASH_NODE *)*MIN_NODES)) == NULL) + goto err1; + for (i=0; ib[i]=NULL; + ret->comp=((c == NULL)?(int (*)(char *, char *))strcmp:c); + ret->hash=((h == NULL)?(unsigned long (*)(char *))lh_strhash:h); + ret->num_nodes=MIN_NODES/2; + ret->num_alloc_nodes=MIN_NODES; + ret->p=0; + ret->pmax=MIN_NODES/2; + ret->up_load=UP_LOAD; + ret->down_load=DOWN_LOAD; + ret->num_items=0; + + ret->num_expands=0; + ret->num_expand_reallocs=0; + ret->num_contracts=0; + ret->num_contract_reallocs=0; + ret->num_hash_calls=0; + ret->num_comp_calls=0; + ret->num_insert=0; + ret->num_replace=0; + ret->num_delete=0; + ret->num_no_delete=0; + ret->num_retreve=0; + ret->num_retreve_miss=0; + ret->num_hash_comps=0; + + return(ret); +err1: + free((char *)ret); +err0: + return(NULL); +} + + + +void lh_free(LHASH *lh) +{ + unsigned int i; + LHASH_NODE *n,*nn; + + for (i=0; inum_nodes; i++) + { + n=lh->b[i]; + while (n != NULL) + { + nn=n->next; + free(n); + n=nn; + } + } + free((char *)lh->b); + free((char *)lh); +} + + + +char *lh_insert(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + if (lh->up_load <= (lh->num_items*LH_LOAD_MULT/lh->num_nodes)) + expand(lh); + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + if ((nn=(LHASH_NODE *)malloc(sizeof(LHASH_NODE))) == NULL) + return(NULL); + nn->data=data; + nn->next=NULL; +#ifndef NO_HASH_COMP + nn->hash=hash; +#endif + *rn=nn; + ret=NULL; + lh->num_insert++; + lh->num_items++; + } + else /* replace same key */ + { + ret= (*rn)->data; + (*rn)->data=data; + lh->num_replace++; + } + return(ret); +} + + + +char *lh_delete(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE *nn,**rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_no_delete++; + return(NULL); + } + else + { + nn= *rn; + *rn=nn->next; + ret=nn->data; + free((char *)nn); + lh->num_delete++; + } + + lh->num_items--; + if ((lh->num_nodes > MIN_NODES) && + (lh->down_load >= (lh->num_items*LH_LOAD_MULT/lh->num_nodes))) + contract(lh); + + return(ret); +} + + + +char *lh_retrieve(LHASH *lh, char *data) +{ + unsigned long hash; + LHASH_NODE **rn; + char *ret; + + rn=getrn(lh,data,&hash); + + if (*rn == NULL) + { + lh->num_retreve_miss++; + return(NULL); + } + else + { + ret= (*rn)->data; + lh->num_retreve++; + } + return(ret); +} + + + +void lh_doall(LHASH *lh, void (*func)(char *, char *)) +//LHASH *lh; +//void (*func)(); +{ + lh_doall_arg(lh,func,NULL); +} + + + +void lh_doall_arg(LHASH *lh, void(*func)(char *, char *), char *arg) +// LHASH *lh; +//void (*func)(); +//char *arg; +{ + int i; + LHASH_NODE *a,*n; + + /* reverse the order so we search from 'top to bottom' + * We were having memory leaks otherwise */ + for (i=lh->num_nodes-1; i>=0; i--) + { + a=lh->b[i]; + while (a != NULL) + { + /* 28/05/91 - eay - n added so items can be deleted + * via lh_doall */ + n=a->next; + func(a->data,arg); + a=n; + } + } +} + + + +static void expand(LHASH *lh) +{ + LHASH_NODE **n,**n1,**n2,*np; + unsigned int p,i,j; + unsigned long hash,nni; + + lh->num_nodes++; + lh->num_expands++; + p=(int)lh->p++; + n1= &(lh->b[p]); + n2= &(lh->b[p+(int)lh->pmax]); + *n2=NULL; /* 27/07/92 - eay - undefined pointer bug */ + nni=lh->num_alloc_nodes; + + for (np= *n1; np != NULL; ) + { +#ifndef NO_HASH_COMP + hash=np->hash; +#else + hash=(*(lh->hash))(np->data); + lh->num_hash_calls++; +#endif + if ((hash%nni) != p) + { /* move it */ + *n1= (*n1)->next; + np->next= *n2; + *n2=np; + } + else + n1= &((*n1)->next); + np= *n1; + } + + if ((lh->p) >= lh->pmax) + { + j=(int)lh->num_alloc_nodes*2; + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)sizeof(LHASH_NODE *)*j); + if (n == NULL) + { + WriteError("lhash: realloc error in expand()"); + lh->p=0; + return; + } + /* else */ + for (i=(int)lh->num_alloc_nodes; ipmax=lh->num_alloc_nodes; + lh->num_alloc_nodes=j; + lh->num_expand_reallocs++; + lh->p=0; + lh->b=n; + } +} + + + +static void contract(LHASH *lh) +{ + LHASH_NODE **n,*n1,*np; + + np=lh->b[lh->p+lh->pmax-1]; + lh->b[lh->p+lh->pmax-1]=NULL; /* 24/07-92 - eay - weird but :-( */ + if (lh->p == 0) + { + n=(LHASH_NODE **)realloc((char *)lh->b, + (unsigned int)(sizeof(LHASH_NODE *)*lh->pmax)); + if (n == NULL) + { + WriteError("lhash: realloc error in contract()"); + return; + } + lh->num_contract_reallocs++; + lh->num_alloc_nodes/=2; + lh->pmax/=2; + lh->p=lh->pmax-1; + lh->b=n; + } + else + lh->p--; + + lh->num_nodes--; + lh->num_contracts++; + + n1=lh->b[(int)lh->p]; + if (n1 == NULL) + lh->b[(int)lh->p]=np; + else + { + while (n1->next != NULL) + n1=n1->next; + n1->next=np; + } +} + + + +static LHASH_NODE **getrn(LHASH *lh, char *data, unsigned long *rhash) +{ + LHASH_NODE **ret,*n1; + unsigned long hash,nn; + int (*cf)(char *, char *); + + hash=(*(lh->hash))(data); + lh->num_hash_calls++; + *rhash=hash; + + nn=hash%lh->pmax; + if (nn < lh->p) + nn=hash%lh->num_alloc_nodes; + + cf=lh->comp; + ret= &(lh->b[(int)nn]); + for (n1= *ret; n1 != NULL; n1=n1->next) + { +#ifndef NO_HASH_COMP + lh->num_hash_comps++; + if (n1->hash != hash) + { + ret= &(n1->next); + continue; + } +#endif + lh->num_comp_calls++; + if ((*cf)(n1->data,data) == 0) + break; + ret= &(n1->next); + } + return(ret); +} + +/* +static unsigned long lh_strhash(str) +char *str; + { + int i,l; + unsigned long ret=0; + unsigned short *s; + + if (str == NULL) return(0); + l=(strlen(str)+1)/2; + s=(unsigned short *)str; + for (i=0; i>2)^v)&0x0f; + ret=(ret<>(32-r)); + ret&=0xFFFFFFFFL; + ret^=v*v; + c++; + } + return((ret>>16)^ret); +} + diff --git a/mbfido/lhash.h b/mbfido/lhash.h new file mode 100644 index 00000000..d7071c47 --- /dev/null +++ b/mbfido/lhash.h @@ -0,0 +1,147 @@ +/* crypto/lhash/lhash.h */ +/* Copyright (C) 1995-1996 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This file is part of an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL + * specification. This library and applications are + * FREE FOR COMMERCIAL AND NON-COMMERCIAL USE + * as long as the following conditions are aheared to. + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. If this code is used in a product, + * Eric Young should be given attribution as the author of the parts used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Eric Young (eay@mincom.oz.au) + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Header for dynamic hash table routines + * Author - Eric Young + */ + +#ifndef HEADER_LHASH_H +#define HEADER_LHASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct lhash_node_st + { + char *data; + struct lhash_node_st *next; +#ifndef NO_HASH_COMP + unsigned long hash; +#endif + } LHASH_NODE; + +typedef struct lhash_st + { + LHASH_NODE **b; + int (*comp)(char *, char *); + unsigned long (*hash)(char *); + unsigned int num_nodes; + unsigned int num_alloc_nodes; + unsigned int p; + unsigned int pmax; + unsigned long up_load; /* load times 256 */ + unsigned long down_load; /* load times 256 */ + unsigned long num_items; + + unsigned long num_expands; + unsigned long num_expand_reallocs; + unsigned long num_contracts; + unsigned long num_contract_reallocs; + unsigned long num_hash_calls; + unsigned long num_comp_calls; + unsigned long num_insert; + unsigned long num_replace; + unsigned long num_delete; + unsigned long num_no_delete; + unsigned long num_retreve; + unsigned long num_retreve_miss; + unsigned long num_hash_comps; + } LHASH; + +#define LH_LOAD_MULT 256 + +#ifndef NOPROTO +LHASH *lh_new(unsigned long (*h)(char *), int (*c)(char *, char *)); +void lh_free(LHASH *lh); +char *lh_insert(LHASH *lh, char *data); +char *lh_delete(LHASH *lh, char *data); +char *lh_retrieve(LHASH *lh, char *data); +void lh_doall(LHASH *lh, void (*func)(char *, char *)); +void lh_doall_arg(LHASH *lh, void (*func)(char *, char *),char *arg); +unsigned long lh_strhash(char *c); + +#ifndef WIN16 +void lh_stats(LHASH *lh, FILE *out); +void lh_node_stats(LHASH *lh, FILE *out); +void lh_node_usage_stats(LHASH *lh, FILE *out); +#endif + +#ifdef HEADER_BUFFER_H +void lh_stats_bio(LHASH *lh, BIO *out); +void lh_node_stats_bio(LHASH *lh, BIO *out); +void lh_node_usage_stats_bio(LHASH *lh, BIO *out); +#else +void lh_stats_bio(LHASH *lh, char *out); +void lh_node_stats_bio(LHASH *lh, char *out); +void lh_node_usage_stats_bio(LHASH *lh, char *out); +#endif +#else +LHASH *lh_new(); +void lh_free(); +char *lh_insert(); +char *lh_delete(); +char *lh_retrieve(); +void lh_doall(); +void lh_doall_arg(); +unsigned long lh_strhash(); + +#ifndef WIN16 +void lh_stats(); +void lh_node_stats(); +void lh_node_usage_stats(); +#endif +void lh_stats_bio(); +void lh_node_stats_bio(); +void lh_node_usage_stats_bio(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mbfido/magic.c b/mbfido/magic.c new file mode 100644 index 00000000..2bbe0519 --- /dev/null +++ b/mbfido/magic.c @@ -0,0 +1,427 @@ +/***************************************************************************** + * + * File ..................: mbfido/magic.c + * Purpose ...............: .TIC files magic processing. + * Last modification date : 16-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbtic.h" +#include "tic.h" +#include "utic.h" +#include "magic.h" + + +long MagicNr; /* Current magic record number */ +int Magics = 0; /* Processed magics */ + + + +char *Magic_Macro(int); +char *Magic_Macro(int C) +{ + static char buf[81]; + + buf[0] = '\0'; + switch(toupper(C)) { + case 'F': + sprintf(buf, "%s/%s", TIC.BBSpath, TIC.NewName); + break; + + case 'P': + sprintf(buf, "%s", TIC.BBSpath); + break; + + case 'N': + sprintf(buf, "%s", strtok(strdup(TIC.NewName), ".")); + break; + + case 'E': + sprintf(buf, "%s", strrchr(TIC.NewName, '.')); + break; + + case 'L': + sprintf(buf, "%s", strrchr(TIC.NewName, '.')); + buf[0] = buf[1]; + buf[1] = buf[2]; + buf[2] = '\0'; + break; + + case 'D': + sprintf(buf, "%03d", Day_Of_Year()); + break; + + case 'C': + sprintf(buf, "%03d", Day_Of_Year()); + buf[0] = buf[1]; + buf[1] = buf[2]; + buf[2] = '\0'; + break; + + case 'A': + sprintf(buf, "%s", TIC.TicIn.Area); + break; + } + + Syslog('f', "Mgc Macro(%c): \"%s\"", C, buf); + return buf; +} + + + + +int GetMagicRec(int Typ, int First) +{ + int Eof = FALSE, DoMagic = TRUE; + int i; + char *temp; + FILE *FeM; + + if (First) + MagicNr = 0; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((FeM = fopen(temp, "r")) == NULL) { + Syslog('+', "Huh? No magic file? (%s)", temp); + free(temp); + return FALSE; + } + + fread(&magichdr, sizeof(magichdr), 1, FeM); + + do { + if (fseek(FeM, magichdr.hdrsize + (MagicNr * magichdr.recsize), SEEK_SET) != 0) { + WriteError("$Can't seek record %ld in %s", MagicNr, temp); + free(temp); + fclose(FeM); + return FALSE; + } + + MagicNr++; + + if (fread(&magic, magichdr.recsize, 1, FeM) == 1) { + + if ((magic.Active) && (magic.Attrib == Typ) && + (strcmp(magic.From, TIC.TicIn.Area) == 0)) { + + /* + * Comparing of the filename must be done in + * two parts, before and after the dot. + */ + if (strlen(magic.Mask) == strlen(TIC.NewName)) { + for (i = 0; i < strlen(magic.Mask); i++) { + switch (magic.Mask[i]) { + case '?': + break; + + case '@': + if ((TIC.NewName[i] < 'a') || (TIC.NewName[i] > 'z')) + DoMagic = FALSE; + break; + + case '#': + if ((TIC.NewName[i] < '0') || (TIC.NewName[i] > '9')) + DoMagic = FALSE; + break; + + default: + if (TIC.NewName[i] != magic.Mask[i]) + DoMagic = FALSE; + } + } + } + + if (DoMagic) { + fclose(FeM); + free(temp); + return TRUE; + } + } + + } else { + Eof = TRUE; + } + + } while (!Eof); + + free(temp); + fclose(FeM); + return FALSE; +} + + + +void MagicResult(char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(1024, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + Syslog('+', "Magic: %s", outputstr); + free(outputstr); + Magics++; +} + + +void Magic_CheckCompile(void); +void Magic_CheckCompile(void) +{ + if (magic.Compile) { + CompileNL = TRUE; + Syslog('+', "Magic: Trigger Compile Nodelists"); + } +} + + + +int Magic_MoveFile(void) +{ + if (GetMagicRec(MG_MOVE, TRUE)) { + strcpy(TIC.TicIn.Area, magic.ToArea); + MagicResult((char *)"Move %s to Area %s", TIC.TicIn.OrgName, TIC.TicIn.Area); + return TRUE; + } else + return FALSE; +} + + + +void Magic_ExecCommand(void) +{ + int i, j, k, Err, First = TRUE; + char Line[256]; + char Temp[81]; + char *cmd, *opts; + + while (GetMagicRec(MG_EXEC, First)) { + First = FALSE; + j = 0; + memset(&Line, 0, sizeof(Line)); + for (i = 0; i < strlen(magic.Cmd); i++) { + if (magic.Cmd[i] != '%') { + Line[j] = magic.Cmd[i]; + j++; + } else { + i++; + if (magic.Cmd[i] == '%') { + Line[j] = '%'; + j++; + } else { + Temp[0] = '\0'; + sprintf(Temp, "%s", Magic_Macro(magic.Cmd[i])); + for (k = 0; k < strlen(Temp); k++) { + Line[j] = Temp[k]; + j++; + } + } + } + } + + cmd = xstrcpy(getenv("MBSE_ROOT")); + cmd = xstrcat(cmd, (char *)"/bin/"); + cmd = xstrcat(cmd, strtok(Line, " ")); + opts = strtok(NULL, "\0"); + MagicResult((char *)"Exec: \"%s %s\"", cmd, opts); + + if ((Err = execute(cmd, opts, NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) == 0) { + Magics++; + } else + Syslog('!', "Mgc Exec: (%s %s) returns %d", cmd, opts, Err); + + Magic_CheckCompile(); + } +} + + + +void Magic_CopyFile(void) +{ + int First = TRUE; + char *From, *To; + + From = calloc(256, sizeof(char)); + To = calloc(256, sizeof(char)); + + while (GetMagicRec(MG_COPY, First)) { + First = FALSE; + sprintf(From, "%s/%s", TIC.BBSpath, TIC.NewName); + sprintf(To, "%s/%s", magic.Path, TIC.NewName); + + if (file_cp(From, To) == 0) { + MagicResult((char *)"%s copied to %s", From, To); + Magic_CheckCompile(); + } else + WriteError("Magic: copy: %s to %s failed"); + } + + free(From); + free(To); +} + + + +void Magic_OtherPath(void) +{ + if (GetMagicRec(MG_OTHER, TRUE)) { + if (access(magic.Path, W_OK) == 0) { + strcpy(TIC.BBSpath, magic.Path); + MagicResult((char *)"Otherpath %s", TIC.BBSpath); + TIC.OtherPath = TRUE; + } else { + WriteError("$Magic: otherpath \"%s\" no access", magic.Path); + } + } +} + + + +void Magic_UnpackFile(void) +{ + int rc, First = TRUE; + char *buf = NULL, *unarc = NULL, *cmd = NULL; + char Fn[128]; + + while (GetMagicRec(MG_UNPACK, First)) { + First = FALSE; + buf = calloc(PATH_MAX, sizeof(char)); /* 06-01-2001 MB. Test if NULL pointer free'd message goes away */ + getcwd(buf, 128); + + if (chdir(magic.Path) == 0) { + sprintf(Fn, "%s/%s", TIC.BBSpath, TIC.NewName); + if ((unarc = unpacker(Fn)) != NULL) { + if (getarchiver(unarc)) { + cmd = xstrcpy(archiver.funarc); + if (strlen(cmd)) { + rc = execute(cmd, Fn, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + if (rc) + WriteError("$Magic: unpack in %s, error %d", magic.Path, rc); + else + MagicResult((char *)"unpacked in %s", magic.Path); + } + free(cmd); + } + } + + chdir(buf); + Magic_CheckCompile(); + } else + WriteError("$Magic: unpack: can't chdir \"%s\"", magic.Path); + + free(buf); + } +} + + + +void Magic_Keepnum(void) +{ + if (GetMagicRec(MG_KEEPNUM, TRUE)) { + TIC.KeepNum = magic.KeepNum; + MagicResult((char *)"Keep %d files", TIC.KeepNum); + } +} + + + +void Magic_UpDateAlias(void) +{ + if (GetMagicRec(MG_UPDALIAS, TRUE)) { + UpDateAlias(TIC.TicIn.Area); + MagicResult((char *)"Update Alias"); + } +} + + + +void Magic_AdoptFile(void) +{ + int First = TRUE; + char *temp; + FILE *Tf; + + temp = calloc(256, sizeof(char)); + + while (GetMagicRec(MG_ADOPT, First)) { + First = FALSE; + + if (SearchTic(magic.ToArea)) { + MagicResult((char *)"Adoptfile in %s", magic.ToArea); + + sprintf(temp, "%s/%s", TIC.Inbound, MakeTicName()); + if ((Tf = fopen(temp, "a+")) == NULL) + WriteError("$Can't create %s", temp); + else { + fprintf(Tf, "Hatch\r\n"); + fprintf(Tf, "NoMove\r\n"); + fprintf(Tf, "Created MBSE BBS v%s, %s\r\n", VERSION, ShortRight); + fprintf(Tf, "Area %s\r\n", magic.ToArea); + fprintf(Tf, "Origin %s\r\n", aka2str(tic.Aka)); + fprintf(Tf, "From %s\r\n", aka2str(tic.Aka)); + if (strlen(TIC.TicIn.Replace)) + fprintf(Tf, "Replaces %s\r\n", TIC.TicIn.Replace); + if (strlen(TIC.TicIn.Magic)) + fprintf(Tf, "Magic %s\r\n", TIC.TicIn.Magic); + fprintf(Tf, "File %s\r\n", TIC.NewName); + fprintf(Tf, "Pth %s\r\n", TIC.BBSpath); + fprintf(Tf, "Desc %s\r\n", TIC.TicIn.Desc); + fprintf(Tf, "Crc %s\r\n", TIC.TicIn.Crc); + fprintf(Tf, "Pw %s\r\n", CFG.hatchpasswd); + fclose(Tf); + } + + SearchTic(TIC.TicIn.Area); + } else + WriteError("Mgc Adopt: Area \"%s\" not found"); + } + + free(temp); +} + + + +int Magic_DeleteFile(void) +{ + int Result; + + if ((Result = GetMagicRec(MG_DELETE, TRUE))) + MagicResult((char *)"Delete file"); + + return Result; +} + + + diff --git a/mbfido/magic.h b/mbfido/magic.h new file mode 100644 index 00000000..9ae4a4b2 --- /dev/null +++ b/mbfido/magic.h @@ -0,0 +1,19 @@ +#ifndef _MAGIC_H +#define _MAGIC_H + + +int GetMagicRec(int, int); +void MagicResult(char *, ...); +int Magic_MoveFile(void); +void Magic_ExecCommand(void); +void Magic_CopyFile(void); +void Magic_OtherPath(void); +void Magic_UnpackFile(void); +void Magic_Keepnum(void); +void Magic_UpDateAlias(void); +void Magic_AdoptFile(void); +int Magic_DeleteFile(void); + + +#endif + diff --git a/mbfido/makestat.c b/mbfido/makestat.c new file mode 100644 index 00000000..325a9d56 --- /dev/null +++ b/mbfido/makestat.c @@ -0,0 +1,434 @@ +/***************************************************************************** + * + * File ..................: mbfido/makestat.c + * Purpose ...............: Make Web statistics + * Last modification date : 08-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "makestat.h" + + + +/* + * Translate ISO 8859-1 characters to named character entities + */ +void html_massage(char *, char *); +void html_massage(char *inbuf, char *outbuf) +{ + char *inptr = inbuf; + char *outptr = outbuf; + + memset(outbuf, 0, sizeof(outbuf)); + + while (*inptr) { + + switch ((unsigned char)*inptr) { + case '"': sprintf(outptr, """); break; + case '&': sprintf(outptr, "&"); break; + case '<': sprintf(outptr, "<"); break; + case '>': sprintf(outptr, ">"); break; + case 160: sprintf(outptr, " "); break; + case 161: sprintf(outptr, "¡"); break; + case 162: sprintf(outptr, "¢"); break; + case 163: sprintf(outptr, "£"); break; + case 164: sprintf(outptr, "¤"); break; + case 165: sprintf(outptr, "¥"); break; + case 166: sprintf(outptr, "¦"); break; + case 167: sprintf(outptr, "§"); break; + case 168: sprintf(outptr, "¨"); break; + case 169: sprintf(outptr, "©"); break; + case 170: sprintf(outptr, "ª"); break; + case 171: sprintf(outptr, "«"); break; + case 172: sprintf(outptr, "¬"); break; + case 173: sprintf(outptr, "­"); break; + case 174: sprintf(outptr, "®"); break; + case 175: sprintf(outptr, "¯"); break; + case 176: sprintf(outptr, "°"); break; + case 177: sprintf(outptr, "&plumn;"); break; + case 178: sprintf(outptr, "²"); break; + case 179: sprintf(outptr, "³"); break; + case 180: sprintf(outptr, "´"); break; + case 181: sprintf(outptr, "µ"); break; + case 182: sprintf(outptr, "¶"); break; + case 183: sprintf(outptr, "·"); break; + case 184: sprintf(outptr, "¸"); break; + case 185: sprintf(outptr, "&supl;"); break; + case 186: sprintf(outptr, "º"); break; + case 187: sprintf(outptr, "»"); break; + case 188: sprintf(outptr, "¼"); break; + case 189: sprintf(outptr, "½"); break; + case 190: sprintf(outptr, "¾"); break; + case 191: sprintf(outptr, "¿"); break; + case 192: sprintf(outptr, "À"); break; + case 193: sprintf(outptr, "Á"); break; + case 194: sprintf(outptr, "Â"); break; + case 195: sprintf(outptr, "Ã"); break; + case 196: sprintf(outptr, "Ä"); break; + case 197: sprintf(outptr, "Å"); break; + case 198: sprintf(outptr, "Æ"); break; + case 199: sprintf(outptr, "Ç"); break; + case 200: sprintf(outptr, "È"); break; + case 201: sprintf(outptr, "É"); break; + case 202: sprintf(outptr, "Ê"); break; + case 203: sprintf(outptr, "Ë"); break; + case 204: sprintf(outptr, "Ì"); break; + case 205: sprintf(outptr, "Í"); break; + case 206: sprintf(outptr, "Î"); break; + case 207: sprintf(outptr, "Ï"); break; + case 208: sprintf(outptr, "Ð"); break; + case 209: sprintf(outptr, "Ñ"); break; + case 210: sprintf(outptr, "Ò"); break; + case 211: sprintf(outptr, "Ó"); break; + case 212: sprintf(outptr, "Ô"); break; + case 213: sprintf(outptr, "Õ"); break; + case 214: sprintf(outptr, "Ö"); break; + case 215: sprintf(outptr, "×"); break; + case 216: sprintf(outptr, "Ø"); break; + case 217: sprintf(outptr, "Ù"); break; + case 218: sprintf(outptr, "Ú"); break; + case 219: sprintf(outptr, "Û"); break; + case 220: sprintf(outptr, "Ü"); break; + case 221: sprintf(outptr, "Ý"); break; + case 222: sprintf(outptr, "Þ"); break; + case 223: sprintf(outptr, "ß"); break; + case 224: sprintf(outptr, "à"); break; + case 225: sprintf(outptr, "á"); break; + case 226: sprintf(outptr, "â"); break; + case 227: sprintf(outptr, "ã"); break; + case 228: sprintf(outptr, "ä"); break; + case 229: sprintf(outptr, "å"); break; + case 230: sprintf(outptr, "æ"); break; + case 231: sprintf(outptr, "ç"); break; + case 232: sprintf(outptr, "è"); break; + case 233: sprintf(outptr, "é"); break; + case 234: sprintf(outptr, "ê"); break; + case 235: sprintf(outptr, "ë"); break; + case 236: sprintf(outptr, "ì"); break; + case 237: sprintf(outptr, "í"); break; + case 238: sprintf(outptr, "î"); break; + case 239: sprintf(outptr, "ï"); break; + case 240: sprintf(outptr, "ð"); break; + case 241: sprintf(outptr, "ñ"); break; + case 242: sprintf(outptr, "ò"); break; + case 243: sprintf(outptr, "ó"); break; + case 244: sprintf(outptr, "ô"); break; + case 245: sprintf(outptr, "õ"); break; + case 246: sprintf(outptr, "ö"); break; + case 247: sprintf(outptr, "÷"); break; + case 248: sprintf(outptr, "ø"); break; + case 249: sprintf(outptr, "ù"); break; + case 250: sprintf(outptr, "ú"); break; + case 251: sprintf(outptr, "û"); break; + case 252: sprintf(outptr, "ü"); break; + case 253: sprintf(outptr, "ý"); break; + case 254: sprintf(outptr, "þ"); break; + case 255: sprintf(outptr, "ÿ"); break; + default: *outptr++ = *inptr; *outptr = '\0'; break; + } + while (*outptr) + outptr++; + + inptr++; + } + *outptr = '\0'; +} + + + +FILE *newpage(char *, char *); +FILE *newpage(char *Name, char *Title) +{ + char linebuf[1024], outbuf[1024]; + static FILE* fa; + time_t later; + + later = time(NULL) + 86400; + sprintf(linebuf, "%s/stat/%s.temp", CFG.www_root, Name); + mkdirs(linebuf); + + if ((fa = fopen(linebuf, "w")) == NULL) { + WriteError("$Can't create %s", linebuf); + } else { + sprintf(linebuf, "%s", Title); + html_massage(linebuf, outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n", rfcdate(later)); + fprintf(fa, "\n"); + fprintf(fa, "\n", CFG.www_charset); + fprintf(fa, "\n", CFG.www_author, outbuf); + fprintf(fa, "\n%s\n", outbuf); + fprintf(fa, "\n", CFG.www_url); + fprintf(fa, "\n\n\n\n"); + fprintf(fa, "

%s

\n", Title); + fprintf(fa, "\n"); + return fa; + } + return NULL; +} + + + +void closepage(FILE *, char *); +void closepage(FILE *fa, char *Name) +{ + char temp1[81], temp2[81]; + + if (fa == NULL) + return; + + fprintf(fa, "

\n"); + fprintf(fa, "

\n"); + fprintf(fa, "Top of page   Statistic index\n"); + fprintf(fa, "
\n\n\n"); + fclose(fa); + sprintf(temp1, "%s/stat/%s.html", CFG.www_root, Name); + sprintf(temp2, "%s/stat/%s.temp", CFG.www_root, Name); + rename(temp2, temp1); + fa = NULL; +} + + + +char *adate(time_t); +char *adate(time_t now) +{ + static char buf[40]; + struct tm ptm; + + if (now == 0L) { + sprintf(buf, "N/A"); + } else { + ptm = *localtime(&now); + sprintf(buf, "%02d-%02d-%04d %02d:%02d", ptm.tm_mday, ptm.tm_mon +1, ptm.tm_year + 1900, + ptm.tm_hour, ptm.tm_min); + } + return buf; +} + + + +void MakeStat(void) +{ + FILE *fg, *fw; + char *name, *p; + int i, Total, Lm, Area; + struct _history hist; + + if (!strlen(CFG.www_root)) + return; + + Syslog('+', "Start making statistic HTML pages"); + name = calloc(128, sizeof(char)); + if (Miy == 0) + Lm = 11; + else + Lm = Miy -1; + + sprintf(name, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("Can't open %s", name); + } else { + if ((fw = newpage((char *)"mgroups", (char *)"Message groups statistics")) != NULL) { + fprintf(fw, "Message group statisticsReceived lastSent last\n"); + fprintf(fw, "GroupCommentAkaLast dateweekmonthweekmonth\n"); + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fg); + while ((fread(&mgroup, mgrouphdr.recsize, 1, fg)) == 1) { + if (mgroup.Active) { + fprintf(fw, "%s%s%s%s%ld%ld%ld%ld\n", + mgroup.Name, mgroup.Comment, aka2str(mgroup.UseAka), adate(mgroup.LastDate), + mgroup.MsgsRcvd.lweek, mgroup.MsgsRcvd.month[Lm], + mgroup.MsgsSent.lweek, mgroup.MsgsSent.month[Lm]); + } + } + fprintf(fw, "\n"); + closepage(fw, (char *)"mgroups"); + } else { + WriteError("Can't create mgroups.html"); + } + fclose(fg); + } + + + sprintf(name, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"mareas", (char *)"Message areas statistics")) != NULL) { + fprintf(fw, "Message areas statisticsReceived lastPosts last\n"); + fprintf(fw, "NrAreaTagGroupLast dateweekmonthweekmonth\n"); + fread(&msgshdr, sizeof(msgshdr), 1, fg); + Area = 0; + while ((fread(&msgs, msgshdr.recsize, 1, fg)) == 1) { + Area++; + if (msgs.Active) { + fprintf(fw, "%d%s%s %s %s%ld%ld%ld%ld\n", + Area, msgs.Name, msgs.Tag, msgs.Group, adate(msgs.LastRcvd), + msgs.Received.lweek, msgs.Received.month[Lm], + msgs.Posted.lweek, msgs.Posted.month[Lm]); + } + fseek(fg, msgshdr.syssize, SEEK_CUR); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"mareas"); + } else { + WriteError("Can't create mareas.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"fgroups", (char *)"TIC file groups statistics")) != NULL) { + fprintf(fw, "TIC file group statisticsLast weekLast month\n"); + fprintf(fw, "GroupCommentAkaLast datefilesKBytesfilesKBytes\n"); + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fg); + while ((fread(&fgroup, fgrouphdr.recsize, 1, fg)) == 1) { + if (fgroup.Active) { + fprintf(fw, "%s%s%s%s%ld%ld%ld%ld\n", + fgroup.Name, fgroup.Comment, aka2str(fgroup.UseAka), adate(fgroup.LastDate), + fgroup.Files.lweek, fgroup.KBytes.lweek, + fgroup.Files.month[Lm], fgroup.KBytes.month[Lm]); + } + } + fprintf(fw, "\n"); + closepage(fw, (char *)"fgroups"); + } else { + WriteError("Can't create fgroups.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"tic", (char *)"TIC file areas statistics")) != NULL) { + fprintf(fw, "TIC file areas statisticsLast weekLast month\n"); + fprintf(fw, "AreaTagGroupLast datefilesKBytesfilesKBytes\n"); + fread(&tichdr, sizeof(tichdr), 1, fg); + while ((fread(&tic, tichdr.recsize, 1, fg)) == 1) { + if (tic.Active) { + fprintf(fw, "%s%s %s %s%ld%ld%ld%ld\n", + tic.Comment, tic.Name, tic.Group, adate(tic.LastAction), + tic.Files.lweek, tic.KBytes.lweek, + tic.Files.month[Lm], tic.KBytes.month[Lm]); + } + fseek(fg, tichdr.syssize, SEEK_CUR); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"tic"); + } else { + WriteError("Can't create tic.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"nodes", (char *)"Nodes statistics")) != NULL) { + fprintf(fw, "Nodes statistics\n"); + fprintf(fw, "NodeSysopStatusStart DateLast dateCreditDebet\n"); + fread(&nodeshdr, sizeof(nodeshdr), 1, fg); + while ((fread(&nodes, nodeshdr.recsize, 1, fg)) == 1) { + fseek(fg, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + p = xstrcpy(adate(nodes.StartDate)); + fprintf(fw, "%s%s%s %s%s%s%ld%ld\n", + aka2str(nodes.Aka[0]), nodes.Sysop, nodes.Crash?"Crash":"", nodes.Hold?"Hold":"", + p, adate(nodes.LastDate), nodes.Credit, nodes.Debet); + free(p); + } + fprintf(fw, "\n"); + closepage(fw, (char *)"nodes"); + } else { + WriteError("Can't create nodes.html"); + } + fclose(fg); + } + + sprintf(name, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) == NULL) { + WriteError("$Can't open %s", name); + } else { + if ((fw = newpage((char *)"mailhistory", (char *)"Mailer history")) != NULL) { + fseek(fg, 0, SEEK_END); + Total = (ftell(fg) / sizeof(hist)) -1; + fseek(fg, 0, SEEK_SET); + fread(&hist, sizeof(hist), 1, fg); + fprintf(fw, "Mailer history since %s\n", adate(hist.online)); + fprintf(fw, "AkaSystemLocationTimeElapsedSentReceivedMode\n"); + + for (i = Total; i > 0; i--) { + fseek(fg, i * sizeof(hist), SEEK_SET); + fread(&hist, sizeof(hist), 1, fg); + fprintf(fw, "%s%s%s%s%s%lu%lu%s", + aka2str(hist.aka), hist.system_name, hist.location, + adate(hist.online), t_elapsed(hist.online, hist.offline), hist.sent_bytes, + hist.rcvd_bytes, hist.inbound ? "In":"Out"); + } + + fprintf(fw, "\n"); + closepage(fw, (char *)"mailhistory"); + } else { + WriteError("Can't create tic.html"); + } + fclose(fg); + } + + sprintf(name, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + if ((fg = fopen(name, "r")) != NULL ) { + fread(&SYSINFO, sizeof(SYSINFO), 1, fg); + if ((fw = newpage((char *)"sysinfo", (char *)"BBS system information")) != NULL) { + fprintf(fw, "BBS system info\n"); + fprintf(fw, "Total calls%lu\n", SYSINFO.SystemCalls); + fprintf(fw, "Pots calls%lu\n", SYSINFO.Pots); + fprintf(fw, "ISDN calls%lu\n", SYSINFO.ISDN); + fprintf(fw, "Network calls%lu\n", SYSINFO.Network); + fprintf(fw, "Local calls%lu\n", SYSINFO.Local); + fprintf(fw, "ADSL calls%lu\n", SYSINFO.ADSL); + fprintf(fw, "Start date%s\n", adate(SYSINFO.StartDate)); + fprintf(fw, "Last caller%s\n", SYSINFO.LastCaller); + fprintf(fw, "\n"); + closepage(fw, (char *)"sysinfo"); + } + fclose(fg); + } + + free(name); + Syslog('+', "Finished making statistic HTML pages"); +} + + diff --git a/mbfido/makestat.h b/mbfido/makestat.h new file mode 100644 index 00000000..22132b1a --- /dev/null +++ b/mbfido/makestat.h @@ -0,0 +1,9 @@ +#ifndef _MAKESTAT_H +#define _MAKESTAT_H + + +void MakeStat(void); + + +#endif + diff --git a/mbfido/maketags.c b/mbfido/maketags.c new file mode 100644 index 00000000..e8306373 --- /dev/null +++ b/mbfido/maketags.c @@ -0,0 +1,132 @@ +/***************************************************************************** + * + * File ..................: mbfido/maketags.c + * Purpose ...............: Make tag files + * Last modification date : 20-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "maketags.h" + + + +void MakeTags(void) +{ + FILE *fg, *fd, *td, *ad; + char *gname, *dname, *tname, *aname; + + Syslog('+', "Start making tagfiles"); + gname = calloc(128, sizeof(char)); + dname = calloc(128, sizeof(char)); + tname = calloc(128, sizeof(char)); + aname = calloc(128, sizeof(char)); + + sprintf(gname, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(dname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if (((fg = fopen(gname, "r")) == NULL) || + ((fd = fopen(dname, "r")) == NULL)) { + WriteError("$Can't open data"); + } else { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fg); + fread(&msgshdr, sizeof(msgshdr), 1, fd); + + while ((fread(&mgroup, mgrouphdr.recsize, 1, fg)) == 1) { + if (mgroup.Active) { + sprintf(tname, "%s/doc/%s.msgs.tag", getenv("MBSE_ROOT"), mgroup.Name); + td = fopen(tname, "w"); + sprintf(aname, "%s/doc/%s.msgs.are", getenv("MBSE_ROOT"), mgroup.Name); + ad = fopen(aname, "w"); + fprintf(ad, "; Mail areas in group %s\n", mgroup.Name); + fprintf(ad, ";\n"); + + fseek(fd, msgshdr.hdrsize, SEEK_SET); + while ((fread(&msgs, msgshdr.recsize, 1, fd)) == 1) { + if (msgs.Active && strlen(msgs.Tag) && + strcmp(mgroup.Name, msgs.Group) == 0) { + fprintf(ad, "%-35s %s\n", msgs.Tag, msgs.Name); + fprintf(td, "%s\n", msgs.Tag); + } + + fseek(fd, msgshdr.syssize, SEEK_CUR); + } + fclose(ad); + fclose(td); + } + } + fclose(fg); + fclose(fd); + } + + sprintf(gname, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(dname, "%s/etc/tic.data", getenv("MBSE_ROOT")); + + if (((fg = fopen(gname, "r")) == NULL) || + ((fd = fopen(dname, "r")) == NULL)) { + WriteError("$Can't open data"); + } else { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fg); + fread(&tichdr, sizeof(tichdr), 1, fd); + + while ((fread(&fgroup, fgrouphdr.recsize, 1, fg)) == 1) { + if (fgroup.Active) { + sprintf(tname, "%s/doc/%s.file.tag", getenv("MBSE_ROOT"), fgroup.Name); + td = fopen(tname, "w"); + sprintf(aname, "%s/doc/%s.file.are", getenv("MBSE_ROOT"), fgroup.Name); + ad = fopen(aname, "w"); + fprintf(ad, "; TIC file areas in group %s\n", fgroup.Name); + fprintf(ad, ";\n"); + + fseek(fd, tichdr.hdrsize, SEEK_SET); + while ((fread(&tic, tichdr.recsize, 1, fd)) == 1) { + if (tic.Active && strlen(tic.Name) && + strcmp(fgroup.Name, tic.Group) == 0) { + fprintf(ad, "%-21s %s\n", tic.Name, tic.Comment); + fprintf(td, "%s\n", tic.Name); + } + + fseek(fd, tichdr.syssize, SEEK_CUR); + } + fclose(ad); + fclose(td); + } + } + fclose(fg); + fclose(fd); + } + + free(aname); + free(tname); + free(dname); + free(gname); +} + + diff --git a/mbfido/maketags.h b/mbfido/maketags.h new file mode 100644 index 00000000..33dbdb24 --- /dev/null +++ b/mbfido/maketags.h @@ -0,0 +1,9 @@ +#ifndef _MAKETAGS_H +#define _MAKETAGS_H + + +void MakeTags(void); + + +#endif + diff --git a/mbfido/maptabs.tgz b/mbfido/maptabs.tgz new file mode 100644 index 0000000000000000000000000000000000000000..9270b3e68afc8b4988fcd88c360af11369a77e21 GIT binary patch literal 10605 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 Juu(9u{{ta$r49f9 literal 0 HcmV?d00001 diff --git a/mbfido/mbaff.c b/mbfido/mbaff.c new file mode 100644 index 00000000..2a6792b7 --- /dev/null +++ b/mbfido/mbaff.c @@ -0,0 +1,196 @@ +/***************************************************************************** + * + * File ..................: mbaff/mbaff.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "announce.h" +#include "filefind.h" +#include "mbaff.h" + + + +int do_announce = FALSE; /* Announce flag */ +int do_filefind = FALSE; /* FileFind flag */ +extern int do_quiet; /* Supress screen output */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBAFF: MBSE BBS %s Announce new files and FileFind\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBAFF finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Mail = FALSE; + char *cmd; + struct passwd *pw; + struct tm *t; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + t = localtime(&t_start); + Diw = t->tm_wday; + Miy = t->tm_mon; + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbaff"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(argv[i], "a", 1)) + do_announce = TRUE; + if (!strncmp(argv[i], "f", 1)) + do_filefind = TRUE; + if (!strncmp(argv[i], "-q", 2)) + do_quiet = TRUE; + + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbaff", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBAFF v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) + printf("\n"); + + if (!diskfree(CFG.freespace)) + die(101); + + memset(&MsgBase, 0, sizeof(MsgBase)); + + if (do_announce) + if (Announce()) + Mail = TRUE; + + if (do_filefind) + if (Filefind()) + Mail = TRUE; + + if (Mail) { + CreateSema((char *)"mailout"); + CreateSema((char *)"msglink"); + } + + die(0); + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbaff [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" a announce Announce new files\n"); + printf(" f filefind FileFind service\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + diff --git a/mbfido/mbaff.h b/mbfido/mbaff.h new file mode 100644 index 00000000..1969a11e --- /dev/null +++ b/mbfido/mbaff.h @@ -0,0 +1,9 @@ +#ifndef _MBAFF_H_ +#define _MBAFF_H + + +void Help(void); /* Show help screen */ + + +#endif + diff --git a/mbfido/mbdiff.c b/mbfido/mbdiff.c new file mode 100644 index 00000000..665651ca --- /dev/null +++ b/mbfido/mbdiff.c @@ -0,0 +1,576 @@ +/***************************************************************************** + * + * File ..................: mbdiff/mbdiff.c + * Purpose ...............: Nodelist diff processor + * Last modification date : 25-May-2001 + * Original ideas ........: Eugene G. Crosser. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbdiff.h" + + + +#ifndef BLKSIZ +#define BLKSIZ 512 +#endif + +extern unsigned short crc16xmodemtab[]; +#define updcrc(cp, crc) ( crc16xmodemtab[((crc >> 8) & 255) ^ cp] ^ (crc << 8)) + +extern int show_log; +extern int e_pid; +extern int do_quiet; /* Supress screen output */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBDIFF: MBSE BBS %s Nodelist diff processor\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBDIFF finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Match; + char *cmd, *nl = NULL, *nd = NULL, *nn; + int rc; + char *p, *q, *arc; + struct passwd *pw; + char *wrk, *onl, *ond; + DIR *dp; + struct dirent *de; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 3) + Help(); + + cmd = xstrcpy((char *)"Cmd: mbdiff"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (i == 1) + if ((nl = argv[i]) == NULL) + Help(); + if (i == 2) + if ((nd = argv[i]) == NULL) + Help(); + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbdiff", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBDIFF v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(12, 0); + printf("\n"); + } + + if (!diskfree(CFG.freespace)) + die(101); + + /* + * Extract work directory from the first commandline parameter + * and set that directory as default. + */ + show_log = TRUE; + wrk = xstrcpy(nl); + if (strrchr(wrk, '/') == NULL) { + WriteError("No path in nodelist name"); + free(wrk); + die(100); + } + if (strrchr(wrk, '.') != NULL) { + WriteError("Filename extension given for nodelist"); + free(wrk); + die(100); + } + if (strrchr(nd, '/') == NULL) { + WriteError("No path in nodediff name"); + free(wrk); + die(100); + } + show_log = FALSE; + + while (wrk[strlen(wrk) -1] != '/') + wrk[strlen(wrk) -1] = '\0'; + wrk[strlen(wrk) -1] = '\0'; + + show_log = TRUE; + if (access(wrk, R_OK|W_OK)) { + WriteError("$No R/W access in %s", wrk); + free(wrk); + die(100); + } + + if (chdir(wrk)) { + WriteError("$Can't chdir to %s", wrk); + free(wrk); + die(100); + } + show_log = FALSE; + + onl = xstrcpy(strrchr(nl, '/') + 1); + onl = xstrcat(onl, (char *)".???"); + + if ((dp = opendir(wrk)) == 0) { + show_log = TRUE; + free(wrk); + WriteError("$Error opening directory %s", wrk); + die(100); + } + + Match = FALSE; + while ((de = readdir(dp))) { + if (strlen(de->d_name) == strlen(onl)) { + Match = TRUE; + for (i = 0; i < strlen(onl); i++) { + if ((onl[i] != '?') && (onl[i] != de->d_name[i])) + Match = FALSE; + } + if (Match) { + free(onl); + onl = xstrcpy(de->d_name); + break; + } + } + } + closedir(dp); + if (!Match) { + show_log = TRUE; + free(wrk); + free(onl); + WriteError("Old nodelist not found"); + die(100); + } + + /* + * Now try to get the diff file into the workdir. + */ + if ((arc = unpacker(nd)) == NULL) { + show_log = TRUE; + free(onl); + free(wrk); + WriteError("Can't get filetype for %s", nd); + die(100); + } + + ond = xstrcpy(strrchr(nd, '/') + 1); + + if (strncmp(arc, "ASC", 3)) { + if (!getarchiver(arc)) { + show_log = TRUE; + free(onl); + free(wrk); + free(ond); + WriteError("Can't find unarchiver %s", arc); + die(100); + } + + /* + * We may both use the unarchive command for files and mail, + * unarchiving isn't recursive anyway. + */ + if (strlen(archiver.funarc)) + cmd = xstrcpy(archiver.funarc); + else + cmd = xstrcpy(archiver.munarc); + + if ((cmd == NULL) || (cmd == "")) { + show_log = TRUE; + free(cmd); + free(onl); + free(wrk); + free(ond); + WriteError("No unarc command available for %s", arc); + die(100); + } + + if (execute(cmd, nd, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) { + show_log = TRUE; + free(cmd); + free(onl); + free(wrk); + free(ond); + WriteError("Unpack error"); + die(100); + } + free(cmd); + + Match = FALSE; + if ((dp = opendir(wrk)) != NULL) { + while ((de = readdir(dp))) { + if (strlen(ond) == strlen(de->d_name)) { + Match = TRUE; + for (i = 0; i < (strlen(ond) -3); i++) + if (toupper(ond[i]) != toupper(de->d_name[i])) + Match = FALSE; + if (Match) { + free(ond); + ond = xstrcpy(de->d_name); + break; + } + } + } + closedir(dp); + } + if (!Match) { + show_log = TRUE; + free(ond); + free(onl); + free(wrk); + WriteError("Could not find extracted file"); + die(100); + } + } else { + if (file_cp(nd, ond)) { + show_log = TRUE; + free(ond); + free(onl); + free(wrk); + WriteError("$Copy %s failed", nd); + die(100); + } + Syslog('s', "Copied %s", nd); + } + + if (((p = strrchr(onl, '.'))) && ((q = strrchr(ond, '.'))) && + (strlen(p) == strlen(q))) { + nn = xstrcpy(onl); + p = strrchr(nn, '.') + 1; + q++; + strcpy(p, q); + } else + nn = xstrcpy((char *)"newnodelist"); + + if (strcmp(onl, nn) == 0) { + show_log = TRUE; + WriteError("Attempt to update nodelist to the same version"); + unlink(ond); + free(ond); + free(onl); + free(wrk); + free(nn); + die(100); + } + + Syslog('+', "Apply %s with %s to %s", onl, ond, nn); + if (!do_quiet) { + colour(3, 0); + printf("Apply %s with %s to %s\n", onl, ond, nn); + } + rc = apply(onl, ond, nn); + + unlink(ond); + if (rc) { + unlink(nn); + free(nn); + free(ond); + free(onl); + free(wrk); + die(rc + 100); + } else { + unlink(onl); + cmd = xstrcpy(archiver.farc); + + if ((cmd == NULL) || (!strlen(cmd))) { + free(cmd); + Syslog('+', "No archive command for %s, fallback to ZIP", arc); + if (!getarchiver((char *)"ZIP")) { + WriteError("No ZIP command available"); + free(ond); + free(onl); + free(wrk); + free(nn); + die(100); + } else { + cmd = xstrcpy(archiver.farc); + } + } else { + free(cmd); + cmd = xstrcpy(archiver.farc); + } + + if ((cmd == NULL) || (!strlen(cmd))) { + WriteError("No archiver command available"); + } else { + free(onl); + onl = xstrcpy(nn); + onl[strlen(onl) -3] = tolower(archiver.name[0]); + tl(onl); + p = xstrcpy(onl); + p = xstrcat(p, (char *)" "); + p = xstrcat(p, nn); + if (execute(cmd, p, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null")) + WriteError("Create %s failed", onl); + else { + CreateSema((char *)"mailin"); + } + free(p); + free(cmd); + } + + free(onl); + free(ond); + free(wrk); + free(nn); + die(0); + } + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbdiff [nodelist] [nodediff] \n\n"); + colour(3, 0); + printf(" The nodelist must be the full path and filename\n"); + printf(" without the dot and daynumber digits to the working\n"); + printf(" directory of that nodelist.\n"); + printf(" The nodediff must be the full path and filename\n"); + printf(" to the (compressed) nodediff file in the download\n"); + printf(" directory.\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(99); +} + + + +int apply(char *nl, char *nd, char *nn) +{ + FILE *fo, *fd, *fn; + unsigned char cmdbuf[BLKSIZ]; + unsigned char lnbuf[BLKSIZ]; + int i, count; + int ac = 0, cc = 0, dc = 0; + int rc = 0; + int firstline = 1; + unsigned short theircrc = 0, mycrc = 0; + unsigned char *p; + + if ((fo = fopen(nl, "r")) == NULL) { + WriteError("$Can't open %s", nl); + return 2; + } + + if ((fd = fopen(nd, "r")) == NULL) { + WriteError("$Can't open %s", nd); + fclose(fo); + return 2; + } + + if ((fn = fopen(nn, "w")) == NULL) { + WriteError("$Can't open %s", nn); + fclose(fo); + fclose(fd); + return 2; + } + + if ((fgets(cmdbuf, sizeof(cmdbuf)-1, fd) == NULL) || + (fgets(lnbuf, sizeof(cmdbuf)-1, fo) == NULL) || + (strcmp(cmdbuf, lnbuf) != 0)) { + rc = 6; + } else { + rewind(fo); + rewind(fd); + + while ((rc == 0) && fgets(cmdbuf, sizeof(cmdbuf)-1, fd)) + switch (cmdbuf[0]) { + case ';': + Striplf(cmdbuf); + break; + case 'A': + count = atoi(cmdbuf+1); + ac += count; + Striplf(cmdbuf); + for (i = 0;(i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf)-1, fd)) { + if (firstline) { + firstline = 0; + if ((p = strrchr(lnbuf, ':'))) { + theircrc = atoi(p+1); + } + } else { + for (p = lnbuf; *p; p++) + mycrc = updcrc(*p, mycrc); + } + fputs(lnbuf, fn); + } else + rc = 3; + break; + case 'D': + count = atoi(cmdbuf + 1); + dc += count; + Striplf(cmdbuf); + for (i = 0;(i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf)-1, fo) == NULL) + rc = 3; + break; + case 'C': + count = atoi(cmdbuf+1); + cc += count; + Striplf(cmdbuf); + for (i = 0; (i < count) && (rc == 0); i++) + if (fgets(lnbuf, sizeof(lnbuf) - 1, fo)) { + for (p = lnbuf; *p; p++) + mycrc = updcrc(*p, mycrc); + fputs(lnbuf, fn); + } else + rc = 3; + break; + default: + rc = 5; + break; + } + } + + fclose(fo); + fclose(fd); + fclose(fn); + + if ((rc != 0) && !do_quiet) { + show_log = TRUE; + colour(12, 0); + } + + if ((rc == 0) && (mycrc != theircrc)) + rc = 4; + + if (rc == 3) + WriteError("Could not read some of the files"); + else if (rc == 4) + WriteError("CRC is %hu, should be %hu", mycrc, theircrc); + else if (rc == 5) + WriteError("Unknown input line: \"%s\"", cmdbuf); + else if (rc == 6) + WriteError("Diff does not match old list"); + else { + Syslog('+', "Copied %d, added %d, deleted %d, difference %d", cc, ac, dc, ac-dc); + if (!do_quiet) + printf("Created new nodelist\n"); + } + + return rc; +} + + diff --git a/mbfido/mbdiff.h b/mbfido/mbdiff.h new file mode 100644 index 00000000..4ebf13ad --- /dev/null +++ b/mbfido/mbdiff.h @@ -0,0 +1,12 @@ +#ifndef _MBFIFF_H +#define _MBDIFF_H + + +void Help(void); +int apply(char *, char *, char *); +char *unpacker(char *); +int getarchiver(char *); + + +#endif + diff --git a/mbfido/mbfido.c b/mbfido/mbfido.c new file mode 100644 index 00000000..9806abc6 --- /dev/null +++ b/mbfido/mbfido.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbfido/mbfido.c + * Purpose ...............: Process Fidonet style mail and files. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbdupe.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "../lib/dbtic.h" +#include "../lib/msg.h" +#include "flock.h" +#include "tosspkt.h" +#include "pack.h" +#include "ulock.h" +#include "tic.h" +#include "fsort.h" +#include "scan.h" +#include "mbfido.h" +#include "tracker.h" +#include "notify.h" +#include "rollover.h" +#include "hatch.h" +#include "scannews.h" +#include "maketags.h" +#include "makestat.h" +#include "newspost.h" +#include "rnews.h" +#include "backalias.h" + + +#define UNPACK_FACTOR 300 + + +int do_toss = FALSE; /* Toss flag */ +int do_scan = FALSE; /* Scan flag */ +int do_tic = FALSE; /* Process .tic files */ +int do_notify = FALSE; /* Create notify messages */ +int do_roll = FALSE; /* Rollover only */ +int do_full = FALSE; /* Full mailscan */ +int do_tags = FALSE; /* Create taglists */ +int do_stat = FALSE; /* Create statistic HTML pages */ +int do_test = FALSE; /* Test routing */ +int do_news = FALSE; /* Process NNTP news */ +int do_uucp = FALSE; /* Process UUCP newsbatch */ +int do_unsec = FALSE; /* Unsecure tossing */ +int do_learn = FALSE; /* News articles learnmode */ +int check_crc = TRUE; /* Check .tic crc values */ +int check_dupe = TRUE; /* Check duplicates */ +int autocrea = FALSE; /* Autocreate new msg areas */ +extern int do_quiet; /* Quiet flag */ +extern int e_pid; /* Pid of child process */ +extern int show_log; /* Show logging on screen */ +int do_unprot = FALSE; /* Unprotected inbound flag */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int packets = 0; /* Tossed packets */ +int packets_ok = 0; /* Tossed packets Ok. */ +char *envptr = NULL; + +extern int net_in, net_imp, net_out, net_bad; +extern int echo_in, echo_imp, echo_out, echo_bad, echo_dupe; +extern int email_in, email_imp, email_out, email_bad; +extern int news_in, news_imp, news_out, news_bad, news_dupe; +extern int tic_in, tic_imp, tic_out, tic_bad, tic_dup; +extern int Magics, Hatched; +extern int notify, filemgr, areamgr; + + + +/* + * If we don't know what to type + */ +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbfido [command(s)] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" ne news Scan for new news\n"); + printf(" no notify Send notify messages\n"); + printf(" r roll Rollover statistic counters\n"); + printf(" s scan Scan outgoing Fido mail\n"); + printf(" ta tag Create taglists\n"); + printf(" te test Do some testing\n"); + printf(" ti tic Process .tic files\n"); + printf(" to toss Toss incoming Fido mail\n"); + printf(" u uucp Process UUCP batchfile\n"); + printf(" w web Create WWW statistics\n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -a -auto Autocreate new msg areas\n"); + printf(" -f -full Full Mailscan\n"); + printf(" -l -learn Learn News dupes\n"); + printf(" -noc -nocrc Skip CRC checking\n"); + printf(" -nod -nodupe Skip dupe checking\n"); + printf(" -q -quiet Quiet mode\n"); + printf(" -uns -unsecure Toss unsecure\n"); + printf(" -unp -unprotect Toss unprotected inbound\n"); + colour(7, 0); + ExitClient(0); +} + + + +/* + * Header, only if not quiet. + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBFIDO: MBSE BBS %s - Fidonet File and Mail processor\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty. + */ + system("stty sane"); + } + + CloseDupes(); + + /* + * Check for locked and open message base. + */ + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + signal(onsig, SIG_IGN); + + if (!do_quiet) { + show_log = TRUE; + colour(3, 0); + } + + if (onsig) { + if (onsig <= NSIG) + WriteError("Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + if (echo_imp + net_imp + net_out + echo_out) + CreateSema((char *)"msglink"); + + if (echo_out + net_out + tic_out) + CreateSema((char *)"scanout"); + + if (tic_imp) + CreateSema((char *)"reqindex"); + + if (net_in + net_imp + net_out + net_bad) + Syslog('+', "Netmail [%4d] import [%4d] out [%4d] bad [%4d]", + net_in, net_imp, net_out, net_bad); + if (email_in + email_imp + email_out + email_bad) + Syslog('+', "Email [%4d] import [%4d] out [%4d] bad [%4d]", + email_in, email_imp, email_out, email_bad); + if (echo_in + echo_imp + echo_out + echo_bad + echo_dupe) + Syslog('+', "Echomail [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + echo_in, echo_imp, echo_out, echo_bad, echo_dupe); + if (news_in + news_imp + news_out + news_bad + news_dupe) + Syslog('+', "News [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + news_in, news_imp, news_out, news_bad, news_dupe); + if (tic_in + tic_imp + tic_out + tic_bad + tic_dup) + Syslog('+', "TICfiles [%4d] import [%4d] out [%4d] bad [%4d] dupe [%4d]", + tic_in, tic_imp, tic_out, tic_bad, tic_dup); + if (Magics + Hatched) + Syslog('+', " Magics [%4d] hatch [%4d]", Magics, Hatched); + if (notify + areamgr + filemgr) + Syslog('+', "Notify msgs [%4d] AreaMgr [%4d] FileMgr [%4d]", notify, areamgr, filemgr); + + time(&t_end); + Syslog(' ', "MBFIDO finished in %s", t_elapsed(t_start, t_end)); + ulockunpack(); + + if (!do_quiet) + colour(7, 0); + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i, Loop; + char *p, *cmd, Options[81]; + struct passwd *pw; + struct tm *t; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from UUCP. + * this will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwuid(getuid()); + if (strcmp(pw->pw_name, "mbse")) { + /* + * We are not running as user mbse. + */ + pw = getpwnam("mbse"); + if (setuid(pw->pw_uid)) { + printf("Fatal error: can't set uid to user mbse\n"); + } + } + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + InitConfig(); + memset(&Options, 0, sizeof(Options)); + + /* + * Initialize global variables, data records. + */ + InitNode(); + InitMsgs(); + InitTic(); + InitUser(); + InitFidonet(); + TermInit(1); + time(&t_start); + t = localtime(&t_start); + Diw = t->tm_wday; + Miy = t->tm_mon; + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if ((p = strrchr(argv[0], '/'))) + p++; + else + p = argv[0]; + if (!strcmp(p, "mbnews")) { + do_quiet = TRUE; + do_uucp = TRUE; + cmd = xstrcpy((char *)"Cmd: mbnews"); + } else { + if (argc < 2) + Help(); + cmd = xstrcpy((char *)"Cmd: mbfido"); + } + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (strncmp(tl(argv[i]), "ne", 2) == 0) + do_news = TRUE; + if (strncmp(tl(argv[i]), "no", 2) == 0) { + do_notify = TRUE; + if (((i + 1) < argc) && + ((strchr(argv[i + 1], ':') != NULL) || + (atoi(argv[i + 1])) || + (strncmp(argv[i + 1], "*", 1) == 0))) { + sprintf(Options, "%s", argv[i + 1]); + i++; + } + } + if (strncmp(tl(argv[i]), "r", 1) == 0) + do_roll = TRUE; + if (strncmp(tl(argv[i]), "s", 1) == 0) + do_scan = TRUE; + if (strncmp(tl(argv[i]), "ta", 2) == 0) + do_tags = TRUE; + if (strncmp(tl(argv[i]), "ti", 2) == 0) + do_tic = TRUE; + if (strncmp(tl(argv[i]), "te", 2) == 0) + do_test = TRUE; + if (strncmp(tl(argv[i]), "to", 2) == 0) + do_toss = TRUE; + if (strncmp(tl(argv[i]), "u", 1) == 0) + do_uucp = TRUE; + if (strncmp(tl(argv[i]), "w", 1) == 0) + do_stat = TRUE; + if (strncmp(tl(argv[i]), "-a", 2) == 0) + autocrea = TRUE; + if (strncmp(tl(argv[i]), "-f", 2) == 0) + do_full = TRUE; + if (strncmp(tl(argv[i]), "-l", 2) == 0) + do_learn = TRUE; + if (strncmp(tl(argv[i]), "-noc", 4) == 0) + check_crc = FALSE; + if (strncmp(tl(argv[i]), "-nod", 4) == 0) + check_dupe = FALSE; + if (strncmp(tl(argv[i]), "-q", 2) == 0) + do_quiet = TRUE; + if (strncmp(tl(argv[i]), "-unp", 4) == 0) + do_unprot = TRUE; + if (strncmp(tl(argv[i]), "-uns", 4) == 0) + do_unsec = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbfido", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFIDO v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + InitDupes(); + + if (!diskfree(CFG.freespace)) + die(101); + + if (lockunpack()) + die(0); + if (initnl()) + die(101); + Rollover(); + if (!do_quiet) + printf("\n"); + + /* + * Read alias file + */ + cmd = calloc(PATH_MAX, sizeof(char)); + sprintf(cmd, "%s/etc/aliases", getenv("MBSE_ROOT")); + if ((do_news || do_scan || do_toss) && file_exist(cmd, R_OK) == 0) + readalias(cmd); + free(cmd); + + if (do_notify) + if (Notify(Options)) + packmail(); + if (do_tic) { + if (IsSema((char *)"mailin")) + RemoveSema((char *)"mailin"); + /* + * Hatch new files and process .tic files + * until nothing left to do. + */ + if (!diskfree(CFG.freespace)) + die(101); + Loop = TRUE; + do { + Hatch(); + switch (Tic()) { + case -1: die(0); + break; + case 0: Loop = FALSE; + break; + default: break; + } + } while (Loop); + } + if (do_news) { + ScanNews(); + if (IsSema((char *)"newnews")) + RemoveSema((char *)"newnews"); + } + if (do_scan) + ScanMail(do_full); + if (do_toss) { + if (IsSema((char *)"mailin")) + RemoveSema((char *)"mailin"); + if (TossMail() == FALSE) + die(0); + } + if (!do_uucp) + newspost(); + if (do_test) + TestTracker(); + if (do_tags) + MakeTags(); + if (do_stat) + MakeStat(); + if (do_uucp) + NewsUUCP(FALSE); + die(0); + return 0; +} + + + +/* + * Toss Fidonet mail + */ +int TossMail(void) +{ + char *inbound, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int files = 0, files_ok = 0; + int rc = 0, maxrc = 0; + fd_list *fdl = NULL; + + if (do_unprot) + inbound = xstrcpy(CFG.inbound); + else + inbound = xstrcpy(CFG.pinbound); + + Syslog('+', "Pass: toss netmail (%s)", inbound); + + if (chdir(inbound) == -1) { + WriteError("$Can't chdir(%s)", inbound); + die(0); + } + + /* + * First toss any netmail packets. + */ + maxrc = rc = TossPkts(); + chdir(inbound); + + /* + * Scan the directory for ARCmail archives. The archive extension + * numbering doesn't matter, as long as there is something, so + * all kind of ARCmail naming schemes are recognized. + */ + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + die(0); + } + + Syslog('+', "Pass: toss ARCmail (%s)", inbound); + + /* + * Add all ARCmail filenames to the memory array. + */ + sync(); + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && + ((strncasecmp(de->d_name+8,".su",3) == 0) || + (strncasecmp(de->d_name+8,".mo",3) == 0) || + (strncasecmp(de->d_name+8,".tu",3) == 0) || + (strncasecmp(de->d_name+8,".we",3) == 0) || + (strncasecmp(de->d_name+8,".th",3) == 0) || + (strncasecmp(de->d_name+8,".fr",3) == 0) || + (strncasecmp(de->d_name+8,".sa",3) == 0))) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + /* + * Now process the archives, the oldest first. + */ + while ((fname = pull_fdlist(&fdl)) != NULL) { + files++; + IsDoing("Unpack arcmail"); + + if (IsSema((char *)"upsalarm")) { + Syslog('+', "Detected upsalarm semafore, aborting toss"); + break; + } + if (!diskfree(CFG.freespace)) { + rc = 101; + break; + } + + if (checkspace(inbound, fname, UNPACK_FACTOR)) + if ((rc = unpack(fname)) == 0) { + files_ok++; + sync(); + rc = TossPkts(); + chdir(inbound); + } else + WriteError("Error unpacking file %s", fname); + else + Syslog('!', "Insufficient space to unpack file %s", fname); + + if (rc > maxrc) + maxrc = rc; + } + + free(inbound); + if ((files || packets) && + ((files_ok != files) || (packets_ok != packets))) + Syslog('!', "Processed %d of %d files, %d of %d packets, rc=%d", + files_ok, files, packets_ok, packets, maxrc); + + return TRUE; +} + + + +/* + * Toss all packets currently in the inbound. Tossing is sorted by + * age of the files. + */ +int TossPkts(void) +{ + char *inbound = NULL, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int rc = 0, maxrc = 0; + fd_list *fdl = NULL; + + IsDoing("Tossing mail"); + + if (do_unprot) + inbound = xstrcpy(CFG.inbound); + else + inbound = xstrcpy(CFG.pinbound); + + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + return FALSE; + } + + /* + * Read all .pkt filenames, get the timestamp and add them + * to the memory array for later sort on filedate. + */ + while((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && + (strncasecmp(de->d_name+8,".pkt",4) == 0)) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + /* + * Get the filenames, the oldest first until nothing left. + */ + while ((fname = pull_fdlist(&fdl)) != NULL) { + + if (!diskfree(CFG.freespace)) + return FALSE; + packets++; + + /* + * See if "pktdate" from Tobias Ernst (or another + * preprocessor) is installed. + */ + if (strlen(CFG.pktdate)) { + rc = execute(CFG.pktdate, fname, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + if (rc) + Syslog('+', "%s preprocessing rc=%d", fname, rc); + } + + if ((rc = toss(fname)) == 0) + packets_ok++; + else + WriteError("Error tossing packet %s", fname); + if (rc > maxrc) + maxrc = rc; + } + + free(inbound); + if (diskfree(CFG.freespace)) + packmail(); + return maxrc; +} + + + +/* + * Toss one packet + */ +int toss(char *fn) +{ + int rc, ld; + char newname[16]; + + rc = 0; + /* + * Lock the packet + */ + if ((ld = f_lock(fn)) == -1) + return 1; + + rc = TossPkt(fn); + if (rc == 0) { + unlink(fn); + } else { + strncpy(newname,fn,sizeof(newname)-1); + strcpy(newname+8,".bad"); + rename(fn,newname); + } + + funlock(ld); + return rc; +} + + diff --git a/mbfido/mbfido.h b/mbfido/mbfido.h new file mode 100644 index 00000000..67facb0f --- /dev/null +++ b/mbfido/mbfido.h @@ -0,0 +1,15 @@ +/* mbfido.h */ + +#ifndef _MBFIDO_H +#define _MBFIDO_H + +void Help(void); +void ProgName(void); +void die(int); +int TossPkts(void); +int TossMail(void); +int toss(char *); + +#endif + + diff --git a/mbfido/mbfile.c b/mbfido/mbfile.c new file mode 100644 index 00000000..02edd1a9 --- /dev/null +++ b/mbfido/mbfile.c @@ -0,0 +1,1002 @@ +/***************************************************************************** + * + * File ..................: mbfile/mbfile.c + * Purpose ...............: File Database Maintenance + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbfile.h" + + + +extern int do_quiet; /* Supress screen output */ +int do_pack = FALSE; /* Pack filebase */ +int do_check = FALSE; /* Check filebase */ +int do_kill = FALSE; /* Kill/move old files */ +int do_index = FALSE; /* Create request index */ +extern int e_pid; /* Pid of external process */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int marker = 0; /* Marker counter */ + + +typedef struct _Index { + struct _Index *next; + struct FILEIndex idx; +} Findex; + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBFILE: MBSE BBS %s File maintenance utility\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + if (!do_quiet) + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBFILE finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGKILL) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mbfile"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(argv[i], "i", 1)) + do_index = TRUE; + if (!strncmp(argv[i], "p", 1)) + do_pack = TRUE; + if (!strncmp(argv[i], "c", 1)) + do_check = TRUE; + if (!strncmp(argv[i], "k", 1)) + do_kill = TRUE; + if (!strncmp(argv[i], "-q", 2)) + do_quiet = TRUE; + } + + if (!(do_pack || do_check || do_kill || do_index)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbfile", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFILE v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) + printf("\n"); + + if (!diskfree(CFG.freespace)) + die(101); + + if (do_kill) + Kill(); + + if (do_check) + Check(); + + if (do_pack) + PackFileBase(); + + if (do_index) + Index(); + + die(0); + return 0; +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbfile [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" c check Check filebase\n"); + printf(" i index Create filerequest index\n"); + printf(" k kill Kill/move old files\n"); + printf(" p pack Pack filebase\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +void Marker(void) +{ + /* + * Keep the connection with the server alive + */ + Nopper(); + + /* + * Release system resources when running in the background + */ + if (CFG.slow_util && do_quiet) + usleep(1); + + if (do_quiet) + return; + + switch (marker) { + case 0: printf(">---"); + break; + + case 1: printf(">>--"); + break; + + case 2: printf(">>>-"); + break; + + case 3: printf(">>>>"); + break; + + case 4: printf("<>>>"); + break; + + case 5: printf("<<>>"); + break; + + case 6: printf("<<<>"); + break; + + case 7: printf("<<<<"); + break; + + case 8: printf("-<<<"); + break; + + case 9: printf("--<<"); + break; + + case 10:printf("---<"); + break; + + case 11:printf("----"); + break; + } + printf("\b\b\b\b"); + fflush(stdout); + + if (marker < 11) + marker++; + else + marker = 0; +} + + + +/* + * Check files for age, and not downloaded for x days. If they match + * one of these criteria (setable in areas setup), the file will be + * move to some retire area or deleted, depending on the setup. + * If they are moved, the upload date is reset to the current date, + * so you can set new removal criteria again. + */ +void Kill(void) +{ + FILE *pAreas, *pFile, *pDest, *pTemp; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iKilled = 0, iMoved = 0; + char *sAreas, *fAreas, *newdir = NULL, *sTemp; + time_t Now; + int rc, Killit, FilesLeft; + struct fileareas darea; + char from[128], to[128]; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + + IsDoing("Kill files"); + if (!do_quiet) { + colour(3, 0); + printf("Kill/move files...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + Now = time(NULL); + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if ((area.Available) && (area.DLdays || area.FDdays) && (!area.CDrom)) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4d => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "Create dir: %s", area.Path); + newdir = xstrcpy(area.Path); + newdir = xstrcat(newdir, (char *)"/"); + mkdirs(newdir); + free(newdir); + newdir = NULL; + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start checking the files in the filedatabase + * against the contents of the directory. + */ + while (fread(&file, sizeof(file), 1, pFile) == 1) { + iTotal++; + Marker(); + + Killit = FALSE; + if (area.DLdays) { + /* + * Test last download date or never downloaded and the + * file is more then n days available for download. + */ + if ((file.LastDL) && + (((Now - file.LastDL) / 84400) > area.DLdays)) { + Killit = TRUE; + } + if ((!file.LastDL) && + (((Now - file.UploadDate) / 84400) > area.DLdays)) { + Killit = TRUE; + } + } + + if (area.FDdays) { + /* + * Check filedate + */ + if (((Now - file.UploadDate) / 84400) > area.FDdays) { + Killit = TRUE; + } + } + + if (Killit) { + do_pack = TRUE; + if (area.MoveArea) { + fseek(pAreas, ((area.MoveArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&darea, areahdr.recsize, 1, pAreas); + sprintf(from, "%s/%s", area.Path, file.Name); + sprintf(to, "%s/%s", darea.Path, file.Name); + if ((rc = file_mv(from, to)) == 0) { + Syslog('+', "Move %s, area %d => %d", file.Name, i, area.MoveArea); + sprintf(to, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), area.MoveArea); + if ((pDest = fopen(to, "a+")) != NULL) { + file.UploadDate = time(NULL); + file.LastDL = time(NULL); + fwrite(&file, sizeof(file), 1, pDest); + fclose(pDest); + } + /* + * Now again if there is a dotted version (thumbnail) of this file. + */ + sprintf(from, "%s/.%s", area.Path, file.Name); + sprintf(to, "%s/.%s", darea.Path, file.Name); + if (file_exist(from, R_OK) == 0) + file_mv(from, to); + file.Deleted = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + iMoved++; + } else { + WriteError("Move %s failed rc = %d", file.Name, rc); + } + } else { + Syslog('+', "Delete %s, area %d", file.Name, i); + file.Deleted = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + iKilled++; + sprintf(from, "%s/%s", area.Path, file.Name); + unlink(from); + } + } + } + + /* + * Now we must pack this area database otherwise + * we run into trouble later on. + */ + fseek(pFile, 0, SEEK_SET); + sprintf(sTemp, "%s/fdb/fdbtmp.data", getenv("MBSE_ROOT")); + + if ((pTemp = fopen(sTemp, "a+")) != NULL) { + FilesLeft = FALSE; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && strcmp(file.Name, "") != 0) { + fwrite(&file, sizeof(file), 1, pTemp); + FilesLeft = TRUE; + } + } + + fclose(pFile); + fclose(pTemp); + if ((rename(sTemp, fAreas)) == 0) { + unlink(sTemp); + chmod(fAreas, 006600); + } + if (!FilesLeft) { + Syslog('+', "Warning: area %d (%s) is empty", i, area.Name); + } + } else + fclose(pFile); + + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + + Syslog('+', "Kill Areas [%5d] Files [%5d] Deleted [%5d] Moved [%5d]", iAreasNew, iTotal, iKilled, iMoved); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(sTemp); + free(sAreas); + free(fAreas); +} + + + +void tidy_index(Findex **); +void tidy_index(Findex **fap) +{ + Findex *tmp, *old; + + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fap = NULL; +} + + + +void fill_index(struct FILEIndex, Findex **); +void fill_index(struct FILEIndex idx, Findex **fap) +{ + Findex *tmp; + + tmp = (Findex *)malloc(sizeof(Findex)); + tmp->next = *fap; + tmp->idx = idx; + *fap = tmp; +} + + +int comp_index(Findex **, Findex **); + +void sort_index(Findex **); +void sort_index(Findex **fap) +{ + Findex *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + + vector = (Findex **)malloc(n * sizeof(Findex *)); + + i = 0; + for (ta = *fap; ta; ta = ta->next) + vector[i++] = ta; + + qsort(vector, n, sizeof(Findex *), + (int(*)(const void*, const void *))comp_index); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int comp_index(Findex **fap1, Findex **fap2) +{ + return strcasecmp((*fap1)->idx.LName, (*fap2)->idx.LName); +} + + + +/* + * Build a sorted index for the file request processor. + */ +void Index(void) +{ + FILE *pAreas, *pFile, *pIndex; + long i, iAreas, iAreasNew = 0, record; + int iTotal = 0; + char *sAreas, *fAreas, *newdir = NULL, *sIndex; + Findex *fdx = NULL; + Findex *tmp; + struct FILEIndex idx; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + sIndex = calloc(81, sizeof(char)); + + IsDoing("Kill files"); + if (!do_quiet) { + colour(3, 0); + printf("Create filerequest index...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + die(0); + } + + sprintf(sIndex, "%s/etc/request.index", getenv("MBSE_ROOT")); + if ((pIndex = fopen(sIndex, "w")) == NULL) { + WriteError("$Can't create %s", sIndex); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if ((area.Available) && (area.FileReq)) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4ld => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "Create dir: %s", area.Path); + newdir = xstrcpy(area.Path); + newdir = xstrcat(newdir, (char *)"/"); + mkdirs(newdir); + free(newdir); + newdir = NULL; + } + + sprintf(fAreas, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start creating the unsorted index. + */ + record = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + iTotal++; + if ((iTotal % 10) == 0) + Marker(); + memset(&idx, 0, sizeof(idx)); + sprintf(idx.Name, "%s", tu(file.Name)); + sprintf(idx.LName, "%s", tu(file.LName)); + idx.AreaNum = i; + idx.Record = record; + fill_index(idx, &fdx); + record++; + } + + fclose(pFile); + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + + sort_index(&fdx); + for (tmp = fdx; tmp; tmp = tmp->next) + fwrite(&tmp->idx, sizeof(struct FILEIndex), 1, pIndex); + fclose(pIndex); + tidy_index(&fdx); + + Syslog('+', "Index Areas [%5d] Files [%5d]", iAreasNew, iTotal); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(sIndex); + free(sAreas); + free(fAreas); + RemoveSema((char *)"reqindex"); +} + + + +/* + * Check file database integrity, all files in the file database must + * exist in real, the size and date/time must match, the files crc is + * checked, and if anything is wrong, the file database is updated. + * If the file is missing the entry is marked as deleted. With the + * pack option that record will be removed. + * After these checks, de database is checked for missing records, if + * there are files on disk but not in the directory these files are + * deleted. System files (beginning with a dot) are left alone and + * the files 'files.bbs', 'files.bak', '00index', 'header' 'readme' + * and 'index.html' too. + * + * Remarks: Maybe if the crc check fails, and the date and time are + * ok, the file is damaged and must be made unavailable. + */ +void Check(void) +{ + FILE *pAreas, *pFile; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iErrors = 0; + char *sAreas, *fAreas, *newdir; + DIR *dp; + struct dirent *de; + int Found, Update; + char fn[128]; + struct stat stb; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + newdir = calloc(81, sizeof(char)); + + if (!do_quiet) { + colour(3, 0); + printf("Checking file database...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if (area.Available) { + + IsDoing("Check area %d", i); + + if (!do_quiet) { + printf("\r%4d => %-44s \b\b\b\b", i, area.Name); + fflush(stdout); + } + + /* + * Check if download directory exists, + * if not, create the directory. + */ + if (access(area.Path, R_OK) == -1) { + Syslog('!', "No dir: %s", area.Path); + sprintf(newdir, "%s/foobar", area.Path); + mkdirs(newdir); + } + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + + /* + * Open the file database, if it doesn't exist, + * create an empty one. + */ + if ((pFile = fopen(fAreas, "r+")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + /* + * Now start checking the files in the filedatabase + * against the contents of the directory. + */ + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + iTotal++; + sprintf(newdir, "%s/%s", area.Path, file.Name); + + if (file_exist(newdir, R_OK)) { + Syslog('+', "File %s area %d not on disk.", newdir, i); + if (!file.NoKill) { + file.Deleted = TRUE; + do_pack = TRUE; + } + iErrors++; + file.Missing = TRUE; + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } else { + /* + * File exists, now check the file. + */ + Marker(); + Update = FALSE; + if (file_time(newdir) != file.FileDate) { + Syslog('!', "Date mismatch area %d file %s", i, file.Name); + file.FileDate = file_time(newdir); + iErrors++; + Update = TRUE; + } + if (file_size(newdir) != file.Size) { + Syslog('!', "Size mismatch area %d file %s", i, file.Name); + file.Size = file_size(newdir); + iErrors++; + Update = TRUE; + } + if (file_crc(newdir, CFG.slow_util && do_quiet) != file.Crc32) { + Syslog('!', "CRC error area %d, file %s", i, file.Name); + file.Crc32 = file_crc(newdir, CFG.slow_util && do_quiet); + iErrors++; + Update = TRUE; + } + Marker(); + if (Update) { + fseek(pFile, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, pFile); + } + } + } + + /* + * Check files in the directory against the database. + * This test is skipped for CD-rom. + */ + if (!area.CDrom) { + if ((dp = opendir(area.Path)) != NULL) { + while ((de = readdir(dp)) != NULL) { + if (de->d_name[0] != '.') { + Marker(); + Found = FALSE; + rewind(pFile); + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if (strcmp(file.Name, de->d_name) == 0) { + Found = TRUE; + break; + } + } + if ((!Found) && + (strncmp(de->d_name, "files.bbs", 9)) && + (strncmp(de->d_name, "files.bak", 9)) && + (strncmp(de->d_name, "00index", 7)) && + (strncmp(de->d_name, "header", 6)) && + (strncmp(de->d_name, "index", 5)) && + (strncmp(de->d_name, "readme", 6))) { + sprintf(fn, "%s/%s", area.Path, de->d_name); + if (stat(fn, &stb) == 0) + if (S_ISREG(stb.st_mode)) { + if (unlink(fn) == 0) { + Syslog('!', "%s not in fdb, deleted from disk", fn); + iErrors++; + } else { + WriteError("$%s not in fdb, cannot delete", fn); + } + } + } + } + } + closedir(dp); + } else { + WriteError("Can't open %s", area.Path); + } + } + + fclose(pFile); + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(newdir); + free(sAreas); + free(fAreas); + + Syslog('+', "Check Areas [%5d] Files [%5d] Errors [%5d]", iAreasNew, iTotal, iErrors); +} + + + +/* + * Removes records who are marked for deletion. If there is still a file + * on disk, it will be removed too. + */ +void PackFileBase(void) +{ + FILE *fp, *pAreas, *pFile; + int i, iAreas, iAreasNew = 0; + int iTotal = 0, iRemoved = 0; + char *sAreas, *fAreas, *fTmp, fn[128]; + + sAreas = calloc(81, sizeof(char)); + fAreas = calloc(81, sizeof(char)); + fTmp = calloc(81, sizeof(char)); + + IsDoing("Pack filebase"); + if (!do_quiet) { + colour(3, 0); + printf("Packing file database...\n"); + } + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + die(0); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreas = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + for (i = 1; i <= iAreas; i++) { + + fseek(pAreas, ((i-1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET); + fread(&area, areahdr.recsize, 1, pAreas); + + if (area.Available && !area.CDrom) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + printf("\r%4d => %-44s", i, area.Name); + fflush(stdout); + } + Marker(); + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), i); + sprintf(fTmp, "%s/fdb/fdbtmp.data", getenv("MBSE_ROOT")); + + if ((pFile = fopen(fAreas, "r")) == NULL) { + Syslog('!', "Creating new %s", fAreas); + if ((pFile = fopen(fAreas, "a+")) == NULL) { + WriteError("$Can't create %s", fAreas); + die(0); + } + } + + if ((fp = fopen(fTmp, "a+")) == NULL) { + WriteError("$Can't create %s", fTmp); + die(0); + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + iTotal++; + + if ((!file.Deleted) && (strcmp(file.Name, "") != 0)) { + fwrite(&file, sizeof(file), 1, fp); + } else { + iRemoved++; + Syslog('+', "Removed file \"%s\" from area %d", file.Name, i); + sprintf(fn, "%s/%s", area.Path, file.Name); + Syslog('+', "Unlink %s result %d", fn, unlink(fn)); + /* + * If a dotted version (thumbnail) exists, remove it silently + */ + sprintf(fn, "%s/.%s", area.Path, file.Name); + unlink(fn); + } + } + + fclose(fp); + fclose(pFile); + + if ((rename(fTmp, fAreas)) == 0) { + unlink(fTmp); + chmod(fAreas, 00660); + } + iAreasNew++; + + } /* if area.Available */ + } + + fclose(pAreas); + Syslog('+', "Pack Areas [%5d] Files [%5d] Removed [%5d]", iAreasNew, iTotal, iRemoved); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + free(fTmp); + free(sAreas); + free(fAreas); +} + + diff --git a/mbfido/mbfile.h b/mbfido/mbfile.h new file mode 100644 index 00000000..e6c8e841 --- /dev/null +++ b/mbfido/mbfile.h @@ -0,0 +1,12 @@ +#ifndef _MBFILE_H_ +#define _MBFILE_H + +void Help(void); /* Show help screen */ +void Check(void); /* Check file database */ +void Index(void); /* Index filerquest */ +void Req(void); /* Check symlinks */ +void Kill(void); /* Kill/move old files */ +void PackFileBase(void); /* Pack / Compress File Base */ +void CreateWeb(void); /* Create WWW pages */ +#endif + diff --git a/mbfido/mbindex.c b/mbfido/mbindex.c new file mode 100644 index 00000000..0c4569ac --- /dev/null +++ b/mbfido/mbindex.c @@ -0,0 +1,985 @@ +/***************************************************************************** + * + * File ..................: mbindex.c + * Purpose ...............: Nodelist Compiler + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbftn.h" + + +#define TMPNAME "TMP." +#define LCKNAME "LOCKFILE" + + +typedef struct _nl_list { + struct _nl_list *next; + struct _nlidx idx; +} nl_list; + + +#include "mbindex.h" + + +FILE *ifp, *ufp, *ffp; +long total = 0, entries = 0; +int filenr = 0; +unsigned short regio; +nl_list *nll = NULL; +static char lockfile[81]; + + +extern int do_quiet; /* Quiet flag */ +extern int show_log; /* Show logging on screen */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ + + +/* + * Put a lock on this program. + */ +int lockindex(void) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/", CFG.nodelists); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + WriteError("$Can't create lockfile \"%s\"", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + WriteError("$Can't open lockfile \"%s\"", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + WriteError("$Can't read old pid from \"%s\"", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + Syslog('+', "Stale lock found for pid %u", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + WriteError("$Kill for %u failed",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + Syslog('+', "mbindex already running, pid=%u", oldpid); + if (!do_quiet) + printf("Another mbindex is already running.\n"); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulockindex(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +/* + * If we don't know what to type + */ +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbindex \n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +/* + * Header, only if not quiet. + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBINDEX: MBSE BBS %s Nodelist Index Compiler\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(3, 0); +} + + + +void die(int onsig) +{ + if (onsig && (onsig < NSIG)) + signal(onsig, SIG_IGN); + + ulockindex(); + + if (!do_quiet) { + colour(3, 0); + show_log = TRUE; + } + + if (IsSema((char *)"mbindex")) + RemoveSema((char *)"mbindex"); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBINDEX finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + + ExitClient(onsig); +} + + + +int main(int argc,char *argv[]) +{ + int i, rc; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + InitFidonet(); + TermInit(1); + t_start = time(NULL); + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + * Don't listen to SIGTERM. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + cmd = xstrcpy((char *)"Command line: mbindex"); + + if (argc > 2) + Help(); + + if (argc == 2) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[1]); + + if (strncasecmp(argv[1], "-q", 2) == 0) + do_quiet = TRUE; + else + Help(); + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbindex", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBINDEX v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!diskfree(CFG.freespace)) + die(101); + + if (lockindex()) { + if (!do_quiet) + printf("Can't lock mbindex, abort.\n"); + die(104); + } + + rc = nodebld(); + die(rc); + return 0; +} + + + +void tidy_nllist(nl_list **fap) +{ + nl_list *tmp, *old; + + Syslog('S', "tidy_nllist"); + for (tmp = *fap; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fap = NULL; +} + + + +int in_nllist(struct _nlidx idx, nl_list **fap, int replace) +{ + nl_list *tmp; + + Syslog('S', "Seeking nlidx match for %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point); + + for (tmp = *fap; tmp; tmp = tmp->next) + if ((tmp->idx.zone == idx.zone) && (tmp->idx.net == idx.net) && + (tmp->idx.node == idx.node) && (tmp->idx.point == idx.point)) { + Syslog('S', "Match found"); + if (replace) { + tmp->idx = idx; + entries++; + } + regio = tmp->idx.region; + return TRUE; + } + return FALSE; +} + + + +void fill_nllist(struct _nlidx idx, nl_list **fap) +{ + nl_list *tmp; + + Syslog('S', "fill_nllist %u:%u/%u.%u", idx.zone, idx.net, idx.node, idx.point); + tmp = (nl_list *)malloc(sizeof(nl_list)); + tmp->next = *fap; + tmp->idx = idx; + *fap = tmp; + total++; + entries++; +} + + + +char *fullpath(char *fname) +{ + static char path[128]; + + sprintf(path, "%s/%s", CFG.nodelists, fname); + return path; +} + + + +void sort_nllist(nl_list **fap) +{ + nl_list *ta, **vector; + size_t n = 0, i; + + if (*fap == NULL) + return; + + for (ta = *fap; ta; ta = ta->next) + n++; + + vector = (nl_list **)malloc(n * sizeof(nl_list *)); + Syslog('s', "Sorting %d nodelist entries", n); + + i = 0; + for (ta = *fap; ta; ta = ta->next) { + vector[i++] = ta; + Syslog('S', "Before %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point); + } + + qsort(vector, n, sizeof(nl_list *), + (int(*)(const void*, const void *))comp_node); + + (*fap) = vector[0]; + i = 1; + + for (ta = *fap; ta; ta = ta->next) { + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + Syslog('S', "After %u:%u/%u.%u", ta->idx.zone, ta->idx.net, ta->idx.node, ta->idx.point); + } + + free(vector); + return; +} + + + +int comp_node(nl_list **fap1, nl_list **fap2) +{ + if ((*fap1)->idx.zone != (*fap2)->idx.zone) + return ((*fap1)->idx.zone - (*fap2)->idx.zone); + else if ((*fap1)->idx.net != (*fap2)->idx.net) + return ((*fap1)->idx.net - (*fap2)->idx.net); + else if ((*fap1)->idx.node != (*fap2)->idx.node) + return ((*fap1)->idx.node - (*fap2)->idx.node); + else + return ((*fap1)->idx.point - (*fap2)->idx.point); +} + + + +int compile(char *nlname, unsigned short zo, unsigned short ne, unsigned short no) +{ + int num, i, rc = 0; + int lineno, boss = FALSE, bossvalid = FALSE; + unsigned short upnet, upnode; + char buf[256], *p, *q; + faddr *tmpa; + FILE *nl; + struct _nlidx ndx; + struct _nlusr udx; + + rc = 0; + if ((nl = fopen(fullpath(nlname), "r")) == NULL) { + WriteError("$Can't open %s", fullpath(nlname)); + return 102; + } + + Syslog('+', "Compiling \"%s\" (%d)", nlname, filenr); + IsDoing("Compile NL %d", filenr +1); + + memset(&ndx, 0, sizeof(ndx)); + ndx.type = NL_NODE; + ndx.fileno = filenr; + upnet = 0; + upnode = 0; + + /* + * If zone is set, it is a overlay segment + */ + if (zo) { + ndx.zone = zo; + ndx.net = ne; + ndx.node = no; + ndx.point = 0; + } + entries = 0; + lineno = 0; + + while (!feof(nl)) { + + ndx.offset = ftell(nl); + lineno++; + if (fgets(buf, sizeof(buf)-1, nl) == NULL) + continue; + + /* + * Next check at and characters + */ + if ((*(buf+strlen(buf) -1) != '\n') && (*(buf + strlen(buf) -1) != '\012')) { + while (fgets(buf, sizeof(buf) -1, nl) && + (*(buf + strlen(buf) -1) != '\n')) /*void*/; + if (strlen(buf) > 1) /* Suppress EOF character */ + Syslog('s', "Nodelist: too long line junked (%d)", lineno); + continue; + } + + if (*(p=buf+strlen(buf) -1) == '\n') + *p-- = '\0'; + if (*p == '\r') + *p = '\0'; + if ((buf[0] == ';') || (buf[0] == '\032') || (buf[0] == '\0')) + continue; + + if (CFG.slow_util && do_quiet) { + if (zo) { + usleep(1); + } else { + if ((lineno % 40) == 0) + usleep(1); + } + } + + if ((p = strchr(buf, ','))) + *p++ = '\0'; + if ((q = strchr(p, ','))) + *q++ = '\0'; + + ndx.type = NL_NONE; + ndx.pflag = 0; + + if (buf[0] == '\0') { + if (boss) + ndx.type = NL_POINT; + else + ndx.type = NL_NODE; + } else + if (strcasecmp(buf,"Boss") == 0) { + ndx.type = NL_POINT; + bossvalid = FALSE; + if ((tmpa=parsefnode(p)) == NULL) { + WriteError("%s(%u): unparsable Boss addr \"%s\"", + nlname,lineno,p); + continue; + } + boss = TRUE; + if (tmpa->zone) + ndx.zone = tmpa->zone; + ndx.net = tmpa->net; + ndx.node = tmpa->node; + ndx.point = 0; + tidy_faddr(tmpa); + Syslog('S', "Boss %u:%u/%u", ndx.zone, ndx.net, ndx.node); + ndx.type = NL_NONE; + + if (in_nllist(ndx, &nll, FALSE)) { + Syslog('S', "Boss exists"); + bossvalid = TRUE; + } + else + Syslog('S', "Boss not found"); + continue; /* no further processing */ + } else { + boss = FALSE; + ndx.type = NL_NONE; + if (!strcasecmp(buf, "Down")) { + ndx.pflag |= NL_DOWN; + ndx.type = NL_NODE; + } + if (!strcasecmp(buf, "Hold")) { + ndx.pflag |= NL_HOLD; + ndx.type = NL_NODE; + } + if (!strcasecmp(buf, "Pvt")) { + ndx.pflag |= NL_PVT; + ndx.type = NL_NODE; + } + + if (!strcasecmp(buf, "Zone")) + ndx.type = NL_ZONE; + if (!strcasecmp(buf, "Region")) + ndx.type = NL_REGION; + if (!strcasecmp(buf, "Host")) + ndx.type = NL_HOST; + if (!strcasecmp(buf, "Hub")) + ndx.type = NL_HUB; + if (!strcasecmp(buf, "Point")) { + ndx.type = NL_POINT; + bossvalid = TRUE; + } + } + + if (ndx.type == NL_NONE) { + for (q = buf; *q; q++) + if (*q < ' ') + *q='.'; + WriteError("%s(%u): unidentified entry \"%s\"", + nlname, lineno, buf); + continue; + } + + Syslog('S',"Got \"%s\" as \"%s\" typ %d", buf, p, ndx.type); + if ((num=atoi(p)) == 0) { + WriteError("%s(%u): bad numeric \"%s\"", + nlname,lineno,p); + continue; + } + + /* + * now update the current address + */ + switch (ndx.type) { + case NL_REGION: ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = ndx.zone; + ndx.upnode= 0; + ndx.region= num; + upnet = num; + upnode = 0; + break; + case NL_ZONE: ndx.zone = num; + ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = 0; + ndx.upnode= 0; + ndx.region= 0; + upnet = num; + upnode = 0; + break; + case NL_HOST: ndx.net = num; + ndx.node = 0; + ndx.point = 0; + ndx.upnet = ndx.region; + ndx.upnode= 0; + upnet = num; + upnode = 0; + break; + case NL_HUB: ndx.node = num; + ndx.point = 0; + ndx.upnet = ndx.net; + ndx.upnode= 0; + upnet = ndx.net; + upnode = num; + break; + case NL_NODE: ndx.node = num; + ndx.point = 0; + ndx.upnet = upnet; + ndx.upnode= upnode; + break; + case NL_POINT: ndx.point = num; + ndx.upnet = ndx.net; + ndx.upnode= ndx.node; + if ((!ndx.region) && bossvalid) + ndx.region = regio; + break; + } + if (!do_quiet) { + printf("\rZone %-6uRegion %-6uNet %-6uNode %-6uPoint %-6u", + ndx.zone, ndx.region, ndx.net, ndx.node, ndx.point); + fflush(stdout); + } + + memset(&udx, 0, sizeof(udx)); + udx.record = total; + + /* + * Read nodelist line and extract username. + */ + for (i = 0; i < 3; i++) { + p = q; + if (p == NULL) + continue; + if ((q = strchr(p, ','))) + *q++ = '\0'; + } + if (strlen(p) > 35) + p[35] = '\0'; + sprintf(udx.user, "%s", p); + + /* + * Now search for the baudrate field, 300 means it's + * and ISDN or TCP/IP only node which is a special case. + */ + for (i = 0; i < 2; i++) { + p = q; + if (p == NULL) + continue; + if ((q = strchr(p, ','))) + *q++ = '\0'; + } + if ((strlen(p) == 3) && (!strcmp(p, "300"))) { + if ((strstr(q, (char *)"X75")) || + (strstr(q, (char *)"V110L")) || + (strstr(q, (char *)"V110H")) || + (strstr(q, (char *)"V120L")) || + (strstr(q, (char *)"V120H")) || + (strstr(q, (char *)"ISDN"))) + ndx.pflag |= NL_ISDN; + if ((strstr(q, (char *)"IFC")) || + (strstr(q, (char *)"IBN")) || + (strstr(q, (char *)"ITN")) || + (strstr(q, (char *)"IVM")) || + (strstr(q, (char *)"IFT")) || + (strstr(q, (char *)"IP"))) + ndx.pflag |= NL_TCPIP; + } + + Syslog('S',"put: %u:%u/%u.%u reg %u upl %u/%u typ %u flg %02X as (%u,%lu)", + ndx.zone,ndx.net,ndx.node, + ndx.point,ndx.region,ndx.upnet,ndx.upnode, + ndx.type,ndx.pflag,ndx.fileno,ndx.offset); + + + /* + * If zone, net and node given, then this list is an + * overlay so we will call in_list() to replace the + * existing records, or append them if they don't exist. + * Also, only points with a valid boss will be added. + */ + if (zo) { + if (!(in_nllist(ndx, &nll, TRUE))) { + if (ndx.point && bossvalid) { + fill_nllist(ndx, &nll); + Syslog('S', "Add point %u:%u/%u.%u", ndx.zone, ndx.net, ndx.node, ndx.point); + } + if (!ndx.point) + fill_nllist(ndx, &nll); + } + } else + fill_nllist(ndx, &nll); + } + + Syslog('+', "%d entries", entries); + + if (!do_quiet) { + printf(" %ld entries\n", entries); + fflush(stdout); + } + + return rc; +} + + + +/* + * Tidy the filearray + */ +void tidy_fdlist(fd_list **fdp) +{ + fd_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a file on the array. + */ +void fill_fdlist(fd_list **fdp, char *filename, time_t filedate) +{ + fd_list *tmp; + + tmp = (fd_list *)malloc(sizeof(fd_list)); + tmp->next = *fdp; + sprintf(tmp->fname, "%s", filename); + tmp->fdate = filedate; + *fdp = tmp; +} + + + +int compfdate(fd_list **, fd_list **); + + +/* + * Sort the array of files by filedate + */ +void sort_fdlist(fd_list **fdp) +{ + fd_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) { + return; + } + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (fd_list **)malloc(n * sizeof(fd_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(fd_list*), (int(*)(const void*, const void*))compfdate); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compfdate(fd_list **fdp1, fd_list **fdp2) +{ + return ((*fdp1)->fdate - (*fdp2)->fdate); +} + + + +/* + * Return the name of the oldest file in the array + */ +char *pull_fdlist(fd_list **fdp) +{ + static char buf[65]; + fd_list *ta; + + if (*fdp == NULL) + return NULL; + + ta = *fdp; + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "%s", ta->fname); + + if (ta->next != NULL) + *fdp = ta->next; + else + *fdp = NULL; + + free(ta); + return buf; +} + + + +int makelist(char *base, unsigned short zo, unsigned short ne, unsigned short no) +{ + int rc = 0, files = 0; + struct dirent *de; + DIR *dp; + char *p = NULL, *q; + struct _nlfil fdx; + fd_list *fdl = NULL; + + if (!strlen(base)) { + WriteError("Error, no nodelist defined for %d:%d/%d", zo, ne, no); + return 0; + } + + if ((dp = opendir(CFG.nodelists)) == NULL) { + WriteError("$Can't open dir %s", CFG.nodelists); + rc = 103; + } else { + while ((de = readdir(dp))) + if (strncmp(de->d_name, base, strlen(base)) == 0) { + /* + * Extension must be at least 2 digits + */ + q = (de->d_name) + strlen(base); + if ((*q == '.') && (strlen(q) > 2) && + (strspn(q+1,"0123456789") == (strlen(q)-1))) { + /* + * Add matched filenames to the array + */ + fill_fdlist(&fdl, de->d_name, file_time(fullpath(de->d_name))); + files++; + } + } + closedir(dp); + + if (files == 0) { + Syslog('+', "No nodelist found for %s", base); + return 103; + } + + /* + * Sort found nodelists by age and kill all but the newest 2. + */ + sort_fdlist(&fdl); + while (files) { + p = pull_fdlist(&fdl); + if (files > 2) { + Syslog('+', "Remove old \"%s\"", p); + unlink(fullpath(p)); + } + files--; + } + tidy_fdlist(&fdl); + + memset(&fdx, 0, sizeof(fdx)); + sprintf(fdx.filename, "%s", p); + sprintf(fdx.domain, "%s", fidonet.domain); + fdx.number = filenr; + fwrite(&fdx, sizeof(fdx), 1, ffp); + + rc = compile(p, zo, ne, no); + filenr++; + } + + return rc; +} + + + +int nodebld(void) +{ + int rc = 0, i; + char *im, *fm, *um, *old, *new; + struct _nlfil fdx; + FILE *fp; + nl_list *tmp; + + memset(&fdx, 0, sizeof(fdx)); + im = xstrcpy(fullpath((char *)"temp.index")); + fm = xstrcpy(fullpath((char *)"temp.files")); + um = xstrcpy(fullpath((char *)"temp.users")); + + if ((ifp = fopen(im, "w+")) == NULL) { + WriteError("$Can't create %s",MBSE_SS(im)); + return 101; + } + if ((ufp = fopen(um, "w+")) == NULL) { + WriteError("$Can't create %s", MBSE_SS(um)); + fclose(ifp); + unlink(im); + return 101; + } + if ((ffp = fopen(fm, "w+")) == NULL) { + WriteError("$Can't create %s", MBSE_SS(fm)); + fclose(ifp); + unlink(im); + fclose(ufp); + unlink(um); + return 101; + } + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if ((fp = fopen(fidonet_fil, "r")) == 0) + rc = 102; + else { + fread(&fidonethdr, sizeof(fidonethdr), 1, fp); + + while (fread(&fidonet, fidonethdr.recsize, 1, fp) == 1) { + if (fidonet.available) { + rc = makelist(fidonet.nodelist, 0, 0, 0); + if (rc) + break; + + for (i = 0; i < 6; i++) { + if (fidonet.seclist[i].zone) { + rc = makelist(fidonet.seclist[i].nodelist, + fidonet.seclist[i].zone, + fidonet.seclist[i].net, + fidonet.seclist[i].node); + if (rc) + break; + } + } + if (rc) + break; + } + } + + fclose(fp); + } + + fclose(ufp); + fclose(ffp); + + if (rc == 0) { + IsDoing("Sorting nodes"); + sort_nllist(&nll); + + IsDoing("Writing files"); + for (tmp = nll; tmp; tmp = tmp->next) + fwrite(&tmp->idx, sizeof(struct _nlidx), 1, ifp); + fclose(ifp); + + Syslog('+', "Compiled %d entries", total); + + /* + * Rename existing files to old.*, they stay on disk in + * case they are open by some program. The temp.* files + * are then renamed to node.* + */ + old = xstrcpy(fullpath((char *)"old.index")); + new = xstrcpy(fullpath((char *)"node.index")); + unlink(old); + rename(new, old); + rename(im, new); + free(old); + free(new); + old = xstrcpy(fullpath((char *)"old.users")); + new = xstrcpy(fullpath((char *)"node.users")); + unlink(old); + rename(new, old); + rename(um, new); + free(old); + free(new); + old = xstrcpy(fullpath((char *)"old.files")); + new = xstrcpy(fullpath((char *)"node.files")); + unlink(old); + rename(new, old); + rename(fm, new); + free(old); + free(new); + } else { + fclose(ifp); + Syslog('+', "Compile failed, rc=%d", rc); + unlink(im); + unlink(fm); + unlink(um); + } + + free(im); + free(fm); + free(um); + tidy_nllist(&nll); + + return rc; +} + + + diff --git a/mbfido/mbindex.h b/mbfido/mbindex.h new file mode 100644 index 00000000..917d30d8 --- /dev/null +++ b/mbfido/mbindex.h @@ -0,0 +1,31 @@ +#ifndef _MBINDEX_H +#define _MBINDEX_H + + +typedef struct _fd_list { + struct _fd_list *next; + char fname[65]; + time_t fdate; +} fd_list; + + +int lockindex(void); +void ulockindex(void); +void Help(void); +void ProgName(void); +void die(int); +char *fullpath(char *); +int compile(char *, unsigned short, unsigned short, unsigned short); +void tidy_fdlist(fd_list **); +void fill_fdlist(fd_list **, char *, time_t); +void sort_fdlist(fd_list **); +char *pull_fdlist(fd_list **); +int makelist(char *, unsigned short, unsigned short, unsigned short); +void tidy_nllist(nl_list **); +int in_nllist(struct _nlidx, nl_list **, int); +void fill_nllist(struct _nlidx, nl_list **); +int comp_node(nl_list **, nl_list **); +int nodebld(void); + +#endif + diff --git a/mbfido/mbmail.c b/mbfido/mbmail.c new file mode 100644 index 00000000..8fe56431 --- /dev/null +++ b/mbfido/mbmail.c @@ -0,0 +1,418 @@ +/***************************************************************************** + * + * File ..................: mbmail/mbmail.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 28-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbftn.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/dbuser.h" +#include "hash.h" +#include "mkftnhdr.h" +#include "message.h" + + +/* ### Modified by P.Saratxaga on 9 Aug 1995 ### + * - added a line so if fmsg->to->name is greater than MAXNAME (35), + * and "@" or "%" or "!" is in it; then UUCP is used instead. So we can + * send messages to old style fido->email gates (that is, using another + * soft than mbmail ;-) ) with long adresses. + */ + +extern int most_debug; +extern int addrerror; +extern int defaultrfcchar; +extern int defaultftnchar; +extern int do_quiet; /* Quiet flag */ +extern int e_pid; /* Pid of child process */ +extern int show_log; /* Show logging on screen */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +extern int usetmp; +int pgpsigned; +extern char *configname; +extern char passwd[]; +int net_in = 0, net_imp = 0, net_out = 0, net_bad = 0; +int dirtyoutcode = CHRS_NOTSET; + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBMAIL: MBSE BBS %s - Internet Fidonet mail gate\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbmail -r -g ...\n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" -r address to route packet\n"); + printf(" -g [ n | c | h ] \"flavor\" of packet\n"); + printf(" -c force the given charset\n"); + printf(" list of receipient addresses\n"); + colour(7, 0); + ExitClient(0); +} + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty. + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (!do_quiet) { + show_log = TRUE; + colour(3, 0); + } + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + Syslog('+', "Msgs in [%4d] imp [%4d] out [%4d] bad [%4d]", net_in, net_imp, net_out, net_bad); + + if (net_out) + CreateSema((char *)"scanout"); + + + time(&t_end); + Syslog(' ', "MBMAIL finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + ExitClient(onsig); +} + + + +int main(int argc, char *argv[]) +{ + char *cmd, *envptr; + struct passwd *pw; + int i, c, rc; + char *routec = NULL; + faddr *route = NULL; + char *p; + char buf[BUFSIZ]; + FILE *fp; + fa_list **envrecip, *envrecip_start = NULL; + int envrecip_count = 0; + rfcmsg *msg=NULL; + ftnmsg *fmsg=NULL; + faddr *taddr; + char cflavor = '\0', flavor; + fa_list *sbl = NULL; + int incode, outcode; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * The next trick is to supply a fake environment variable + * MBSE_ROOT in case we are started from the MTA. + * Some MTA's can't change uid to mbse, so if that's the + * case we will try it ourself. + * This will setup the variable so InitConfig() will work. + * The /etc/passwd must point to the correct homedirectory. + */ + pw = getpwuid(getuid()); + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwuid(getuid()); + if (strcmp(pw->pw_name, "mbse")) { + /* + * We are not running as user mbse. + */ + pw = getpwnam("mbse"); + if (setuid(pw->pw_uid)) { + printf("Fatal error: can't set uid to user mbse\n"); + } + } + envptr = xstrcpy((char *)"MBSE_ROOT="); + envptr = xstrcat(envptr, pw->pw_dir); + putenv(envptr); + } + + do_quiet = TRUE; + InitConfig(); + InitFidonet(); + InitNode(); + InitMsgs(); + InitUser(); + TermInit(1); + time(&t_start); + umask(002); + + /* + * Catch all the signals we can, and ignore the rest. + */ + for(i = 0; i < NSIG; i++) { + + if ((i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Cmd line: mbmail"); + + while ((c = getopt(argc, argv, "g:r:c:h")) != -1) { + cmd = xstrcat(cmd, (char *)" - "); + cmd[strlen(cmd) -1] = c; + switch (c) { + case 'h': Help(); + case 'g': if (optarg && ((*optarg == 'n') || (*optarg == 'c') || (*optarg == 'h'))) { + cflavor = *optarg; + cmd = xstrcat(cmd, optarg); + } else { + Help(); + } + break; + case 'r': routec = optarg; cmd = xstrcat(cmd, optarg); break; + case 'c': dirtyoutcode = readchrs(optarg); + cmd = xstrcat(cmd, optarg); + if (dirtyoutcode == CHRS_NOTSET) + dirtyoutcode = getcode(optarg); + break; + default: Help(); + } + } + + ProgName(); + InitClient(pw->pw_name, (char *)"mbmail", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBMAIL v%s", VERSION); + most_debug = TRUE; + + if (!diskfree(CFG.freespace)) + die(101); + + + if (cflavor == 'n') + cflavor='o'; + + if ((routec) && ((route=parsefaddr(routec)) == NULL)) + WriteError("unparsable route address \"%s\" (%s)", MBSE_SS(routec),addrerrstr(addrerror)); + + if ((p=strrchr(argv[0],'/'))) + p++; + else + p=argv[0]; + + envrecip = &envrecip_start; + while (argv[optind]) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[optind]); + if ((taddr = parsefaddr(argv[optind++]))) { + (*envrecip)=(fa_list*)malloc(sizeof(fa_list)); + (*envrecip)->next=NULL; + (*envrecip)->addr=taddr; + envrecip=&((*envrecip)->next); + envrecip_count++; + } else + WriteError("unparsable recipient \"%s\" (%s), ignored", argv[optind-1], addrerrstr(addrerror)); + } + Syslog(' ', cmd); + free(cmd); + + if (!envrecip_count) { + WriteError("No valid receipients specified, aborting"); + die(105); + } + + for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) + Syslog('+', "envrecip: %s",ascfnode((*envrecip)->addr,0x7f)); + Syslog('+', "route: %s",ascfnode(route,0x1f)); + + umask(066); /* packets may contain confidential information */ + + while (!feof(stdin)) { + usetmp = 0; + tidyrfc(msg); + msg = parsrfc(stdin); + + incode = outcode = CHRS_NOTSET; + pgpsigned = 0; + + p = hdr((char *)"Content-Type",msg); + if (p) + incode = readcharset(p); + if (incode == CHRS_NOTSET) { + p = hdr((char *)"X-FTN-CHRS",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CHARSET",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CODEPAGE",msg); + if (p) + incode = readchrs(p); + if ((p = hdr((char *)"Message-ID",msg)) && (chkftnmsgid(p))) + incode = defaultftnchar; + else + incode = defaultrfcchar; + } + if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p, (char *)"multipart/signed")) || + (strcasestr(p,(char *)"application/pgp")))) { + pgpsigned = 1; + outcode = incode; + } else if ((p=hdr((char *)"X-FTN-ORIGCHRS",msg))) + outcode = readchrs(p); + else if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + else + outcode = getoutcode(incode); + + flavor = cflavor; + + if ((p = hdr((char *)"X-FTN-FLAGS",msg))) { + if (!flavor) { + if (flag_on((char *)"CRS",p)) + flavor = 'c'; + else if (flag_on((char *)"HLD",p)) + flavor = 'h'; + else + flavor = 'o'; + } + if (flag_on((char *)"ATT",p)) + attach(*route, hdr((char *)"Subject",msg), 0, flavor); + if (flag_on((char *)"TFS",p)) + attach(*route, hdr((char *)"Subject",msg), 1, flavor); + if (flag_on((char *)"KFS",p)) + attach(*route, hdr((char *)"Subject",msg), 2, flavor); + } + if ((!flavor) && ((p = hdr((char *)"Priority",msg)) || + (p = hdr((char *)"Precedence",msg)) || (p = hdr((char *)"X-Class",msg)))) { + while (isspace(*p)) + p++; + if ((strncasecmp(p,"fast",4) == 0) || (strncasecmp(p,"high",4) == 0) || + (strncasecmp(p,"crash",5) == 0) || (strncasecmp(p,"airmail",5) == 0) || + (strncasecmp(p,"special-delivery",5) == 0) || (strncasecmp(p,"first-class",5) == 0)) + flavor='c'; + else if ((strncasecmp(p,"slow",4) == 0) || (strncasecmp(p,"low",3) == 0) || + (strncasecmp(p,"hold",4) == 0) || (strncasecmp(p,"news",4) == 0) || + (strncasecmp(p,"bulk",4) == 0) || (strncasecmp(p,"junk",4) == 0)) + flavor='h'; + } + if (!flavor) + flavor='o'; + + if (envrecip_count > 1) { + if ((fp = tmpfile()) == NULL) { + WriteError("$Cannot open temporary file"); + die(102); + } + while (bgets(buf, sizeof(buf)-1, stdin)) + fputs(buf, fp); + rewind(fp); + usetmp = 1; + } else { + fp = stdin; + usetmp = 0; + } + + tidy_ftnmsg(fmsg); + if ((fmsg = mkftnhdr(msg, incode, outcode, FALSE)) == NULL) { + WriteError("Unable to create FTN headers from RFC ones, aborting"); + die(103); + } + + for (envrecip = &envrecip_start; *envrecip; envrecip = &((*envrecip)->next)) { + fmsg->to = (*envrecip)->addr; + if ((!fmsg->to->name) || ((strlen(fmsg->to->name) > MAXNAME) + && ((strstr(fmsg->to->name,"@")) || (strstr(fmsg->to->name,"%")) + || (strstr(fmsg->to->name,"!"))))) + fmsg->to->name = (char *)"UUCP"; + rc = putmessage(msg, fmsg, fp, route, flavor, &sbl, incode, outcode); + if (rc == 1) { + WriteError("Unable to put netmail message into the packet, aborting"); + die(104); + } + if (rc == 2) { + WriteError("Unable to import netmail messages into the messabe base"); + die(105); + } + if (usetmp) + rewind(fp); + fmsg->to = NULL; + } + net_in++; + if (usetmp) + fclose(fp); + } + + closepkt(); + die(0); + return 0; +} + diff --git a/mbfido/mbmail.h b/mbfido/mbmail.h new file mode 100644 index 00000000..c4b0273a --- /dev/null +++ b/mbfido/mbmail.h @@ -0,0 +1,6 @@ +#ifndef _MBMAIL_H +#define _MBMAIL_H + + +#endif + diff --git a/mbfido/mbmsg.c b/mbfido/mbmsg.c new file mode 100644 index 00000000..9d6256f9 --- /dev/null +++ b/mbfido/mbmsg.c @@ -0,0 +1,702 @@ +/***************************************************************************** + * + * File ..................: mbmsg/mbmsg.c + * Purpose ...............: Message Base Maintenance + * Last modification date : 27-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/dbcfg.h" +#include "post.h" +#include "mbmsg.h" + + + +int do_pack = FALSE; /* Pack flag */ +int do_kill = FALSE; /* Kill flag (age and maxmsgs) */ +int do_index = FALSE; /* Index flag */ +int do_link = FALSE; /* Link messages */ +int do_post = FALSE; /* Post a Message */ +extern int do_quiet; /* Quiet flag */ +extern int show_log; /* Show loglines */ +long do_area = 0; /* Do only one area */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int are_tot = 0; /* Total areas */ +int are_proc = 0; /* Areas processed */ +int msg_tot = 0; /* Total messages */ +int msg_del = 0; /* Deleted messages */ +int msg_link = 0; /* Linked messages */ +int processed = FALSE; /* Did process something */ +int oldmask; + + + + +/* + * Header, only if not quiet + */ +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBMSG: MBSE BBS %s - Message Base Maintenance Utility\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(7, 0); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd, *too = NULL, *subj = NULL, *mfile = NULL, *flavor = NULL; + struct passwd *pw; + long tarea = 0; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + oldmask = umask(007); + time(&t_start); + + /* + * Catch all signals we can, and ignore or catch them + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Cmd:"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (strncasecmp(argv[i], "i", 1) == 0) + do_index = TRUE; + if (strncasecmp(argv[i], "l", 1) == 0) + do_link = TRUE; + if (strncasecmp(argv[i], "k", 1) == 0) + do_kill = TRUE; + if (strncasecmp(argv[i], "pa", 2) == 0) + do_pack = TRUE; + if (strncasecmp(argv[i], "po", 2) == 0) { + do_post = TRUE; + too = argv[++i]; + cmd = xstrcat(cmd, (char *)" \""); + cmd = xstrcat(cmd, too); + tarea = atoi(argv[++i]); + cmd = xstrcat(cmd, (char *)"\" "); + cmd = xstrcat(cmd, argv[i]); + subj = argv[++i]; + cmd = xstrcat(cmd, (char *)" \""); + cmd = xstrcat(cmd, subj); + mfile = argv[++i]; + cmd = xstrcat(cmd, (char *)"\" "); + cmd = xstrcat(cmd, mfile); + flavor = argv[++i]; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, flavor); + } + if (strncasecmp(argv[i], "-a", 2) == 0) { + i++; + do_area = atoi(argv[i]); + } + if (strncasecmp(argv[i], "-q", 2) == 0) + do_quiet = TRUE; + } + + if (!(do_index || do_link || do_kill || do_pack || do_post)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbmsg", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBMSG v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + printf("\n"); + colour(3, 0); + } + + if (do_index || do_link || do_kill || do_pack) { + memset(&MsgBase, 0, sizeof(MsgBase)); + DoMsgBase(); + } + + if (do_post) { + Post(too, tarea, subj, mfile, flavor); + } + + die(0); + return 0; +} + + + +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(12, 0); + printf("\n Usage: mbmsg [command(s)] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); +// printf(" i index Create new index files\n"); + printf(" l link Link messages by subject\n"); + printf(" k kill Kill messages (age & count)\n"); + printf(" pa pack Pack deleted messages\n"); + printf(" po post <#> Post file in message area #\n\n"); + colour(9, 0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -a -area <#> Process area <#> only\n"); + printf(" -q -quiet Quiet mode\n"); + + printf("\n"); + die(0); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + if (!do_quiet) { + printf("\r"); + colour(3, 0); + } + + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + if (onsig == SIGSEGV) + Syslog('+', "Last msg area %s", msgs.Name); + + if (are_tot || are_proc || msg_link) + Syslog('+', "Areas [%5d] Processed [%5d] Linked [%5d]", are_tot, are_proc, msg_link); + if (msg_tot || msg_del) + Syslog('+', "Msgs [%5d] Deleted [%5d]", msg_tot, msg_del); + + time(&t_end); + Syslog(' ', "MBMSG finished in %s", t_elapsed(t_start, t_end)); + + umask(oldmask); + if (!do_quiet) { + colour(7, 0); + printf("\r \n"); + } + ExitClient(onsig); +} + + + +void DoMsgBase() +{ + FILE *pAreas; + char *sAreas, *Name; + long arearec; + int Del = 0; + + sAreas = calloc(81, sizeof(char)); + Name = calloc(81, sizeof(char )); + + IsDoing("Msg Maintenance"); + + if (do_area) + Syslog('+', "Processing message area %ld", do_area); + else + Syslog('+', "Processing all message areas"); + + if (do_kill) { + Syslog('-', " Total Max. Days/Killed Max. Age/Killed Area name"); + Syslog('-', "------ ------ ------ ------ ------ ----------------------------------"); + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + die(SIGILL); + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + if (do_area) { + if (fseek(pAreas, (msgshdr.recsize + msgshdr.syssize) * (do_area - 1), SEEK_CUR) == 0) { + fread(&msgs, msgshdr.recsize, 1, pAreas); + if (msgs.Active) { + + if (!diskfree(CFG.freespace)) + die(101); + + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", do_area, msgs.Name); + fflush(stdout); + } + are_tot++; + if (do_kill) + KillArea(msgs.Base, msgs.Name, msgs.DaysOld, msgs.MaxMsgs); + if (do_pack || msg_del) + PackArea(msgs.Base); + if (do_index) + IndexArea(msgs.Base); + if (do_link) + LinkArea(msgs.Base); + if (processed) + are_proc++; + } + } + } else { + arearec = 0; + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + arearec++; + if (msgs.Active) { + + if (!diskfree(CFG.freespace)) + die(101); + + Nopper(); + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", arearec, msgs.Name); + fflush(stdout); + } + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(msgs.Base, msgs.Name, msgs.DaysOld, msgs.MaxMsgs); + if (do_pack || (Del != msg_del)) { + PackArea(msgs.Base); + } + Del = msg_del; + if (do_index) + IndexArea(msgs.Base); + if (do_link) + LinkArea(msgs.Base); + if (processed) + are_proc++; + } + } + } + fclose(pAreas); + + if (!do_area) { + sprintf(sAreas, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + die(SIGILL); + } + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pAreas); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pAreas) == 1) { + if (usrconfig.Email && strlen(usrconfig.Name)) { + Nopper(); + sprintf(Name, "User %s email area: mailbox", usrconfig.Name); + if (!do_quiet) { + colour(3, 0); + printf("\r .. %-40s", Name); + fflush(stdout); + } + sprintf(sAreas, "%s/%s/mailbox", CFG.bbs_usersdir, usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, 0, CFG.defmsgs); + if (do_pack || (Del != msg_del)) { + PackArea(sAreas); + } + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + sprintf(sAreas, "%s/%s/archive", CFG.bbs_usersdir, usrconfig.Name); + sprintf(Name, "User %s email area: archive", usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, 0, CFG.defmsgs); + if (do_pack || (Del != msg_del)) + PackArea(sAreas); + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + sprintf(sAreas, "%s/%s/trash", CFG.bbs_usersdir, usrconfig.Name); + sprintf(Name, "User %s email area: trash", usrconfig.Name); + are_tot++; + processed = FALSE; + if (do_kill) + KillArea(sAreas, Name, CFG.defdays, CFG.defmsgs); + if (do_pack || (Del != msg_del)) + PackArea(sAreas); + Del = msg_del; + if (do_index) + IndexArea(sAreas); + if (do_link) + LinkArea(sAreas); + if (processed) + are_proc++; + + } + } + + fclose(pAreas); + } + + if (do_link) + RemoveSema((char *)"msglink"); + + free(sAreas); + free(Name); + die(0); +} + + + +typedef struct { + unsigned long Subject; + unsigned long Number; +} MSGLINK; + + + +void LinkArea(char *Path) +{ + int i, m; + unsigned long Number, Prev, Next, Crc, Total; + char Temp[128], *p; + MSGLINK *Link; + + IsDoing("Linking"); + + if (Msg_Open(Path)) { + if (!do_quiet) { + colour(12, 0); + printf(" (linking)"); + colour(13, 0); + fflush(stdout); + } + + if ((Total = Msg_Number()) != 0L) { + if (Msg_Lock(30L)) { + if ((Link = (MSGLINK *)malloc(Total * sizeof(MSGLINK))) != NULL) { + memset(Link, 0, Total * sizeof(MSGLINK)); + Number = Msg_Lowest(); + i = 0; + do { + Msg_ReadHeader(Number); + strcpy(Temp, Msg.Subject); + p = strupr(Temp); + if (!strncmp(p, "RE:", 3)) { + p += 3; + if (*p == ' ') + p++; + } + Link[i].Subject = StringCRC32(p); + Link[i].Number = Number; + i++; + + if (CFG.slow_util && do_quiet && ((i % 5) == 0)) + usleep(1); + + if (((i % 10) == 0) && (!do_quiet)) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + } while(Msg_Next(&Number) == TRUE); + + if (!do_quiet) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + Number = Msg_Lowest(); + i = 0; + do { + Msg_ReadHeader(Number); + Prev = Next = 0; + Crc = Link[i].Subject; + + for (m = 0; m < Total; m++) { + if (m == i) + continue; + if (Link[m].Subject == Crc) { + if (m < i) + Prev = Link[m].Number; + else if (m > i) { + Next = Link[m].Number; + break; + } + } + } + + if (CFG.slow_util && do_quiet && ((i % 5) == 0)) + usleep(1); + + if (((i % 10) == 0) && (!do_quiet)) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + if (Msg.Original != Prev || Msg.Reply != Next) { + Msg.Original = Prev; + Msg.Reply = Next; + Msg_WriteHeader(Number); + processed = TRUE; + msg_link++; + } + + i++; + } while(Msg_Next(&Number) == TRUE); + + if (!do_quiet) { + printf("%6d / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", i, Total); + fflush(stdout); + } + + free(Link); + } + + if (!do_quiet) { + printf(" \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + Msg_UnLock(); + } else { + Syslog('+', "Can't lock %s", Path); + } + } + + Msg_Close(); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } +} + + + +/* + * Kill messages according to age and max messages. + */ +void KillArea(char *Path, char *Name, int DaysOld, int MaxMsgs) +{ + unsigned long Number, TotalMsgs = 0, Highest, *Active, Counter = 0; + int i, DelCount = 0, DelAge = 0, Done; + time_t Today, MsgDate; + + IsDoing("Killing"); + Today = time(NULL) / 86400L; + + if (Msg_Open(Path)) { + + if (!do_quiet) { + colour(12, 0); + printf(" (Killing)"); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Lock(30L)) { + + TotalMsgs = Msg_Number(); + + if (TotalMsgs) { + if ((Active = (unsigned long *)malloc((size_t)((TotalMsgs + 100L) * sizeof(unsigned long)))) != NULL) { + i = 0; + Number = Msg_Lowest(); + do { + Active[i++] = Number; + } while (Msg_Next(&Number) == TRUE); + } + } else + Active = NULL; + + Number = Msg_Lowest(); + Highest = Msg_Highest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if ((!do_quiet) && ((Counter % 10L) == 0)) { + printf("%6lu / %6lu\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", Counter, TotalMsgs); + fflush(stdout); + } + if ((Counter % 10L) == 0) + DoNop(); + + Counter++; + msg_tot++; + + if (Msg_ReadHeader(Number) == TRUE) { + Done = FALSE; + if (DaysOld) { + /* + * GoldED doesn't fill the Msg.Arrived field, use the + * written date instead. + */ + if (Msg.Arrived == 0L) + MsgDate = Msg.Written / 86400L; + else + MsgDate = Msg.Arrived / 86400L; + + if ((Today - MsgDate) > DaysOld) { + Msg_Delete(Number); + Done = TRUE; + DelAge++; + msg_del++; + if (Active != NULL) { + for (i = 0; i < TotalMsgs; i++) { + if (Active[i] == Number) + Active[i] = 0L; + } + } + } + } + + if (Done == FALSE && (MaxMsgs) && Msg_Number() > MaxMsgs) { + Msg_Delete(Number); + DelCount++; + msg_del++; + if (Active != NULL) { + for (i = 0; i < TotalMsgs; i++) { + if (Active[i] == Number) + Active[i] = 0L; + } + } + } + } + } while (Msg_Next(&Number) == TRUE); + + if (Active != NULL) + free(Active); + Msg_UnLock(); + } else { + Syslog('+', "Can't lock msgbase %s", Path); + } + + if (!do_quiet) { + printf(" \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + Msg_Close(); + Syslog('-', "%6d %6d %6d %6d %6d %s", TotalMsgs, DaysOld, DelAge, MaxMsgs, DelCount, Name); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } else + Syslog('+', "Failed to open %s", Path); +} + + + +void IndexArea(char *Path) +{ +} + + + +/* + * Pack message area if there are deleted messages. + */ +void PackArea(char *Path) +{ + IsDoing("Packing"); + if (Msg_Open(Path)) { + + if (!do_quiet) { + colour(12, 0); + printf(" (Packing)"); + fflush(stdout); + } + + if (Msg_Lock(30L)) { + Msg_Pack(); + Msg_UnLock(); + } else + Syslog('+', "Can't lock %s", Path); + + Msg_Close(); + + if (!do_quiet) { + printf("\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + } + + if (CFG.slow_util && do_quiet) + usleep(1); +} + + diff --git a/mbfido/mbmsg.h b/mbfido/mbmsg.h new file mode 100644 index 00000000..45f12989 --- /dev/null +++ b/mbfido/mbmsg.h @@ -0,0 +1,14 @@ +#ifndef _MBMSG_H +#define _MBMSG_H + +void ProgName(void); +void Help(void); +void die(int); +void DoMsgBase(void); +void PackArea(char *); +void LinkArea(char *); +void IndexArea(char *); +void KillArea(char *, char *, int, int); + +#endif + diff --git a/mbfido/mbseq.c b/mbfido/mbseq.c new file mode 100644 index 00000000..d3cbe0ba --- /dev/null +++ b/mbfido/mbseq.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * File ..................: mbfido/mbseq.c + * Purpose ...............: give a hexadecimal sequence to stdout + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbseq.h" + + + +int main(int argc, char **argv) +{ + struct passwd *pw; + unsigned long seq; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + + pw = getpwuid(getuid()); + + InitClient(pw->pw_name, (char *)"mbseq", CFG.location, + CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBSEQ v%s", VERSION); + + seq = sequencer(); + Syslog('+', "Sequence string %08lx", seq); + printf("%08lx", seq); + fflush(stdout); + + Syslog(' ', "MBSEQ finished"); + ExitClient(0); + return 0; +} + + + diff --git a/mbfido/mbseq.h b/mbfido/mbseq.h new file mode 100644 index 00000000..4b1ccc43 --- /dev/null +++ b/mbfido/mbseq.h @@ -0,0 +1,6 @@ +#ifndef _MBSEQ_H +#define _MBSEQ_H + + +#endif + diff --git a/mbfido/message.c b/mbfido/message.c new file mode 100644 index 00000000..7c8e4123 --- /dev/null +++ b/mbfido/message.c @@ -0,0 +1,882 @@ +/***************************************************************************** + * + * File ..................: mbmail/message.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 02-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/dbuser.h" + + +/* ### Modified by P.Saratxaga on 7 Aug 1995 ### + * - Newsgroups: line is now gated if there is more than one newsgroup + * - Added support for X-FTN-To and X-FTN-From generated by other gates + * - modified removemime to kludgerise lines if charset != us-ascii + * - creation of ^aACUPDATE kludges from Supersedes: and cancel's + * - added charset support (see Changelog for details) + * - added recognition of X-Fsc- + * - added support to dequote MIME quoted printable messages. Code by T.Tanaka + * - added removemsgid and removeinreply + */ +#include "bread.h" +#include "bwrite.h" +#include "hash.h" +#include "mkftnhdr.h" +#include "tracker.h" +#include "viadate.h" +#include "importnet.h" + + +#define MAXHDRSIZE 2048 +#define MAXSEEN 70 +#define MAXPATH 73 + + +extern time_t now; +extern char *replyaddr; +extern faddr *bestaka; +extern int pgpsigned; +extern int net_bad; +extern int net_out; +extern char *ftnmsgidstyle; + + +char *subj; +char *localdomain=NULL; +static int removemime; +static int removeorg; +static int removemsgid; +static int removeref; +static int removeinreply; +static int removesupersedes; +static int removeapproved; +static int removefrom; +static int removereplyto; +static int removereturnto; +static int ftnorigin; + + +void StatAdd(statcnt *S, unsigned long V) +{ + S->total += V; + S->tweek += V; + S->tdow[Diw] += V; + S->month[Miy] += V; +} + + +int needputrfc(rfcmsg *msg) +{ + faddr *ta; + + /* 0-junk, 1-kludge, 2-pass */ + + if (!strcasecmp(msg->key,"X-UUCP-From")) + return 0; + if (!strcasecmp(msg->key,"X-Body-Start")) + return 0; + if (!strncasecmp(msg->key,".",1)) + return 0; + if (!strncasecmp(msg->key,"X-FTN-",6)) + return 0; + if (!strncasecmp(msg->key,"X-Fsc-",6)) + return 0; + if (!strncasecmp(msg->key,"X-ZC-",5)) + return 0; + if (!strcasecmp(msg->key,"X-Gateway")) + return 0; + if (!strcasecmp(msg->key,"Path")) + return 0; + if (!strcasecmp(msg->key,"Newsgroups")) { + if ((hdr((char *)"X-Origin-Newsgroups",msg))) + return 0; + else + return 1; + } + if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) { + return 1; + } + if (!strcasecmp(msg->key,"Control")) { + if (CFG.allowcontrol) { + if (strstr(msg->val,"cancel")) + return 1; + else + return 0; + } else + return 0; + } + if (!strcasecmp(msg->key,"Return-Path")) + return 1; + if (!strcasecmp(msg->key,"Xref")) + return 0; + if (!strcasecmp(msg->key,"Approved")) + return removeapproved ?0:2; + if (!strcasecmp(msg->key,"X-URL")) + return 0; + if (!strcasecmp(msg->key,"Return-Receipt-To")) + return removereturnto ?0:1; + if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) + return 0; + if (!strcasecmp(msg->key,"Received")) { + return ftnorigin ?0:1; + } + if (!strcasecmp(msg->key,"From")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return removefrom ?0:2; + } + if (!strcasecmp(msg->key,"To")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return 2; + } + if (!strcasecmp(msg->key,"Cc")) + return 2; + if (!strcasecmp(msg->key,"Bcc")) + return 0; + if (!strcasecmp(msg->key,"Reply-To")) { + if ((ta=parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else + return removereplyto ?0:2; + } + if (!strcasecmp(msg->key,"Lines")) + return 0; + if (!strcasecmp(msg->key,"Date")) + return 0; + if (!strcasecmp(msg->key,"Subject")) { + if ((msg->val) && (strlen(msg->val) > MAXSUBJ)) + return 2; + else + return 0; + } + if (!strcasecmp(msg->key,"Organization")) + return removeorg ?0:1; + if (!strcasecmp(msg->key,"Comment-To")) + return 0; + if (!strcasecmp(msg->key,"X-Comment-To")) + return 0; + if (!strcasecmp(msg->key,"X-Apparently-To")) + return 0; + if (!strcasecmp(msg->key,"Apparently-To")) + return 0; + if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) + return 0; + if (!strcasecmp(msg->key,"Keywords")) + return 2; + if (!strcasecmp(msg->key,"Summary")) + return 2; + if (!strcasecmp(msg->key,"MIME-Version")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Type")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Length")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) + return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Name")) + return 2; + if (!strcasecmp(msg->key,"Content-Description")) + return 2; + if (!strcasecmp(msg->key,"Message-ID")) + return removemsgid ?0:1; + if (!strcasecmp(msg->key,"References")) + return removeref ?0:1; + if (!strcasecmp(msg->key,"In-Reply-To")) + return removeinreply ?0:1; + if (!strcasecmp(msg->key,"Supersedes")) + return removesupersedes ?0:1; + if (!strcasecmp(msg->key,"Distribution")) + return 0; + if (!strcasecmp(msg->key,"X-Newsreader")) + return 0; + if (!strcasecmp(msg->key,"X-Mailer")) + return 0; + if (!strcasecmp(msg->key,"User-Agent")) + return 0; + if (!strncasecmp(msg->key,"NNTP-",5)) + return 0; + if (!strncasecmp(msg->key,"X-Trace",7)) + return 0; + if (!strncasecmp(msg->key,"X-Complaints",12)) + return 0; + if (!strncasecmp(msg->key,"X-MSMail",9)) + return 0; + if (!strncasecmp(msg->key,"X-MimeOLE",9)) + return 0; + if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) + return 0; + if (!strcasecmp(msg->key,"X-Origin-Date")) + return 0; + if (!strncasecmp(msg->key,"X-PGP-",6)) + return 0; + if (!strncasecmp(msg->key,"Resent-",7)) + return 0; + if (!strcasecmp(msg->key,"X-Mailing-List")) + return 0; + if (!strcasecmp(msg->key,"X-Loop")) + return 0; + if (!strcasecmp(msg->key,"Precedence")) + return 0; + /*if (!strcasecmp(msg->key,"")) return ;*/ + return 1; +} + + + +int putmessage(rfcmsg *msg, ftnmsg *fmsg, FILE *fp, faddr *route, char flavor,fa_list **sbl, int incode, int outcode) +{ + char buf[BUFSIZ],*p,*q,newsubj[4 * (MAXSUBJ+1)],*oldsubj; + rfcmsg *tmp; + int rfcheaders, postlocal; + int needsplit,hdrsize,datasize,splitpart,forbidsplit; + int sot_kludge, eot_kludge; + int qp_or_base64; /* 0=plain text, 1=quoted-printable, 2=base64 */ + int html_message; + int tinyorigin=0; + fa_list *ptl=NULL; + faddr *ta; + int i; + FILE *pkt; + fidoaddr Dest, Route, *dest; + time_t Now; + + Syslog('m', "putmessage from %s",ascfnode(fmsg->from,0x7f)); + Syslog('m', "putmessage to %s",ascfnode(fmsg->to,0x7f)); + Syslog('m', "putmessage subj %s",MBSE_SS(fmsg->subj)); + Syslog('m', "putmessage flags %04x",fmsg->flags); + Syslog('m', "putmessage msgid %s %lx",MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + Syslog('m', "putmessage reply %s %lx",MBSE_SS(fmsg->reply_a),fmsg->reply_n); + Syslog('m', "putmessage date %s",ftndate(fmsg->date)); + + removemime = FALSE; + removeorg = FALSE; + removemsgid = FALSE; + removeref = FALSE; + removeinreply = FALSE; + removesupersedes = FALSE; + removeapproved = FALSE; + removefrom = TRUE; + removereplyto = TRUE; + removereturnto = TRUE; + ftnorigin=fmsg->ftnorigin; + sot_kludge = 0; + eot_kludge = 0; + qp_or_base64 = 0; + html_message = 0; + + if ((hdr((char *)"X-PGP-Signed",msg))) + pgpsigned = TRUE; + Syslog('m', "pgpsigned = %s", pgpsigned ? "True":"False"); + + q = hdr((char *)"Content-Transfer-Encoding",msg); + if (q) + while (*q && isspace(*q)) + q++; + if (!(q)) + q = (char *)"8bit"; + if ((p = hdr((char *)"Content-Type",msg))) { + while (*p && isspace(*p)) + p++; + + /* + * turn the quoted-printable decode mode on; remember FTN is virtually 8-bit clean + */ + if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "quoted-printable", 16) == 0)) + qp_or_base64 = 1; + /* + * turn the base64 decode mode on + */ + else if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "base64", 6) == 0)) + qp_or_base64 = 2; + + /* + * text/html support from FSC-HTML 001 proposal of Odinn Sorensen (2:236/77) + */ + if (strncasecmp(p, "text/html", 9) == 0) + html_message = TRUE; + for (tmp=msg;tmp;tmp=tmp->next) + if (((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) && (strcasecmp(tmp->val,"FSCHTML") == 0)) || + (strcasecmp(tmp->key,"X-FTN-HTML") == 0)) + html_message = FALSE; + + if ((readcharset(p) != CHRS_NOTSET ) && ((q == NULL) || (strncasecmp(q,"7bit",4) == 0) || + ((!pgpsigned) && (qp_or_base64==1)) || ((!pgpsigned) && (qp_or_base64==2)) || (strncasecmp(q,"8bit",4) == 0))) + removemime = TRUE; /* no need in MIME headers */ + + /* + * some old MUA puts "text" instead of "text/plain; charset=..." + */ + else if ((strcasecmp(p,"text\n") == 0)) + removemime = TRUE; + + } + Syslog('m', "removemime=%s, qp_or_base64 = %d, html_message=%s", removemime ? "True":"False", qp_or_base64, + html_message ? "True":"False"); + + if ((p = hdr((char *)"Message-ID",msg))) { + if (!removemsgid) + removemsgid = chkftnmsgid(p); + } + Syslog('m', "removemsgid = %s", removemsgid ? "True":"False"); + + if ((p = hdr((char *)"In-Reply-To",msg))) { + p = xstrcpy(p); + q = strtok(p," \t\n"); + if ((q) && (strtok(NULL," \t\n") == NULL)) + removeinreply = chkftnmsgid(q); + free(p); + } + Syslog('m', "removeinreply = %s", removeinreply ? "True":"False"); + + if ((p = hdr((char *)"Reply-To",msg))) { + removereplyto = FALSE; + if ((!removereplyto) && (q = hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); + p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereplyto = TRUE; + free(r); + } + } + Syslog('m', "removereplyto = %s", removereplyto ? "True":"False"); + + if ((p = hdr((char *)"Return-Receipt-To",msg))) { + removereturnto = FALSE; + if ((!removereturnto) && (q=hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereturnto = TRUE; +// free(r); + } + } + Syslog('m', "removereturnto = %s", removereturnto ? "True":"False"); + + p = ascfnode(fmsg->from,0x1f); + i = 79-11-3-strlen(p); + if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) { + /* This is a kludge... I don't like it too much. But well, + if this is a message of FTN origin, the original origin (:) + line MUST have been short enough to fit in 79 chars... + So we give it a try. Probably it would be better to keep + the information about the address format from the origin + line in a special X-FTN-... header, but this seems even + less elegant. Any _good_ ideas, anyone? */ + + /* OK, I am keeping this, though if should never be used + al long as X-FTN-Origin is used now */ + + p = ascfnode(fmsg->from,0x0f); + i = 79-11-3-strlen(p); + tinyorigin = TRUE; + } + Syslog('m', "tinyorigin = %s", tinyorigin ? "True":"False"); + + if ((fmsg->origin) && (strlen(fmsg->origin) > i)) + fmsg->origin[i]='\0'; + forbidsplit=(ftnorigin || (hdr((char *)"X-FTN-Split",msg))); + needsplit = 0; + splitpart = 0; + hdrsize = 20; + hdrsize += (fmsg->subj)?strlen(fmsg->subj):0; + if (fmsg->from) + hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0; + if (fmsg->to) + hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0; + do { + Syslog('m', "split loop, splitpart = %d", splitpart); + datasize=0; + + if (splitpart) { + sprintf(newsubj,"[part %d] ",splitpart+1); + strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj)); + } else { + strncpy(newsubj,fmsg->subj,MAXSUBJ); + } + strcpy(newsubj, hdrnconv(newsubj, incode, outcode, MAXSUBJ)); + newsubj[MAXSUBJ]='\0'; + + if (splitpart) { + hash_update_n(&fmsg->msgid_n,splitpart); + } + + oldsubj=fmsg->subj; + fmsg->subj=newsubj; + + /* + * We got the routing address from the mailer which was given by our Host's sendmail. + * This is probably our address so we need to get the address for the next hop. + */ + dest = faddr2fido(fmsg->to); + memcpy(&Dest, dest, sizeof(fidoaddr)); + free(dest); + if (TrackMail(Dest, &Route) == R_LOCAL) { + /* + * Mail for our local system. Instead of adding the message to a .pkt create + * a temporary file which later will be send via the importnet function. + */ + postlocal = TRUE; + pkt = tmpfile(); + } else { + /* + * New outbound route. + */ + route = fido2faddr(Route); + postlocal = FALSE; + if ((pkt = ftnmsghdr(fmsg, NULL, route, flavor, (char *)"MBSE-FIDO")) == NULL) { + return 1; + } + } + fmsg->subj=oldsubj; + + Syslog('m', "replyaddr=%s removereplyto=%s removefrom=%s", + printable(replyaddr, 0), removereplyto?"True":"False", removefrom?"True":"False"); + + /* + * Add FTN MSGID: and REPLY: if needed. + */ + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + if (postlocal) { + fprintf(pkt, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\n", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n); + fprintf(pkt, "\001TZUTC: %s\n", gmtoffset(Now)); + } else { + fprintf(pkt, "\001MSGID: %s %08lx\r", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(pkt, "\1REPLY: %s\r", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(pkt, "\1REPLY: %s %08lx\r", fmsg->reply_a, fmsg->reply_n); + fprintf(pkt, "\001TZUTC: %s\r", gmtoffset(Now)); + } + + if ((p=hdr((char *)"X-FTN-REPLYADDR",msg))) { + hdrsize += 10+strlen(p); + fprintf(pkt,"\1REPLYADDR:"); + kwrite(p,pkt,postlocal); + } else if ((replyaddr) && ((!removereplyto) || (!removefrom))) { + hdrsize += 10+strlen(replyaddr); + fprintf(pkt,"\1REPLYADDR: "); + kwrite(replyaddr,pkt,postlocal); + } + + if ((p=hdr((char *)"X-FTN-REPLYTO",msg))) { + hdrsize += 8+strlen(p); + fprintf(pkt,"\1REPLYTO:"); + kwrite(p,pkt,postlocal); + } else if ((replyaddr) && ((!removereplyto) || (!removefrom))) { + hdrsize += 15; + if (postlocal) + fprintf(pkt,"\1REPLYTO: %s UUCP\n", ascfnode(bestaka,0x1f)); + else + fprintf(pkt,"\1REPLYTO: %s UUCP\r", ascfnode(bestaka,0x1f)); + } else if ((p=hdr((char *)"Reply-To",msg))) { + if ((ta=parsefaddr(p))) { + if ((q=hdr((char *)"From",msg))) { + if (!strcasestr(q,p)) { + if (postlocal) + fprintf(pkt,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name); + else + fprintf(pkt,"\1REPLYTO: %s %s\r", ascfnode(ta,0x1f), ta->name); + } + tidy_faddr(ta); + } + } + /* Added 15-Apr-2001 MB. Add UUCP reply info if there is nothing. */ + } else if ((p=hdr((char *)"X-UUCP-From",msg)) && (q=hdr((char *)"From",msg))) { + hdrsize += 15; + Striplf(q); + if (postlocal) { + fprintf(pkt,"\1REPLYADDR: %s\n", q); + fprintf(pkt,"\1REPLYTO: %s UUCP\n", ascfnode(bestaka,0x1f)); + } else { + fprintf(pkt,"\1REPLYADDR: %s\r", q); + fprintf(pkt,"\1REPLYTO: %s UUCP\r", ascfnode(bestaka,0x1f)); + } + } + + if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) { + hdrsize += 15; + if (postlocal) + fprintf(pkt,"\1FLAGS:%s\n",p); + else + fprintf(pkt,"\1FLAGS:%s\r",p); + free(p); + } + + if (!hdr((char *)"X-FTN-PID", msg)) { + p = hdr((char *)"User-Agent", msg); + if (p == NULL) + p = hdr((char *)"X-Newsreader", msg); + if (p == NULL) + p = hdr((char *)"X-Mailer", msg); + if (p) { + hdrsize += 4 + strlen(p); + fprintf(pkt, "\1PID:"); + kwrite(p, pkt, postlocal); + } else { + if (postlocal) + fprintf(pkt, "\001PID: MBSE-MAIL %s\n", VERSION); + else + fprintf(pkt, "\001PID: MBSE-MAIL %s\r", VERSION); + } + } + + hdrsize += 15; + if (postlocal) + writechrs(outcode,pkt,3); + else + writechrs(outcode,pkt,1); + + if (html_message) { + hdrsize += 9; + if (postlocal) + fprintf(pkt, "\1HTML: 5\n"); + else + fprintf(pkt, "\1HTML: 5\r"); + } + +#ifdef FSC_0070 + /* FSC-0070 */ + if ((p = hdr((char *)"Message-ID", msg)) && !(hdr((char *)"X-FTN-RFCID", msg))) { + q = strdup(p); + fprintf(pkt,"\1RFCID:"); + if ((l = strrchr(q, '<')) && (r = strchr(q, '>')) && (l < r)) { + *l++ = ' '; + while(*l && isspace(*l)) + l++; + l--; /* leading ' ' */ + *r-- = '\0'; + while(*r && isspace(*r)) + *r-- = '\0'; + } else + l = q; + kwrite(l, pkt, postlocal); + hdrsize += 6 + strlen(l); + free(q); + } +#endif /* FSC_0070 */ + + if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) { + sprintf(buf, " mbmail %s", VERSION); + hdrsize += 4 + strlen(buf); + fprintf(pkt, "\1TID:"); + kwrite(buf, pkt, postlocal); + } + + if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) { + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-Fsc-",6)) || + (!strncmp(tmp->key,"X-FTN-",6) && + strcasecmp(tmp->key,"X-FTN-Tearline") && + strcasecmp(tmp->key,"X-FTN-Origin") && + strcasecmp(tmp->key,"X-FTN-Sender") && + strcasecmp(tmp->key,"X-FTN-Split") && + strcasecmp(tmp->key,"X-FTN-FLAGS") && + strcasecmp(tmp->key,"X-FTN-AREA") && + strcasecmp(tmp->key,"X-FTN-MSGID") && + strcasecmp(tmp->key,"X-FTN-REPLY") && + strcasecmp(tmp->key,"X-FTN-SEEN-BY") && + strcasecmp(tmp->key,"X-FTN-PATH") && + strcasecmp(tmp->key,"X-FTN-REPLYADDR") && + strcasecmp(tmp->key,"X-FTN-REPLYTO") && + strcasecmp(tmp->key,"X-FTN-To") && + strcasecmp(tmp->key,"X-FTN-From") && + strcasecmp(tmp->key,"X-FTN-CHARSET") && + strcasecmp(tmp->key,"X-FTN-CHRS") && + strcasecmp(tmp->key,"X-FTN-CODEPAGE") && + strcasecmp(tmp->key,"X-FTN-ORIGCHRS") && + strcasecmp(tmp->key,"X-FTN-SOT") && + strcasecmp(tmp->key,"X-FTN-EOT") && + strcasecmp(tmp->key,"X-FTN-Via"))) { + if (strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) { + if (!strcasecmp(tmp->val," SOT:\n")) + sot_kludge = 1; + else if (!strcasecmp(tmp->val," EOT:\n")) + eot_kludge = 1; + else { + hdrsize += strlen(tmp->val); + fprintf(pkt,"\1"); + /* we should have restored the original string here... */ + kwrite((tmp->val)+1, pkt, postlocal); + } + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1%s:",tmp->key+6); + kwrite(tmp->val, pkt, postlocal); + } + } + /* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-ZC-",5))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt, "\1%s:", tmp->key+2); + kwrite(tmp->val, pkt, postlocal); + } + /* mondo.org gateway uses ".MSGID: ..." in usenet */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1%s:",tmp->key+1); + kwrite(tmp->val, pkt, postlocal); + } + + rfcheaders = 0; + for (tmp=msg;tmp;tmp=tmp->next) + if ((needputrfc(tmp) == 1)) { + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(pkt,"\1RFC-Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1RFC-%s:",tmp->key); + } + kwrite(hdrconv(tmp->val, incode, outcode),pkt, postlocal); + } + for (tmp=msg;tmp;tmp=tmp->next) + if ((needputrfc(tmp) > 1)) { + rfcheaders++; + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(pkt,"Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"%s:",tmp->key); + } + cwrite(hdrconv(tmp->val, incode, outcode),pkt,postlocal); + } + if (rfcheaders) + cwrite((char *)"\n",pkt, postlocal); + if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge)) { + if (postlocal) + fprintf(pkt,"\1SOT:\n"); + else + fprintf(pkt,"\1SOT:\r"); + } + if ((splitpart == 0) && (hdr((char *)"X-PGP-Signed",msg))) { + if (postlocal) + fprintf(pkt,PGP_SIGNED_BEGIN"\n"); + else + fprintf(pkt,PGP_SIGNED_BEGIN"\r"); + } + } + + if (replyaddr) { +// free(replyaddr); /* Gives SIGSEGV */ + replyaddr=NULL; + } + if (needsplit) { + if (postlocal) + fprintf(pkt," * Continuation %d of a split message *\n\n", splitpart); + else + fprintf(pkt," * Continuation %d of a split message *\r\r", splitpart); + needsplit=0; + } else if ((p=hdr((char *)"X-Body-Start",msg))) { + datasize += strlen(p); + if (qp_or_base64==1) + cwrite(strkconv(qp_decode(p), incode, outcode), pkt, postlocal); + else if (qp_or_base64==2) + cwrite(strkconv(b64_decode(p), incode, outcode), pkt, postlocal); + else + cwrite(strkconv(p, incode, outcode), pkt, postlocal); + } + while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) || + (!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(buf,sizeof(buf)-1,fp))) { +// Syslog('m', "putmessage body %s",buf); + datasize += strlen(buf); + if (qp_or_base64==1) + cwrite(strkconv(qp_decode(buf), incode, outcode), pkt, postlocal); + else if (qp_or_base64==2) + cwrite(strkconv(b64_decode(buf), incode, outcode), pkt, postlocal); + else + cwrite(strkconv(buf, incode, outcode), pkt, postlocal); + } + if (needsplit) { + if (postlocal) + fprintf(pkt,"\n * Message split, to be continued *\n"); + else + fprintf(pkt,"\r * Message split, to be continued *\r"); + splitpart++; + } else if ((p=hdr((char *)"X-PGP-Signed",msg))) { + if (postlocal) + fprintf(pkt,PGP_SIG_BEGIN"\n"); + else + fprintf(pkt,PGP_SIG_BEGIN"\r"); + if ((q=hdr((char *)"X-PGP-Version",msg))) { + fprintf(pkt,"Version:"); + cwrite(q,pkt, postlocal); + } + if ((q=hdr((char *)"X-PGP-Charset",msg))) { + fprintf(pkt,"Charset:"); + cwrite(q,pkt, postlocal); + } + if ((q=hdr((char *)"X-PGP-Comment",msg))) { + fprintf(pkt,"Comment:"); + cwrite(q,pkt, postlocal); + } + if (postlocal) + fprintf(pkt,"\n"); + else + fprintf(pkt,"\r"); + p=xstrcpy(p); + q=strtok(p," \t\n"); + if (postlocal) + fprintf(pkt,"%s\n",q); + else + fprintf(pkt,"%s\r",q); + while ((q=(strtok(NULL," \t\n")))) { + if (postlocal) + fprintf(pkt,"%s\n",q); + else + fprintf(pkt,"%s\r",q); + } + if (postlocal) + fprintf(pkt,PGP_SIG_END"\n"); + else + fprintf(pkt,PGP_SIG_END"\r"); + } + + if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge)) { + if (postlocal) + fprintf(pkt,"\1EOT:\n"); + else + fprintf(pkt,"\1EOT:\r"); + } + + if ((p=hdr((char *)"X-FTN-Tearline",msg))) { + fprintf(pkt,"---"); + if (strcasecmp(p," (none)\n") == 0) + cwrite((char *)"\n",pkt,postlocal); + else + cwrite(p,pkt,postlocal); + } else { + if (postlocal) + fprintf(pkt,"--- MBSE BBSv.%s\n",VERSION); + else + fprintf(pkt,"--- MBSE BBSv.%s\r",VERSION); + } + + if ((p=hdr((char *)"X-FTN-Origin",msg))) { + if (*(q=p+strlen(p)-1) == '\n') + *q='\0'; + fprintf(pkt," * Origin:"); + cwrite(hdrconv(p, incode, outcode),pkt, postlocal); + if (postlocal) + fprintf(pkt, "\n"); + else + fprintf(pkt,"\r"); + } else { + fprintf(pkt," * Origin: "); + if (fmsg->origin) + cwrite(hdrconv(fmsg->origin, incode, outcode), pkt, postlocal); + else + fprintf(pkt, "%s", CFG.origin); + if (postlocal) + fprintf(pkt, " (%s)\n", ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + else + fprintf(pkt, " (%s)\r", ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + } + + for (tmp = msg; tmp; tmp = tmp->next) + if (!strcasecmp(tmp->key,"X-FTN-Via")) { + datasize += strlen(tmp->key)+strlen(tmp->val); + fprintf(pkt,"\1Via"); + kwrite(tmp->val,pkt, postlocal); + } + + /* + * @Via mbmail 2:293/2219@fidonet, Wed Jan 3 1996 at 07:49 (2.8c) + */ + if (postlocal) + fprintf(pkt,"\1Via mbmail %s, %s (%s)\n", ascfnode(bestaka,0x1f), viadate(),VERSION); + else + fprintf(pkt,"\1Via mbmail %s, %s (%s)\r", ascfnode(bestaka,0x1f), viadate(),VERSION); + + if (postlocal) { + subj = xstrcpy(fmsg->subj); + + /* + * Check userlist real names, handles, unix names. + * Import if one fits. + */ + if (!SearchUser(fmsg->to->name)) { + Syslog('+', " \"%s\" is not a known BBS user", fmsg->to->name); + /* + * Unknown, readdress it to the sysop. + */ + net_bad++; + Syslog('+', " Readdress from %s to %s", fmsg->to->name, CFG.sysop_name); + fmsg->to->name = xstrcpy(CFG.sysop_name); + } + if (SearchUser(fmsg->to->name)) { + Syslog('m', "importnet(%s, %s, %s, %04x)", ascfnode(fmsg->from,0x7f), + ascfnode(fmsg->to,0x7f), ftndate(fmsg->date), fmsg->flags); + if (importnet(fmsg->from, fmsg->to, fmsg->date, fmsg->flags, pkt)) + return 2; + } else { + WriteError("Unknown bbs user"); + return 2; + } + } else { + awrite((char *)"",pkt); /* trailing zero byte */ + if (ferror(pkt)) { + WriteError("$error writing to ftn packet"); + return 1; + } + net_out++; + } + tidy_falist(&ptl); + } + while (needsplit); + + Syslog('m', "putmessage exiting..."); + return 0; +} + diff --git a/mbfido/message.h b/mbfido/message.h new file mode 100644 index 00000000..ce27317a --- /dev/null +++ b/mbfido/message.h @@ -0,0 +1,12 @@ +#ifndef _MESSAGE_H +#define _MESSAGE_H + + +void StatAdd(statcnt *, unsigned long); +int needputrfc(rfcmsg*); +char *viadate(void); +int putmessage(rfcmsg *, ftnmsg *, FILE *, faddr *, char,fa_list **, int, int); + + +#endif + diff --git a/mbfido/mgrutil.c b/mbfido/mgrutil.c new file mode 100644 index 00000000..4b97573b --- /dev/null +++ b/mbfido/mgrutil.c @@ -0,0 +1,223 @@ +/***************************************************************************** + * + * File ..................: mbfido/mgrutil.c + * Purpose ...............: AreaMgr and FileMgr utilities. + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "sendmail.h" +#include "mgrutil.h" + + + + +void WriteMailGroups(FILE *fp, faddr *f) +{ + int Count = 0, First = TRUE; + char *Group, *temp; + FILE *gp; + + temp = calloc(128, sizeof(char)); + fprintf(fp, "Dear %s\r\r", nodes.Sysop); + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + fprintf(fp, "The following is a list of mail groups at %s\r\r", ascfnode(f, 0x1f)); + + if ((gp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp); + + +// 123456789012 1234567890123456789012345678901234567890123456789012345 + fprintf(fp, "Group Description\r"); + fprintf(fp, "--------------------------------------------------------------------\r"); + + while (TRUE) { + Group = GetNodeMailGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, mgrouphdr.hdrsize, SEEK_SET); + while (fread(&mgroup, mgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(mgroup.Name, Group)) && + (mgroup.UseAka.zone == f->zone) && + (mgroup.UseAka.net == f->net) && + (mgroup.UseAka.node == f->node) && + (mgroup.UseAka.point == f->point)) { + fprintf(fp, "%-12s %s\r", mgroup.Name, mgroup.Comment); + Count++; + break; + } + } + } + + fprintf(fp, "--------------------------------------------------------------------\r"); + fprintf(fp, "%d group(s)\r\r\r", Count); + + fclose(gp); + free(temp); +} + + + +void WriteFileGroups(FILE *fp, faddr *f) +{ + int Count = 0, First = TRUE; + char *Group, *temp; + FILE *gp; + + temp = calloc(128, sizeof(char)); + fprintf(fp, "Dear %s\r\r", nodes.Sysop); + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + fprintf(fp, "The following is a list of file groups at %s\r\r", ascfnode(f, 0x1f)); + + if ((gp = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return; + } + fread(&fgrouphdr, sizeof(fgrouphdr), 1, gp); + + +// 123456789012 1234567890123456789012345678901234567890123456789012345 + fprintf(fp, "Group Description\r"); + fprintf(fp, "--------------------------------------------------------------------\r"); + + while (TRUE) { + Group = GetNodeFileGrp(First); + if (Group == NULL) + break; + First = FALSE; + + fseek(gp, fgrouphdr.hdrsize, SEEK_SET); + while (fread(&fgroup, fgrouphdr.recsize, 1, gp) == 1) { + if ((!strcmp(fgroup.Name, Group)) && + (fgroup.UseAka.zone == f->zone) && + (fgroup.UseAka.net == f->net) && + (fgroup.UseAka.node == f->node) && + (fgroup.UseAka.point == f->point)) { + fprintf(fp, "%-12s %s\r", fgroup.Name, fgroup.Comment); + Count++; + break; + } + } + } + + fprintf(fp, "--------------------------------------------------------------------\r"); + fprintf(fp, "%d group(s)\r\r\r", Count); + + fclose(gp); + free(temp); +} + + + +char *GetBool(int Flag) +{ + if (Flag) + return (char *)"Yes"; + else + return (char *)"No"; +} + + + +void ShiftBuf(char *Buf, int Cnt) +{ + int i; + + for (i = Cnt; i < strlen(Buf); i++) + Buf[i - Cnt] = Buf[i]; + Buf[i - Cnt] = '\0'; +} + + + +void CleanBuf(char *Buf) +{ + while (strlen(Buf) && ((Buf[0] == ' ') || (Buf[0] == '='))) + ShiftBuf(Buf, 1); +} + + + +void MgrPasswd(faddr *t, char *Buf, FILE *tmp, int Len) +{ + fidoaddr Node; + + ShiftBuf(Buf, Len); + CleanBuf(Buf); + + if ((strlen(Buf) < 3) || (strlen(Buf) > 15)) { + fprintf(tmp, "A new password must be between 3 and 15 characters in length\n"); + Syslog('+', "XxxxMgr: Password length %d, not changed", strlen(Buf)); + return; + } + + memset(&nodes.Apasswd, 0, 16); + sprintf(nodes.Apasswd, "%s", tu(Buf)); + fprintf(tmp, "AreaMgr and FileMgr password is now \"%s\"\n", nodes.Apasswd); + Syslog('+', "XxxxMgr: Password \"%s\"", nodes.Apasswd); + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); +} + + + +void MgrNotify(faddr *t, char *Buf, FILE *tmp) +{ + fidoaddr Node; + + /* + * First strip leading garbage + */ + ShiftBuf(Buf, 7); + CleanBuf(Buf); + + if (!strncasecmp(Buf, "on", 2)) + nodes.Notify = TRUE; + else if (!strncasecmp(Buf, "off", 3)) + nodes.Notify = FALSE; + else + return; + + UpdateNode(); + memcpy(&Node, faddr2fido(t), sizeof(fidoaddr)); + SearchNode(Node); + Syslog('+', "XxxxMgr: Notify %s", GetBool(nodes.Notify)); + fprintf(tmp, "AreaMgr and FileMgr Notify is %s\n", GetBool(nodes.Notify)); +} + + diff --git a/mbfido/mgrutil.h b/mbfido/mgrutil.h new file mode 100644 index 00000000..7fbd2fa8 --- /dev/null +++ b/mbfido/mgrutil.h @@ -0,0 +1,15 @@ +#ifndef _MGRUTIL_H +#define _MGRUTIL_H + + +void WriteMailGroups(FILE *, faddr *); +void WriteFileGroups(FILE *, faddr *); +char *GetBool(int); +void CleanBuf(char *); +void ShiftBuf(char *, int); +void MgrPasswd(faddr *, char *, FILE *, int); +void MgrNotify(faddr *, char *, FILE *); + + +#endif + diff --git a/mbfido/mkftnhdr.c b/mbfido/mkftnhdr.c new file mode 100644 index 00000000..074c2ac5 --- /dev/null +++ b/mbfido/mkftnhdr.c @@ -0,0 +1,543 @@ +/***************************************************************************** + * + * File ..................: mbmail/mkftnhdr.c + * Purpose ...............: MBSE BBS Mail Gate + * Last modification date : 25-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* Base on E.C. Crosser's ifmail. + * + * ### Modified by P.Saratxaga on 19 Sep 1995 ### + * - Added X-FTN-From and X-FTN-To support + * - added code by T.Tanaka, dated 13 Mar 1995, to put the freename in the ftn + * header, instead of the userid, when the address is fido parseable + * - modified ^aREPLY: code, to look in In-Reply-To: + * - support to decode MSGID from fidogate "Message-ID: " + * - suport for X-Apparently-To: (generated by the french fido->usenet gate) + * - added don't regate code by Wim Van Sebroeck + * - corriged a bug when Organization: has only blanks + */ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "atoul.h" +#include "hash.h" +#include "aliasdb.h" +#include "mkftnhdr.h" + + + +#ifndef ULONG_MAX +#define ULONG_MAX 4294967295 +#endif + + +char *replyaddr=NULL; +char *ftnmsgidstyle=NULL; +faddr *bestaka; + + + +int ftnmsgid(char *msgid, char **s, unsigned long *n, char *areaname) +{ + char *buf, *l, *r, *p; + unsigned long nid = 0L; + faddr *tmp; + static int ftnorigin = 0; + + if (msgid == NULL) { + *s = NULL; + *n = 0L; + return ftnorigin; + } + + buf = malloc(strlen(msgid)+65); + strcpy(buf, msgid); + if ((l = strchr(buf,'<'))) + l++; + else + l = buf; + while (isspace(*l)) + l++; + if ((r = strchr(l,'>'))) + *r = '\0'; + r = l + strlen(l) - 1; + while (isspace(*r) && (r > l)) + (*r--)='\0'; + if ((tmp = parsefaddr(l))) { + if (tmp->name) { + if (strspn(tmp->name,"0123456789") == strlen(tmp->name)) + nid = atoul(tmp->name); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) { + hash_update_s(&nid, tmp->name); + } else + ftnorigin = 1; + } else { + hash_update_s(&nid,l); + } + *s = xstrcpy(ascfnode(tmp, 0x1f)); + tidy_faddr(tmp); + } else { + if ((r=strchr(l,'@')) == NULL) { /* should never happen */ + Syslog('!', "ftnmsgid: should never happen"); + *s = xstrcpy(l); + hash_update_s(&nid,l); + /* */ + } else if (strncmp(l,"MSGID_",6) == 0) { + *r = '\0'; + r = strrchr(l+6,'_'); + if (r) + *r++ = '\0'; + *s = xstrcpy(qp_decode(l+6)); + if (r) + sscanf(r,"%lx",&nid); + ftnorigin = 1; + /* */ + } else if (strncmp(l,"NOMSGID_",8) == 0) { + *s = NULL; + *n = 0L; + ftnorigin = 1; + return ftnorigin; + /* */ + } else if (strncmp(l,"ftn_",4) == 0) { + *r = '\0'; + if ((r = strchr(l+4,'$')) || (r=strchr(l+4,'#'))) { + if (*r=='$') + *r='@'; + if ((r=strchr(l+4,'.'))) + *r=':'; + if ((r=strchr(l+4,'.'))) + *r='/'; + } + while ((r=strrchr(l+4,'_')) != strchr(l+4,'_')) + *r='\0'; + r=strchr(l+4,'_'); + *r++='\0'; + *s=xstrcpy(l+4); + sscanf(r,"%lx",&nid); + ftnorigin=1; + /* */ + } else if (strncmp(l,"wgcid$",6) == 0) { + *r='\0'; + if ((r=strstr(l+6,"$g"))) { + *r='\0'; + *s=xstrcpy(l+6); + *s=xstrcat(*s,(char *)":"); + l=r+2; + } + if ((r=strstr(l,"$h"))) { + *r++='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"/"); + l=r+2; + } + if ((r=strstr(l,"$i"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"."); + l=r+2; + } + if ((r=strstr(l,"$k"))) { + *r='\0'; + *s=xstrcat(*s,l); + *s=xstrcat(*s,(char *)"@"); + l=r+2; + } + if ((r=strstr(l,"$j"))) { + *r='\0'; + *s=xstrcat(*s,l); + sscanf(r+2,"%lx",&nid); + } + } else { + *r='\0'; + if ((p=strchr(l,'%'))) { + *p='\0'; + if (strspn(l,"0123456789") == strlen(l)) { + *r='@'; + r=p; + } else + *p='%'; + } + r++; + if (strspn(l,"0123456789") == strlen(l)) + nid = atoul(l); + else + nid = ULONG_MAX; + if (nid == ULONG_MAX) + hash_update_s(&nid,l); + *s=xstrcpy(r); + } + } + *n=nid; + + free(buf); + return ftnorigin; +} + + + +ftnmsg *mkftnhdr(rfcmsg *msg, int incode, int outcode, int newsmode) +{ + char *freename = NULL, *rfcfrom = NULL, *p, *q, *l, *r; + char *fbuf = NULL; + char *ftnfrom=NULL; + static ftnmsg *tmsg; + int needreplyaddr = 1; + faddr *tmp; + + tmsg=(ftnmsg *)malloc(sizeof(ftnmsg)); + memset(tmsg, 0, sizeof(ftnmsg)); + + if (newsmode) { + p = xstrcpy(hdr((char *)"Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-FTN-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Fidonet-Comment-To",msg)); + if (p == NULL) + p = xstrcpy(hdr((char *)"X-Apparently-To",msg)); + if (p) { + Syslog('N', "getting `to' address from: \"%s\"",p); + if ((tmsg->to = parsefaddr(p)) == NULL) + tmsg->to = parsefaddr((char *)"All@p0.f0.n0.z0"); + if ((l = strrchr(p,'<')) && (r = strchr(p,'>')) && (l < r)) { + r = l; + *r-- = '\0'; + if ((l = strchr(p,'"')) && (r = strrchr(p,'"')) && (l < r)) { + l++; + *r-- = '\0'; + } + while (isspace(*r)) + *r-- = '\0'; + if (!l) + l = p; + while (isspace(*l)) + l++; + } else if ((l = strrchr(p,'(')) && (r = strchr(p,')')) && (l < r)) { + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + l++; + while (isspace(*l)) + l++; + } else { + l = p; + while (isspace(*l)) + l++; + r = p + strlen(p) -1; + if (*r == '\n') + *r-- = '\0'; + while (isspace(*r)) + *r-- = '\0'; + } + + if (*l) { + strcpy(l,hdrnconv(l,incode,outcode,MAXNAME)); + if (strlen(l) > MAXNAME) + l[MAXNAME]='\0'; + free(tmsg->to->name); + tmsg->to->name=xstrcpy(l); + } + free(p); + } else + tmsg->to = parsefaddr((char *)"All@p0.f0.n0.z0"); + Syslog('n', "TO: %s",ascinode(tmsg->to,0x7f)); + } + + p = fbuf = xstrcpy(hdr((char *)"Reply-To", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + fbuf = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + fbuf = xstrcat(fbuf, (char *)"@"); + fbuf = xstrcat(fbuf, parserfcaddr(q).target); + } + rfcfrom = fbuf; + } + if (p) + free(p); + p = NULL; + if (!rfcfrom) + rfcfrom = xstrcpy((char *)"postmaster"); + p = fbuf = xstrcpy(hdr((char *)"From", msg)); + if (fbuf == NULL) + p = fbuf = xstrcpy(hdr((char *)"X-UUCP-From", msg)); + if (p) { + q = p; + while (isspace(*q)) + q++; + if ((q) && (*q != '\0')) + freename = parserfcaddr(q).comment; + else + freename = NULL; + } else + freename = xstrcpy((char *)"Unidentified User"); + if (freename) { + while (isspace(*freename)) + freename++; + } +// if (p) NOT IN IFMAIL +// free(p); +// p = NULL; + if (rfcfrom) { + while (isspace(*rfcfrom)) + rfcfrom++; + p = rfcfrom + strlen(rfcfrom) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + } + + if ((freename) && (*freename != '\0')) { + while (isspace(*freename)) + freename++; + p = freename + strlen(freename) -1; + while ((isspace(*p)) || (*p == '\n')) + *(p--)='\0'; + strcpy(freename, hdrconv(freename, incode, outcode)); + if ((*freename == '\"') && (*(p=freename+strlen(freename)-1) == '\"')) { + freename++; + *p='\0'; + } + } + if ((!freename) || ((freename) && (*freename == '\0')) || (strcmp(freename,".")==0)) + freename=rfcfrom; + +// p = NULL; + if (newsmode) + Syslog('n', "FROM: %s <%s>", freename, rfcfrom); + else + Syslog('+', "from: %s <%s>",freename,rfcfrom); + + needreplyaddr = 1; + if ((tmsg->from=parsefaddr(rfcfrom)) == NULL) { + if (freename && rfcfrom) + if (!strchr(freename,'@') && !strchr(freename,'%') && + strncasecmp(freename,rfcfrom,MAXNAME) && + strncasecmp(freename,"uucp",4) && + strncasecmp(freename,"usenet",6) && + strncasecmp(freename,"news",4) && + strncasecmp(freename,"super",5) && + strncasecmp(freename,"admin",5) && + strncasecmp(freename,"postmaster",10) && + strncasecmp(freename,"sys",3)) + needreplyaddr=registrate(freename,rfcfrom); + } else { + tmsg->ftnorigin = 1; + tmsg->from->name = xstrcpy(freename); + if (strlen(tmsg->from->name) > MAXNAME) + tmsg->from->name[MAXNAME]='\0'; + } + if (replyaddr) { + free(replyaddr); + replyaddr=NULL; + } + if (needreplyaddr && (tmsg->from == NULL)) { + Syslog('m', "fill replyaddr with \"%s\"",rfcfrom); + replyaddr=xstrcpy(rfcfrom); + } + + Syslog('m', "From address was%s distinguished as ftn", tmsg->from ? "" : " not"); + + /* FIXME: received email from an Unix mailer comes here as well, only the From address is set. + The msgs.Aka next is not valid. */ + if ((tmsg->from == NULL) && ((bestaka = bestaka_s(fido2faddr(msgs.Aka))))) { + if (CFG.dontregate) { + p = xstrcpy(hdr((char *)"X-FTN-Sender",msg)); + if (p == NULL) { + if ((p = hdr((char *)"X-FTN-From",msg))) { + tmp = parsefnode(p); + p = xstrcpy(ascinode(tmp, 0xff)); + tidy_faddr(tmp); + } + } + if (p) { + q = p; + while (isspace(*q)) + q++; + ftnfrom = parserfcaddr(q).remainder; + if (parserfcaddr(q).target) { + ftnfrom = xstrcat(ftnfrom,(char *)"@"); + ftnfrom = xstrcat(ftnfrom,parserfcaddr(q).target); + } + Syslog('m', "Ftn gateway: \"%s\"", ftnfrom); + Syslog('+', "Ftn sender: %s",ftnfrom); + if (ftnfrom) + tmsg->from = parsefaddr(ftnfrom); + if ((tmsg->from) && (!tmsg->from->name)) + tmsg->from->name = xstrcpy(rfcfrom); + } + if (p) + free(p); + p = NULL; + if (tmsg->from == NULL) { + tmsg->from=(faddr *)malloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } else { + tmsg->from=(faddr *)xmalloc(sizeof(faddr)); + tmsg->from->name=xstrcpy(freename); + if (tmsg->from->name && (strlen(tmsg->from->name) > MAXNAME)) + tmsg->from->name[MAXNAME]='\0'; + tmsg->from->point=bestaka->point; + tmsg->from->node=bestaka->node; + tmsg->from->net=bestaka->net; + tmsg->from->zone=bestaka->zone; + tmsg->from->domain=xstrcpy(bestaka->domain); + } + } + if (fbuf) + free(fbuf); + fbuf = NULL; + + p = hdr((char *)"Subject", msg); + if (p) { + while (isspace(*p)) + p++; + /* + * charset conversion for subject line is done in message.c + * here we only convert quoted-printable and base64 to 8 bit + */ + tmsg->subj = xstrcpy(hdrnconv(p, 0, 0, MAXSUBJ)); + tmsg->subj = xstrcpy(p); + if (*(p=tmsg->subj+strlen(tmsg->subj)-1) == '\n') + *p='\0'; + if (strlen(tmsg->subj) > MAXSUBJ) + tmsg->subj[MAXSUBJ]='\0'; + } else { + tmsg->subj = xstrcpy((char *)" "); + } +// if (p) +// free(p); +// p = NULL; + + Syslog('m', "SUBJ: \"%s\"", tmsg->subj); + + if ((p = hdr((char *)"X-FTN-FLAGS",msg))) + tmsg->flags |= flagset(p); + if (hdr((char *)"Return-Receipt-To",msg)) + tmsg->flags |= M_RRQ; + if (hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) + tmsg->flags |= M_RRQ; + if (!newsmode) { + tmsg->flags |= M_PVT; + tmsg->flags |= M_KILLSENT; + } + + if ((p = hdr((char *)"X-Origin-Date",msg))) + tmsg->date = parsedate(p, NULL); + else if ((p = hdr((char *)"Date",msg))) + tmsg->date = parsedate(p, NULL); + else + tmsg->date = time((time_t *)NULL); + + if ((p = hdr((char *)"X-FTN-MSGID", msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)".MSGID",msg))) { + tmsg->ftnorigin &= 1; + while (isspace(*p)) + p++; + tmsg->msgid_s = xstrcpy(p); + if (*(p = tmsg->msgid_s + strlen(tmsg->msgid_s) -1) == '\n') + *p='\0'; + } else if ((p = hdr((char *)"Message-ID",msg))) { + tmsg->ftnorigin &= ftnmsgid(p,&(tmsg->msgid_a),&(tmsg->msgid_n),tmsg->area); + } else + tmsg->msgid_a = NULL; + + if ((p = hdr((char *)"X-FTN-REPLY",msg))) { + while (isspace(*p)) + p++; + tmsg->reply_s = xstrcpy(p); + if (*(p=tmsg->reply_s + strlen(tmsg->reply_s) -1) == '\n') + *p='\0'; + } else { + if (newsmode) { + p = hdr((char *)"References",msg); + if (p) { + l = xstrcpy(p); + r = strtok(l," \t\n"); + while ((l=strtok(NULL," \t\n")) != NULL) + r = l; + p = r; + free(l); + } + } else + p = hdr((char *)"In-Reply-To",msg); + } + if (p) + (void)ftnmsgid(p,&(tmsg->reply_a),&(tmsg->reply_n),NULL); + else + tmsg->reply_a=NULL; + + Syslog('m', "DATE: %s, MSGID: %s %lx, REPLY: %s %lx", + ftndate(tmsg->date), MBSE_SS(tmsg->msgid_a),tmsg->msgid_n, MBSE_SS(tmsg->reply_a),tmsg->reply_n); + + if ((p = hdr((char *)"Organization",msg))) { + while (isspace(*p)) + p++; + tmsg->origin = xstrcpy(hdrconv(p, incode, outcode)); + if (tmsg->origin) + if (*(p = tmsg->origin + strlen(tmsg->origin)-1) == '\n') + *p='\0'; + } else { + /* + * No Organization header, insert the default BBS origin. + */ + tmsg->origin = xstrcpy(CFG.origin); + } + + Syslog('m', "ORIGIN: %s", MBSE_SS(tmsg->origin)); + return tmsg; +} + + diff --git a/mbfido/mkftnhdr.h b/mbfido/mkftnhdr.h new file mode 100644 index 00000000..ad06c554 --- /dev/null +++ b/mbfido/mkftnhdr.h @@ -0,0 +1,10 @@ +#ifndef _MKFTNHDR_H +#define _MKFTNHDR_H + + +int ftnmsgid(char *,char **,unsigned long *,char *); +ftnmsg *mkftnhdr(rfcmsg *, int, int, int); + + +#endif + diff --git a/mbfido/mkrfcmsg.c b/mbfido/mkrfcmsg.c new file mode 100644 index 00000000..e62c1564 --- /dev/null +++ b/mbfido/mkrfcmsg.c @@ -0,0 +1,1490 @@ +/***************************************************************************** + * + * File ..................: mbfido/mkrfcmsg.c + * Purpose ...............: Import a email or news + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbftn.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "rollover.h" +#include "aliasdb.h" +#include "postemail.h" +#include "backalias.h" +#include "mkrfcmsg.h" + + +#define KWDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" +#define MAXPATH 73 +#define BOUNDARY 79 + +/* + * Global variables + */ +extern int news_in; /* Total news articles */ +extern int news_out; /* News articles posted */ +extern int news_bad; /* News articles refused */ +extern int defaultrfcchar; /* Default RFC charset */ +extern int defaultftnchar; /* Default FTN charset */ + +int newsopen = FALSE; /* News tempfile status */ +FILE *nfp; /* News tempfile */ + + +void fill_rlist(fa_list **, char *); +void fill_rlist(fa_list **fap, char *str) +{ + fa_list *tmp; + faddr *ta; + static unsigned int oldnet; + char *buf, *p, *q; + + if ((str == NULL) || (*str == '\0')) + return; + + Syslog('N' ,"fill_rlist %s",str); + buf = xstrcpy(str); + for (p = buf, q = strchr(p,'!'); *p; p = q, q = strchr(p,'!')) { + if (q) + *q++='\0'; + else + q=p+strlen(p); + if ((ta=parsefaddr(p))) { + if (ta->net == 0) + ta->net=oldnet; + else + oldnet=ta->net; + tmp=(fa_list *)malloc(sizeof(fa_list)); + tmp->next=*fap; + tmp->addr=ta; + *fap=tmp; + } + } + free(buf); + for (tmp=*fap;tmp;tmp=tmp->next) + Syslog('N', "fill_rlist returns: %s",ascfnode(tmp->addr,0x06)); + return; +} + + + +char *rfcmsgid(char *, faddr *); +char *rfcmsgid(char *msgid, faddr *bestaka) +{ + static char *buf, *p, *q, *r; + unsigned long id = 0L; + faddr *ta = NULL; + + if (msgid == NULL) + return NULL; + + /* + * +40 for the additionnal stuff we need to write, should be enough + * FIXME: This buffer is never freed!!!! + */ + buf = malloc(strlen(msgid)+40); + if ((r = strrchr(msgid,'\n'))) + *r = '\0'; + /* + * sometimes there is "^aMSGID: 1:23/45@@domain 152ad589" + */ + if ((p = strstr(msgid, "@@"))) { + *p='\0'; + strcat(msgid, p+1); + } else if ((p = strstr(msgid,"@ "))) { + /* + * other times there is "^aMSGID: 1:23/45@ 152ad589" + */ + *p='\0'; + strcat(msgid,p+1); + } + + if ((p=strrchr(msgid,' '))) { + /* + * here we have a parseable address + */ + *p = '\0'; + sscanf(p+1, "%lx", &id); + ta = parsefnode(msgid); + *p=' '; + } + + if (id != 0L) { + /* if we only check for (ta) a Message-ID like + * <123456.7890@internet.domain> will be recognized as + * a fidonet one (ta->node=123456, ta->point=7890, + * ta->domain="internet", but ta->net=0) which obviously + * isn't the case. By cheking also (ta->net) we avoid that + */ + if ((ta) && (ta->net)) { + sprintf(buf,"<%lu@%s.ftn>",id,ascinode(ta,0x1f)); + } else { + p=xstrcpy(msgid); + if ((q=strchr(p,' '))) + *q='\0'; + /* ### Modified by P.Saratxaga on 18 Aug 1995 */ + if (strstr(p,"@")) { + /* "mid__" are generated by gigo */ + if (!strncmp(p,"mid__<",6)) { + sprintf(buf,"%s",p+6); + while ((q=strstr(buf,">_<"))) + *(q+1)=' '; + } + /* "mid__local@domain" are also generated by gigo */ + else if (!strncmp(p,"mid__",5)) + sprintf(buf,"<%s>",p+5); + /* "wgmid$" */ + else if (!strncmp(p,"wgmid$<",7)) + sprintf(buf,"%s",p+6); + /* in case we have "" */ + else if (!strncmp(p,"<",1)) + sprintf(buf,"%s",p); + /* or "local@domain" */ + else + sprintf(buf,"<%s>",p); + while ((q = strchr(buf, '@')) != strrchr(buf, '@')) { + /* we (still) have more than one @ */ + *q = '%'; + } + } else { + sprintf(buf,"<%lu@%s>",id,p); + } + free(p); + } + } else { + sprintf(buf,"<%lu@%s.ftn>",(unsigned long)sequencer(), ascinode(bestaka,0x1f)); + } + tidy_faddr(ta); + if (r) + *r='\n'; + return buf; +} + + + +/* + * check address for localness, substitute alises and replace it *in place* + */ +void substitude(char *); +void substitute(char *buf) +{ + faddr *fa; + char *l,*r,*p=NULL; + int inquotes,inbrackets; + + Syslog('m', "to address before subst: \"%s\"",buf); + if ((l=strchr(buf,'<')) && (r=strchr(buf,'>')) && (l < r)) { + l++; + *r='\0'; + } else + l=buf; + while (*l == ' ') + l++; + for (r=l,inquotes=0,inbrackets=0;*r;r++) + switch (*r) { + case '"': inquotes=(!inquotes); break; + case ',': + case ' ': if (!inquotes && !inbrackets) *r='\0'; break; + case '(': if (!inquotes) inbrackets++; break; + case ')': if (!inquotes && inbrackets) inbrackets--; break; + default: break; + } + if ((fa=parsefaddr(l))) { + Syslog('m', "it is an ftn address: %s",ascfnode(fa,0x7f)); + if (is_local(fa)) { + Syslog('m', "it is local"); + sprintf(buf,"%s",fa->name); + if (!strchr(buf,'@') && (p=strrchr(buf,'%'))) + *p='@'; + if (!strchr(buf,'@')) { + /* + * Lookup the name first in the alias database, then + * the userbase and finally check the password file + * (gecos->username). If not found it's and error. + */ + if ((p = lookup(buf))) + strcpy(buf, p); + else if (SearchUser(buf)) + sprintf(buf, "%s@%s", usr.Name, CFG.sysdomain); + else if (!strcasecmp(buf,"sysop")) + strcpy(buf,"postmaster"); + else + sprintf(buf,"%s",ascinode(fa,0x7f)); + } + } else { + WriteError("substitute(%s) it is not local, may not happen", buf); + sprintf(buf,"%s",ascinode(fa,0x7f)); + } + tidy_faddr(fa); + } else { + Syslog('m', "it is not ftn address"); + for (r=buf;*l;l++,r++) + *r=*l; + *r='\0'; + } + if (buf[0] == '\0') + strcpy(buf,"postmaster"); + Syslog('m', "to address after subst: \"%s\"",buf); + return; +} + + + +/* + * Lines to send, terminated with a newline character. + */ +void Send(int, const char *, ...); +void Send(int newsmode, const char *format, ...) +{ + char *outstr, *p; + va_list va_ptr; + unsigned long crc; + + outstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + fwrite(outstr, 1, strlen(outstr), nfp); + + if (newsmode) { + Striplf(outstr); + if (strncmp(outstr, (char*)"Message-ID: ", 12) == 0) { + /* + * The Message-ID that is sent to the newsserver is stored in + * the dupes database. The database isn't checked for dupes, this + * message is already checked for dupes. The function that will + * pull news articles from the news server will check the dupes + * database and thus will not fetch this local posted article. + */ + p = xstrcpy(outstr+12); + p = xstrcat(p, msgs.Newsgroup); + crc = str_crc32(p); + CheckDupe(crc, D_NEWS, CFG.nntpdupes); + free(p); + } + } + + free(outstr); +} + + + +/* + * Import gated email into users email box or import news article + * on the news server. + * + * 0 - All seems well. + * 1 - Something went wrong. + * 4 - Unable to open temporary file + * + */ +int mkrfcmsg(faddr *f, faddr *t, char *subj, char *origline, time_t mdate, int flags, FILE *pkt, off_t endoff, int ftn_from) +{ + int rrq, result = 1, modtype = 0; + int incode = CHRS_NOTSET, outcode = CHRS_NOTSET; + int waskludge = FALSE, badkludge, pgpsigned = FALSE; + int bNeedToGetAddressFromMsgid = (int)NULL; + int newsmode = 0, lines, pass, count, first; + char *newsgroup = NULL, *distribution = NULL, *moderator = NULL; + char *temp, *p, *q, *r, *l, *b; + char *To = NULL, buf[4096], *charset, c; + time_t now; + rfcmsg *kmsg = NULL, **tmsg, *qmsg, *msg = NULL; + off_t endmsg_off, tear_off, orig_off, via_off; + faddr *o, *bestaka, *ta, *tfaddr; + FILE *fp; + fa_list *rlist, *tfa, *ftnpath = NULL; + int dirtyoutcode = CHRS_NOTSET; + struct utsname utsbuf; + char MailFrom[128], MailTo[128]; + + temp = calloc(2048, sizeof(char)); + tmsg = &kmsg; + tear_off = orig_off = via_off = 0L; + + if ((fp = tmpfile()) == NULL) { + WriteError("$Unable to open temporary file"); + free(temp); + return 4; + } + + Syslog('m', "Message input start ============="); + rewind(pkt); + while ((fgets(buf, sizeof(buf)-2, pkt)) != NULL) { + /* + * Simple test to see how large the buffer must be. 2048 bytes has been seen. + */ + if (strlen(buf) > (sizeof(buf) /2)) + Syslog('+', "Possible bufferoverflow: line read %d bytes", strlen(buf)); + if (strlen(buf) > 200) { + Syslog('m', "Next line should be %d characters", strlen(buf)); + Syslogp('m', printable(buf, 200)); +// } else { +// Syslogp('m', printable(buf, 0)); + } + if ((buf[0] == '\1') || !strncmp(buf,"AREA:",5) || !strncmp(buf,"SEEN-BY",7)) { /* This is a kluge line */ + waskludge = TRUE; + badkludge = FALSE; + if (buf[0] == '\1') { + l = buf+1; + if (!strncmp(l,"AREA:",5) || !strncmp(l,"SEEN-BY",7)) + badkludge = TRUE; + } else + l = buf; + if (*l == '\n') + badkludge = TRUE; + else + while (isspace(*l)) + l++; + if (strncmp(l, "RFC-", 4)) + for (p = l; *p; p++) + if ((*p != '\n') && (((*p)&0x7f) < ' ')) + badkludge = TRUE; + p = strchr(l,':'); + r = strchr(l,' '); + if (p && (!r || (r > p))) + r = p; + else + p = r; + if (r == NULL) + badkludge = TRUE; + else if (!*(p+1) || (*(p+1)=='\n')) + badkludge = TRUE; + else { + c = *r; + *r = '\0'; + if (strspn(l,KWDCHARS) != strlen(l)) + badkludge = TRUE; + *r = c; + } + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + if (badkludge) { + (*tmsg)->key = xstrcpy((char *)"KLUDGE"); + p = printable(l,0); + r = p+strlen(p)-2; + if (strcmp(r,"\\n") == 0) { + *r++ = '\n'; + *r = '\0'; + } + (*tmsg)->val = xstrcpy(p); + } else { + *r++ = '\0'; + while (isspace(*r)) + r++; + (*tmsg)->key = xstrcpy(l); + (*tmsg)->val = xstrcpy(r); + } + tmsg = &((*tmsg)->next); + + if (!strcmp(l,"Via") && (via_off == 0L)) { + via_off = ftell(fp); + Syslog('m', "^AVia \"%s\" at offset %ld", printable(buf, 0), (long)via_off); + } + } else { + /* + * this is not a kludge line + */ + if (waskludge && (isspace(buf[0]))) + fputs("\n",fp); /* first body line is not RFC hdr */ + waskludge=0; + if (!strncmp(buf,PGP_SIGNED_BEGIN, strlen(PGP_SIGNED_BEGIN))) + pgpsigned = TRUE; + else if ((!strncmp(buf,"---",3)) && ((buf[3] == '\r') || (buf[3] == ' ') || (buf[3] == '\n'))) { + tear_off=ftell(fp); + if ((hdr((char *)"Tearline",kmsg) == NULL)) { + *tmsg=(rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next=NULL; + (*tmsg)->key=xstrcpy((char *)"Tearline"); + if (strlen(buf+3) == strspn(buf+3," \t\r\n")) + (*tmsg)->val=xstrcpy((char *)"(none)\n"); + else + (*tmsg)->val=xstrcpy(buf+4); + tmsg=&((*tmsg)->next); + } + Syslog('M', "tearline \"%s\" at offset %ld", buf,(long)tear_off); + } else if (!strncmp(buf," * Origin:",10)) { + orig_off = ftell(fp); + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + (*tmsg)->key = xstrcpy((char *)"Origin"); + (*tmsg)->val = xstrcpy(buf+11); + tmsg = &((*tmsg)->next); + Syslog('M', "origin \"%s\" at offset %ld", buf,(long)orig_off); + p = buf+10; + while (*p == ' ') + p++; + if ((l = strrchr(p,'(')) && (r = strrchr(p,')')) && (l < r)) { + /* + * Extract origin address from the Origin line. + */ + *l = '\0'; + *r = '\0'; + l++; + if ((o = parsefnode(l))) { + f->point = o->point; + f->node = o->node; + f->net = o->net; + f->zone = o->zone; + if (o->domain) + f->domain = o->domain; + o->domain = NULL; + tidy_faddr(o); + } + } else { + bNeedToGetAddressFromMsgid = !NULL; + Syslog('+', "Couldn't find address in origin line (%s of %s, [%s])", + f->name, ascfnode(f, 0x1f), hdr((char *)"Origin", kmsg)); + if (*(l = p+strlen(p)-1) == '\n') + *l = '\0'; + } + for (l = p+strlen(p)-1; *l == ' '; l--) + *l = '\0'; + origline = xstrcpy(p); + } else if (!strncmp(buf," * Message split",16)) { + *tmsg = (rfcmsg *)malloc(sizeof(rfcmsg)); + (*tmsg)->next = NULL; + (*tmsg)->key = xstrcpy((char *)"Split"); + (*tmsg)->val = xstrcpy((char *)"already\n"); + tmsg=&((*tmsg)->next); + Syslog('m', "Split indicator found"); + } + fputs(buf,fp); + } + + } + Syslog('m', "Message input end ==============="); + + if (bNeedToGetAddressFromMsgid && (p = hdr((char *)"MSGID", kmsg))) { + Syslog('m', "Need To Get Address From Msgid start..."); + l = p; + while(isspace(*l) && *l) + l++; + r = strchr(l, ' '); + if(r) { + *r-- = '\0'; + while(isspace(*r) && *r) + r--; + } + if (l && r && l > r) { + if ((o = parsefnode(l))) { + f->point = o->point; + f->node = o->node; + f->net = o->net; + f->zone = o->zone; + if (o->domain) + f->domain = o->domain; + o->domain = NULL; + tidy_faddr(o); + Syslog('+', "Origin from: %s (src MSGID)", ascfnode(f,0x7f)); + } + } + } + + endmsg_off=ftell(fp); + if ((tear_off) && (tear_off < endmsg_off)) + endmsg_off = tear_off; + if ((orig_off) && (orig_off < endmsg_off)) + endmsg_off = orig_off; + if ((via_off) && (via_off < endmsg_off)) + endmsg_off = via_off; + Syslog('M', "end message offset %ld",(long)endmsg_off); + + rewind(fp); + msg = parsrfc(fp); + bestaka = bestaka_s(f); + rewind(fp); + + p = hdr((char *)"CHRS", kmsg); + if (p == NULL) + p = hdr((char *)"CHARSET", kmsg); + if (p == NULL) + p = hdr((char *)"CODEPAGE", kmsg); + if (p) + outcode = readchrs(p); + else { + p=hdr((char *)"Content-Type",msg); + if (p == NULL) + p=hdr((char *)"RFC-Content-Type",kmsg); + if (p == NULL) + p=hdr((char *)"Content-Type",kmsg); + if (p) + outcode=readcharset(p); + else { + q = rfcmsgid(hdr((char *)"MSGID",kmsg),bestaka); + Syslog('m', "start headers checking 1j"); + if ((hdr((char *)"Message-ID",msg)) || (hdr((char *)"RFC-Message-ID",kmsg)) || + (hdr((char *)"Message-ID",kmsg)) || (hdr((char *)"RFCID",kmsg)) || + (hdr((char *)"ORIGID",kmsg)) || ((hdr((char *)"MSGID",kmsg)) && (!chkftnmsgid(q)))) + outcode = defaultrfcchar; + else + outcode = defaultftnchar; + if (q) + free(q); + q = NULL; + } + } + + /* + * A hack for TerMail + */ + p = hdr((char *)"PID", kmsg); + if ((p) && (!strncmp(p, "TerMail", 7)) && (outcode == defaultrfcchar)) + outcode = defaultftnchar; + + if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + if (pgpsigned) + incode = outcode; + + if (kmsg && !strcmp(kmsg->key,"AREA")) { + /* + * The msgs record is already loaded. + */ + newsgroup = xstrcpy(msgs.Newsgroup); + if (strlen(msgs.Distribution)) + distribution = xstrcpy(msgs.Distribution); + if (strlen(msgs.Moderator)) { + moderator = xstrcpy(msgs.Moderator); + if (msgs.MsgKinds == USEMOD) + modtype = 1; + } + Syslog('m', "newsgroup %s, distribution %s, moderator %s modtype %d", + printable(newsgroup, 0), printable(distribution, 0), printable(moderator, 0), modtype); + newsmode = TRUE; + if ((modtype == 1) && (!hdr((char *)"Approved",msg)) && + (!hdr((char *)"RFC-Approved",kmsg)) && (!hdr((char *)"Approved",kmsg))) + newsmode = TRUE; + } else + newsmode = FALSE; + Syslog('m', "Got %s message", newsmode?"echo":"netmail"); + + if ((outcode == CHRS_NOTSET) && (hdr((char *)"MSGID", kmsg))) { + p = rfcmsgid(hdr((char *)"MSGID",kmsg),bestaka); + if ((hdr((char *)"Message-ID",msg)) || (hdr((char *)"RFC-Message-ID",kmsg)) || + (hdr((char *)"Message-ID",kmsg)) || (hdr((char *)"RFCID",kmsg)) || + (hdr((char *)"ORIGID",kmsg)) || ((hdr((char *)"MSGID",kmsg)) && (!chkftnmsgid(p)))) + outcode = defaultrfcchar; + else + outcode = defaultftnchar; + free(p); + } + if (pgpsigned) + incode = outcode; + else if (incode == CHRS_NOTSET) + incode = getincode(outcode); + + + /* + * fsc-0038 defines "^aDOMAIN: othernet 99:12/34 fidonet 2:293/2219" + */ + if ((p=hdr((char *)"DOMAIN",kmsg)) && (!strchr(p,'@'))) { + strncpy(buf,p,sizeof(buf)-1); + buf[sizeof(buf)-1]='\0'; + l=strtok(buf," \n"); + p=strtok(NULL," \n"); + r=strtok(NULL," \n"); + q=strtok(NULL," \n"); + if ((ta=parsefnode(p))) { + t->point=ta->point; + t->node=ta->node; + t->net=ta->net; + t->zone=ta->zone; + tidy_faddr(ta); + } + t->domain=xstrcpy(l); + if ((ta=parsefnode(q))) { + f->point=ta->point; + f->node=ta->node; + f->net=ta->net; + f->zone=ta->zone; + tidy_faddr(ta); + } + f->domain=xstrcpy(r); + } else if ((p=hdr((char *)"INTL",kmsg))) { + strncpy(buf,p,sizeof(buf)-1); + buf[sizeof(buf)-1]='\0'; + l=strtok(buf," \n"); + r=strtok(NULL," \n"); + if ((ta=parsefnode(l))) { + t->point=ta->point; + t->node=ta->node; + t->net=ta->net; + t->zone=ta->zone; + if (ta->domain) { + if (t->domain) + free(t->domain); + t->domain=ta->domain; + ta->domain=NULL; + } + tidy_faddr(ta); + } + if ((ta=parsefnode(r))) { + f->point=ta->point; + f->node=ta->node; + f->net=ta->net; + f->zone=ta->zone; + if (ta->domain) { + if (f->domain) + free(f->domain); + f->domain=ta->domain; + ta->domain=NULL; + } + tidy_faddr(ta); + } + } + + /* + * fidogate generates "^aDOMAIN: Z2@fidonet" + */ + if ((f->domain==NULL) && ((p=hdr((char *)"DOMAIN",kmsg)) && (q=strchr(p,'@')))) { + *q='\0'; + f->domain=xstrcpy(q+1); + *q='@'; + } + + if ((p=hdr((char *)"FMPT",kmsg))) + f->point=atoi(p); + if ((p=hdr((char *)"TOPT",kmsg))) + t->point=atoi(p); + + Syslog('m', "final from: %s",ascfnode(f,0xff)); + Syslog('m', "final to: %s",ascfnode(t,0xff)); + + if (!newsmode) { + p=hdr((char *)"Resent-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if (p == NULL) + p=hdr((char *)"RFC-Resent-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if (p && is_local(t)) { + while (*p == ' ') + p++; + strncpy(buf, p, sizeof(buf) -1); + if (*(p = buf + strlen(buf) -1) == '\n') + *p='\0'; + } else if (modtype == 1) + sprintf(buf,"%s",moderator); + else + sprintf(buf,"%s",ascinode(t,0x7f)); + substitute(buf); + Syslog('+', "mail from %s to %s",ascfnode(f,0x7f),buf); + To = xstrcpy(buf); + } + + + if (!newsmode) { + Syslog('m', "Preparing email"); +// if (p) +// free(p); + p = NULL; + p = hdr((char *)"Return-Path",msg); + if (p == NULL) + p=hdr((char *)"RFC-Return-Path",kmsg); + if (p == NULL) + p=hdr((char *)"Return-Path",kmsg); + if (p) + sprintf(MailFrom, "%s", p); + else + sprintf(MailFrom, "%s", ascinode(f,0x7f)); + Syslog('m', "MailFrom: %s", MailFrom); + + if (To) + sprintf(MailTo, "%s", To); + else + sprintf(MailTo, "%s", t->name); + Syslog('m', "MailTo: %s", MailTo); + + /* + * Because we need the same stream for news and email + * we need to check if the newsfile is already open. + */ + if (newsopen) { + fclose(nfp); + newsopen = FALSE; + } + + if ((nfp = tmpfile()) == NULL) { + WriteError("$Unable to open temporary file"); + return 4; + } + + Syslog('m', "Prepare is ready"); + + if (modtype == 1) + newsmode = TRUE; + } + + if (newsmode) { + /* + * Open temporary newsfile, append messages if it already exists. + */ + if (!newsopen) { + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/tmp/newsout", getenv("MBSE_ROOT")); + if ((nfp = fopen(p, "a")) == NULL) { + WriteError("$Can't open %s", p); + free(p); + return 2; + } + free(p); + newsopen = TRUE; + } + + if ((p=hdr((char *)"Path",msg)) == NULL) + p=hdr((char *)"RFC-Path",kmsg); + rlist=NULL; + fill_rlist(&rlist, p); + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (strcasecmp(qmsg->key, "SPTH") == 0) + fill_list(&ftnpath, qmsg->val, &rlist, FALSE); + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (strcasecmp(qmsg->key, "PATH") == 0) + fill_list(&ftnpath, qmsg->val, &rlist, FALSE); + tidy_falist(&rlist); + + /* + * Build Path: headerline + */ + q = xstrcpy((char *)"Path: "); + if (CFG.newsfeed == FEEDUUCP) { + /* + * If we don't run our own newsserver we have to simulate and + * add the UUCP nodename here. + */ + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf)) { + WriteError("Can't get system nodename"); + } else { + q = xstrcat(q, utsbuf.nodename); + q = xstrcat(q, (char *)"!"); + } + } + tfaddr = fido2faddr(msgs.Aka); + q = xstrcat(q, ascinode(tfaddr, 0x07)); + tidy_faddr(tfaddr); + q = xstrcat(q, (char *)"!"); + if (ftnpath) + for (tfa=ftnpath->next;tfa;tfa=tfa->next) { + /* FIXME: possible memory leak */ + q = xstrcat(q, ascinode(tfa->addr,0x1f)); + q = xstrcat(q, (char *)"!"); + } + tidy_falist(&ftnpath); + + if (p) { + while (isspace(*p)) + p++; + q = xstrcat(q, p); + } else + q = xstrcat(q, (char *)"not-for-mail"); + Send(newsmode, "%s\n", q); + + if ((p = hdr((char *)"Newsgroups",msg))) { + /* + * The gate at puddle.fidonet.org put spaces in Newsgroups header + */ + if ((strstr(p,", "))) { + while ((r = strchr(p, ' '))) { + *r = '\0'; + strcat(p,r+1); + } + } + } + + if (p == NULL) + p=hdr((char *)"RFC-Newsgroups",kmsg); + if (p == NULL) + p=hdr((char *)"Newsgroups",kmsg); + if (p) { + while (*p && isspace(*p)) + p++; + Send(newsmode,"Newsgroups: %s\n",newsgroup); + Send(newsmode,"X-Origin-Newsgroups: %s",p); + } else + Send(newsmode,"Newsgroups: %s\n",newsgroup); + + if ((p=hdr((char *)"Distribution",msg))) + Send(newsmode,"Distribution:%s",p); + else if ((p=hdr((char *)"RFC-Distribution",kmsg))) + Send(newsmode,"Distribution: %s",p); + else if ((p=hdr((char *)"Distribution",kmsg))) + Send(newsmode,"Distribution: %s",p); + else if (distribution) + Send(newsmode,"Distribution: %s\n",distribution); + + p = hdr((char *)"Comment-To",msg); + if (p == NULL) + p=hdr((char *)"X-Comment-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if ((p) && (strcasecmp(p,"All\n"))) + Send(newsmode,"X-Comment-To:%s",hdrconv(p,outcode,incode)); + else { + if (p == NULL) + p=hdr((char *)"RFC-X-Comment-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-Comment-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if ((p) && (strcasecmp(p,"All\n"))) + Send(newsmode,"X-Comment-To: %s",hdrconv(p,outcode,incode)); + else if ((t) && (t->name) && (strcasecmp(t->name,"All"))) + Send(newsmode,"X-Comment-To: %s\n",hdrconv(t->name,outcode,incode)); + else + Send(newsmode,"X-Comment-To: All\n"); + } + +// for (tmpml=approve;tmpml;tmpml=tmpml->next) { +// if ((strncmp(newsgroup,tmpml->prefix, strlen(tmpml->prefix)) == 0)) { +// modtype=2; +// moderator=xstrcpy(tmpml->address); +// break; +// } +// } + + if ((p=hdr((char *)"Approved",msg))) + Send(newsmode,"Approved:%s",p); + else if ((p=hdr((char *)"RFC-Approved",kmsg))) + Send(newsmode,"Approved: %s",p); + else if ((p=hdr((char *)"Approved",kmsg))) + Send(newsmode,"Approved: %s",p); + else if (modtype==2) + Send(newsmode,"Approved: %s\n",moderator); + + } else { /* if newsmode */ + time(&now); + if (CFG.EmailMode == E_NOISP) { + /* + * Probaly not needed as messages for systems without ISP never get here. + * Perhaps only news to moderators. + */ + Send(FALSE, "From: %s!", ascinode(f,0x3f)); + Send(FALSE, "%s %s", ascinode(f,0x40), ctime(&mdate)); + } + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (!strcasecmp(qmsg->key,"RFC-Received")) + Send(FALSE, "%s: %s", qmsg->key+4, qmsg->val); + for (qmsg = msg; qmsg; qmsg = qmsg->next) + if (!strcasecmp(qmsg->key,"Received")) + Send(FALSE, "%s:%s", qmsg->key, qmsg->val); + + if ((p=hdr((char *)"Apparently-To",msg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((p=hdr((char *)"RFC-Apparently-To",kmsg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((p=hdr((char *)"Apparently-To",kmsg))) + Send(FALSE, "Apparently-To: %s\n",p); + else if ((is_local(t))) + Send(FALSE, "Apparently-To: %s\n",buf); + + if (flags & M_RRQ) + rrq=TRUE; + else + rrq=FALSE; + if (rrq && !hdr((char *)"RFC-Return-Receipt-To",kmsg) && + !hdr((char *)"Return-Receipt-To",msg) && + !hdr((char *)"RFC-Notice-Requested-Upon-Delivery-To",kmsg) && + !hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) { + Send(FALSE,"Notice-Requested-Upon-Delivery-To: %s\n",buf); + } + + if (t->name == NULL) + t->name=xstrcpy((char *)"Postmaster"); + p=hdr((char *)"Resent-To",msg); + if (p == NULL) + p=hdr((char *)"To",msg); + if (p) { + Send(FALSE,"To:%s",p); + } else { + if (p == NULL) + p=hdr((char *)"RFC-Resent-To",kmsg); + if (p == NULL) + p=hdr((char *)"RFC-To",kmsg); + if (p) { + Syslog('m', "2"); + Send(FALSE,"To: %s\n",p); + } else if (modtype == 1) + Send(FALSE,"To: %s\n",moderator); + else if (is_local(t)) { + Syslog('m', "3"); + Send(FALSE, "To: %s <%s>\n", t->name, buf); + } else { + Syslog('m', "4"); + Send(FALSE,"To: %s\n",ascinode(t,0xff)); + } + } + } + + if ((p = hdr((char *)"From",msg))) { + if (!ftn_from) + Send(newsmode, "From:%s", hdrconv(p,outcode,incode)); + else + Send(newsmode, "From: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + } else if ((p = hdr((char *)"RFC-From",kmsg))) { + Syslog('m', "b"); + Send(newsmode, "From: %s", hdrconv(p,outcode,incode)); + } else if ((p = hdr((char *)"From\n",kmsg))) { + Syslog('m', "c"); + Send(newsmode, "From: %s", hdrconv(p,outcode,incode)); + } else if ((p = hdr((char *)"X-PcBoard-FROM",msg))) { + if (f->name) { + while (isspace(*p)) + p++; + p[strlen(p)-1] = '\0'; + Send(newsmode,"From: %s <%s>\n", hdrconv(f->name,outcode,incode), p); + } else { + Send(newsmode,"From:%s\n", p); + } + } else if ((hdr((char *)"REPLYADDR",kmsg)) && (p=xstrcpy(hdr((char *)"REPLYADDR",kmsg)))) { + if (*(r=p+strlen(p)-1) == '\n') + *(r--)='\0'; + while (isspace(*r)) + *(r--)='\0'; + q=xstrcpy(hdr((char *)"X-RealName",msg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"RealName",msg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"X-RealName",kmsg)); + if (q == NULL) + q=xstrcpy(hdr((char *)"RealName",kmsg)); + if (q) { + if (*(r=q+strlen(q)-1) == '\n') + *(r--)='\0'; + while (isspace(*r)) + *(r--)='\0'; + for (l=q; isspace(*l); ) + l++; + if ((*l == '\"') && (*r == '\"')) { + l++; + *r--='\0'; + } + Syslog('m', "d"); + Send(newsmode,"From: \"%s\" <%s>\n",hdrconv(l,outcode,incode),p); + free(q); + } else if (f->name) { + Syslog('m', "e"); + Send(newsmode,"From: \"%s\" <%s>\n",hdrconv(f->name,outcode,incode),p); + } else { + Syslog('m', "f"); + Send(newsmode,"From: %s\n",p); + } + free(p); + } + + if (p) + Send(newsmode,"X-FTN-Sender: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + else + Send(newsmode,"From: %s\n",hdrconv(ascinode(f,0xff),outcode,incode)); + + if ((p=hdr((char *)"Reply-To",msg))) + Send(newsmode,"Reply-To:%s",p); + else if ((p=hdr((char *)"RFC-Reply-To",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if ((p=hdr((char *)"Reply-To",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if (((p=backalias(f))) && strlen(CFG.sysdomain)) + Send(newsmode,"Reply-To: %s@%s\n",p,CFG.sysdomain); + else if ((p=hdr((char *)"REPLYADDR",kmsg))) + Send(newsmode,"Reply-To: %s",p); + else if ((p=hdr((char *)"REPLYTO",kmsg))) + Send(newsmode,"Reply-To: %s\n",ascinode(parsefaddr(p),0xff)); + + if ((p=hdr((char *)"Date",msg))) + Send(newsmode,"Date:%s",p); + else if ((p=hdr((char *)"RFC-Date",kmsg))) + Send(newsmode,"Date: %s",p); + else if ((p=hdr((char *)"Date",kmsg))) + Send(newsmode,"Date: %s",p); + else if (newsmode) { + /* + * Restamp future postings + */ + if(mdate > time(&now)) { + Syslog('+', "Future posting: %s", rfcdate(mdate)); + Send(newsmode,"Date: %s\n", rfcdate(now)); + Send(newsmode,"X-Origin-Date: %s\n", rfcdate(mdate)); + } else if((mdate < time(&now)-14*24*60*60) && (mdate > time(&now)-RESTAMP_OLD_POSTINGS*24*60*60)) { + /* + * Restamp old postings + */ + Syslog('+', "Article too old, restamped: %s", rfcdate(mdate)); + Send(newsmode,"Date: %s\n", rfcdate(now)); + Send(newsmode,"X-Origin-Date: %s\n", rfcdate(mdate)); + } else + Send(newsmode,"Date: %s\n",rfcdate(mdate)); + } else + Send(newsmode,"Date: %s\n",rfcdate(mdate)); + + if ((p = hdr((char *)"Subject",msg))) + Send(newsmode, "Subject:%s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"RFC-Subject",kmsg))) + Send(newsmode, "Subject: %s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"Subject",kmsg))) + Send(newsmode, "Subject: %s", hdrconv(p,outcode,incode)); + else if ((p = hdr((char *)"X-PcBoard-SUBJECT",msg))) + Send(newsmode, "Subject:%s", hdrconv(p,outcode,incode)); + else if (subj && (strspn(subj," \t\n\r") != strlen(subj))) + Send(newsmode, "Subject: %s\n", hdrconv(subj,outcode,incode)); + else + Send(newsmode, "Subject: \n"); + + if ((p=hdr((char *)"Message-ID",msg))) + Send(newsmode,"Message-ID:%s",p); + else if ((p=hdr((char *)"RFC-Message-ID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p=hdr((char *)"Message-ID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p=hdr((char *)"RFCID",kmsg))) + if ((p[0]=='<')) { + /* "^aRFCID: " */ + if ((p[strlen(p)-2]=='>')) + Send(newsmode,"Message-ID: %s",p); + /* "^aRFCID: \n",p); + } + } + /* "^aRFCID: local@machine" */ + else { + p[strlen(p)-1]='\0'; + Send(newsmode,"Message-ID: <%s>\n",p); + } else if ((p=hdr((char *)"ORIGID",kmsg))) + Send(newsmode,"Message-ID: %s",p); + else if ((p = hdr((char *)"MSGID",kmsg))) { + q = rfcmsgid(p, bestaka); + Send(newsmode,"Message-ID: %s\n", q); + free(q); + } else + Send(newsmode,"Message-ID: <%lu@%s.ftn>\n", mdate^(subj?str_crc32(subj):0L), ascinode(f,0x1f)); + + if (newsmode) { + if ((p=hdr((char *)"References",msg))) + Send(newsmode,"References:%s",p); + else if ((p=hdr((char *)"RFC-References",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"References",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"ORIGREF",kmsg))) + Send(newsmode,"References: %s",p); + else if ((p=hdr((char *)"REPLY",kmsg))) { + q = rfcmsgid(p, bestaka); + Send(newsmode,"References: %s\n", q); + free(q); + } + } else { + if ((p=hdr((char *)"In-Reply-To",msg))) + Send(newsmode,"In-Reply-To:%s",p); + else if ((p=hdr((char *)"RFC-In-Reply-To",kmsg))) + Send(newsmode,"In-Reply-To: %s",p); + else if ((p=hdr((char *)"REPLY",kmsg))) { + q = rfcmsgid(p,bestaka); + Send(newsmode,"In-Reply-To: %s\n", q); + free(q); + } + } + + if ((p=hdr((char *)"Organization",msg))) + Send(newsmode,"Organization:%s",hdrconv(p,outcode,incode)); + else if ((p=hdr((char *)"RFC-Organization",kmsg))) + Send(newsmode,"Organization: %s",hdrconv(p,outcode,incode)); + else if ((p=hdr((char *)"Organization",kmsg))) + Send(newsmode,"Organization: %s",hdrconv(p,outcode,incode)); + else if (origline) + Send(newsmode,"Organization: %s\n",hdrconv(origline,outcode,incode)); + + if ((p=hdr((char *)"Supersedes",msg))) + Send(newsmode,"Supersedes:%s",p); + else if ((p=hdr((char *)"RFC-Supersedes",kmsg))) + Send(newsmode,"Supersedes: %s",p); + else if ((p=hdr((char *)"Supersedes",kmsg))) + Send(newsmode,"Supersedes: %s",p); + else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"MODIFY"))) { + q = rfcmsgid(p+8,bestaka); + Send(newsmode,"Supersedes: %s\n", q); + free(q); + } + if (CFG.allowcontrol) { + if ((p=hdr((char *)"Control",msg))) + Send(newsmode,"Control:%s",p); + else if ((p=hdr((char *)"RFC-Control",kmsg))) + Send(newsmode,"Control: %s",p); + else if ((p=hdr((char *)"Control",kmsg))) + Send(newsmode,"Control: %s",p); + else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"DELETE"))) { + q = rfcmsgid(p+8,bestaka); + Send(newsmode,"Control: cancel %s\n", q); + free(q); + } + } + + Send(newsmode, "X-FTN-CHRS: %s\n", getchrs(incode)); + if (incode != outcode) + Send(newsmode, "X-FTN-ORIGCHRS: %s\n", getchrs(outcode)); + charset = getcharset(incode); + + if ((p=hdr((char *)"Mime-Version",msg))) + Send(newsmode,(char *)"Mime-Version:%s",p); + else if ((p=hdr((char *)"RFC-Mime-Version",kmsg))) + Send(newsmode,(char *)"Mime-Version: %s",p); + else if ((p=hdr((char *)"Mime-Version",kmsg))) + Send(newsmode,(char *)"Mime-Version: %s",p); + else if ((charset) && (incode != CHRS_NOTSET)) + Send(newsmode,"Mime-Version: 1.0\n"); + + temp[0] = '\0'; + if ((p=hdr((char *)"Content-Type",msg))) + Send(newsmode,"Content-Type:%s",p); + else if ((p=hdr((char *)"RFC-Content-Type",kmsg))) + Send(newsmode,"Content-Type: %s",p); + else if ((p=hdr((char *)"Content-Type",kmsg))) + Send(newsmode,"Content-Type: %s",p); + else if ((charset) && (incode != CHRS_NOTSET)) { + if ((p=hdr((char *)"FSCHTML",kmsg)) || (p=hdr((char *)"HTML",kmsg))) + Send(newsmode,"Content-Type: text/html; charset=%s\n",charset); + else + Send(newsmode,"Content-Type: text/plain; charset=%s\n",charset); + } + + if ((p=hdr((char *)"Content-Length",msg))) + Send(newsmode,"Content-Length%s",p); + else if ((p=hdr((char *)"RFC-Content-Length",kmsg))) + Send(newsmode,"Content-Length: %s",p); + else if ((p=hdr((char *)"Content-Length",kmsg))) + Send(newsmode,"Content-Length: %s",p); + + temp[0] = '\0'; + if ((p=hdr((char *)"Content-Transfer-Encoding",msg))) + sprintf(temp,"Content-Transfer-Encoding:%s",p); + else if ((p=hdr((char *)"RFC-Content-Transfer-Encoding",kmsg))) + sprintf(temp,"Content-Transfer-Encoding: %s",p); + else if ((p=hdr((char *)"Content-Transfer-Encoding",kmsg))) + sprintf(temp,"Content-Transfer-Encoding: %s",p); + else if ((charset) && (incode == CHRS_ISO_8859_1_QP)) + sprintf(temp,"Content-Transfer-Encoding: quoted-printable\n"); + else if ((charset) && (incode != CHRS_NOTSET)) { + if ((incode == CHRS_ASCII || incode == CHRS_UTF_7)) + sprintf(temp,"Content-Transfer-Encoding: 7bit\n"); + else if (strncasecmp(charset,"iso-2022-",9) == 0) + sprintf(temp,"Content-Transfer-Encoding: 7bit\n"); + else + sprintf(temp,"Content-Transfer-Encoding: 8bit\n"); /* all others are 8 bit */ + } + if (temp[0]) + Send(newsmode, temp); + + if (newsmode) { + if ((p=hdr((char *)"X-Newsreader",msg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"RFC-X-Newsreader",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"X-Newsreader",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + else if ((p=hdr((char *)"PID",kmsg))) + Send(newsmode,"X-Newsreader: %s",p); + } else { + if ((p=hdr((char *)"X-Mailer",msg))) + Send(newsmode,"X-Mailer:%s",p); + else if ((p=hdr((char *)"RFC-X-Mailer",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + else if ((p=hdr((char *)"X-Mailer",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + else if ((p=hdr((char *)"PID",kmsg))) + Send(newsmode,"X-Mailer: %s",p); + } + + for (qmsg=msg;qmsg;qmsg=qmsg->next) { + if (strcasecmp(qmsg->key,"X-Body-Start") && + strcasecmp(qmsg->key,"X-PcBoard-FROM") && + strcasecmp(qmsg->key,"X-PcBoard-SUBJECT") && + strcasecmp(qmsg->key,"X-PcBoard-PACKOUT") && + (strcasecmp(qmsg->key,"Control") || !CFG.allowcontrol) && + strcasecmp(qmsg->key,"Supersedes") && + strcasecmp(qmsg->key,"Mime-Version") && + strcasecmp(qmsg->key,"Content-Type") && + strcasecmp(qmsg->key,"Content-Lenght") && + strcasecmp(qmsg->key,"Content-Transfer-Encoding") && + strcasecmp(qmsg->key,"Lines") && + strcasecmp(qmsg->key,"Path") && + strcasecmp(qmsg->key,"Received") && + strcasecmp(qmsg->key,"From") && + strcasecmp(qmsg->key,"To") && + strcasecmp(qmsg->key,"Comment-To") && + strcasecmp(qmsg->key,"X-Comment-To") && + strcasecmp(qmsg->key,"Date") && + strcasecmp(qmsg->key,"Subject") && + strcasecmp(qmsg->key,"Reply-To") && + strcasecmp(qmsg->key,"In-Reply-To") && + strcasecmp(qmsg->key,"References") && + strcasecmp(qmsg->key,"Organization") && + strcasecmp(qmsg->key,"X-Mailer") && + strcasecmp(qmsg->key,"X-Newsreader") && + (strcasecmp(qmsg->key,"Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"Apparently-To") && + strcasecmp(qmsg->key,"Distribution") && + strcasecmp(qmsg->key,"Approved") && + strcasecmp(qmsg->key,"Message-ID")) + Send(newsmode,"%s:%s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + } + + if ((p=compose_flags(flags,hdr((char *)"FLAGS",kmsg)))) { + Send(newsmode,"X-FTN-FLAGS:%s\n",p); + free(p); + } + + for (qmsg=kmsg;qmsg;qmsg=qmsg->next) { + if (strcasecmp(qmsg->key,"INTL") && + strcasecmp(qmsg->key,"FMPT") && + strcasecmp(qmsg->key,"TOPT") && + strcasecmp(qmsg->key,"FLAGS") && + strcasecmp(qmsg->key,"CHARSET") && + strcasecmp(qmsg->key,"CHRS") && + strcasecmp(qmsg->key,"CODEPAGE") && + strcasecmp(qmsg->key,"ORIGCHRS") && + /* + * RFC: is used by fidogate to tell how completly RFC headers were + * gated (0=no headers at all; 1=some headers; 2=all headers) + */ + strcasecmp(qmsg->key,"RFC") && + strcasecmp(qmsg->key,"RFCID") && + strcasecmp(qmsg->key,"ORIGID") && + strcasecmp(qmsg->key,"ORIGREF") && + strcasecmp(qmsg->key,"X-GATEWAY") && + strcasecmp(qmsg->key,"Lines") && + /* strcmp(qmsg->key,"Path") && */ + strcasecmp(qmsg->key,"PATH") && + strcasecmp(qmsg->key,"Received") && + strcasecmp(qmsg->key,"From") && + strcasecmp(qmsg->key,"To") && + strcasecmp(qmsg->key,"Comment-To") && + strcasecmp(qmsg->key,"X-Comment-To") && + strcasecmp(qmsg->key,"Date") && + strcasecmp(qmsg->key,"Subject") && + strcasecmp(qmsg->key,"Reply-To") && + strcasecmp(qmsg->key,"In-Reply-To") && + strcasecmp(qmsg->key,"References") && + strcasecmp(qmsg->key,"Organization") && + strcasecmp(qmsg->key,"X-Mailer") && + strcasecmp(qmsg->key,"X-Newsreader") && + (strcasecmp(qmsg->key,"Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"Apparently-To") && + strcasecmp(qmsg->key,"Message-ID") && + strcasecmp(qmsg->key,"Mime-Version") && + strcasecmp(qmsg->key,"Content-Type") && + strcasecmp(qmsg->key,"Content-Lenght") && + strcasecmp(qmsg->key,"Content-Transfer-Encoding") && + (strcasecmp(qmsg->key,"RFC-Control") || !CFG.allowcontrol) && + strcasecmp(qmsg->key,"RFC-Supersedes") && + strcasecmp(qmsg->key,"RFC-Mime-Version") && + strcasecmp(qmsg->key,"RFC-Content-Type") && + strcasecmp(qmsg->key,"RFC-Content-Lenght") && + strcasecmp(qmsg->key,"RFC-Content-Transfer-Encoding") && + strcasecmp(qmsg->key,"RFC-Lines") && + strcasecmp(qmsg->key,"RFC-Path") && + strcasecmp(qmsg->key,"RFC-Received") && + strcasecmp(qmsg->key,"RFC-From") && + strcasecmp(qmsg->key,"RFC-To") && + strcasecmp(qmsg->key,"RFC-Comment-To") && + strcasecmp(qmsg->key,"RFC-X-Comment-To") && + strcasecmp(qmsg->key,"RFC-Date") && + strcasecmp(qmsg->key,"RFC-Subject") && + strcasecmp(qmsg->key,"RFC-Reply-To") && + strcasecmp(qmsg->key,"RFC-In-Reply-To") && + strcasecmp(qmsg->key,"RFC-References") && + strcasecmp(qmsg->key,"RFC-Organization") && + strcasecmp(qmsg->key,"RFC-X-Mailer") && + strcasecmp(qmsg->key,"RFC-X-Newsreader") && + (strcasecmp(qmsg->key,"RFC-Newsgroups") || !newsmode) && + strcasecmp(qmsg->key,"RFC-Apparently-To") && + strcasecmp(qmsg->key,"RFC-Distribution") && + strcasecmp(qmsg->key,"RFC-Approved") && + strcasecmp(qmsg->key,"RFC-Message-ID")) { + if (!strncmp(qmsg->key,"RFC-",4)) + Send(newsmode,"%s: %s",qmsg->key+4,hdrconv(qmsg->val,outcode,incode)); + else if ((!strncasecmp(qmsg->key,"X-",2)) || (!strncasecmp(qmsg->key,"NNTP-",5))) + Send(newsmode,"%s: %s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + else if ((!strncasecmp(qmsg->key,"ZC-",3))) + Send(newsmode,"X-%s: %s",qmsg->key,qmsg->val); + else if ((!strcasecmp(qmsg->key,"Origin")) || (!strcasecmp(qmsg->key,"MOOD"))) + Send(newsmode,"X-FTN-%s: %s",qmsg->key,hdrconv(qmsg->val,outcode,incode)); + else + Send(newsmode,"X-FTN-%s: %s",qmsg->key,qmsg->val); + } + } + + if (newsmode) { + fa_list *tmpl,*ptl=NULL; + char sbe[16]; + int seenlen=0,oldnet; + + for (qmsg = kmsg; qmsg; qmsg = qmsg->next) + if (!strcmp(qmsg->key, "PATH")) { + fill_path(&ptl, qmsg->val); + } + + uniq_list(&ptl); + + /* + * ensure it will not match for the first entry + */ + oldnet = ptl->addr->net-1; + q = xstrcpy((char*)"X-FTN-PATH:"); + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet=tmpl->addr->net; + seenlen+=strlen(sbe); + if (seenlen > MAXPATH) { + seenlen=0; + Send(newsmode, "%s\n", q); + free(q); + q = xstrcpy((char *)"X-FTN-PATH:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen=strlen(sbe); + } + q = xstrcat(q, sbe); + } + Send(newsmode,"%s\n", q); + free(q); + tidy_falist(&ptl); + + if ((hdr((char *)"X-FTN-SPTH", msg))) + Send(newsmode,"X-FTN-SPTH: %s\n", ascfnode(bestaka,0x1f)); + } + + /* + * Search past RFC headers. + */ + while (fgets(buf,sizeof(buf)-1,fp)) { + if ((strlen(buf) == 1) && (buf[0] == '\n')) { + break; + } + } + + /* + * Send the message body + */ + pass=1; + count = lines = 0; + first = TRUE; + + Syslog('M', "Start sending message body"); + while (fgets(buf,sizeof(buf)-1,fp) && pass) { + if (first) { + Send(newsmode, (char *)"\n"); + first = FALSE; + +/* FIXME: Maybe scan now for repeating headers and drop them as they will appear in the message text */ + + if ((p=hdr((char *)"X-Body-Start",msg))) { + lines++; + Send(newsmode, "%s", strkconv(p, outcode, incode)); + } + } + + if (ftell(fp) > endmsg_off) { + Syslog('M', "line \"%s\" past message end %ld %ld", buf,(long)endmsg_off, ftell(fp)); + pass=0; + } + if (pass) { + p=buf; + b=NULL; + while ((c=*p++)) { + switch (c) { + case ' ': b=p-1; break; + case '\n': b=NULL; count=0; lines++; break; + } + if ((count++ > BOUNDARY) && (!pgpsigned)) { + if (b) { + *b++='\r'; + *b = '\n'; + p=b+2; + b=NULL; + lines++; + count=0; + } + } + } + if (strncmp(buf, ".\r\n", 3)) + Send(newsmode, strkconv(buf, outcode, incode)); + else + Send(newsmode, (char *)" .\n"); + } + } + Syslog('M', "End sending message body"); + + if ((modtype==1) && (!hdr((char *)"Approved",msg)) && + (!hdr((char *)"RFC-Approved",kmsg)) && (!hdr((char *)"Approved",kmsg))) + newsmode = FALSE; + + tidyrfc(msg); + fclose(fp); + tidyrfc(kmsg); + + if (!newsmode) { + result = postemail(nfp, MailFrom, MailTo); + fclose(nfp); + } else { + news_in++; + /* + * The newsfile stays open and will be closed later after processing + * all echomail. + */ + fprintf(nfp, ".\n"); + } + +// if (p) Geeft segfault +// free(p); + if (newsgroup) + free(newsgroup); + if (distribution) + free(distribution); + if (moderator) + free(moderator); + free(temp); + return result; +} + + diff --git a/mbfido/mkrfcmsg.h b/mbfido/mkrfcmsg.h new file mode 100644 index 00000000..f8eafc5b --- /dev/null +++ b/mbfido/mkrfcmsg.h @@ -0,0 +1,8 @@ +#ifndef _MKRFCMSG_H +#define _MKRFCMSG_H + + +int mkrfcmsg(faddr *, faddr *, char *, char *, time_t, int, FILE *, off_t, int); + +#endif + diff --git a/mbfido/mover.c b/mbfido/mover.c new file mode 100644 index 00000000..35ecf4a0 --- /dev/null +++ b/mbfido/mover.c @@ -0,0 +1,73 @@ +/***************************************************************************** + * + * File ..................: mbfido/mover.c + * Purpose ...............: Bad file mover + * Last modification date : 02-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "mover.h" + + + +void mover(char *srcdir, char *fn) +{ + char *From, *To; + + From = calloc(128, sizeof(char)); + To = calloc(128, sizeof(char)); + + sprintf(From, "%s%s", srcdir, fn); + sprintf(To, "%s/%s", CFG.badtic, fn); + Syslog('!', "Moving %s to %s", From, To); + + if (mkdirs(To)) { + if (file_mv(From, To) != 0) + WriteError("$Failed to move %s to %s", From, To); + } + + free(From); + free(To); +} + + + +/* + * Move the file and .tic file to the bad directory + */ +void MoveBad() +{ + mover(TIC.Inbound, TIC.TicName); + mover(TIC.FilePath, TIC.TicIn.OrgName); +} + + diff --git a/mbfido/mover.h b/mbfido/mover.h new file mode 100644 index 00000000..2b1c7f60 --- /dev/null +++ b/mbfido/mover.h @@ -0,0 +1,10 @@ +#ifndef _MOVER_H +#define _MOVER_H + + +void mover(char *, char *); +void MoveBad(void); + + +#endif + diff --git a/mbfido/msgutil.c b/mbfido/msgutil.c new file mode 100644 index 00000000..0f3018f8 --- /dev/null +++ b/mbfido/msgutil.c @@ -0,0 +1,226 @@ +/***************************************************************************** + * + * File ..................: mbaff/msgutil.c + * Purpose ...............: Announce new files and FileFind + * Last modification date : 21-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "msgutil.h" + + +extern int do_quiet; /* Supress screen output */ + + +/* + * Translation table from Hi-USA-ANSI to Lo-ASCII + */ +char lotab[] = { +"\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017" +"\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +"\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" +"\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" +"\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" +"\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" +"\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" +"\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" +"\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" +"\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" +"\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" +"\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" +"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" +"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" +"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" +"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + + + +void Msg_Id(fidoaddr aka) +{ + char *temp; + unsigned long crc = -1; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + Msg.ReplyCRC = 0xffffffff; + free(temp); +} + + + +void Msg_Pid(void) +{ + char *temp; + time_t tt; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "\001PID: MBSE-FIDO %s", VERSION); + MsgText_Add2(temp); + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + (void)time(&tt); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + free(temp); +} + + + +void Msg_Top(void) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "System name %s", CFG.bbs_name); + MsgText_Add2(temp); + sprintf(temp, "Sysop %s", CFG.sysop_name); + MsgText_Add2(temp); + sprintf(temp, "Location %s", CFG.location); + MsgText_Add2(temp); + sprintf(temp, "Remark %s", CFG.comment); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) != NULL) { + + MsgText_Add2((char *)"Line Phone number Maximum speed Fidonet Flags"); + MsgText_Add2((char *)"---- -------------------- -------------------- -------------------------"); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fp); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fp) == 1) { + if (((ttyinfo.type == POTS) || (ttyinfo.type == ISDN)) && + ttyinfo.available && strlen(ttyinfo.phone)) { + switch (ttyinfo.type) { + case POTS: sprintf(temp, "POTS %-20s %-20s %s", ttyinfo.phone, ttyinfo.speed, ttyinfo.flags); + break; + case ISDN: sprintf(temp, "ISDN %-20s %-20s %s", ttyinfo.phone, ttyinfo.speed, ttyinfo.flags); + break; + } + MsgText_Add2(temp); + } + } + + fclose(fp); + } + + MsgText_Add2((char *)""); + MsgText_Add2((char *)""); + free(temp); +} + + + +void Msg_Bot(fidoaddr UseAka, char *Org) +{ + char *temp, *aka; + + temp = calloc(81, sizeof(char)); + aka = calloc(40, sizeof(char)); + + MsgText_Add2((char *)""); + sprintf(temp, "With regards, %s", CFG.sysop_name); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (UseAka.point) + sprintf(aka, "(%d:%d/%d.%d)", UseAka.zone, UseAka.net, UseAka.node, UseAka.point); + else + sprintf(aka, "(%d:%d/%d)", UseAka.zone, UseAka.net, UseAka.node); + + sprintf(temp, " * Origin: %s %s", Org, aka); + MsgText_Add2(temp); + free(aka); + free(temp); +} + + + +void CountPosted(char *Base) +{ + char *temp; + FILE *fp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fp); + + while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + if (msgs.Active && (strlen(Base) == strlen(msgs.Base)) && + (!strcmp(Base, msgs.Base))) { + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + fseek(fp, - msgshdr.recsize, SEEK_CUR); + fwrite(&msgs, msgshdr.recsize, 1, fp); + break; + } + fseek(fp, msgshdr.syssize, SEEK_CUR); + } + + fclose(fp); + } else { + WriteError("$Can't open %s", temp); + } + + free(temp); +} + + + +char *To_Low(char *inp, int High) +{ + static char temp[81]; + int i; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%s", inp); + + if (High) + return temp; + + for (i = 0; i < strlen(temp); i++) + temp[i] = lotab[temp[i] & 0xff]; + + return temp; +} + + diff --git a/mbfido/msgutil.h b/mbfido/msgutil.h new file mode 100644 index 00000000..12349cec --- /dev/null +++ b/mbfido/msgutil.h @@ -0,0 +1,13 @@ +#ifndef _MSGUTIL_H +#define _MSGUTIL_H + + +void Msg_Id(fidoaddr); +void Msg_Pid(void); +void Msg_Top(void); +void Msg_Bot(fidoaddr, char *); +void CountPosted(char *); +char *To_Low(char *, int); + +#endif + diff --git a/mbfido/newspost.c b/mbfido/newspost.c new file mode 100644 index 00000000..4629972d --- /dev/null +++ b/mbfido/newspost.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * File ..................: mbfido/newspost.c + * Purpose ...............: Post newsarticles in temp newsfile. + * Last modification date : 21-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2801 + * Beekmansbos 10 Internet: mbroek@users.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "newspost.h" + + +extern FILE *nfp; +extern int newsopen; +extern int news_out; +extern int news_bad; + + + +int newspost(void) +{ + int start = TRUE; + char *buf, *p; + long curpos, count, seqnr; + FILE *ofp = NULL, *nb; + struct utsname utsbuf; + + if (newsopen) + fclose(nfp); + buf = calloc(10240, sizeof(char)); + + /* + * Now reopen the file for reading. If it fails and + * the file was original closed we leave quiet. + * If the file wasn't open previously but there is + * a file, try to post the articles. They may be + * still here if the newsserver wasn't available. + */ + sprintf(buf, "%s/tmp/newsout", getenv("MBSE_ROOT")); + if ((nfp = fopen(buf, "r")) == NULL) { + if (newsopen) + WriteError("$Can't reopen %s", buf); + free(buf); + return newsopen; + } + IsDoing("Post news"); + + if (CFG.newsfeed == FEEDINN) { + Syslog('+', "Posting news articles to the NNTP server"); + if (nntp_connect() == -1) { + free(buf); + return TRUE; + } + + while (fgets(buf, 10240, nfp)) { + if (start) { + if (nntp_cmd((char *)"POST\r\n", 340) != 0) { + WriteError("NNTP POST refused"); + free(buf); + return TRUE; + } + } + start = FALSE; + if (!strcmp(buf, ".\n")) { + if (nntp_cmd((char *)".\r\n", 240) == 0) { + news_out++; + } else { + WriteError("NNTP: refused article %d", news_out+1); + news_bad++; + } + start = TRUE; + } else { + /* + * Most NNTP servers like cr/lf after each line. + */ + Striplf(buf); + p = buf+strlen(buf); + *p++ = '\r'; + *p++ = '\n'; + *p = '\0'; + nntp_send(buf); + } + Nopper(); + } + nntp_close(); + } + + /* + * Create newsbatch file. + */ + if ((CFG.newsfeed == FEEDUUCP) || (CFG.newsfeed == FEEDRNEWS)) { + Syslog('n', "Building uncompressed batchfile"); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + if ((ofp = fopen(buf, "w+")) == NULL) { + WriteError("$Can't create %s", buf); + free(buf); + fclose(nfp); + return TRUE; + } + buf = calloc(10240, sizeof(char)); + + count = curpos = 0; + while (feof(ofp) == 0) { + /* + * Count the total length of the message + */ + while (fgets(buf, 10240, nfp)) { + if (strcmp(buf, ".\n")) { + count += strlen(buf); + } else { + break; + } + } + if (!count) + break; + fseek(nfp, curpos, SEEK_SET); + fprintf(ofp, "#! rnews %ld\n", count); + while (fgets(buf, 10240, nfp)) { + if (strcmp(buf, ".\n")) { + fprintf(ofp, buf); + } else { + break; + } + } + news_out++; + curpos = ftell(nfp); + count = 0; + } + /* + * Rewind the newsbatch and leave it open. + */ + rewind(ofp); + } + + fclose(nfp); + newsopen = FALSE; + + /* + * Mode rnews, pipe just created newsbatch to rnews. + */ + if (CFG.newsfeed == FEEDRNEWS) { + if ((nb = (expipe(CFG.rnewspath, NULL, NULL))) == NULL) { + WriteError("Could not open (pip) output for %s", CFG.rnewspath); + newsopen = FALSE; + return TRUE; + } + while (fgets(buf, 10240, ofp)) { + fputs(buf, nb); + } + if (exclose(nb)) { + WriteError("Error closing pipe"); + newsopen = FALSE; + return TRUE; + } else + Syslog('+', "Articles send through %s", CFG.rnewspath); + fclose(ofp); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + unlink(buf); + } + + /* + * Mode UUCP, create UUCP files. + */ + if (CFG.newsfeed == FEEDUUCP) { + seqnr = sequencer(); + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf)) { + WriteError("Can't get system nodename"); + newsopen = FALSE; + return TRUE; + } + + sprintf(buf, "%s/C.%s%lx", CFG.rnewspath, CFG.nntpnode, seqnr); + if ((nb = fopen(buf, "a")) == NULL) { + WriteError("Can't create %s", buf); + newsopen = FALSE; + return TRUE; + } + seqnr = sequencer(); + fprintf(nb, "E D.%s%lx D.%s%lx news -C D.%s%lx 0666 \"\" 0 rnews\n", + utsbuf.nodename, seqnr, utsbuf.nodename, seqnr, utsbuf.nodename, seqnr); + fclose(nb); + sprintf(buf, "%s/D.%s%lx", CFG.rnewspath, utsbuf.nodename, seqnr); + if ((nb = fopen(buf, "a")) == NULL) { + WriteError("Can't create %s", buf); + newsopen = FALSE; + return TRUE; + } + while (fgets(buf, 10240, ofp)) { + fputs(buf, nb); + } + Syslog('+', "Articles placed in %s", CFG.rnewspath); + fclose(ofp); + sprintf(buf, "%s/tmp/newsbatch", getenv("MBSE_ROOT")); + unlink(buf); + } + + sprintf(buf, "%s/tmp/newsout", getenv("MBSE_ROOT")); + unlink(buf); + free(buf); + return FALSE; +} + + diff --git a/mbfido/newspost.h b/mbfido/newspost.h new file mode 100644 index 00000000..2117b755 --- /dev/null +++ b/mbfido/newspost.h @@ -0,0 +1,9 @@ +#ifndef _NEWSPOST_H +#define _NEWSPOST_H + + +int newspost(void); + + +#endif + diff --git a/mbfido/notify.c b/mbfido/notify.c new file mode 100644 index 00000000..9ddeadc9 --- /dev/null +++ b/mbfido/notify.c @@ -0,0 +1,170 @@ +/***************************************************************************** + * + * File ..................: mbfido/notify.c + * Purpose ...............: Write notify messages. + * Last modification date : 28-Nov-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbnode.h" +#include "filemgr.h" +#include "areamgr.h" +#include "sendmail.h" +#include "notify.h" + + + +extern int do_quiet; /* Quiet flag */ +int notify = 0; /* Nr of notify messages */ + + + +/* + * Write AreaMgr and FileMgr notify messages. + */ +int Notify(char *Options) +{ + short Zones = -1, Nets = -1, Nodes = -1, Points = -1; + short Lzone, Lnet; + FILE *np; + char *temp, Opt[44]; + int i; + + Syslog('+', "Notify \"%s\"", Options); + + if (!do_quiet) { + colour(9, 0); + printf("Writing notify messages\n"); + colour(3, 0); + } + + if (strlen(Options)) { + sprintf(Opt, "%s~", Options); + if (strchr(Opt, '.') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "/")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + temp = strdup(strtok(NULL, ".")); + if (strncmp(temp, "*", 1)) + Nodes = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) + Points = atoi(temp); + else + Points = -1; + } else if (strchr(Opt, '/') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "/")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) { + Nodes = atoi(temp); + Points = 0; + } + } else if (strchr(Opt, ':') != NULL) { + temp = strdup(strtok(Opt, ":")); + if (atoi(temp)) + Zones = atoi(temp); + temp = strdup(strtok(NULL, "~")); + if (strncmp(temp, "*", 1)) + Nets = atoi(temp); + } else { + temp = strdup(strtok(Opt, "~")); + if (atoi(temp)) + Zones = atoi(temp); + } + } + Syslog('m', "Parsing nodes %d:%d/%d.%d", Zones, Nets, Nodes, Points); + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((np = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + return FALSE; + } + fread(&nodeshdr, sizeof(nodeshdr), 1, np); + + while (fread(&nodes, nodeshdr.recsize, 1, np) == 1) { + Lzone = Lnet = 0; + for (i = 0; i < 20; i++) { + if ((((Zones == -1) && nodes.Notify) || (Zones == nodes.Aka[i].zone)) && + (((Nets == -1) && nodes.Notify) || (Nets == nodes.Aka[i].net)) && + (((Nodes == -1) && nodes.Notify) || (Nodes == nodes.Aka[i].node)) && + (((Points == -1) && nodes.Notify) || (Points == nodes.Aka[i].point)) && + (nodes.Aka[i].zone) && + ((Lzone != nodes.Aka[i].zone) || + (Lnet != nodes.Aka[i].net))) { + Lzone = nodes.Aka[i].zone; + Lnet = nodes.Aka[i].net; + + Syslog('m', "Notify to %s", aka2str(nodes.Aka[i])); + if (!do_quiet) { + printf("\rNotify %-24s", aka2str(nodes.Aka[i])); + fflush(stdout); + } + + if (i == 0) { + F_Status(fido2faddr(nodes.Aka[i])); + A_Status(fido2faddr(nodes.Aka[i])); + } + F_List(fido2faddr(nodes.Aka[i]), TRUE); + A_List(fido2faddr(nodes.Aka[i]), TRUE); + A_Flow(fido2faddr(nodes.Aka[i]), TRUE); + notify++; + } + } + fseek(np, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + + fclose(np); + free(temp); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } + + if (notify) + return TRUE; + else + return FALSE; +} + + + diff --git a/mbfido/notify.h b/mbfido/notify.h new file mode 100644 index 00000000..af6eb3de --- /dev/null +++ b/mbfido/notify.h @@ -0,0 +1,9 @@ +#ifndef _NOTIFY_H +#define _NOTIFY_H + + +int Notify(char *); + + +#endif + diff --git a/mbfido/pack.c b/mbfido/pack.c new file mode 100644 index 00000000..19cf1417 --- /dev/null +++ b/mbfido/pack.c @@ -0,0 +1,416 @@ +/***************************************************************************** + * + * File ..................: tosser/pack.c + * Purpose ...............: Pack mail + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbftn.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "pack.h" + + +extern int do_quiet; /* Quiet flag */ + + +/* + * Pack queued arcmail mail for a node. If the node is locked, the mail won't + * be packed, and the queue stays as it is. The mail will then be packed + * on a next run. + */ +int pack_queue(char *name) +{ + FILE *fp; + faddr noden; + fidoaddr nodenr; + char flavor, nr, oldnr, maxnr; + char srcfile[128], *arcfile, *pktfile; + int Attach, fage; + long fsize; + time_t Now; + + sprintf(srcfile, "%s", name); + + /* + * Get the nodenumber from the filename + */ + noden.domain = NULL; + noden.name = NULL; + noden.zone = atoi(strtok(name, ".")); + noden.net = atoi(strtok(NULL, ".")); + noden.node = atoi(strtok(NULL, ".")); + noden.point = atoi(strtok(NULL, ".")); + if (SearchFidonet(noden.zone)) + noden.domain = xstrcpy(fidonet.domain); + + memset(&nodenr, 0, sizeof(nodenr)); + nodenr.zone = noden.zone; + nodenr.net = noden.net; + nodenr.node = noden.node; + nodenr.point = noden.point; + sprintf(nodenr.domain, "%s", noden.domain); + + if (!SearchNode(nodenr)) { + WriteError("Downlink %s not found", aka2str(nodenr)); + if (noden.domain) + free(noden.domain); + return FALSE; + } + + /* + * If we route via another aka, change everything. + */ + if (nodes.RouteVia.zone) { + Syslog('p', "Route Via %s", aka2str(nodes.RouteVia)); + noden.zone = nodes.RouteVia.zone; + noden.net = nodes.RouteVia.net; + noden.node = nodes.RouteVia.node; + noden.point = nodes.RouteVia.point; + if (noden.domain) + free(noden.domain); + noden.domain = xstrcpy(nodes.RouteVia.domain); + /* + * Load routevia noderecord to get the correct flavor. + * If there is no noderecord, reload the old one. + */ + if (!SearchNode(nodes.RouteVia)) + SearchNode(nodenr); + } + + Syslog('+', "Pack ARCmail for %s, via %s", aka2str(nodenr), ascfnode(&noden, 0x1f)); + + if (!do_quiet) { + printf("\rAdding ARCmail for %s ", ascfnode(&noden, 0x1f)); + fflush(stdout); + } + + if (getarchiver((char *)"ZIP")) { + flavor = 'f'; + if (nodes.Crash) + flavor = 'c'; + if (nodes.Hold) + flavor = 'h'; + } else { + WriteError("Archiver ZIP not found"); + return FALSE; + } + + /* + * Generate ARCmail filename and .PKT filename, + */ + arcfile = calloc(128, sizeof(char)); + sprintf(arcfile, "%s", arcname(&noden, nodes.Aka[0].zone, nodes.ARCmailCompat)); + pktfile = calloc(40, sizeof(char)); + sprintf(pktfile, "%08lx.pkt", sequencer()); + + if (nodelock(&noden)) { + WriteError("Node %s lock error", ascfnode(&noden, 0x1f)); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + + if (rename(srcfile, pktfile)) { + WriteError("$Can't rename %s to %s", srcfile, pktfile); + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + + /* + * Add zero word at the end of the .pkt file + */ + if ((fp = fopen(pktfile, "a+")) == NULL) { + WriteError("$Can't open %s", pktfile); + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return FALSE; + } + putc('\0', fp); + putc('\0', fp); + fsync(fileno(fp)); + fclose(fp); + + /* + * Check the size of the existing archive if there is a size limit. + * Change to new archive names if the existing is too large. + * If the archive size is zero, it's an already sent archive, the + * number will be bumped also. + * If the archive is older then 6 days, the name is also bumped. + * Do this until we find a new name or if the last digit is a '9' or 'z'. + * Purge archives older then toss_days. + */ + nr = oldnr = '0'; + Now = time(NULL); + if (nodes.ARCmailAlpha) + maxnr = 'z'; + else + maxnr = '9'; + Attach = FALSE; + + for (;;) { + fsize = file_size(arcfile); + fage = (int)((Now - file_time(arcfile)) / 86400); + + if (fsize == -1L) { + Attach = TRUE; + break; + } + + if (fsize == 0L) { + if ((fage > 6) && (nr < maxnr)) { + /* + * Remove truncated ARCmail files older then 6 days. + */ + unlink(arcfile); + fsize = -1L; + Attach = TRUE; + break; + } + /* + * Increase filename extension if there is a truncated file of today. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + + } else if (CFG.maxarcsize && (fsize > (CFG.maxarcsize * 1024)) && (nr < maxnr)) { + /* + * Use a new ARCmail file if the last one is too big. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + } + + fsize = file_size(arcfile); + fage = (int)((Now - file_time(arcfile)) / 86400); + + if ((fsize > 0L) && (fage > 6) && (nr < maxnr)) { + /* + * If there is ARCmail of a week old or older, add mail + * to a new ARCmail bundle. + */ + nr++; + if (nr == ('9' +1)) + nr = 'a'; + arcfile[strlen(arcfile) -1] = nr; + } + + if (oldnr == nr) + break; + else + oldnr = nr; + } + + fsize = file_size(arcfile); + if (execute(archiver.marc, arcfile, pktfile, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) + unlink(pktfile); + + /* + * Attach file to .flo + */ + if (Attach) + attach(noden, arcfile, TFS, flavor); + + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(arcfile); + free(pktfile); + return TRUE; +} + + + +/* + * Add queued unpacked mail for a node. If the node is locked, the mail + * stays in the queue. + */ +int add_queue(char *name) +{ + faddr noden; + char flavor; + char srcfile[128], *outfile; + char *buf; + FILE *inf, *ouf; + int bread; + + sprintf(srcfile, "%s", name); + + /* + * Get the nodenumber from the filename + */ + noden.domain = NULL; + noden.name = NULL; + noden.zone = atoi(strtok(name, ".")); + noden.net = atoi(strtok(NULL, ".")); + noden.node = atoi(strtok(NULL, ".")); + noden.point = atoi(strtok(NULL, ".")); + if (SearchFidonet(noden.zone)) + noden.domain = xstrcpy(fidonet.domain); + + Syslog('+', "Add Netmail for %s", ascfnode(&noden, 0x1f)); + if (!do_quiet) { + printf("\rAdding Netmail for %s ", ascfnode(&noden, 0x1f)); + fflush(stdout); + } + + outfile = calloc(128, sizeof(char)); + if (strstr(srcfile, ".iii")) + flavor = 'i'; + else if (strstr(srcfile, ".ccc")) + flavor = 'c'; + else if (strstr(srcfile, ".hhh")) + flavor = 'h'; + else + flavor = 'f'; + sprintf(outfile, "%s", pktname(&noden, flavor)); + Syslog('p', "Outfile: %s", outfile); + + if (nodelock(&noden)) { + WriteError("Node %s lock error", ascfnode(&noden, 0x1f)); + free(outfile); + if (noden.domain) + free(noden.domain); + return FALSE; + } + + /* + * Now we must see if there is already mail in the outbound. + * If that's the case, we must skip the .pkt header from the queue + * because there is already a .pkt header also, append to the + * outbound 2 bytes before the end of file, this is the zero word. + */ + if ((inf = fopen(srcfile, "r")) != NULL) { + if (access(outfile, R_OK) == -1) { + ouf = fopen(outfile, "w"); /* create new */ + Syslog('p', "Create new %s", outfile); + } else { + ouf = fopen(outfile, "r+"); /* open R/W */ + fseek(ouf, -2, SEEK_END); /* b4 0 word */ + fseek(inf, 58, SEEK_SET); /* skip header */ + Syslog('p', "Append to %s", outfile); + } + if (ouf != NULL) { + buf = malloc(16384); + + do { + bread = fread(buf, 1, 16384, inf); + fwrite(buf, 1, bread, ouf); + } while (bread); + + free(buf); + putc('\0', ouf); + putc('\0', ouf); + fsync(fileno(ouf)); + fclose(ouf); + fclose(inf); + unlink(srcfile); + } else { + WriteError("$Can't open %s", outfile); + fclose(inf); + } + } + + nodeulock(&noden); + if (noden.domain) + free(noden.domain); + free(outfile); + return TRUE; +} + + + +/* + * Pack mailqueue file(s) in the $MBSE_ROOT/tmp directory. + */ +void packmail() +{ + char *temp; + struct dirent *de; + DIR *dp; + + IsDoing("Packing mail"); + if (!do_quiet) { + colour(9, 0); + printf("Packing mail\n"); + colour(3, 0); + } + + temp = calloc(129, sizeof(char)); + sprintf(temp, "%s/tmp", getenv("MBSE_ROOT")); + + if (chdir(temp) == -1) { + WriteError("$Error chdir to %s", temp); + free(temp); + return; + } + + if ((dp = opendir(temp)) == NULL) { + WriteError("$Error opendir %s", temp); + free(temp); + return; + } + + /* + * Scan the $MBSE_ROOT/tmp directory for .qqq or .nnn files + */ + while ((de = readdir(dp))) { + if (strstr(de->d_name, ".qqq")) + pack_queue(de->d_name); + if (strstr(de->d_name, ".nnn") || strstr(de->d_name, ".iii") || + strstr(de->d_name, ".ccc") || strstr(de->d_name, ".hhh")) + add_queue(de->d_name); + } + + closedir(dp); + free(temp); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + diff --git a/mbfido/pack.h b/mbfido/pack.h new file mode 100644 index 00000000..b2a4f635 --- /dev/null +++ b/mbfido/pack.h @@ -0,0 +1,11 @@ +#ifndef _PACK_H +#define _PACK_H + + +int pack_queue(char *); +int add_queue(char *); +void packmail(void); + + +#endif + diff --git a/mbfido/paths.h.in b/mbfido/paths.h.in new file mode 100644 index 00000000..46ab79c9 --- /dev/null +++ b/mbfido/paths.h.in @@ -0,0 +1,7 @@ +/* + Autogenerated by configure + */ +#define _PATH_COMPRESS "@COMPRESS@" +#define _PATH_GZIP "@GZIP@" + + diff --git a/mbfido/ping.c b/mbfido/ping.c new file mode 100644 index 00000000..ad6a41a6 --- /dev/null +++ b/mbfido/ping.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: mbfido/ping.c + * Purpose ...............: Ping Service + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "../lib/dbcfg.h" +#include "../lib/dbnode.h" +#include "../lib/dbtic.h" +#include "../lib/dbdupe.h" +#include "../lib/dbuser.h" +#include "../lib/dbftn.h" +#include "sendmail.h" +#include "mgrutil.h" +#include "postnetmail.h" +#include "ping.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +extern int net_in; /* Netmails received */ +extern int net_out; /* Netmails forwarded */ +extern int net_bad; /* Bad netmails (tracking errors */ +extern char *subj; /* Message subject */ +extern char *msgid; /* Original message id */ + + + +int Ping(faddr *f, faddr *t, FILE *fp, int intransit) +{ + int rc = 0; + char *Buf; + FILE *np; + time_t Now; + faddr *from; + + Now = time(NULL); + if (SearchFidonet(f->zone)) + f->domain = xstrcpy(fidonet.domain); + + Syslog('+', "%s ping msg from %s", intransit ? "Intransit":"Final", ascfnode(f, 0xff)); + Buf = calloc(2049, sizeof(char)); + rewind(fp); + + np = tmpfile(); + from = bestaka_s(f); + if (intransit) { + from->name = xstrcpy((char *)"Ping TRACE service"); + } else { + from->zone = t->zone; + from->net = t->net; + from->node = t->node; + from->point = t->point; + from->name = xstrcpy((char *)"Ping service"); + } + + if (f->point) + fprintf(np, "\001TOPT %d\r", f->point); + if (from->point) + fprintf(np, "\001FMPT %d\r", from->point); + fprintf(np, "\001INTL %d:%d/%d %d:%d/%d\r", f->zone, f->net, f->node, from->zone, from->net, from->node); + + /* + * Add MSGID, REPLY and PID + */ + fprintf(np, "\001MSGID: %s %08lx\r", ascfnode(from, 0x1f), sequencer()); + while ((fgets(Buf, 2048, fp)) != NULL) { + Striplf(Buf); + if (strncmp(Buf, "\001MSGID:", 7) == 0) { + fprintf(np, "\001REPLY:%s\r", Buf+7); + } + } + fprintf(np, "\001PID: MBSE-FIDO %s\r", VERSION); + fprintf(np, "\001TZUTC: %s\r", gmtoffset(Now)); + + fprintf(np, " Dear %s\r\r", MBSE_SS(f->name)); + if (intransit) { + fprintf(np, "You did send a PING to %s\r", ascfnode(t, 0x1f)); + fprintf(np, "This is a TRACE response from \"%s\" aka %s\r", CFG.bbs_name, ascfnode(from, 0x1f)); + fprintf(np, "The time of arrival is %s\r", rfcdate(Now)); + } else + fprintf(np, "Your Ping arrived here at %s\r", rfcdate(Now)); + fprintf(np, "Here are all the detected Via lines of the message from you:\r\r"); + fprintf(np, "======================================================================\r"); + + rewind(fp); + while ((fgets(Buf, 2048, fp)) != NULL) { + Striplf(Buf); + if (strncmp(Buf, "\1Via", 4) == 0) { + fprintf(np, "%s\r", Buf+1); + } + } + fprintf(np, "======================================================================\r"); + + fprintf(np, "\rWith regards, %s\r\r", CFG.sysop_name); + fprintf(np, "--- MBSE BBS v%s (Linux)\r", VERSION); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + rc = postnetmail(np, from, f, NULL, (char *)"Re: Ping", Now, 0x0000, FALSE); + tidy_faddr(from); + + fclose(np); + + free(Buf); + return rc; +} + + diff --git a/mbfido/ping.h b/mbfido/ping.h new file mode 100644 index 00000000..182ee991 --- /dev/null +++ b/mbfido/ping.h @@ -0,0 +1,9 @@ +#ifndef _PINGMGR_H +#define _PINGMGR_H + + +int Ping(faddr *, faddr *, FILE *, int); + + +#endif + diff --git a/mbfido/post.c b/mbfido/post.c new file mode 100644 index 00000000..b12db6d3 --- /dev/null +++ b/mbfido/post.c @@ -0,0 +1,245 @@ +/***************************************************************************** + * + * File ..................: mbfido/post.c + * Purpose ...............: Post a message from a file. + * Last modification date : 20-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "post.h" + + +extern int do_quiet; /* Supress screen output */ + + + +void Post(char *To, long Area, char *Subj, char *File, char *Flavor) +{ + int i, rc = FALSE; + char *aka, *temp, *sAreas; + FILE *fp, *tp; + unsigned long crc = -1; + time_t tt; + struct tm *t; + + + if (!do_quiet) { + colour(3, 0); + printf("Post \"%s\" to \"%s\" in area %ld\n", File, To, Area); + } + + IsDoing("Posting"); + Syslog('+', "Post \"%s\" area %ld to \"%s\" flavor %s", File, Area, To, Flavor); + Syslog('+', "Subject: \"%s\"", Subj); + + if ((tp = fopen(File, "r")) == NULL) { + WriteError("$Can't open %s", File); + return; + } + + sAreas = calloc(128, sizeof(char)); + sprintf(sAreas, "%s//etc/mareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(sAreas, "r")) == NULL) { + WriteError("$Can't open %s", sAreas); + free(sAreas); + fclose(tp); + return; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fp); + if (fseek(fp, (msgshdr.recsize + msgshdr.syssize) * (Area - 1), SEEK_CUR) == 0) { + if (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + rc = TRUE; + } else { + WriteError("$Can't read area %ld", Area); + } + } else { + WriteError("$Can't seek area %ld", Area); + } + + free(sAreas); + if (rc == FALSE) { + fclose(fp); + fclose(tp); + return; + } + + if (!msgs.Active) { + WriteError("Area %s not active", msgs.Name); + fclose(fp); + fclose(tp); + return; + } + + if (!Msg_Open(msgs.Base)) { + WriteError("Can't open %s", msgs.Base); + fclose(fp); + fclose(tp); + return; + } + + if (!Msg_Lock(30L)) { + WriteError("Can't lock %s", msgs.Base); + Msg_Close(); + fclose(fp); + fclose(tp); + return; + } + + (void)time(&tt); + t = localtime(&tt); + Diw = t->tm_wday; + Miy = t->tm_mon; + memset(&Msg, 0, sizeof(Msg)); + Msg_New(); + + /* + * Update statistic counter for message area + */ + fseek(fp, - msgshdr.recsize, SEEK_CUR); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + fwrite(&msgs, msgshdr.recsize, 1, fp); + fclose(fp); + + /* + * Start writing the message + */ + sprintf(Msg.From, CFG.sysop_name); + sprintf(Msg.To, To); + + /* + * If netmail, clean the To field. + */ + if ((msgs.Type == NETMAIL) && strchr(To, '@')) { + for (i = 0; i < strlen(Msg.To); i++) { + if (Msg.To[i] == '_') + Msg.To[i] = ' '; + if (Msg.To[i] == '@') { + Msg.To[i] = '\0'; + break; + } + } + } + + sprintf(Msg.Subject, "%s", Subj); + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + Msg.Written = time(NULL); + Msg.Arrived = time(NULL); + Msg.Local = TRUE; + + if (strchr(Flavor, 'c')) + Msg.Crash = TRUE; + if (strchr(Flavor, 'p')) + Msg.Private = TRUE; + if (strchr(Flavor, 'h')) + Msg.Hold = TRUE; + + switch (msgs.Type) { + case LOCALMAIL: + Msg.Localmail = TRUE; + break; + + case NETMAIL: + Msg.Netmail = TRUE; + sprintf(Msg.ToAddress, "%s", ascfnode(parsefaddr(To), 0xff)); + break; + + case ECHOMAIL: + Msg.Echomail = TRUE; + break; + + case NEWS: + Msg.News = TRUE; + break; + } + + temp = calloc(128, sizeof(char)); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(msgs.Aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + Msg.ReplyCRC = 0xffffffff; + sprintf(temp, "\001PID: MBSE-FIDO %s", VERSION); + MsgText_Add2(temp); + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + MsgText_Add2(temp); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + + /* + * Add the file as text + */ + Msg_Write(tp); + fclose(tp); + + /* + * Finish the message + */ + aka = calloc(40, sizeof(char)); + MsgText_Add2((char *)""); + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (msgs.Aka.point) + sprintf(aka, "(%d:%d/%d.%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node, msgs.Aka.point); + else + sprintf(aka, "(%d:%d/%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (strlen(msgs.Origin)) + sprintf(temp, " * Origin: %s %s", msgs.Origin, aka); + else + sprintf(temp, " * Origin: %s %s", CFG.origin, aka); + + MsgText_Add2(temp); + free(aka); + + Msg_AddMsg(); + Msg_UnLock(); + Syslog('+', "Posted message %ld", Msg.Id); + + sprintf(temp, "%s/tmp/%smail.jam", getenv("MBSE_ROOT"), (msgs.Type == ECHOMAIL) ? "echo" : "net"); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", msgs.Base, Msg.Id); + fclose(fp); + } + free(temp); + Msg_Close(); + CreateSema((char *)"mailout"); + + return; +} + + diff --git a/mbfido/post.h b/mbfido/post.h new file mode 100644 index 00000000..abab25f5 --- /dev/null +++ b/mbfido/post.h @@ -0,0 +1,9 @@ +#ifndef _POST_H +#define _POST_H + + +void Post(char *, long, char *, char *, char *); /* Post a Message */ + + +#endif + diff --git a/mbfido/postemail.c b/mbfido/postemail.c new file mode 100644 index 00000000..a1d52d2b --- /dev/null +++ b/mbfido/postemail.c @@ -0,0 +1,122 @@ +/***************************************************************************** + * + * File ..................: mbfido/postemail.c + * Purpose ...............: Post Email message from temp file + * Last modification date : 06-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbuser.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "postemail.h" + + +/* + * Global variables + */ +extern int email_in; /* Total emails processed */ +extern int email_imp; /* Netmails imported */ +extern int email_bad; /* Bad netmails */ + + + +/* + * Post email message + * + * 0 - All seems well. + * 1 - Something went wrong. + * 2 - SMTP error. + * + */ +int postemail(FILE *fp, char *MailFrom, char *MailTo) +{ + char *temp, *p; + char buf[4096]; + int result = 1; + + temp = calloc(2048, sizeof(char)); + rewind(fp); + + Syslog('+', "SMTP: posting from %s to %s", MailFrom, MailTo); + if (smtp_connect() == -1) { + WriteError("SMTP: connection refused"); + return 2; + } + + sprintf(temp, "MAIL FROM: <%s>\r\n", MailFrom); + if (smtp_cmd(temp, 250)) { + WriteError("SMTP: refused FROM <%s>", MailFrom); + return 2; + } + + sprintf(temp, "RCPT TO: <%s>\r\n", MailTo); + if (smtp_cmd(temp, 250)) { + WriteError("SMTP: refused TO <%s>", MailTo); + return 2; + } + + if (smtp_cmd((char *)"DATA\r\n", 354)) { + WriteError("SMTP refused DATA mode"); + return 2; + } + + while ((fgets(buf, sizeof(buf)-2, fp)) != NULL) { + if (strncmp(buf, ".\r\n", 3)) { + p = buf+strlen(buf)-1; + if (*p == '\n') { + *p++ = '\r'; + *p++ = '\n'; + *p = '\0'; + } + smtp_send(buf); + } else { + sprintf(temp, " .\r\n"); + smtp_send(temp); + } + } + + email_in++; + if (smtp_cmd((char *)".\r\n", 250) == 0) { + Syslog('+', "SMTP: Message accepted"); + result = 0; + email_imp++; + } else { + WriteError("SMTP: refused message"); + email_bad++; + } + + free(temp); + smtp_close(); + + return result; +} + + diff --git a/mbfido/postemail.h b/mbfido/postemail.h new file mode 100644 index 00000000..07ce68de --- /dev/null +++ b/mbfido/postemail.h @@ -0,0 +1,8 @@ +#ifndef _POSTEMAIL_H +#define _POSTEMAIL_H + + +int postemail(FILE *, char *, char *); + +#endif + diff --git a/mbfido/postnetmail.c b/mbfido/postnetmail.c new file mode 100644 index 00000000..b0448f33 --- /dev/null +++ b/mbfido/postnetmail.c @@ -0,0 +1,316 @@ +/***************************************************************************** + * + * File ..................: mbfido/postnetmail.c + * Purpose ...............: Post Netmail message from temp file + * Last modification date : 21-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/dbcfg.h" +#include "../lib/dbuser.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tracker.h" +#include "addpkt.h" +#include "importnet.h" +#include "mkrfcmsg.h" +#include "areamgr.h" +#include "filemgr.h" +#include "ping.h" +#include "postemail.h" + + + +/* + * Global variables + */ +extern int net_in; /* Total netmails processed */ +extern int net_out; /* Netmails exported */ +extern int net_imp; /* Netmails imported */ +extern int net_bad; /* Bad netmails */ +extern int most_debug; /* Headvy debugging flag */ + + + +/* + * Post netmail message for temp file. The tempfile is an FTN style message. + * + * 0 - All seems well. + * 1 - Something went wrong. + * + */ +int postnetmail(FILE *fp, faddr *f, faddr *t, char *orig, char *subject, time_t mdate, int flags, int DoPing) +{ + char *p, *reply = NULL; + char name[36], *buf; + char System[36], ext[4]; + int result = 1, email = FALSE; + faddr *ta, *ra; + fidoaddr na, route, Orig; + FILE *sfp, *net; + time_t now; + struct tm *tm; + + Syslog('m', "Post netmail from: %s", ascfnode(f, 0xff)); + Syslog('m', "Post netmail to : %s", ascfnode(t, 0xff)); + Syslog('m', "Post netmail subj: %s", MBSE_SS(subject)); + net_in++; + + memset(&na, 0, sizeof(na)); + na.zone = t->zone; + na.net = t->net; + na.node = t->node; + na.point = t->point; + if (SearchFidonet(na.zone)) + sprintf(na.domain, "%s", fidonet.domain); + + switch(TrackMail(na, &route)) { + case R_LOCAL: + /* + * Check the To: field. + */ + if (strchr(t->name, '@') != NULL) { + sprintf(name, "%s", strtok(t->name, "@")); + sprintf(System, "%s", strtok(NULL, "\000")); + email = TRUE; + } else { + sprintf(name, "%s", t->name); + sprintf(System, "%s", CFG.sysdomain); + } + + if (email) { + /* + * Send this netmail via mkrfcmsg -> postemail. + */ + if (reply) + free(reply); + most_debug = TRUE; + result = mkrfcmsg(f, t, subject, orig, mdate, flags, fp, 0L, FALSE); + most_debug = FALSE; + return result; + } + + /* + * If message to "sysop" or "postmaster" replace it + * with the sysops real name. + */ + if ((strncasecmp(name, "sysop", 5) == 0) || (strcasecmp(name, "postmaster") == 0)) { + Syslog('+', " Readdress from %s to %s", name, CFG.sysop_name); + sprintf(name, "%s", CFG.sysop_name); + } + + /* + * If the message is a service message, check the + * services database to see what action is needed. + * First make sure that the right noderecord is loaded. + */ + (void)noderecord(f); + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((sfp = fopen(p, "r")) == NULL) { + WriteError("$Can't open %s", p); + } else { + fread(&servhdr, sizeof(servhdr), 1, sfp); + while (fread(&servrec, servhdr.recsize, 1, sfp) == 1) { + if ((strncasecmp(servrec.Service, name, strlen(servrec.Service)) == 0) && servrec.Active) { + switch (servrec.Action) { + case AREAMGR: result = AreaMgr(f, t, mdate, flags, fp); + break; + case FILEMGR: result = FileMgr(f, t, mdate, flags, fp); + break; + case EMAIL: most_debug = TRUE; + result = mkrfcmsg(f, t, subject, orig, mdate, flags, fp, 0L, FALSE); + most_debug = FALSE; + break; + } + Syslog('m', "Handled service %s, rc=%d", servrec.Service, result); + if (reply) + free(reply); + fclose(sfp); + return result; + } + } + fclose(sfp); + } + free(p); + + /* + * Ping function + */ + if (!strcasecmp(name, (char *)"ping") && DoPing) { + return Ping(f, t, fp, FALSE); + } + + /* + * Check userlist real names, handles, unix names. + * Import if one fits. + */ + if (SearchUser(name)) { + if (reply) + free(reply); + return importnet(f, t, mdate, flags, fp); + } + + Syslog('+', " \"%s\" is not a known BBS user", name); + /* + * Unknown, readdress it to the sysop. + */ + net_bad++; + Syslog('+', " Readdress from %s to %s", name, CFG.sysop_name); + sprintf(name, "%s", CFG.sysop_name); + if (SearchUser(name)) { + return importnet(f, t, mdate, flags, fp); + } else { + WriteError("Readdress import failed"); + return 0; + } + break; + + case R_DIRECT: + case R_ROUTE: + Syslog('+', "Route netmail via %s", aka2str(route)); + if (!strcasecmp(t->name, (char *)"ping") && DoPing) { + Syslog('+', "In transit \"Ping\" message detected"); + Ping(f, t, fp, TRUE); + (void)noderecord(f); + } + + /* + * Forward this message. Will not work for unknown + * direct links. + */ + if (SearchNode(route)) { + memset(&Orig, 0, sizeof(Orig)); + ra = fido2faddr(route); + ta = bestaka_s(ra); + Orig.zone = ta->zone; + Orig.net = ta->net; + Orig.node = ta->node; + Orig.point = ta->point; + tidy_faddr(ra); + tidy_faddr(ta); + + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + + if ((net = OpenPkt(Orig , route, (char *)ext)) == NULL) { + net_bad++; + WriteError("Can't create netmail"); + return 0; + } + } else { + /* + * If it's not a direct link, create a outbound + * .pkt anyway, better then that this mail is + * lost. It gets the normal status, it might + * get delivered during ZMH this way. + */ + Syslog('!', "Warning: not a direct link, check setup"); + memset(&Orig, 0, sizeof(Orig)); + ra = fido2faddr(route); + ta = bestaka_s(ra); + Orig.zone = ta->zone; + Orig.net = ta->net; + Orig.node = ta->node; + Orig.point = ta->point; + tidy_faddr(ra); + tidy_faddr(ta); + + if ((net = OpenPkt(Orig , route, (char *)"nnn")) == NULL) { + net_bad++; + WriteError("Can't create netmail"); + return 0; + } + } + + /* + * Now start forward. + */ + Syslog('m', "Net from %s", ascfnode(f, 0xff)); + Syslog('m', "Net to %s", ascfnode(t, 0xff)); + Syslog('m', "Net flags %08x", flags); + Syslog('m', "Net subj %s", subject); + + if (AddMsgHdr(net, f, t, flags, 0, mdate, t->name, f->name, subject)) { + WriteError("Can't write message header"); + net_bad++; + return 0; + } + rewind(fp); + + /* + * Copy all text including kludges, when + * finished, insert our ^aVia line. + */ + buf = calloc(2048, sizeof(char)); + while ((fgets(buf, 2048, fp)) != NULL) + fprintf(net, "%s\r", buf); + + now = time(NULL); + tm = gmtime(&now); + fprintf(net, "\001Via %s @%d%02d%02d.%02d%02d%02d.00.UTC mbfido %s\r", + ascfnode(bestaka_s(t), 0x1f), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, net); + fclose(net); + free(buf); + net_out++; + if (reply) + free(reply); + Syslog('m', "Forward done."); + return 0; + + default: + /* + * If we came this far, there's definitly something wrong + * with this netmail. + */ + WriteError("No ROUTE for this netmail"); + net_bad++; + if (reply) + free(reply); + return importnet(f, t, mdate, flags, fp); + break; + } + + /* Never reached */ + return result; +} + + diff --git a/mbfido/postnetmail.h b/mbfido/postnetmail.h new file mode 100644 index 00000000..10b4b315 --- /dev/null +++ b/mbfido/postnetmail.h @@ -0,0 +1,8 @@ +#ifndef _POSTNETMAIL_H +#define _POSTNETMAIL_H + + +int postnetmail(FILE *, faddr *, faddr *, char *, char *, time_t, int, int); + +#endif + diff --git a/mbfido/ptic.c b/mbfido/ptic.c new file mode 100644 index 00000000..b74a5df1 --- /dev/null +++ b/mbfido/ptic.c @@ -0,0 +1,782 @@ +/***************************************************************************** + * + * File ..................: mbfido/ptic.c + * Purpose ...............: Process 1 .tic file + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbtic.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbdupe.h" +#include "ulock.h" +#include "mover.h" +#include "toberep.h" +#include "tic.h" +#include "utic.h" +#include "addbbs.h" +#include "magic.h" +#include "forward.h" +#include "rollover.h" +#include "ptic.h" +#include "magic.h" + + +#define UNPACK_FACTOR 300 + +extern int tic_bad; +extern int tic_dup; +extern int tic_out; +extern int do_quiet; +extern int check_crc; +extern int check_dupe; + + +/* + * Return values: + * 0 - Success + * 1 - Some error + * 2 - Orphaned tic + */ +int ProcessTic(fa_list *sbl, char *Realname) +{ + time_t Now, Fdate; + int Age, First, Listed = FALSE; + int DownLinks = 0; + int MustRearc = FALSE, MustVirus = FALSE; + int IsVirus = FALSE, UnPacked = FALSE, IsArchive = FALSE; + int i, j, k, File_Id = FALSE; + char *Temp, *Temp2, *unarc = NULL, *cmd = NULL; + char temp1[PATH_MAX], temp2[PATH_MAX], sbe[24], TDesc[256]; + unsigned long crc, crc2, Kb; + sysconnect Link; + FILE *fp; + long FwdCost = 0, FwdSize = 0; + struct utimbuf ut; + int BBS_Imp = FALSE, DidBanner = FALSE; + + + time(&Now); + + if (TIC.PathErr) { + WriteError("Our Aka is in the path"); + return 1; + } + + Temp = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + + if (!do_quiet) { + colour(10, 0); + printf("Checking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + /* + * A hack to work around received uppercase or mixed case filenames. + */ + Temp2 = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp2, "%s%s", TIC.FilePath, Realname); + if (file_exist(Temp, R_OK) && !file_exist(Temp2, R_OK)) { + if (rename(Temp2, Temp)) + WriteError("$Rename %s to %s failed", Temp2, Temp); + else + Syslog('f', "File %s renamed to %s", Temp2, Temp); + } + free(Temp2); + + crc = file_crc(Temp, CFG.slow_util && do_quiet); + if (crc == -1) { + WriteError("File not in inbound: %s", Temp); + /* + * Now check the age of the .tic file. + */ + sprintf(Temp, "%s%s", TIC.Inbound, TIC.TicName); + Fdate = file_time(Temp); + Age = (Now - Fdate) / 84400; + Syslog('+', "Orphaned tic age %d days", Age); + + if (Age > 21) { + tic_bad++; + mover(TIC.Inbound, TIC.TicName); + } + + free(Temp); + return 2; + } + + TIC.FileSize = file_size(Temp); + TIC.FileDate = file_time(Temp); + + if (TIC.TicIn.Size) { + if (TIC.TicIn.Size != TIC.FileSize) + WriteError("Size is %ld, expected %ld", TIC.FileSize, TIC.TicIn.Size); + } + + if (TIC.Crc_Int) { + if (crc != TIC.Crc_Int) { + Syslog('!', "CRC: expected %08lX, the file is %08lX", TIC.Crc_Int, crc); + if (check_crc) { + Bad((char *)"CRC: error, %s may be damaged", TIC.TicIn.OrgName); + free(Temp); + return 1; + } else { + Syslog('!', "CRC: error, recalculating crc"); + ReCalcCrc(Temp); + } + } + } else { + Syslog('+', "CRC: missing, calculating CRC"); + ReCalcCrc(Temp); + } + + /* + * Load and check the .TIC area. + */ + if (!SearchTic(TIC.TicIn.Area)) { + Bad((char *)"Unknown file area %s", TIC.TicIn.Area); + free(Temp); + return 1; + } + + if ((tic.Secure) && (!TIC.Hatch)) { + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if (Link.aka.zone) { + if ((Link.aka.zone == TIC.Aka.zone) && + (Link.aka.net == TIC.Aka.net) && + (Link.aka.node == TIC.Aka.node) && + (Link.aka.point== TIC.Aka.point) && + (Link.receivefrom)) + Listed = TRUE; + } + } + if (!Listed) { + Bad((char *)"%s NOT connected to %s", aka2str(TIC.Aka), TIC.TicIn.Area); + free(Temp); + return 1; + } + } + + if ((!SearchNode(TIC.Aka)) && (!TIC.Hatch)) { + Bad((char *)"%s NOT known", aka2str(TIC.Aka)); + free(Temp); + return 1; + } + + if (!TIC.Hatch) { + if (strcasecmp(TIC.TicIn.Pw, nodes.Fpasswd)) { + Bad((char *)"Pwd error, got %s, expected %s", TIC.TicIn.Pw, nodes.Fpasswd); + free(Temp); + return 1; + } + } else { + if (strcasecmp(TIC.TicIn.Pw, CFG.hatchpasswd)) { + Bad((char *)"Password error in local Hatch"); + WriteError("WARNING: it might be a Trojan in your inbound"); + free(Temp); + return 1; + } + } + + if (Magic_DeleteFile()) { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicName); + file_rm(temp1); + Syslog('+', "Deleted file %s", temp1); + free(Temp); + return 0; + } + + + if (Magic_MoveFile()) { + if (!SearchTic(TIC.TicIn.Area)) { + Bad((char *)"Unknown Area: %s", TIC.TicIn.Area); + free(Temp); + return 1; + } + } + + strcpy(T_File.Echo, tic.Name); + strcpy(T_File.Group, tic.Group); + TIC.KeepNum = tic.KeepLatest; + + Magic_Keepnum(); + + if (!tic.FileArea) { + Syslog('f', "Passthru area!"); + strcpy(TIC.BBSpath, CFG.ticout); + strcpy(TIC.BBSdesc, tic.Comment); + } else { + sprintf(Temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fp = fopen(Temp, "r")) == NULL) { + WriteError("Can't access fareas.data area: %ld", tic.FileArea); + free(Temp); + return 1; + } + fread(&areahdr, sizeof(areahdr), 1, fp); + if (fseek(fp, ((tic.FileArea -1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET)) { + fclose(fp); + WriteError("Can't seek area %ld in fareas.data", tic.FileArea); + free(Temp); + return 1; + } + if (fread(&area, areahdr.recsize, 1, fp) != 1) { + fclose(fp); + WriteError("Can't read area %ld in fareas.data", tic.FileArea); + free(Temp); + return 1; + } + fclose(fp); + strcpy(TIC.BBSpath, area.Path); + strcpy(TIC.BBSdesc, area.Name); + + /* + * If the File area has a special announce group, change + * the group to that name. + */ + if (strlen(area.NewGroup)) + strcpy(T_File.Group, area.NewGroup); + } + strcpy(T_File.Comment, tic.Comment); + + /* + * The destination may be changed now. + */ + Magic_OtherPath(); + + /* + * Check if the destination area really exists, it may be that + * the area is not linked to an existing BBS area. + */ + if (tic.FileArea && access(TIC.BBSpath, W_OK)) { + WriteError("$No write access to \"%s\"", TIC.BBSpath); + Bad((char *)"Dest directory not available"); + free(Temp); + return 1; + } + + if ((tic.DupCheck) && (check_dupe)) { + sprintf(Temp, "%s%s", TIC.TicIn.Area, TIC.TicIn.Crc); + crc2 = 0xffffffff; + crc2 = upd_crc32(Temp, crc2, strlen(Temp)); + if (CheckDupe(crc2, D_FILEECHO, CFG.tic_dupes)) { + Bad((char *)"Duplicate file"); + tic_dup++; + free(Temp); + return 1; + } + } + + /* + * Count the actual downlinks for this area + */ + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto)) + DownLinks++; + } + + /* + * Calculate the cost of this file + */ + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + if ((fgroup.UnitCost) || (TIC.TicIn.UplinkCost)) + TIC.Charge = TRUE; + else + TIC.Charge = FALSE; + + if (TIC.Charge) { + /* + * Calculate our filetransfer cost. + */ + FwdCost = fgroup.UnitCost; + FwdSize = fgroup.UnitSize; + + /* + * If FwdSize <> 0 then calculate per size, else + * charge for each file. + */ + if (FwdSize) + TIC.FileCost = ((TIC.FileSize / 1024) / FwdSize) * FwdCost; + else + TIC.FileCost = FwdCost; + + if (TIC.TicIn.UplinkCost) + TIC.FileCost += TIC.TicIn.UplinkCost; + + if (fgroup.AddProm) + TIC.FileCost += (TIC.FileCost * fgroup.AddProm / 1000); + + if (fgroup.DivideCost) { + /* + * If not a passthru area, we are a link too. + */ + if (DownLinks) + TIC.FileCost = TIC.FileCost / (DownLinks + 1); + } + + /* + * At least charge one unit. + */ + if (!TIC.FileCost) + TIC.FileCost = 1; + + Syslog('+', "The file cost will be %ld", TIC.FileCost); + } + + /* + * Update the uplink's counters. + */ + Kb = TIC.FileSize / 1024; + if (SearchNode(TIC.Aka)) { + nodes.Debet -= TIC.TicIn.UplinkCost; + if (TIC.TicIn.UplinkCost) + Syslog('f', "Uplink cost %ld, debet %ld", TIC.TicIn.UplinkCost, nodes.Debet); + StatAdd(&nodes.FilesRcvd, 1L); + StatAdd(&nodes.F_KbRcvd, Kb); + UpdateNode(); + SearchNode(TIC.Aka); + } + + /* + * Update the fileecho and group counters. + */ + StatAdd(&fgroup.Files, 1L); + StatAdd(&fgroup.KBytes, Kb); + fgroup.LastDate = time(NULL); + StatAdd(&tic.Files, 1L); + StatAdd(&tic.KBytes, Kb); + tic.LastAction = time(NULL); + UpdateTic(); + + if (!TIC.HatchNew) { + + if (!do_quiet) { + printf("Unpacking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + /* + * Move the file to the inbound directory if it isn't + * already there (needed by unpacker). + */ + if (strcmp(TIC.FilePath,TIC.Inbound)) { + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + sprintf(temp2, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + if (!file_mv(temp1, temp2)) { + sprintf(TIC.FilePath, "%s/", TIC.Inbound); + } else { + WriteError("Can't move %s to inbound", temp1); + } + } + + /* + * Check if this is an archive, and if so, compression method + * is used for this file. + */ + if (strlen(tic.Convert) || tic.VirScan || tic.FileId || tic.ConvertAll || strlen(tic.Banner)) { + if ((unarc = unpacker(TIC.TicIn.OrgName)) == NULL) + Syslog('+', "Unknown archive format %s", TIC.TicIn.OrgName); + else { + IsArchive = TRUE; + if ((strlen(tic.Convert) && (strcmp(unarc, tic.Convert) == 0)) || (tic.ConvertAll)) + MustRearc = TRUE; + } + } + + /* + * Copy the file if there are downlinks and we send the + * original file, but want to rearc it for ourself, or if + * it's a passthru area. + */ + if (((tic.SendOrg) && (MustRearc || strlen(tic.Banner))) || (!tic.FileArea)) { + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + sprintf(temp2, "%s/%s", CFG.ticout, TIC.TicIn.OrgName); + if (file_cp(temp1, temp2) == 0) { + TIC.SendOrg = TRUE; + } else { + WriteError("$Copy %s to %s failed", temp1, temp2); + } + } + + if ((tic.VirScan) && (IsArchive)) + MustVirus = TRUE; + + if (MustVirus || MustRearc) { + + /* + * Check if there is a temp directory for the archive + * conversion. + */ + sprintf(temp2, "%s/tmp/arc", getenv("MBSE_ROOT")); + if ((access(temp2, R_OK)) != 0) { + if (mkdir(temp2, 0777)) { + WriteError("$Can't create %s", temp2); + free(Temp); + return 1; + } + } + + /* + * Check for stale FILE_ID.DIZ files + */ + sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (!unlink(temp1)) + Syslog('+', "Removed stale %s", temp1); + sprintf(temp1, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (!unlink(temp1)) + Syslog('+', "Removed stale %s", temp1); + + if (!checkspace(temp2, TIC.TicIn.OrgName, UNPACK_FACTOR)) { + Bad((char *)"Not enough free diskspace left"); + free(Temp); + return 1; + } + + if (chdir(temp2) != 0) { + WriteError("$Can't change to %s", temp2); + free(Temp); + return 1; + } + + if (!getarchiver(unarc)) { + chdir(TIC.Inbound); + free(Temp); + return 1; + } + + cmd = xstrcpy(archiver.funarc); + + if ((cmd == NULL) || (cmd == "")) { + Syslog('!', "No unarc command available"); + } else { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + UnPacked = TRUE; + } else { + chdir(TIC.Inbound); + Bad((char *)"Archive maybe corrupt"); + free(Temp); + DeleteVirusWork(); + return 1; + } + free(cmd); + } + } + + if (MustVirus && UnPacked) { + + if (!do_quiet) { + printf("Virscan \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + sprintf(temp2, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp2, "r")) == NULL) { + WriteError("No virus scanners defined"); + } else { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + cmd = NULL; + if (virscan.available) { + cmd = xstrcpy(virscan.scanner); + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, virscan.options); + if (execute(cmd, (char *)"*", (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") != virscan.error) { + Syslog('!', "Virus found by %s", virscan.comment); + IsVirus = TRUE; + } + free(cmd); + } + } + fclose(fp); + + if (IsVirus) { + DeleteVirusWork(); + chdir(TIC.Inbound); + Bad((char *)"Possible virus found!"); + free(Temp); + return 1; + } + } + + if (!do_quiet) { + printf("Checking \b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + + } /* MustVirus and Unpacked */ + + if (tic.FileId && tic.FileArea && IsArchive) { + if (UnPacked) { + sprintf(temp1, "%s/tmp/arc/FILE_ID.DIZ", getenv("MBSE_ROOT")); + sprintf(temp2, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if (file_cp(temp1, temp2) == 0) + File_Id = TRUE; + } else { + if (!getarchiver(unarc)) { + chdir(TIC.Inbound); + } else { + cmd = xstrcpy(archiver.iunarc); + + if (cmd == NULL) { + WriteError("No unarc command available"); + } else { + sprintf(temp1, "%s/tmp", getenv("MBSE_ROOT")); + chdir(temp1); + sprintf(temp1, "%s%s FILE_ID.DIZ", TIC.Inbound, TIC.TicIn.OrgName); + if (execute(cmd, temp1, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + File_Id = TRUE; + } + free(cmd); + } + } /* if getarchiver */ + } /* if not unpacked */ + } /* if need FILE_ID.DIZ and not passthru */ + + /* + * Create internal file description, priority is FILE_ID.DIZ, + * 2nd LDesc, and finally the standard description. + */ + if (!Get_File_Id()) { + if (TIC.TicIn.TotLDesc > 2) { + for (i = 0; i < TIC.TicIn.TotLDesc; i++) { + strcpy(temp1, TIC.TicIn.LDesc[i]); + temp1[48] = '\0'; + strcpy(TIC.File_Id[i], temp1); + } + TIC.File_Id_Ct = TIC.TicIn.TotLDesc; + } else { + /* + * Format the description line (max 255 chars) + * in parts of 48 characters. + */ + if (strlen(TIC.TicIn.Desc) <= 48) { + strcpy(TIC.File_Id[0], TIC.TicIn.Desc); + TIC.File_Id_Ct++; + } else { + memset(&TDesc, 0, sizeof(TDesc)); + strcpy(TDesc, TIC.TicIn.Desc); + while (strlen(TDesc) > 48) { + j = 48; + while (TDesc[j] != ' ') + j--; + strncat(TIC.File_Id[TIC.File_Id_Ct], TDesc, j); + TIC.File_Id_Ct++; + k = strlen(TDesc); + j++; /* Correct space */ + for (i = 0; i <= k; i++, j++) + TDesc[i] = TDesc[j]; + } + strcpy(TIC.File_Id[TIC.File_Id_Ct], TDesc); + TIC.File_Id_Ct++; + } + } + } /* not get FILE_ID.DIZ */ + + if ((MustRearc) && (UnPacked) && (tic.FileArea)) { + if (Rearc(tic.Convert)) { + if (strlen(tic.Banner)) { + Syslog('f', "Must replace banner 1"); + } + + /* + * Get new filesize for import and announce + */ + sprintf(temp1, "%s%s", TIC.FilePath, TIC.NewName); + TIC.FileSize = file_size(temp1); + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + /* + * Calculate the CRC if we must send the new + * archived file. + */ + if (!TIC.SendOrg) { + ReCalcCrc(temp1); + } + } else { + WriteError("Rearc failed"); + } /* if Rearc() */ + } else { + /* + * If the file is not unpacked, change the banner + * direct if this is needed. + */ + if ((strlen(tic.Banner)) && IsArchive) { + cmd = xstrcpy(archiver.barc); + if ((cmd == NULL) || (!strlen(cmd))) { + Syslog('!', "No banner command for %s", archiver.name); + } else { + sprintf(temp1, "%s%s", TIC.Inbound, TIC.TicIn.OrgName); + sprintf(Temp, "%s/etc/%s", getenv("MBSE_ROOT"), tic.Banner); + if (execute(cmd, temp1, (char *)NULL, Temp, (char *)"/dev/null", (char *)"/dev/null")) { + WriteError("$Changing the banner failed"); + } else { + Syslog('+', "New banner %s", tic.Banner); + TIC.FileSize = file_size(temp1); + T_File.Size = TIC.FileSize; + T_File.SizeKb = TIC.FileSize / 1024; + ReCalcCrc(temp1); + DidBanner = TRUE; + } + } + } + } /* if MustRearc and Unpacked and not Passthtru */ + + if (UnPacked) + DeleteVirusWork(); + + chdir(TIC.Inbound); + + /* + * If the file is converted, we set the date of the original + * received file as the file creation date. + */ + if (MustRearc || DidBanner) { + if ((!tic.NoTouch) && (tic.FileArea)) { + ut.actime = mktime(localtime(&TIC.FileDate)); + ut.modtime = mktime(localtime(&TIC.FileDate)); + sprintf(Temp, "%s%s", TIC.FilePath, TIC.NewName); + utime(Temp, &ut); + } + } + + if (tic.FileArea) { + Syslog('+', "Import: %s Area: %s", TIC.NewName, TIC.TicIn.Area); + + if (TIC.OtherPath) { + /* BBS_Imp = Add_DOS */ + } else { + BBS_Imp = Add_BBS(); + } + + if (!BBS_Imp) { + Bad((char *)"File Import Error"); + free(Temp); + return 1; + } + } + + } /* Not TIC.HatchNew */ + + chdir(TIC.Inbound); + + if ((!TIC.HatchNew) && (tic.FileArea)) { + if (strlen(TIC.TicIn.Magic)) + UpDateAlias(TIC.TicIn.Magic); + else + Magic_UpDateAlias(); + + for (i = 0; i <= TIC.File_Id_Ct; i++) + strcpy(T_File.LDesc[i], TIC.File_Id[i]); + T_File.TotLdesc = TIC.File_Id_Ct; + T_File.Announce = tic.Announce; + strcpy(T_File.Name, TIC.NewName); + T_File.Fdate = TIC.FileDate; + T_File.Cost = TIC.TicIn.UplinkCost; + Add_ToBeRep(); + } + + if (TIC.SendOrg && !tic.FileArea) { + /* + * If it's a passthru area we don't need the + * file in the inbound anymore so it can be + * deleted. + */ + sprintf(temp1, "%s%s", TIC.FilePath, TIC.TicIn.OrgName); + if (file_rm(temp1) == 0) + Syslog('f', "Deleted %s", temp1); + } + + if (DownLinks) { + First = TRUE; + + /* + * Add all our system aka's to the seenby lines in the same zone + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (tic.Aka.zone == CFG.aka[i].zone) && + !((tic.Aka.net == CFG.aka[i].net) && (tic.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u:%u/%u", CFG.aka[i].zone, CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + + /* + * Add downlinks to seenby lines + */ + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.aka.point)) { + if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) && + (TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) { + sprintf(sbe, "%u:%u/%u", Link.aka.zone, Link.aka.net, Link.aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + } + uniq_list(&sbl); + sort_list(&sbl); + + /* + * Now start forwarding files + */ + First = TRUE; + while (GetTicSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + if (!((TIC.Aka.zone == Link.aka.zone) && (TIC.Aka.net == Link.aka.net) && + (TIC.Aka.node == Link.aka.node) && (TIC.Aka.point == Link.aka.point))) { + tic_out++; + ForwardFile(Link.aka, sbl); + } + } + } + } + + if (!TIC.HatchNew) { + Magic_ExecCommand(); + Magic_CopyFile(); + Magic_UnpackFile(); + Magic_AdoptFile(); + } + + sprintf(Temp, "%s%s", TIC.Inbound, TIC.TicName); + unlink(Temp); + free(Temp); + return 0; +} + + diff --git a/mbfido/ptic.h b/mbfido/ptic.h new file mode 100644 index 00000000..8842416e --- /dev/null +++ b/mbfido/ptic.h @@ -0,0 +1,7 @@ +#ifndef _PTIC_H +#define _PTIC_H + +int ProcessTic(fa_list *, char *); + +#endif + diff --git a/mbfido/rnews.c b/mbfido/rnews.c new file mode 100644 index 00000000..b59f12b7 --- /dev/null +++ b/mbfido/rnews.c @@ -0,0 +1,652 @@ +/***************************************************************************** + * + * File ..................: mbfido/rnews.c + * Purpose ...............: rnews function + * Last modification date : 19-Jul-2001 + * Remarks ...............: Most of these functions are borrowed from inn. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/dbdupe.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "pack.h" +#include "scannews.h" +#include "mbfido.h" +#include "paths.h" +#include "rnews.h" + + +#define UUCPBUF 10240 + + +typedef struct _HEADER { + char *Name; + int size; +} HEADER; +typedef void *POINTER; + +static char UNPACK[] = "gzip"; +static HEADER RequiredHeaders[] = { + { (char *)"Message-ID", 10 }, +#define _messageid 0 + { (char *)"Newsgroups", 10 }, +#define _newsgroups 1 + { (char *)"From", 4 }, +#define _from 2 + { (char *)"Date", 4 }, +#define _date 3 + { (char *)"Subject", 7 }, +#define _subject 4 + { (char *)"Path", 4 }, +#define _path 5 +}; +#define IS_MESGID(hp) ((hp) == &RequiredHeaders[_messageid]) +#define IS_PATH(hp) ((hp) == &RequiredHeaders[_path]) +#define IS_NG(hp) ((hp) == &RequiredHeaders[_newsgroups]) + + +/* + * Some macro's + */ +#define NEW(T, c) ((T *)xmalloc((unsigned int)(sizeof (T) * (c)))) +#define RENEW(p, T, c) (p = (T *)realloc((char *)(p), (unsigned int)(sizeof (T) * (c)))) +#define DISPOSE(p) free((void *)p) +#define SIZEOF(array) ((int)(sizeof array / sizeof array[0])) +#define ENDOF(array) (&array[SIZEOF(array)]) +#define ISWHITE(c) ((c) == ' ' || (c) == '\t') +#define caseEQn(a, b, n) (strncasecmp((a), (b), (size_t)(n)) == 0) + +/* + * External variables + */ +extern int do_quiet; +extern int most_debug; +extern int news_in; +extern int news_dupe; + + +void ProcessOne(FILE *); + + +/* + * Find a header in an article. + */ +const char *HeaderFindMem(const char *, const int, const char *, const int); +const char *HeaderFindMem(const char *Article, const int ArtLen, const char *Header, const int HeaderLen) +{ + const char *p; + + for (p = Article; ; ) { + /* Match first character, then colon, then whitespace (don't + * delete that line -- meet the RFC!) then compare the rest + * of the word. */ + if (HeaderLen + 1 < Article + ArtLen - p && p[HeaderLen] == ':' + && ISWHITE(p[HeaderLen + 1]) && caseEQn(p, Header, (size_t)HeaderLen)) { + p += HeaderLen + 2; + while (1) { + for (; p < Article + ArtLen && ISWHITE(*p); p++) + continue; + if (p == Article+ArtLen) + return NULL; + else { + if (*p != '\r' && *p != '\n') + return p; + else { + /* handle multi-lined header */ + if (++p == Article + ArtLen) + return NULL; + if (ISWHITE(*p)) + continue; + if (p[-1] == '\r' && *p== '\n') { + if (++p == Article + ArtLen) + return NULL; + if (ISWHITE(*p)) + continue; + return NULL; + } + return NULL; + } + } + } + } + if ((p = memchr(p, '\n', ArtLen - (p - Article))) == NULL || + (++p >= Article + ArtLen) || (*p == '\n') || + (((*p == '\r') && (++p >= Article + ArtLen)) || (*p == '\n'))) + return NULL; + } +} + + + +/* + * Open up a pipe to a process with fd tied to its stdin. Return a + * descriptor tied to its stdout or -1 on error. + */ +static int StartChild(int, char *, char *[]); +static int StartChild(int fd, char *path, char *argv[]) +{ + int pan[2]; + int i; + pid_t pid; + + /* Create a pipe. */ + if (pipe(pan) < 0) { + WriteError("%Cant pipe for %s", path); + die(101); + } + + /* Get a child. */ + for (i = 0; (pid = fork()) < 0; i++) { + if (i == MAX_FORKS) { + WriteError("$Cant fork %s -- spooling", path); + return -1; + } + Syslog('n', "Cant fork %s -- waiting", path); + (void)sleep(60); + } + + /* Run the child, with redirection. */ + if (pid == 0) { + (void)close(pan[PIPE_READ]); + + /* Stdin comes from our old input. */ + if (fd != STDIN) { + if ((i = dup2(fd, STDIN)) != STDIN) { + WriteError("$Cant dup2 %d to 0 got %d", fd, i); + _exit(1); + } + (void)close(fd); + } + + /* Stdout goes down the pipe. */ + if (pan[PIPE_WRITE] != STDOUT) { + if ((i = dup2(pan[PIPE_WRITE], STDOUT)) != STDOUT) { + WriteError("$Cant dup2 %d to 1 got %d", pan[PIPE_WRITE], i); + _exit(1); + } + (void)close(pan[PIPE_WRITE]); + } + + Syslog('n', "execv %s %s", MBSE_SS(path), MBSE_SS(argv[1])); + (void)execv(path, argv); + WriteError("$Cant execv %s", path); + _exit(1); + } + + (void)close(pan[PIPE_WRITE]); + (void)close(fd); + return pan[PIPE_READ]; +} + + + +/* + * Wait for the specified number of children. + */ +void WaitForChildren(int i) +{ + pid_t pid; + int status; + + while (--i >= 0) { + pid = waitpid(-1, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + WriteError("$Cant wait"); + break; + } + } +} + + + +/* + * Write an article to the rejected directory. + */ +static void Reject(const char *, const char *, const char *); +static void Reject(const char *article, const char *reason, const char *arg) +{ +#if defined(DO_RNEWS_SAVE_BAD) + char buff[SMBUF]; + FILE *F; + int i; +#endif /* defined(DO_RNEWS_SAVE_BAD) */ + + WriteError(reason, arg); +#if defined(DO_RNEWS_SAVE_BAD) +// TempName(PATHBADNEWS, buff); +// if ((F = fopen(buff, "w")) == NULL) { +// syslog(L_ERROR, "cant fopen %s %m", buff); +// return; +// } +// i = strlen(article); +// if (fwrite((POINTER)article, (size_t)1, (size_t)i, F) != i) +// syslog(L_ERROR, "cant fwrite %s %m", buff); +// if (fclose(F) == EOF) +// syslog(L_ERROR, "cant close %s %m", buff); +#endif /* defined(DO_RNEWS_SAVE_BAD) */ +} + + + +/* + * Process one article. Return TRUE if the article was okay; FALSE if the + * whole batch needs to be saved (such as when the server goes down or if + * the file is corrupted). + */ +static int Process(char *); +static int Process(char *article) +{ + HEADER *hp; + char *p; + char *id = NULL; + FILE *fp; + + Syslog('n', "Process article"); + /* + * Empty article? + */ + if (*article == '\0') + return TRUE; + + /* + * Make sure that all the headers are there. + */ + for (hp = RequiredHeaders; hp < ENDOF(RequiredHeaders); hp++) { + if ((p = (char *)HeaderFindMem(article, strlen(article), hp->Name, hp->size)) == NULL) { + Reject(article, "bad_article missing %s", hp->Name); + return FALSE; + } + if (IS_MESGID(hp)) { + id = p; + continue; + } + } + + /* + * Put the article in a temp file, all other existing functions + * did already work with tempfiles. + */ + fp = tmpfile(); + fwrite(article, 1, strlen(article), fp); + ProcessOne(fp); + fclose(fp); + + return TRUE; +} + + + +/* + * Read the rest of the input as an article. Just punt to stdio in + * this case and let it do the buffering. + */ +static int ReadRemainder(register int, char, char); +static int ReadRemainder(register int fd, char first, char second) +{ + register FILE *F; + register char *article; + register int size; + register int used; + register int left; + register int i; + int ok; + + /* Turn the descriptor into a stream. */ + if ((F = fdopen(fd, "r")) == NULL) { + WriteError("$Can't fdopen %d", fd); + die(101); + } + + /* Get an initial allocation, leaving space for the \0. */ + size = BUFSIZ + 1; + article = NEW(char, size + 2); + article[0] = first; + article[1] = second; + used = second ? 2 : 1; + left = size - used; + + /* Read the input. */ + while ((i = fread((POINTER)&article[used], (size_t)1, (size_t)left, F)) != 0) { + if (i < 0) { + WriteError("$Cant fread after %d bytes", used); + die(101); + } + used += i; + left -= i; + if (left < SMBUF) { + size += BUFSIZ; + left += BUFSIZ; + RENEW(article, char, size); + } + } + if (article[used - 1] != '\n') + article[used++] = '\n'; + article[used] = '\0'; + (void)fclose(F); + + ok = Process(article); + DISPOSE(article); + return ok; +} + + + +/* + * Read an article from the input stream that is artsize bytes long. + */ +static int ReadBytecount(register int, int); +static int ReadBytecount(register int fd, int artsize) +{ + static char *article; + static int oldsize; + register char *p; + register int left; + register int i; + + /* If we haven't gotten any memory before, or we didn't get enough, + * then get some. */ + if (article == NULL) { + oldsize = artsize; + article = NEW(char, oldsize + 1 + 1); + } else if (artsize > oldsize) { + oldsize = artsize; + RENEW(article, char, oldsize + 1 + 1); + } + + /* Read in the article. */ + for (p = article, left = artsize; left; p += i, left -= i) + if ((i = read(fd, p, left)) <= 0) { + i = errno; + WriteError("$Cant read wanted %d got %d", artsize, artsize - left); +#if 0 + /* Don't do this -- if the article gets re-processed we + * will end up accepting the truncated version. */ + artsize = p - article; + article[artsize] = '\0'; + Reject(article, "short read (%s?)", strerror(i)); +#endif /* 0 */ + return TRUE; + } + if (p[-1] != '\n') + *p++ = '\n'; + *p = '\0'; + + return Process(article); +} + + + +/* + * Read a single text line; not unlike fgets(). Just more inefficient. + */ +static int ReadLine(char *, int, int); +static int ReadLine(char *p, int size, int fd) +{ + char *save; + + /* Fill the buffer, a byte at a time. */ + for (save = p; size > 0; p++, size--) { + if (read(fd, p, 1) != 1) { + *p = '\0'; + WriteError("$Cant read first line got %s", save); + die(101); + } + if (*p == '\n') { + *p = '\0'; + return TRUE; + } + } + *p = '\0'; + WriteError("bad_line too long %s", save); + return FALSE; +} + + + +/* + * Unpack a single batch. + */ +static int UnpackOne(int *, int *); +static int UnpackOne(int *fdp, int *countp) +{ + char buff[SMBUF]; + char *cargv[4]; + int artsize; + int i; + int gzip = 0; + int HadCount; + int SawCunbatch; + + *countp = 0; + for (SawCunbatch = FALSE, HadCount = FALSE; ; ) { + /* Get the first character. */ + if ((i = read(*fdp, &buff[0], 1)) < 0) { + WriteError("$cant read first character"); + return FALSE; + } + if (i == 0) + break; + + if (buff[0] == 0x1f) + gzip = 1; + else if (buff[0] != RNEWS_MAGIC1) + /* Not a batch file. If we already got one count, the batch + * is corrupted, else read rest of input as an article. */ + return HadCount ? FALSE : ReadRemainder(*fdp, buff[0], '\0'); + + /* Get the second character. */ + if ((i = read(*fdp, &buff[1], 1)) < 0) { + WriteError("$Cant read second character"); + return FALSE; + } + if (i == 0) + /* A one-byte batch? */ + return FALSE; + + /* Check second magic character. */ + /* gzipped ($1f$8b) or compressed ($1f$9d) */ + if (gzip && ((buff[1] == (char)0x8b) || (buff[1] == (char)0x9d))) { + cargv[0] = (char *)"gzip"; + cargv[1] = (char *)"-d"; + cargv[2] = NULL; + lseek(*fdp, (long) 0, 0); /* Back to the beginning */ + *fdp = StartChild(*fdp, (char*)_PATH_GZIP, cargv); + if (*fdp < 0) + return FALSE; + (*countp)++; + SawCunbatch = TRUE; + continue; + } + if (buff[1] != RNEWS_MAGIC2) + return HadCount ? FALSE : ReadRemainder(*fdp, buff[0], buff[1]); + + /* Some kind of batch -- get the command. */ + if (!ReadLine(&buff[2], (int)(sizeof buff - 3), *fdp)) + return FALSE; + + if (strncmp(buff, "#! rnews ", 9) == 0) { + artsize = atoi(&buff[9]); + if (artsize <= 0) { + WriteError("Bad_line bad count %s", buff); + return FALSE; + } + HadCount = TRUE; + if (ReadBytecount(*fdp, artsize)) + continue; + return FALSE; + } + + if (HadCount) + /* Already saw a bytecount -- probably corrupted. */ + return FALSE; + + if (strcmp(buff, "#! cunbatch") == 0) { + Syslog('n', "Compressed newsbatch"); + if (SawCunbatch) { + WriteError("Nested_cunbatch"); + return FALSE; + } + cargv[0] = UNPACK; + cargv[1] = (char *)"-d"; + cargv[2] = NULL; + *fdp = StartChild(*fdp, (char *)_PATH_GZIP, cargv); + if (*fdp < 0) + return FALSE; + (*countp)++; + SawCunbatch = TRUE; + continue; + } + + WriteError("bad_format unknown command %s", buff); + return FALSE; + } + return TRUE; +} + + + +void NewsUUCP(int unspool) +{ + int fd = STDIN, i, rc; + + Syslog('+', "Processing UUCP newsbatch"); + IsDoing((char *)"UUCP Batch"); + + if (!do_quiet) { + colour(10, 0); + printf("Process UUCP Newsbatch\n"); + } + + if (unspool) { +// Unspool(); + } else { +// if (!UnpackOne(&fd, &i)) +// Spool(fd); + most_debug = TRUE; + rc = UnpackOne(&fd, &i); + most_debug = FALSE; + Syslog('+', "Batch result=%d", rc); + WaitForChildren(i); + } + + Syslog('+', "End of UUCP batch"); + packmail(); + + if (!do_quiet) + printf("\r \r"); +} + + + +/* + * Process one newsarticle. + */ +void ProcessOne(FILE *fp) +{ + char *p, *fn, *buf, *gbuf, *mbuf, *group, *groups[25]; + int i, nrofgroups; + unsigned long crc; + + buf = calloc(UUCPBUF, sizeof(char)); + fn = calloc(PATH_MAX, sizeof(char)); + + /* + * Find newsgroups names in article. + */ + rewind(fp); + nrofgroups = 0; + mbuf = NULL; + gbuf = NULL; + while (fgets(buf, UUCPBUF, fp)) { + if (!strncasecmp(buf, "Newsgroups: ", 12)) { + gbuf = xstrcpy(buf+12); + Striplf(gbuf); + strtok(buf, " "); + while ((group = strtok(NULL, ",\n"))) { + if (SearchMsgsNews(group)) { + Syslog('n', "Add group %s (%s)", msgs.Newsgroup, msgs.Tag); + groups[nrofgroups] = xstrcpy(group); + nrofgroups++; + } else { + Syslog('n', "Newsgroup %s doesn't exist", group); + } + } + } + if (!strncasecmp(buf, "Message-ID: ", 12)) { + /* + * Store the Message-ID without the < > characters. + */ + mbuf = xstrcpy(buf+13); + mbuf[strlen(mbuf)-2] = '\0'; + Syslog('n', "Message ID \"%s\"", printable(mbuf, 0)); + } + } + + if (nrofgroups == 0) { + WriteError("No newsgroups found: %s", gbuf); + } else if (mbuf == NULL) { + WriteError("No valid Message-ID found"); + } else { + news_in++; + IsDoing("Article %d", (news_in + 1)); + for (i = 0; i < nrofgroups; i++) { + Syslog('n', "Process %s", groups[i]); + p = xstrcpy(mbuf); + p = xstrcat(p, groups[i]); + crc = str_crc32(p); + if (CheckDupe(crc, D_NEWS, CFG.nntpdupes)) { + news_dupe++; + Syslog('+', "Duplicate article \"%s\" in group %s", mbuf, groups[i]); + } else { + if (SearchMsgsNews(groups[i])) { + do_article(fp); + } + } + free(groups[i]); + } + } + + if (mbuf) + free(mbuf); + if (gbuf) + free(gbuf); + + free(buf); + free(fn); +} + + + diff --git a/mbfido/rnews.h b/mbfido/rnews.h new file mode 100644 index 00000000..7f832492 --- /dev/null +++ b/mbfido/rnews.h @@ -0,0 +1,20 @@ +#ifndef _RNEWS_H +#define _RNEWS_H + + +#define MAX_FORKS 10 +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 +#define PIPE_READ 0 +#define PIPE_WRITE 1 +#define RNEWS_MAGIC1 '#' +#define RNEWS_MAGIC2 '!' +#define SMBUF 256 + + +void NewsUUCP(int); + + +#endif + diff --git a/mbfido/rollover.c b/mbfido/rollover.c new file mode 100644 index 00000000..7a0c9369 --- /dev/null +++ b/mbfido/rollover.c @@ -0,0 +1,418 @@ +/***************************************************************************** + * + * File ..................: mbfido/rollover.c + * Purpose ...............: Statistic rollover util. + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "rollover.h" + + +extern int do_quiet; + + +void StatAdd(statcnt *S, unsigned long V) +{ + S->total += V; + S->tweek += V; + S->tdow[Diw] += V; + S->month[Miy] += V; +} + + + +void RollWeek(statcnt *); +void RollWeek(statcnt *S) +{ + int i; + + for (i = 0; i < 7; i++) { + S->ldow[i] = S->tdow[i]; + S->tdow[i] = 0L; + } + + S->lweek = S->tweek; + S->tweek = 0L; + + if (CFG.slow_util && do_quiet) + usleep(1); +} + + + +FILE *OpenData(char *); +FILE *OpenData(char *Name) +{ + char *temp; + FILE *fp; + + temp = calloc(128, sizeof(char)); + + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), Name); + if ((fp = fopen(temp, "r+")) == NULL) { + WriteError("$Can't open %s", temp); + free(temp); + return NULL; + } + + free(temp); + return fp; +} + + + +/* + * Test all files with statistic counters if a new week has started + * or a new month has started. All the record counters will be + * updated if one of these is the case. + */ +void Rollover() +{ + time_t Now; + struct tm *t; + FILE *fp, *ft; + int do_week, do_month, Day, i; + char *temp, *temp1; + struct _history history; + + IsDoing("Date rollover"); + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + Day = t->tm_yday; + + if ((fp = OpenData((char *)"nodes.data")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fp); + t = localtime(&nodeshdr.lastupd); + + /* + * Test if it's sunday, and the last update wasn't today. + * If it's not sunday, and the last update was more then + * 7 days ago, we maybe missed last sunday and the update + * is still done. + */ + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + + /* + * If the month is different then the last update, we must + * be in a new month. + */ + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover nodes.data"); + + while (fread(&nodes, nodeshdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&nodes.FilesSent); + RollWeek(&nodes.FilesRcvd); + RollWeek(&nodes.F_KbSent); + RollWeek(&nodes.F_KbRcvd); + RollWeek(&nodes.MailSent); + RollWeek(&nodes.MailRcvd); + } + if (do_month) { + nodes.FilesSent.month[Miy] = 0; + nodes.FilesRcvd.month[Miy] = 0; + nodes.F_KbSent.month[Miy] = 0; + nodes.F_KbRcvd.month[Miy] = 0; + nodes.MailSent.month[Miy] = 0; + nodes.MailRcvd.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - nodeshdr.recsize, SEEK_CUR); + fwrite(&nodes, nodeshdr.recsize, 1, fp); + fseek(fp, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + + fseek(fp, 0, SEEK_SET); + nodeshdr.lastupd = time(NULL); + fwrite(&nodeshdr, nodeshdr.hdrsize, 1, fp); + } + + fclose(fp); + } + + if ((fp = OpenData((char *)"mareas.data")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fp); + t = localtime(&msgshdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover mareas.data"); + + while (fread(&msgs, msgshdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&msgs.Received); + RollWeek(&msgs.Posted); + } + if (do_month) { + msgs.Received.month[Miy] = 0; + msgs.Posted.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - msgshdr.recsize, SEEK_CUR); + fwrite(&msgs, msgshdr.recsize, 1, fp); + fseek(fp, msgshdr.syssize, SEEK_CUR); + } + + msgshdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&msgshdr, msgshdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"mgroups.data")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fp); + t = localtime(&mgrouphdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover mgroups.data"); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&mgroup.MsgsRcvd); + RollWeek(&mgroup.MsgsSent); + } + if (do_month) { + mgroup.MsgsRcvd.month[Miy] = 0; + mgroup.MsgsSent.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - mgrouphdr.recsize, SEEK_CUR); + fwrite(&mgroup, mgrouphdr.recsize, 1, fp); + } + + mgrouphdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&mgrouphdr, mgrouphdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"tic.data")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fp); + t = localtime(&tichdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover tic.data"); + + while (fread(&tic, tichdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&tic.Files); + RollWeek(&tic.KBytes); + } + if (do_month) { + tic.Files.month[Miy] = 0; + tic.KBytes.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - tichdr.recsize, SEEK_CUR); + fwrite(&tic, tichdr.recsize, 1, fp); + fseek(fp, tichdr.syssize, SEEK_CUR); + } + + tichdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&tichdr, tichdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"fgroups.data")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fp); + t = localtime(&fgrouphdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover fgroups.data"); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fp) == 1) { + if (do_week) { + RollWeek(&fgroup.Files); + RollWeek(&fgroup.KBytes); + } + if (do_month) { + fgroup.Files.month[Miy] = 0; + fgroup.KBytes.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - fgrouphdr.recsize, SEEK_CUR); + fwrite(&fgroup, fgrouphdr.recsize, 1, fp); + } + + fgrouphdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&fgrouphdr, fgrouphdr.hdrsize, 1, fp); + } + fclose(fp); + } + + if ((fp = OpenData((char *)"hatch.data")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fp); + t = localtime(&hatchhdr.lastupd); + + if (((Diw == 0) && (Day != t->tm_yday)) || ((Day - t->tm_yday) > 7)) + do_week = TRUE; + else + do_week = FALSE; + if (Miy != t->tm_mon) + do_month = TRUE; + else + do_month = FALSE; + + if (do_week || do_month) { + Syslog('+', "Rollover hatch.data"); + + while (fread(&hatch, hatchhdr.recsize, 1, fp) == 1) { + if (do_week) + RollWeek(&hatch.Hatched); + if (do_month) { + hatch.Hatched.month[Miy] = 0; + if (CFG.slow_util && do_quiet) + usleep(1); + } + fseek(fp, - hatchhdr.recsize, SEEK_CUR); + fwrite(&hatch, hatchhdr.recsize, 1, fp); + } + + hatchhdr.lastupd = time(NULL); + fseek(fp, 0, SEEK_SET); + fwrite(&hatchhdr, hatchhdr.hdrsize, 1, fp); + } + fclose(fp); + } + + temp = calloc(128, sizeof(char)); + temp1 = calloc(128, sizeof(char)); + sprintf(temp, "%s/var/mailer.hist", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r"))) { + fread(&history, sizeof(history), 1, fp); + t = localtime(&history.online); + if (t->tm_mon != Miy) { + /* + * Calculate date/time for records to delete + */ + t = localtime(&Now); + if (t->tm_mon == 0) { + t->tm_mon = 11; + t->tm_year--; + } else { + t->tm_mon--; + } + t->tm_mday = 1; + t->tm_hour = 0; + t->tm_min = 0; + t->tm_sec = 0; + Now = mktime(t); + Syslog('+', "Packing mailer history since %s", rfcdate(Now)); + sprintf(temp1, "%s/var/mailer.temp", getenv("MBSE_ROOT")); + if ((ft = fopen(temp1, "a")) == NULL) { + WriteError("$Can't create %s", temp1); + fclose(fp); + } else { + memset(&history, 0, sizeof(history)); + history.online = time(NULL); + history.offline = time(NULL); + fwrite(&history, sizeof(history), 1, ft); + + i = 0; + while (fread(&history, sizeof(history), 1, fp)) { + if (history.online >= Now) { + fwrite(&history, sizeof(history), 1, ft); + i++; + } + } + fclose(ft); + fclose(fp); + unlink(temp); + rename(temp1, temp); + Syslog('+', "Written %d records", i); + } + } else { + fclose(fp); + } + } + free(temp); + free(temp1); +} + + + diff --git a/mbfido/rollover.h b/mbfido/rollover.h new file mode 100644 index 00000000..bfd8f71b --- /dev/null +++ b/mbfido/rollover.h @@ -0,0 +1,10 @@ +#ifndef _ROLLOVER_H +#define _ROLLOVER_H + + +void StatAdd(statcnt *, unsigned long); +void Rollover(void); + + +#endif + diff --git a/mbfido/scan.c b/mbfido/scan.c new file mode 100644 index 00000000..12792b3a --- /dev/null +++ b/mbfido/scan.c @@ -0,0 +1,1085 @@ +/***************************************************************************** + * + * File ..................: mbfido/scan.h + * Purpose ...............: Scan for outgoing mail. + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msg.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "pack.h" +#include "tracker.h" +#include "mkrfcmsg.h" +#include "postemail.h" +#include "scan.h" + + +extern int do_quiet; +extern int net_out; +extern int net_bad; +extern int echo_in; +extern int email_out; +extern int echo_out; +extern int email_imp; +extern int email_bad; +extern int most_debug; +int scanned; + +#define MAXSEEN 70 + + +/* + * Internal prototypes + */ +void ScanFull(void); +void ScanOne(char *, unsigned long); +void ExportEcho(sysconnect, unsigned long, fa_list **); +void ExportNews( unsigned long, fa_list **); +void ExportNet(unsigned long, int); +void ExportEmail(unsigned long); + + + +/* + * Scan for outgoing mail. If using the files $MBSE_ROOT/tmp/echomail.jam + * or netmail.jam not all mail is scanned a full mailscan will be + * performed. + */ +void ScanMail(int DoAll) +{ + int DoFull = FALSE, i = 0; + unsigned long msg; + char *Fname = NULL, *temp, *path; + FILE *fp; + + if (DoAll) { + DoFull = TRUE; + } else { + scanned = 0; + Fname = calloc(128, sizeof(char)); + temp = calloc(128, sizeof(char)); + + sprintf(Fname, "%s/tmp/echomail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(Fname, "r")) != NULL) { + while ((fgets(temp, 128, fp)) != NULL) { + path = strtok(temp, " "); + msg = atol(strtok(NULL, "\n")); + Syslog('+', "Export message %lu from %s", msg, path); + ScanOne(path, msg); + i++; + } + fclose(fp); + unlink(Fname); + } + + sprintf(Fname, "%s/tmp/netmail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(Fname, "r")) != NULL) { + while ((fgets(temp, 128, fp)) != NULL) { + path = strtok(temp, " "); + msg = atol(strtok(NULL, "\n")); + Syslog('+', "Export message %lu from %s", msg, path); + ScanOne(path, msg); + i++; + } + fclose(fp); + unlink(Fname); + } + + if ((i != scanned) || (i == 0)) { + Syslog('+', "Not all messages exported, forcing full mail scan"); + Syslog('+', "i=%d scanned=%d", i, scanned); + DoFull = TRUE; + } + free(Fname); + free(temp); + } + + if (DoFull) + ScanFull(); + + if (echo_out || net_out) + packmail(); + RemoveSema((char *)"mailout"); +} + + + +void ScanFull() +{ + char sAreas[81], sbe[128]; + FILE *pAreas; + long arearec = 0, sysstart, nextstart; + unsigned long Total, Number; + int i; + sysconnect Link; + fa_list *sbl = NULL; + + Syslog('+', "Full mailscan"); + IsDoing("Scanning mail"); + + if (!do_quiet) { + colour(9, 0); + printf("Scanning mail\n"); + colour(3, 0); + fflush(stdout); + } + + sprintf(sAreas, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pAreas); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pAreas) == 1) { + if (usrconfig.Email && strlen(usrconfig.Name)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%8s %-40s", usrconfig.Name, usrconfig.sUserName); + colour(13, 0); + fflush(stdout); + } + + sprintf(sAreas, "%s/%s/mailbox", CFG.bbs_usersdir, usrconfig.Name); + if (Msg_Open(sAreas)) { + if ((Total = Msg_Number()) != 0L) { + Number = Msg_Lowest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (((Number % 10) == 0) && (!do_quiet)) { + printf("%6lu\b\b\b\b\b\b", Number); + fflush(stdout); + } + + Msg_ReadHeader(Number); + if (Msg.Local) { + if (Msg_Lock(15L)) { + Syslog('m', "Export %lu email from %s", Number, usrconfig.Name); + ExportEmail(Number); + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(Number); + Msg_UnLock(); + } + } + + } while (Msg_Next(&Number) == TRUE); + } + Msg_Close(); + if (!do_quiet) { + printf(" \b\b\b\b\b\b"); + fflush(stdout); + } + } + } + } + fclose(pAreas); + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + sysstart = ftell(pAreas); + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + nextstart = ftell(pAreas); + arearec++; + + if ((msgs.Active) && (msgs.Type == ECHOMAIL || msgs.Type == NETMAIL || msgs.Type == NEWS)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", arearec, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + if ((Total = Msg_Number()) != 0L) { + Number = Msg_Lowest(); + + do { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (((Number % 10) == 0) && (!do_quiet)) { + printf("%6lu\b\b\b\b\b\b", Number); + fflush(stdout); + } + + Msg_ReadHeader(Number); + if (Msg.Local) { + if (Msg_Lock(15L)) { + Syslog('m', "Export %lu from area %ld", Number, arearec); + + /* + * Setup SEEN-BY lines + */ + if ((msgs.Type == ECHOMAIL) || (msgs.Type == NEWS)) { + echo_in++; + fill_list(&sbl, aka2str(msgs.Aka), NULL, FALSE); + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && + (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && + (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, + CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + fill_list(&sbl, aka2str(Link.aka), NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if (Link.aka.zone) + ExportEcho(Link, Number, &sbl); + } + if (strlen(msgs.Newsgroup)) + ExportNews(Number, &sbl); + + tidy_falist(&sbl); + } + if (msgs.Type == NETMAIL) { + ExportNet(Number, FALSE); + most_debug = FALSE; + } + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(Number); + Msg_UnLock(); + } + } + + } while (Msg_Next(&Number) == TRUE); + } + + Msg_Close(); + + if (!do_quiet) { + printf(" \b\b\b\b\b\b"); + fflush(stdout); + } + } + + /* + * Make sure to start at the next area. + */ + fseek(pAreas, nextstart, SEEK_SET); + } + } + + fclose(pAreas); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + +void ScanOne(char *path, unsigned long MsgNum) +{ + char sAreas[81], sbe[128]; + FILE *pAreas; + long sysstart; + unsigned long Total, Area = 0; + int i; + sysconnect Link; + fa_list *sbl = NULL; + + IsDoing("Scanning mail"); + + if (!do_quiet) { + colour(9, 0); + printf("Scanning mail\n"); + colour(3, 0); + fflush(stdout); + } + + if (strncmp(CFG.bbs_usersdir, path, strlen(CFG.bbs_usersdir)) == 0) { + if (Msg_Open(path)) { + if (((Total = Msg_Number()) != 0L) && (Msg_ReadHeader(MsgNum)) && Msg.Local) { + if (Msg_Lock(15L)) { + scanned++; + ExportEmail(MsgNum); + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(MsgNum); + Msg_UnLock(); + } + + } + Msg_Close(); + } else { + WriteError("Can't open %s", path); + } + return; + } + + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(sAreas, "r")) == NULL) { + WriteError("Can't open %s", sAreas); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + + /* + * Seek the path we want + */ + while (TRUE) { + if (fread(&msgs, msgshdr.recsize, 1, pAreas) != 1) { + fclose(pAreas); + Syslog('m', "ScanOne() reached end of areas"); + return; + } + Area++; + sysstart = ftell(pAreas); + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + if (strcmp(msgs.Base, path) == 0) + break; + } + + if ((msgs.Active) && (msgs.Type == ECHOMAIL || msgs.Type == NETMAIL || msgs.Type == NEWS)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", Area, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + if ((Total = Msg_Number()) != 0L) { + if (Msg_ReadHeader(MsgNum)) { + if (Msg.Local) { + if (Msg_Lock(15L)) { + scanned++; + /* + * Setup SEEN-BY lines + */ + if (msgs.Type == ECHOMAIL || msgs.Type == NEWS) { + echo_in++; + fill_list(&sbl, aka2str(msgs.Aka), NULL, FALSE); + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && + (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && + (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, + CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause)) { + fill_list(&sbl, aka2str(Link.aka), NULL, FALSE); + } + } + uniq_list(&sbl); + sort_list(&sbl); + + fseek(pAreas, sysstart, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&Link, sizeof(sysconnect), 1, pAreas); + if (Link.aka.zone) { + ExportEcho(Link, MsgNum, &sbl); + } + } + if (strlen(msgs.Newsgroup)) + ExportNews(MsgNum, &sbl); + + tidy_falist(&sbl); + } + if (msgs.Type == NETMAIL) { + ExportNet(MsgNum, FALSE); + most_debug = FALSE; + } + + Msg.Local = FALSE; + Msg.Arrived = time(NULL); + Msg_WriteHeader(MsgNum); + Msg_UnLock(); + } + } + + } + } + + Msg_Close(); + } + } else { + WriteError("Config error: area %d not active or not Echo/Netmail area", Area); + } + + fclose(pAreas); + + if (!do_quiet) { + printf("\r \r"); + fflush(stdout); + } +} + + + +int RescanOne(faddr *L, char *marea, unsigned long Num) +// Return: 0 -> Ok +// 1 -> Unknown area +// 2 -> Node cant rescan this area +{ + unsigned long Total, MsgNum, Area = 0; + fa_list *sbl = NULL; + fidoaddr *l; + int First, Found; + unsigned long rescanned; + sysconnect Link; + + IsDoing("ReScan mail"); + + if (!do_quiet) { + colour(9, 0); + printf("ReScan mail\n"); + colour(3, 0); + fflush(stdout); + } + + l = faddr2fido( L ); + rescanned = 0L; + if (!SearchMsgs(marea)) { + syslog('+',"ReScan of unknown echo area %s", marea); + return 1; + } + + First = TRUE; + Found = FALSE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((l->zone == Link.aka.zone) && + (l->net == Link.aka.net) && + (l->node == Link.aka.node) && + (l->point == Link.aka.point)) { + Found = TRUE; + break; + } + } + if (!Found) { + Syslog('+',"Node %s can't Rescan area %s", L, marea); + return 2; + } + + if ((msgs.Active) && (msgs.Type == ECHOMAIL)) { + if (!do_quiet) { + colour(3, 0); + printf("\r%5ld .. %-40s", Area, msgs.Name); + colour(13, 0); + fflush(stdout); + } + + if (Msg_Open(msgs.Base)) { + Total = Msg_Number(); + MsgNum = 1; + if (Num!=0 && Numaddr->net - 1; + for (tmpl = *sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(qp, "\rSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(qp, "%s", sbe); + } + fprintf(qp, "\r\001PATH: %u/%u\r", msgs.Aka.net, msgs.Aka.node); + putc(0, qp); + fclose(qp); + + echo_out++; +} + + + +/* + * Export message to the newsserver. The messagebase is locked. + */ +void ExportNews(unsigned long MsgNum, fa_list **sbl) +{ + char *p; + int seenlen, oldnet, flags = 0; + char sbe[16]; + fa_list *tmpl; + FILE *qp; + faddr *from, *dest; + int is_pid = FALSE, kludges = TRUE; + + qp = tmpfile(); + + Syslog('m', "Msg.From %s", Msg.From); + Syslog('m', "Msg.FromAddress %s", Msg.FromAddress); + Syslog('m', "Msg.To %s", Msg.To); + Syslog('m', "Msg.ToAdrress", Msg.ToAddress); + + flags |= (Msg.Private) ? M_PVT : 0; + from = fido2faddr(msgs.Aka); + + /* + * Add name with echo to news gate. + */ + from->name = xstrcpy(Msg.From); + Syslog('m', "from %s", ascinode(from, 0xff)); + dest = NULL; + + fprintf(qp, "AREA:%s\n", msgs.Tag); + Syslog('m', "AREA:%s", msgs.Tag); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (kludges) { + if (p[0] != '\001') { + /* + * After the first kludges, send RFC headers + */ + kludges = FALSE; + fprintf(qp, "Subject: %s\n", Msg.Subject); + Syslog('m', "Subject: %s", Msg.Subject); + fprintf(qp, "\n"); + Syslog('m', "\n"); + fprintf(qp, "%s\n", p); + Syslog('m', "%s", p); + } else { + fprintf(qp, "%s\n", p+1); + Syslog('m', "%s", p+1); + } + } else { + if ((strncmp(p, " * Origin:", 10) == 0) && !is_pid) { + /* + * If there was no PID kludge, insert the TID + * kludge anyway. + */ + fprintf(qp, "\001TID: MBSE-FIDO %s\n", VERSION); + Syslog('m', "\\001TID: MBSE-FIDO %s", VERSION); + } + fprintf(qp, "%s", p); + Syslog('m', "%s", printable(p, 0)); + if (strncmp(p, " * Origin:", 10) == 0) + break; + + /* + * Only append NL if not the last line + */ + fprintf(qp, "\n"); + + /* + * Append ^aTID line + */ + if (strncmp(p, "\001PID", 4) == 0) { + fprintf(qp, "\001TID: MBSE-FIDO %s\n", VERSION); + Syslog('m', "\\001TID: MBSE-FIDO %s", VERSION); + is_pid = TRUE; + } + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + seenlen = MAXSEEN + 1; + /* + * Ensure that it will not match the first entry. + */ + oldnet = (*sbl)->addr->net - 1; + for (tmpl = *sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe, " %u", tmpl->addr->node); + else + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(qp, "\nSEEN-BY:"); + sprintf(sbe, " %u/%u", tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(qp, "%s", sbe); + } + fprintf(qp, "\n\001PATH: %u/%u\n", msgs.Aka.net, msgs.Aka.node); + Syslog('m', "\\001PATH: %u/%u", msgs.Aka.net, msgs.Aka.node); + + rewind(qp); + most_debug = TRUE; + mkrfcmsg(from, dest, NULL, NULL, Msg.Written + (gmt_offset((time_t)0) * 60), flags, qp, 0L, FALSE); + most_debug = FALSE; + tidy_faddr(from); + fclose(qp); +} + + + +/* + * Export Netmail message, the messagebase is locked. + */ +void ExportNet(unsigned long MsgNum, int UUCPgate) +{ + char *p, *q, ext[4], fromname[37]; + int i, rc, flags = 0, first; + FILE *qp, *fp; + fidoaddr Dest, Route, *dest; + time_t now; + struct tm *tm; + char flavor; + faddr *from, *too, *ta; + int is_fmpt = FALSE, is_topt = FALSE, is_intl = FALSE; + unsigned short point; + char MailFrom[128], MailTo[128]; + + Syslog('m', "Export netmail to %s of %s (%s) %s mode", Msg.To, Msg.ToAddress, + (Msg.Crash || Msg.Direct || Msg.FileAttach) ? "Direct" : "Routed", UUCPgate ? "UUCP" : "Netmail"); + + /* + * Check if this a netmail to our own local UUCP gate. + */ + if ((!strcmp(Msg.To, "UUCP")) && (is_local(parsefnode(Msg.ToAddress)))) { + most_debug = TRUE; + Syslog('m', "We are the UUCP gate"); + Syslog('m', "From %s FromAddress %s", Msg.From, Msg.FromAddress); + if ((fp = tmpfile()) == NULL) { + WriteError("$Can't open tempfile"); + return; + } + from = fido2faddr(msgs.Aka); + sprintf(fromname, "%s", Msg.From); + for (i = 0; i < strlen(fromname); i++) + if (fromname[i] == ' ') + fromname[i] = '_'; + sprintf(MailFrom, "%s@%s", fromname, ascinode(from, 0x2f)); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (strncmp(p, "To: ", 4) == 0) { + q = strtok(p, "<"); + q = strtok(NULL, ">"); + sprintf(MailTo, "%s", q); + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * First send all headers + */ + fprintf(fp, "Date: %s\n", rfcdate(Msg.Written)); + fprintf(fp, "From: %s@%s\n", fromname, ascinode(from, 0x2f)); + tidy_faddr(from); + fprintf(fp, "Subject: %s\n", Msg.Subject); + fprintf(fp, "MIME-Version: 1.0\n"); + fprintf(fp, "Content-Type: text/plain\n"); + fprintf(fp, "Content-Transfer-Encoding: 8bit\n"); + fprintf(fp, "X-Mailreader: MBSE BBS %s\r\n", VERSION); + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + if (strncmp(p, "\001INTL", 5) == 0) + fprintf(fp, "X-FTN-INTL: %s\n", p+4); + else + fprintf(fp, "X-FTN-%s\n", p+1); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] != '\001') { + fprintf(fp, "%s\n", p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + postemail(fp, MailFrom, MailTo); + fclose(fp); + return; + } + + if (UUCPgate) { + memcpy(&Dest, &CFG.UUCPgate, sizeof(fidoaddr)); + memset(&msgs, 0, sizeof(msgs)); + memcpy(&msgs.Aka, &CFG.EmailFidoAka, sizeof(fidoaddr)); + } else { + ta = parsefnode(Msg.ToAddress); + dest = faddr2fido(ta); + tidy_faddr(ta); + memcpy(&Dest, dest, sizeof(fidoaddr)); + } + Dest.domain[0] = '\0'; + + if (!(Msg.Crash || Msg.Immediate || Msg.Direct || Msg.FileAttach)) { + if (!TrackMail(Dest, &Route)) { + Syslog('!', "No route to %s, message orphaned", Msg.ToAddress); + Msg.Orphan = TRUE; + net_bad++; + return; + } + } + + Msg.Sent = TRUE; + if (Msg.KillSent) + Msg.Deleted = TRUE; + + if (Msg.Crash || Msg.Direct || Msg.FileAttach || Msg.Immediate) { + memset(&ext, 0, sizeof(ext)); + if (Msg.Immediate) + sprintf(ext, (char *)"iii"); + else if (Msg.Crash) + sprintf(ext, (char *)"ccc"); + else + sprintf(ext, (char *)"nnn"); + point = Dest.point; + Dest.point = 0; + if (point) + Syslog('+', "Routing via Boss %s", aka2str(Dest)); + if ((qp = OpenPkt(msgs.Aka, Dest, (char *)ext)) == NULL) { + net_bad++; + return; + } + Dest.point = point; + + } else { + Syslog('m', "Route via %s", aka2str(Route)); + if (!SearchNode(Route)) { + WriteError("Routing node %s not in setup, aborting", aka2str(Route)); + return; + } + + /* + * Note that even if the exported netmail is not crash, that if + * the routing node has crash status, this netmail will be send + * crash. + */ + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + if ((qp = OpenPkt(msgs.Aka, Route, (char *)ext)) == NULL) { + net_bad++; + return; + } + } + + flags |= (Msg.Private) ? M_PVT : 0; + flags |= (Msg.Crash) ? M_CRASH : 0; + flags |= (Msg.Hold) ? M_HOLD : 0; + flags |= (Msg.Immediate) ? M_CRASH : 0; + flags |= (Msg.FileRequest) ? M_REQ : 0; + flags |= (Msg.FileAttach) ? M_FILE : 0; + flags |= (Msg.ReceiptRequest) ? M_RRQ : 0; + flags |= (Msg.ConfirmRequest) ? M_AUDIT : 0; + + too = fido2faddr(Dest); + from = fido2faddr(msgs.Aka); + if (UUCPgate) { + Syslog('m', "AddMsgHdr(%s, %s, %s)", (char *)"UUCP", Msg.From, Msg.Subject); + rc = AddMsgHdr(qp, from, too, flags, 0, Msg.Written, (char *)"UUCP", Msg.From, Msg.Subject); + } else { + rc = AddMsgHdr(qp, from, too, flags, 0, Msg.Written, Msg.To, Msg.From, Msg.Subject); + } + tidy_faddr(from); + tidy_faddr(too); + + if (rc) { + WriteError("Create message failed"); + return; + } + + /* + * Analyze this message if it contains INTL, FMPT and TOPT kludges + * and check if we need them. If they are missing they are inserted. + * GoldED doesn't insert them but MBSE does. + */ + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (strncmp(p, "\001FMPT", 5) == 0) + is_fmpt = TRUE; + if (strncmp(p, "\001TOPT", 5) == 0) + is_topt = TRUE; + if (strncmp(p, "\001INTL", 5) == 0) + is_intl = TRUE; + if (strncmp(p, "--- ", 4) == 0) + break; + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + if (msgs.Aka.point && !is_fmpt) + fprintf(qp, "\001FMPT %d\r", msgs.Aka.point); + if (Dest.point && !is_topt) + fprintf(qp, "\001TOPT %d\r", Dest.point); + if (!is_intl) + fprintf(qp, "\001INTL %d:%d/%d %d:%d/%d\r", Dest.zone, Dest.net, Dest.node, + msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (Msg_Read(MsgNum, 78)) { + first = TRUE; + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (UUCPgate && first && (p[0] != '\001')) { + /* + * Past the kludges at the message start. + * Add the To: name@dom.com and a blank line. + */ + fprintf(qp, "To: %s\r", Msg.To); + fprintf(qp, "\r"); + first = FALSE; + } + fprintf(qp, "%s\r", p); + if (strncmp(p, "--- ", 4) == 0) + break; + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + now = time(NULL); + tm = gmtime(&now); + fprintf(qp, "\001Via %s @%d%02d%02d.%02d%02d%02d.01.UTC MBSE BBS %s\r", + aka2str(msgs.Aka), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, qp); + fclose(qp); + + if (Msg.FileAttach) { + if (Msg.Crash) + flavor = 'c'; + else + flavor = 'f'; + + ta = parsefnode(Msg.ToAddress); + if (strlen(CFG.dospath)) { + rc = attach(*ta, Dos2Unix(Msg.Subject), LEAVE, flavor); + Syslog('+', "FileAttach %s %s", Dos2Unix(Msg.Subject), rc ? "Success":"Failed"); + } else { + rc = attach(*ta, Msg.Subject, LEAVE, flavor); + Syslog('+', "FileAttach %s %s", Msg.Subject, rc ? "Success":"Failed"); + } + tidy_faddr(ta); + } + + net_out++; +} + + + +/* + * Export Email message, the messagebase is locked. + */ +void ExportEmail(unsigned long MsgNum) +{ + char *p; + FILE *qp; + int retval, flags = 0; + faddr *from, *too; + int kludges = TRUE; + + Syslog('m', "Export email to %s", Msg.To); + Msg.Sent = TRUE; + if (Msg.KillSent) + Msg.Deleted = TRUE; + + /* + * For local scanned messages both addresses are the same. + */ + from = fido2faddr(CFG.EmailFidoAka); + too = fido2faddr(CFG.EmailFidoAka); + qp = tmpfile(); + + flags |= (Msg.Private) ? M_PVT : 0; + flags |= (Msg.Crash) ? M_CRASH : 0; + flags |= (Msg.Hold) ? M_HOLD : 0; + flags |= (Msg.Immediate) ? M_CRASH : 0; + flags |= (Msg.FileRequest) ? M_REQ : 0; + flags |= (Msg.FileAttach) ? M_FILE : 0; + flags |= (Msg.ReceiptRequest) ? M_RRQ : 0; + flags |= (Msg.ConfirmRequest) ? M_AUDIT : 0; + + if (Msg_Read(MsgNum, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + fprintf(qp, "%s\n", p+1); + if (!strncmp(p, "\001PID:", 5)) { + fprintf(qp, "TID: MBSE-FIDO %s\n", VERSION); + } + } else { + if (kludges) { + kludges = FALSE; + fprintf(qp, "\n"); + } + fprintf(qp, "%s\n", p); + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + rewind(qp); + most_debug = TRUE; + retval = mkrfcmsg(from, too, Msg.Subject, NULL, Msg.Written, flags, qp, 0L, TRUE); + most_debug = FALSE; + Syslog('m', "mkrfcmsg rc=%d", retval); + email_out++; +} + diff --git a/mbfido/scan.h b/mbfido/scan.h new file mode 100644 index 00000000..4a655674 --- /dev/null +++ b/mbfido/scan.h @@ -0,0 +1,10 @@ +#ifndef _SCAN_H +#define _SCAN_H + + +void ScanMail(int); +int RescanOne(faddr *, char *, unsigned long); + + +#endif + diff --git a/mbfido/scannews.c b/mbfido/scannews.c new file mode 100644 index 00000000..c7fe85d8 --- /dev/null +++ b/mbfido/scannews.c @@ -0,0 +1,1437 @@ +/***************************************************************************** + * + * File ..................: mbfido/scannews.c + * Purpose ...............: Scan for new News + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/dbdupe.h" +#include "../lib/dbnode.h" +#include "../lib/dbmsgs.h" +#include "../lib/msg.h" +#include "../lib/msgtext.h" +#include "mkftnhdr.h" +#include "hash.h" +#include "echoout.h" +#include "rollover.h" +#include "pack.h" +#include "scannews.h" + + +#define MAXHDRSIZE 2048 +#define MAXSEEN 70 +#define MAXPATH 73 + + +/* + * Global variables + */ +POverview xoverview = NULL; +int marker = 0; +static int ftnorigin; +static int removemime; +static int removemsgid; +static int removeref; +static int removeinreply; +static int removesupersedes; +static int removeapproved; +static int removereplyto; +static int removereturnto; +static int dirtyoutcode = CHRS_NOTSET; + + + +/* + * External variables + */ +extern int do_quiet; +extern int do_learn; +extern int most_debug; +extern int news_in; +extern int news_imp; +extern int news_dupe; +extern int echo_out; +extern int echo_in; +extern char *replyaddr; + +extern char *toname; /* To user */ +extern char *fromname; /* From user */ +extern char *subj; /* Message subject */ + + +/* + * Internal functions + */ +int do_one_group(List **, char *, char *); +int get_xover(char *, long, long, List **); +int get_xoverview(void); +void tidy_artlist(List **); +void fill_artlist(List **, char *, long, int); +void Marker(void); +int get_article(char *, char *); +int needputrfc(rfcmsg *); + + +void tidy_artlist(List **fdp) +{ + List *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add article to the list + */ +void fill_artlist(List **fdp, char *id, long nr, int dupe) +{ + List **tmp; + + Syslog('N', "Fill %s %ld %s", id, nr, dupe ? "Dupe":"New msg"); + + for (tmp = fdp; *tmp; tmp = &((*tmp)->next)); + *tmp = (List *)malloc(sizeof(List)); + (*tmp)->next = NULL; + sprintf((*tmp)->msgid, "%s", id); + (*tmp)->nr = nr; + (*tmp)->isdupe = dupe; +} + + + +/* + * write an arbitrary line to message body, + * if a line starts with three dashes, insert a dash and a blank + */ +int charwrite(char *, FILE *); +int charwrite(char *s, FILE *fp) +{ + if ((strlen(s) >= 3) && (strncmp(s,"---",3) == 0) && (s[3] != '-')) { + putc('-',fp); + putc(' ',fp); + } + while (*s) { + putc(*s, fp); + s++; + } + return 0; +} + + + +/* + * write (multiline) header to kluge: change \n to ' ' and end line with \n + */ +int kludgewrite(char *, FILE *); +int kludgewrite(char *s, FILE *fp) +{ + while (*s) { + if (*s == '\r') + putc('\n', fp); + else { + if (*s != '\n') + putc(*s, fp); + else if (*(s+1)) + putc(' ',fp); + } + s++; + } + putc('\n',fp); + return 0; +} + + + +void Marker(void) +{ + if (do_quiet) + return; + + switch (marker) { + case 0: printf(">---"); + break; + + case 1: printf(">>--"); + break; + + case 2: printf(">>>-"); + break; + + case 3: printf(">>>>"); + break; + + case 4: printf("<>>>"); + break; + + case 5: printf("<<>>"); + break; + + case 6: printf("<<<>"); + break; + + case 7: printf("<<<<"); + break; + + case 8: printf("-<<<"); + break; + + case 9: printf("--<<"); + break; + + case 10:printf("---<"); + break; + + case 11:printf("----"); + break; + } + printf("\b\b\b\b"); + fflush(stdout); + + if (marker < 11) + marker++; + else + marker = 0; +} + + + +/* + * Scan for new news available at the nntp server. + */ +void ScanNews(void) +{ + List *art = NULL; + POverview tmp, old; + FILE *pAreas; + char *sAreas; + struct msgareashdr Msgshdr; + struct msgareas Msgs; + + IsDoing((char *)"Scan News"); + if (nntp_connect() == -1) { + WriteError("Can't connect to newsserver"); + return; + } + if (get_xoverview()) + return; + + if (!do_quiet) { + colour(10, 0); + printf("Scan for new news articles\n"); + } + + sAreas = calloc(PATH_MAX, sizeof(char)); + sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open Messages Areas File."); + return; + } + fread(&Msgshdr, sizeof(Msgshdr), 1, pAreas); + + while (fread(&Msgs, Msgshdr.recsize, 1, pAreas) == 1) { + fseek(pAreas, Msgshdr.syssize, SEEK_CUR); + if ((Msgs.Active) && strlen(Msgs.Newsgroup)) { + if (IsSema((char *)"upsalarm")) { + Syslog('+', "Detected upsalarm semafore, aborting newsscan"); + break; + } + Syslog('n', "Scan newsgroup: %s", Msgs.Newsgroup); + if (!do_quiet) { + colour(3, 0); + printf("\r%-40s", Msgs.Newsgroup); + fflush(stdout); + } + Nopper(); + if (do_one_group(&art, Msgs.Newsgroup, Msgs.Tag) == RETVAL_ERROR) + break; + } + } + fclose(pAreas); + free(sAreas); + + for (tmp = xoverview; tmp; tmp = old) { + old = tmp->next; + if (tmp->header) + free(tmp->header); + if (tmp->field) + free(tmp->field); + free(tmp); + } + packmail(); + + if (!do_quiet) + printf("\r \r"); +} + + + +int do_one_group(List **art, char *grpname, char *ftntag) +{ + List *tmp; + char temp[128], *resp; + int retval; + long total, start, end; + + Syslog('N', "do_one_group(%s, %s)", grpname, ftntag); + IsDoing((char *)"Scan %s", grpname); + sprintf(temp, "GROUP %s\r\n", grpname); + nntp_send(temp); + resp = nntp_receive(); + retval = atoi(strtok(resp, " ")); + if (retval != 211) { + if (retval == 411) + WriteError("No such newsgroup: %s", grpname); + else + WriteError("Unknown response %d to GROUP command", retval); + return RETVAL_ERROR; + } + + total = atol(strtok(NULL, " ")); + start = atol(strtok(NULL, " ")); + end = atol(strtok(NULL, " '\0'")); + if (!total) { + Syslog('N', "No articles"); + return RETVAL_OK; + } + + retval = get_xover(grpname, start, end, art); + if (retval != RETVAL_OK) { + tidy_artlist(art); + return retval; + } + + if (!do_learn) { + for (tmp = *art; tmp; tmp = tmp->next) { + if (!tmp->isdupe) { + /* + * If the message isn't a dupe, it must be new for us. + */ + most_debug = TRUE; + get_article(tmp->msgid, ftntag); + most_debug = FALSE; + } + } + } + + tidy_artlist(art); + return RETVAL_OK; +} + + + +int get_article(char *msgid, char *ftntag) +{ + char cmd[81], *resp; + int retval, done = FALSE; + FILE *fp = NULL; + + Syslog('n', "Get article %s, %s", msgid, ftntag); + if (!SearchMsgs(ftntag)) { + WriteError("Search message area %s failed", ftntag); + return RETVAL_ERROR; + } + IsDoing("Article %d", (news_in + 1)); + sprintf(cmd, "ARTICLE %s\r\n", msgid); + nntp_send(cmd); + resp = nntp_receive(); + retval = atoi(strtok(resp, " ")); + switch (retval) { + case 412: WriteError("No newsgroup selected"); + return RETVAL_UNEXPECTEDANS; + case 420: WriteError("No current article has been selected"); + return RETVAL_UNEXPECTEDANS; + case 423: WriteError("No such article in this group"); + return RETVAL_UNEXPECTEDANS; + case 430: WriteError("No such article found"); + return RETVAL_UNEXPECTEDANS; + case 220: if ((fp = tmpfile()) == NULL) { + WriteError("$Can't open tmpfile"); + return RETVAL_UNEXPECTEDANS; + } + while (done == FALSE) { + resp = nntp_receive(); + if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) { + done = TRUE; + } else { + fwrite(resp, strlen(resp), 1, fp); + fputc('\n', fp); + } + } + break; + } + + news_in++; + IsDoing("Article %d", (news_in)); + retval = do_article(fp); + fclose(fp); + return retval; +} + + + +int do_article(FILE *fp) +{ + char sbe[16], *p, *q, *temp; + int i, incode, outcode, pgpsigned; + int First = TRUE, seenlen, oldnet; + sysconnect Link; + rfcmsg *msg = NULL, *tmsg, *tmp; + ftnmsg *fmsg = NULL; + FILE *ofp; + fa_list *sbl = NULL, *ptl = NULL, *tmpl; + faddr *ta, *From; + unsigned long svmsgid, svreply; + int sot_kludge = FALSE, eot_kludge = FALSE, qp_or_base64 = FALSE, tinyorigin = FALSE; + int needsplit, hdrsize, datasize, splitpart, forbidsplit, rfcheaders; + char newsubj[4 * (MAXSUBJ+1)], *oldsubj, *acup_a = NULL; + unsigned long acup_n = 0, crc2; + int html_message = FALSE; + time_t Now; + + rewind(fp); + msg = parsrfc(fp); + incode = outcode = CHRS_NOTSET; + pgpsigned = FALSE; + + p = hdr((char *)"Content-Type",msg); + if (p) + incode=readcharset(p); + if (incode == CHRS_NOTSET) { + p = hdr((char *)"X-FTN-CHRS",msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CHARSET", msg); + if (p == NULL) + p = hdr((char *)"X-FTN-CODEPAGE", msg); + if (p) + incode = readchrs(p); + } + + if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p,(char *)"multipart/signed")) || + (strcasestr(p,(char *)"application/pgp")))) { + pgpsigned = TRUE; + outcode = incode; + } else if ((p = hdr((char *)"X-FTN-ORIGCHRS", msg))) + outcode = readchrs(p); + else if (dirtyoutcode != CHRS_NOTSET) + outcode = dirtyoutcode; + else + outcode = getoutcode(incode); + for (tmsg = msg; tmsg; tmsg = tmsg->next) + if (strcasecmp(tmsg->key, "X-FTN-SEEN-BY") == 0) + fill_list(&sbl, tmsg->val, NULL, TRUE); + + if (!CFG.allowcontrol) { + if (hdr((char *)"Control",msg)) { + Syslog('n', "skipping news message"); + tidy_falist(&sbl); + tidyrfc(msg); + return RETVAL_OK; + } + } + + if ((fmsg = mkftnhdr(msg, incode, outcode, TRUE)) == NULL) { + WriteError("Unable to create FTN headers from RFC ones, aborting"); + tidy_falist(&sbl); + tidyrfc(msg); + return RETVAL_ERROR; + } + + /* + * Setup PATH line + */ + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl, sbe); + fmsg->area = xstrcpy(msgs.Tag); + svmsgid = fmsg->msgid_n; + svreply = fmsg->reply_n; + if ((p = hdr((char *)"Message-ID",msg))) { + ftnmsgid(p, &fmsg->msgid_a, &fmsg->msgid_n, fmsg->area); + hash_update_s(&fmsg->msgid_n, fmsg->area); + } + + if ((p = hdr((char *)"References",msg))) { + p = strrchr(p,' '); + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } else if ((p = hdr((char *)"In-Reply-To",msg))) { + ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area); + if (!chkftnmsgid(p)) { + hash_update_s(&fmsg->reply_n, fmsg->area); + } + } + + if (incode == CHRS_NOTSET) + incode = msgs.Rfccode; + if (outcode == CHRS_NOTSET) + outcode = msgs.Ftncode; + if ((incode == CHRS_NOTSET) && (hdr((char *)"Message-ID",msg))) { + if (chkftnmsgid(hdr((char *)"Message-ID",msg))) + incode = CHRS_DEFAULT_FTN; + else + incode = CHRS_DEFAULT_RFC; + } + temp = calloc(4096, sizeof(char)); + removemime = FALSE; + removemsgid = FALSE; + removeref = FALSE; + removeinreply = FALSE; + removesupersedes = FALSE; + removeapproved = FALSE; + removereplyto = TRUE; + removereturnto = TRUE; + ftnorigin = fmsg->ftnorigin; + if ((hdr((char *)"X-PGP-Signed",msg))) + pgpsigned = TRUE; + if (pgpsigned) + Syslog('n', "pgpsigned = %s", pgpsigned ? "True":"False"); + + q = hdr((char *)"Content-Transfer-Encoding",msg); + if (q) + while (*q && isspace(*q)) + q++; + if (!(q)) + q = (char *)"8bit"; + if ((p = hdr((char *)"Content-Type",msg))) { + while (*p && isspace(*p)) + p++; + + /* + * turn the quoted-printable decode mode on; remember FTN is virtually 8-bit clean + */ + if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "quoted-printable", 16) == 0)) + qp_or_base64 = 1; + /* + * turn the base64 decode mode on + */ + else if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "base64", 6) == 0)) + qp_or_base64 = 2; + + /* + * text/html support from FSC-HTML 001 proposal of Odinn Sorensen (2:236/77) + */ + if (strncasecmp(p, "text/html", 9) == 0) + html_message = TRUE; + for (tmp = msg; tmp; tmp = tmp->next) + if (((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) && (strcasecmp(tmp->val,"FSCHTML") == 0)) || + (strcasecmp(tmp->key,"X-FTN-HTML") == 0)) + html_message = FALSE; + + if ((readcharset(p) != CHRS_NOTSET ) && ((q == NULL) || (strncasecmp(q,"7bit",4) == 0) || + ((!pgpsigned) && (qp_or_base64==1)) || ((!pgpsigned) && (qp_or_base64==2)) || (strncasecmp(q,"8bit",4) == 0))) + removemime=1; /* no need in MIME headers */ + /* + * some old MUA puts "text" instead of "text/plain; charset=..." + */ + else if ((strcasecmp(p,"text\n") == 0)) + removemime = TRUE; + } + if (removemime || qp_or_base64 || html_message) + Syslog('n', "removemime=%s, qp_or_base64 = %d, html_message=%s", removemime ? "True":"False", qp_or_base64, + html_message ? "True":"False"); + + if ((p = hdr((char *)"Message-ID",msg))) { + if (!removemsgid) + removemsgid = chkftnmsgid(p); + } + Syslog('n', "removemsgid = %s", removemsgid ? "True":"False"); + + if ((!removeref) && (p = hdr((char *)"References",msg))) { + p = xstrcpy(p); + q = strtok(p," \t\n"); + if ((q) && (strtok(NULL," \t\n") == NULL)) + removeref = chkftnmsgid(q); + free(p); + } + if (removeref) + Syslog('n', "removeref = %s", removeref ? "True":"False"); + + if ((p = hdr((char *)"Supersedes",msg))) + removesupersedes = chkftnmsgid(p); + if (removesupersedes) + Syslog('n', "removesupersedes = %s", removesupersedes ? "True":"False"); + + if ((p = hdr((char *)"Approved",msg))) { + while (*p && isspace(*p)) + p++; + if ((q = strchr(p,'\n'))) + *q='\0'; + if (strlen(msgs.Moderator) && (strcasestr(msgs.Moderator,p))) + removeapproved = TRUE; + if (q) + *q='\n'; + } + if (removeapproved) + Syslog('n', "removeapproved = %s", removeapproved ? "True":"False"); + + if ((p = hdr((char *)"Reply-To",msg))) { + removereplyto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + r = xstrcpy(p); + p = r; + while(*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereplyto = TRUE; + free(r); + } + } + Syslog('n', "removereplyto = %s", removereplyto ? "True":"False"); + + if ((p = hdr((char *)"Return-Receipt-To",msg))) { + removereturnto = FALSE; + if ((q = hdr((char *)"From",msg))) { + char *r; + + r = xstrcpy(p); + p = r; + while (*p && isspace(*p)) + p++; + if (p[strlen(p)-1] == '\n') + p[strlen(p)-1]='\0'; + if (strcasestr(q,p)) + removereturnto = TRUE; +// free(r); + } + } + if (!removereturnto) + Syslog('n', "removereturnto = %s", removereturnto ? "True":"False"); + + p = ascfnode(fmsg->from,0x1f); + i = 79-11-3-strlen(p); + if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) { + /* This is a kludge... I don't like it too much. But well, + if this is a message of FTN origin, the original origin (:) + line MUST have been short enough to fit in 79 chars... + So we give it a try. Probably it would be better to keep + the information about the address format from the origin + line in a special X-FTN-... header, but this seems even + less elegant. Any _good_ ideas, anyone? */ + + /* OK, I am keeping this, though if should never be used + al long as X-FTN-Origin is used now */ + + p = ascfnode(fmsg->from,0x0f); + Syslog('n', "checkorigin 3"); + i = 79-11-3-strlen(p); + tinyorigin = TRUE; + } + if (tinyorigin) + Syslog('n', "tinyorigin = %s", tinyorigin ? "True":"False"); + + if ((fmsg->origin) && (strlen(fmsg->origin) > i)) + fmsg->origin[i]='\0'; + forbidsplit = (ftnorigin || (hdr((char *)"X-FTN-Split",msg))); + needsplit = 0; + splitpart = 0; + hdrsize = 20; + hdrsize += (fmsg->subj)?strlen(fmsg->subj):0; + if (fmsg->from) + hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0; + if (fmsg->to) + hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0; + do { + Syslog('n', "split loop, splitpart = %d", splitpart); + datasize = 0; + + if (splitpart) { + sprintf(newsubj,"[part %d] ",splitpart+1); + strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj)); + } else { + strncpy(newsubj,fmsg->subj,MAXSUBJ); + } + strcpy(newsubj, hdrnconv(newsubj, incode, outcode, MAXSUBJ)); + newsubj[MAXSUBJ]='\0'; + + if (splitpart) { + hash_update_n(&fmsg->msgid_n,splitpart); + } + oldsubj = fmsg->subj; + fmsg->subj = newsubj; + + /* + * Create a new temp message in FTN style format + */ + if ((ofp = tmpfile()) == NULL) { + WriteError("$Can't open second tmpfile"); + tidy_falist(&sbl); + tidy_falist(&ptl); + tidyrfc(msg); + return RETVAL_ERROR; + } + fprintf(ofp, "AREA:%s\n", msgs.Tag); + fprintf(ofp, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n); + if (fmsg->reply_s) + fprintf(ofp, "\1REPLY: %s\n", fmsg->reply_s); + else if (fmsg->reply_a) + fprintf(ofp, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n); + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + fprintf(ofp, "\001TZUTC: %s\n", gmtoffset(Now)); + fmsg->subj = oldsubj; + if ((p = hdr((char *)"X-FTN-REPLYADDR",msg))) { + Syslog('n', "replyaddr 1 %s", p); + hdrsize += 10+strlen(p); + fprintf(ofp,"\1REPLYADDR:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + Syslog('n', "replyaddr 2"); + hdrsize += 10+strlen(replyaddr); + fprintf(ofp,"\1REPLYADDR: "); + kludgewrite(replyaddr,ofp); + } + if ((p = hdr((char *)"X-FTN-REPLYTO",msg))) { + hdrsize += 8+strlen(p); + fprintf(ofp,"\1REPLYTO:"); + kludgewrite(p,ofp); + } else if (replyaddr) { + hdrsize += 15; + fprintf(ofp,"\1REPLYTO: %s UUCP\n", aka2str(msgs.Aka)); + } else if ((p = hdr((char *)"Reply-To",msg))) { + if ((ta = parsefaddr(p))) { + if ((q = hdr((char *)"From",msg))) { + if (!strcasestr(q,p)) { + fprintf(ofp,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name); + } + tidy_faddr(ta); + } + } + } + if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) { + hdrsize += 15; + fprintf(ofp,"\1FLAGS:%s\n",p); + free(p); + } + if (!hdr((char *)"X-FTN-PID", msg)) { + p = hdr((char *)"User-Agent", msg); + if (p == NULL) + p = hdr((char *)"X-Newsreader", msg); + if (p == NULL) + p = hdr((char *)"X-Mailer", msg); + if (p) { + hdrsize += 4 + strlen(p); + fprintf(ofp, "\1PID:"); + kludgewrite(p, ofp); + } else { + fprintf(ofp, "\001PID: MBSE-FIDO %s\n", VERSION); + } + } + + hdrsize += 8 + strlen(getchrs(outcode)); + fprintf(ofp, "\001CHRS: %s\n", getchrs(outcode)); + if (html_message) { + hdrsize += 9; + fprintf(ofp, "\1HTML: 5\n"); + } + + if (CFG.allowcontrol && (!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Control",msg))) { + if (strstr(p,"cancel")) { + ftnmsgid(p,&acup_a,&acup_n,fmsg->area); + if (acup_a) { + hash_update_s(&acup_n,fmsg->area); + hdrsize += 26 + strlen(acup_a); + fprintf(ofp,"\1ACUPDATE: DELETE %s %08lx\n", acup_a,acup_n); + } + } + } + if ((!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Supersedes",msg))) { + ftnmsgid(p,&acup_a,&acup_n,fmsg->area); + if (acup_a) { + hash_update_s(&acup_n,fmsg->area); + hdrsize += 26 + strlen(acup_a); + fprintf(ofp,"\1ACUPDATE: MODIFY %s %08lx\n", acup_a,acup_n); + } + } +#ifdef FSC_0070 + /* FSC-0070 */ + if((p = hdr((char *)"Message-ID", msg)) && !(hdr((char *)"X-FTN-RFCID", msg))) { + q = strdup(p); + fprintf(ofp,"\1RFCID:"); + if ((l = strrchr(q, '<')) && (r = strchr(q, '>')) && (l < r)) { + *l++ = ' '; + while(*l && isspace(*l)) + l++; + l--; /* leading ' ' */ + *r-- = '\0'; + while(*r && isspace(*r)) + *r-- = '\0'; + } else + l = q; + kludgewrite(l, ofp); + hdrsize += 6 + strlen(l); + free(q); + } +#endif /* FSC_0070 */ + + if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) { + sprintf(temp, " MBSE-FIDO %s", VERSION); + hdrsize += 4 + strlen(temp); + fprintf(ofp, "\1TID:"); + kludgewrite(temp, ofp); + } + if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) { + for (tmp = msg; tmp; tmp = tmp->next) { + if ((!strncmp(tmp->key,"X-Fsc-",6)) || + (!strncmp(tmp->key,"X-FTN-",6) && + strcasecmp(tmp->key,"X-FTN-Tearline") && + strcasecmp(tmp->key,"X-FTN-Origin") && + strcasecmp(tmp->key,"X-FTN-Sender") && + strcasecmp(tmp->key,"X-FTN-Split") && + strcasecmp(tmp->key,"X-FTN-FLAGS") && + strcasecmp(tmp->key,"X-FTN-AREA") && + strcasecmp(tmp->key,"X-FTN-MSGID") && + strcasecmp(tmp->key,"X-FTN-REPLY") && + strcasecmp(tmp->key,"X-FTN-SEEN-BY") && + strcasecmp(tmp->key,"X-FTN-PATH") && + strcasecmp(tmp->key,"X-FTN-REPLYADDR") && + strcasecmp(tmp->key,"X-FTN-REPLYTO") && + strcasecmp(tmp->key,"X-FTN-To") && + strcasecmp(tmp->key,"X-FTN-From") && + strcasecmp(tmp->key,"X-FTN-CHARSET") && + strcasecmp(tmp->key,"X-FTN-CHRS") && + strcasecmp(tmp->key,"X-FTN-CODEPAGE") && + strcasecmp(tmp->key,"X-FTN-ORIGCHRS") && + strcasecmp(tmp->key,"X-FTN-SOT") && + strcasecmp(tmp->key,"X-FTN-EOT") && + strcasecmp(tmp->key,"X-FTN-Via"))) { + if ((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0)) { + if (!strcasecmp(tmp->val," SOT:\n")) + sot_kludge = TRUE; + else if (!strcasecmp(tmp->val," EOT:\n")) + eot_kludge = TRUE; + else { + hdrsize += strlen(tmp->val); + fprintf(ofp,"\1"); + /* we should have restored the original string here... */ + kludgewrite((tmp->val)+1,ofp); + } + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+6); + kludgewrite(tmp->val,ofp); + } + } + } + /* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,"X-ZC-",5))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+2); + kludgewrite(tmp->val,ofp); + } + + /* mondo.org gateway uses ".MSGID: ..." in usenet */ + for (tmp=msg;tmp;tmp=tmp->next) + if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1%s:",tmp->key+1); + kludgewrite(tmp->val,ofp); + } + rfcheaders=0; + for (tmp = msg; tmp; tmp = tmp->next) { + if ((needputrfc(tmp) == 1)) { + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"\1RFC-Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"\1RFC-%s:",tmp->key); + } + kludgewrite(hdrconv(tmp->val, incode, outcode),ofp); + } + } + + for (tmp=msg;tmp;tmp=tmp->next) { + if ((needputrfc(tmp) > 1)) { + rfcheaders++; + if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) { + hdrsize += 10+strlen(tmp->val); + fprintf(ofp,"Newsgroups:"); + } else { + hdrsize += strlen(tmp->key)+strlen(tmp->val); + fprintf(ofp,"%s:",tmp->key); + } + charwrite(hdrconv(tmp->val, incode, outcode),ofp); + } + } + if (rfcheaders) + charwrite((char *)"\n",ofp); + if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge)) + fprintf(ofp,"\1SOT:\n"); + if ((splitpart == 0) && (hdr((char *)"X-PGP-Signed",msg))) + fprintf(ofp,PGP_SIGNED_BEGIN"\n"); + } + if (replyaddr) { +// free(replyaddr); /* Gives SIGSEGV */ + replyaddr = NULL; + } + if (needsplit) { + fprintf(ofp," * Continuation %d of a split message *\n\n", splitpart); + needsplit = FALSE; + } else if ((p=hdr((char *)"X-Body-Start",msg))) { + datasize += strlen(p); + if (qp_or_base64==1) + charwrite(strkconv(qp_decode(p), incode, outcode), ofp); + else if (qp_or_base64==2) + charwrite(strkconv(b64_decode(p), incode, outcode), ofp); + else + charwrite(strkconv(p, incode, outcode), ofp); + } + while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) || + (!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(temp,4096-1,fp))) { + datasize += strlen(temp); + if (qp_or_base64==1) + charwrite(strkconv(qp_decode(temp), incode, outcode), ofp); + else if (qp_or_base64==2) + charwrite(strkconv(b64_decode(temp), incode, outcode), ofp); + else + charwrite(strkconv(temp, incode, outcode), ofp); + } + if (needsplit) { + fprintf(ofp,"\n * Message split, to be continued *\n"); + splitpart++; + } else if ((p=hdr((char *)"X-PGP-Signed",msg))) { + fprintf(ofp,PGP_SIG_BEGIN"\n"); + if ((q=hdr((char *)"X-PGP-Version",msg))) { + fprintf(ofp,"Version:"); + charwrite(q,ofp); + } + if ((q=hdr((char *)"X-PGP-Charset",msg))) { + fprintf(ofp,"Charset:"); + charwrite(q,ofp); + } + if ((q=hdr((char *)"X-PGP-Comment",msg))) { + fprintf(ofp,"Comment:"); + charwrite(q,ofp); + } + fprintf(ofp,"\n"); + p=xstrcpy(p); + q=strtok(p," \t\n"); + fprintf(ofp,"%s\n",q); + while ((q=(strtok(NULL," \t\n")))) + fprintf(ofp,"%s\n",q); + fprintf(ofp,PGP_SIG_END"\n"); + } + if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge)) + fprintf(ofp,"\1EOT:\n"); + + if ((p=hdr((char *)"X-FTN-Tearline",msg))) { + fprintf(ofp,"---"); + if (strcasecmp(p," (none)\n") == 0) + charwrite((char *)"\n",ofp); + else + charwrite(p,ofp); + } else + fprintf(ofp,"--- MBSE BBSv.%s\n",VERSION); + + if ((p = hdr((char *)"X-FTN-Origin",msg))) { + if (*(q=p+strlen(p)-1) == '\n') + *q='\0'; + fprintf(ofp," * Origin:"); + charwrite(hdrconv(p, incode, outcode),ofp); + } else { + fprintf(ofp," * Origin: "); /* strlen=11 */ + if (fmsg->origin) + charwrite(hdrconv(fmsg->origin, incode, outcode), ofp); + else + charwrite(CFG.origin, ofp); + fprintf(ofp," (%s)", + ascfnode(fmsg->from,tinyorigin?0x0f:0x1f)); + } + /* + * Setup SEEN-BY lines + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && + !((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) { + sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node); + fill_list(&sbl, sbe, NULL, FALSE); + } + } + sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node); + First = TRUE; + /* + * Count downlinks, if there are none then no more SEEN-BY entries will be added. + */ + i = 0; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node); + fill_list(&sbl, sbe, NULL, FALSE); + i++; + } + } + uniq_list(&sbl); + sort_list(&sbl); + seenlen=MAXSEEN+1; + if (i) { + /* ensure it will not match for the first entry */ + oldnet = sbl->addr->net-1; + for (tmpl = sbl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXSEEN) { + seenlen = 0; + fprintf(ofp,"\nSEEN-BY:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + } else { + fprintf(ofp,"\nSEEN-BY: %s",sbe); + } + + for (tmp = msg; tmp; tmp = tmp->next) { + if (!strcasecmp(tmp->key,"X-FTN-PATH")) { + fill_path(&ptl,tmp->val); + } + } + sprintf(sbe,"%u/%u",msgs.Aka.net, msgs.Aka.node); + fill_path(&ptl,sbe); + uniq_list(&ptl); + seenlen = MAXPATH+1; + /* ensure it will not match for the first entry */ + oldnet = ptl->addr->net-1; + for (tmpl = ptl; tmpl; tmpl = tmpl->next) { + if (tmpl->addr->net == oldnet) + sprintf(sbe," %u",tmpl->addr->node); + else + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + oldnet = tmpl->addr->net; + seenlen += strlen(sbe); + if (seenlen > MAXPATH) { + seenlen = 0; + fprintf(ofp,"\n\1PATH:"); + sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node); + seenlen = strlen(sbe); + } + fprintf(ofp,"%s",sbe); + } + fprintf(ofp,"\n"); + + tidy_falist(&ptl); + fflush(ofp); + rewind(ofp); + Syslog('n', "========== Fido start"); + while (fgets(temp, 4096, ofp) != NULL) { + /* + * Only log kludges, skip the body + */ + if ((temp[0] == '\001') || !strncmp(temp, "AREA:", 5) || !strncmp(temp, "SEEN-BY", 7)) { + Striplf(temp); + Syslogp('n', printable(temp, 0)); + } + } + Syslog('n', "========== Fido end"); + + rewind(ofp); + Msg_New(); + + if ((fmsg->to != NULL) && (fmsg->to->name != NULL)) + strcpy(Msg.To, fmsg->to->name); + else + sprintf(Msg.To, "All"); + Syslog('n', "Msg.To: %s", printable(Msg.To, 0)); + toname = xstrcpy(Msg.To); + + if ((fmsg->from != NULL) && (fmsg->from->name != NULL)) { + strcpy(Msg.From, fmsg->from->name); + Syslog('n', "Msg.From: %s", printable(Msg.From, 0)); + fromname = xstrcpy(Msg.From); + } else { + Syslog('n', "Warning: no Msg.From name found"); + } + + strcpy(Msg.Subject, fmsg->subj); + subj = xstrcpy(Msg.Subject); + Msg.Echomail = TRUE; + Msg.Written = fmsg->date; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + /* + * These are the only usefull flags in echomail + */ + if ((fmsg->flags & M_PVT) && ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE))) + Msg.Private = TRUE; + if (fmsg->flags & M_FILE) + Msg.FileAttach = TRUE; + + /* + * Set MSGID and REPLYID crc. + */ + if (fmsg->msgid_a != NULL) { + crc2 = -1; + Msg.MsgIdCRC = upd_crc32(fmsg->msgid_a, crc2, strlen(fmsg->msgid_a)); + } + if (fmsg->reply_a != NULL) { + crc2 = -1; + Msg.ReplyCRC = upd_crc32(fmsg->reply_a, crc2, strlen(fmsg->reply_a)); + } + + if (Msg_Open(msgs.Base)) { + if (Msg_Lock(30L)) { + rewind(ofp); + fgets(temp, 2048, ofp); /* "Eat" the first line AREA:... */ + Msg_Write(ofp); + Msg_AddMsg(); + Msg_UnLock(); + echo_in++; + Syslog('+', "Newsgate %s => %s msg %ld", msgs.Newsgroup, msgs.Tag, Msg.Id); + } + Msg_Close(); + StatAdd(&msgs.Received, 1); + time(&msgs.LastRcvd); + StatAdd(&mgroup.MsgsRcvd, 1); + time(&mgroup.LastDate); + } + + /* + * Now start exporting this echomail. + */ + First = TRUE; + while (GetMsgSystem(&Link, First)) { + First = FALSE; + if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) { + if (SearchNode(Link.aka)) { + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(Link.aka); + } + echo_out++; + Syslog('n', "Export to %s", aka2str(Link.aka)); + From = fido2faddr(msgs.Aka); + EchoOut(From, Link.aka, ofp, fmsg->flags, 0, fmsg->date); + tidy_faddr(From); + } + } + + free(fromname); + free(toname); + free(subj); + fclose(ofp); + } while (needsplit); + tidy_falist(&sbl); + tidy_falist(&ptl); + free(temp); + news_imp++; + tidyrfc(msg); + tidy_ftnmsg(fmsg); + UpdateMsgs(); + + return RETVAL_OK; +} + + + +int get_xover(char *grpname, long startnr, long endnr, List **art) +{ + char cmd[81], *ptr, *ptr2, *resp, *p; + int retval, dupe, done = FALSE; + long nr; + unsigned long crc; + POverview pov; + + sprintf(cmd, "XOVER %ld-%ld\r\n", startnr, endnr); + if ((retval = nntp_cmd(cmd, 224))) { + switch (retval) { + case 412: + WriteError("No newsgroup selected"); + return RETVAL_NOXOVER; + case 502: + WriteError("Permission denied"); + return RETVAL_NOXOVER; + case 420: + Syslog('n', "No articles in group %s", grpname); + return RETVAL_OK; + } + } + + while (done == FALSE) { + resp = nntp_receive(); + if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) { + done = TRUE; + } else { + Marker(); + pov = xoverview; + ptr = resp; + ptr2 = ptr; + + /* + * First item is the message number. + */ + while (*ptr2 != '\0' && *ptr2 != '\t') + ptr2++; + if (*ptr2 != '\0') + *(ptr2) = '\0'; + nr = atol(ptr); + ptr = ptr2; + ptr++; + + /* + * Search the message-id + */ + while (*ptr != '\0' && pov != NULL && strcmp(pov->header, "Message-ID:") != 0) { + /* + * goto the next field, past the tab. + */ + pov = pov->next; + + while (*ptr != '\t' && *ptr != '\0') + ptr++; + if (*ptr != '\0') + ptr++; + } + if (*ptr != '\0' && pov != NULL) { + /* + * Found it, now find start of msgid + */ + while (*ptr != '\0' && *ptr != '<') + ptr++; + if(ptr != '\0') { + ptr2 = ptr; + while(*ptr2 != '\0' && *ptr2 != '>') + ptr2++; + if (*ptr2 != '\0') { + *(ptr2+1) = '\0'; + p = xstrcpy(ptr); + p = xstrcat(p, grpname); + crc = str_crc32(p); + dupe = CheckDupe(crc, D_NEWS, CFG.nntpdupes); + fill_artlist(art, ptr, nr, dupe); + free(p); + if (CFG.slow_util && do_quiet) + usleep(1); + } + } + } + } + } + + return RETVAL_OK; +} + + + +int get_xoverview(void) +{ + int retval, len, full, done = FALSE; + char *resp; + POverview tmp, curptr = NULL; + + Syslog('n', "Getting overview format list"); + if ((retval = nntp_cmd((char *)"LIST overview.fmt\r\n", 215)) == 0) { + while (done == FALSE) { + resp = nntp_receive(); + if ((strcmp(resp, ".") == 0) && (strlen(resp) == 1)) { + done = TRUE; + } else { + len = strlen(resp); + /* + * Check for the full flag, which means the field name + * is in the xover string. + */ + full = (strstr(resp, ":full") == NULL) ? FALSE : TRUE; + /* + * Now get rid of everything back to : + */ + while (resp[len] != ':') + resp[len--] = '\0'; + len++; + + tmp = malloc(sizeof(Overview)); + tmp->header = calloc(len + 1, sizeof(char)); + strncpy(tmp->header, resp, len); + tmp->header[len] = '\0'; + tmp->next = NULL; + tmp->field = NULL; + tmp->fieldlen = 0; + tmp->full = full; + + if (curptr == NULL) { + /* at head of list */ + curptr = tmp; + xoverview = tmp; + } else { + /* add to linked list */ + curptr->next = tmp; + curptr = tmp; + } + } + } + + if ((tmp = xoverview) != NULL) { + Syslog('N', "--Xoverview.fmt list"); + while (tmp != NULL) { + if (tmp->header != NULL) { + Syslog('N', "item = %s -- full = %s", tmp->header, tmp->full ? "True":"False"); + } + tmp = tmp->next; + } + } + } else { + return 1; + } + return 0; +} + + + +int needputrfc(rfcmsg *msg) +{ + faddr *ta; + + /* 0-junk, 1-kludge, 2-pass */ + +// Syslog('M', "needputrfc(%s)", printable(msg->key,0)); + if ((msg->key == NULL) || (strlen(msg->key) == 0)) return 0; + + if (!strcasecmp(msg->key,"X-UUCP-From")) return -1; + if (!strcasecmp(msg->key,"X-Body-Start")) return -1; + if (!strncasecmp(msg->key,".",1)) return 0; + if (!strncasecmp(msg->key,"X-FTN-",6)) return 0; + if (!strncasecmp(msg->key,"X-Fsc-",6)) return 0; + if (!strncasecmp(msg->key,"X-ZC-",5)) return 0; + if (!strcasecmp(msg->key,"X-Gateway")) return 0; + if (!strcasecmp(msg->key,"Path")) return 0; + if (!strcasecmp(msg->key,"Newsgroups")) { + if ((hdr((char *)"X-Origin-Newsgroups",msg))) + return 0; + else if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) { + if (strstr(msg->val,",")) + return 1; + else + return 0; + } + + if (!strcasecmp(msg->key,"Control")) { + if (CFG.allowcontrol) { + if (strstr(msg->val,"cancel")) + return 1; + else + return 0; + } else + return 0; + } + if (!strcasecmp(msg->key,"Return-Path")) return 1; + if (!strcasecmp(msg->key,"Xref")) return 0; + if (!strcasecmp(msg->key,"Approved")) return removeapproved ? -1:2; + if (!strcasecmp(msg->key,"X-URL")) return 0; + if (!strcasecmp(msg->key,"Return-Receipt-To")) return removereturnto? 0:1; + if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) return 0; + if (!strcasecmp(msg->key,"Received")) return 0; + if (!strcasecmp(msg->key,"From")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return 0; + } else { + return 2; + } + } + if (!strcasecmp(msg->key,"To")) { + return 0; + } + if (!strcasecmp(msg->key,"Cc")) return 2; + if (!strcasecmp(msg->key,"Bcc")) return 0; + if (!strcasecmp(msg->key,"Reply-To")) { + if ((ta = parsefaddr(msg->val))) { + tidy_faddr(ta); + return -1; + } else + return removereplyto ?0:4; + } + if (!strcasecmp(msg->key,"Lines")) return 0; + if (!strcasecmp(msg->key,"Date")) return 0; + if (!strcasecmp(msg->key,"Subject")) { + if ((msg->val) && (strlen(msg->val) > MAXSUBJ)) + return 2; + else + return 0; + } + if (!strcasecmp(msg->key,"Organization")) return 1; + if (!strcasecmp(msg->key,"Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Comment-To")) return 0; + if (!strcasecmp(msg->key,"X-Apparently-To")) return 0; + if (!strcasecmp(msg->key,"Apparently-To")) return 0; + if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) return 0; + if (!strcasecmp(msg->key,"Keywords")) return 2; + if (!strcasecmp(msg->key,"Summary")) return 2; + if (!strcasecmp(msg->key,"MIME-Version")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Type")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Length")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) return removemime ?0:1; + if (!strcasecmp(msg->key,"Content-Name")) return 2; + if (!strcasecmp(msg->key,"Content-Description")) return 2; + if (!strcasecmp(msg->key,"Message-ID")) return removemsgid ?0:1; + if (!strcasecmp(msg->key,"References")) return removeref ?0:1; + if (!strcasecmp(msg->key,"Supersedes")) return removesupersedes ?0:1; + if (!strcasecmp(msg->key,"Distribution")) return ftnorigin ?0:0; + if (!strcasecmp(msg->key,"X-Newsreader")) return 0; + if (!strcasecmp(msg->key,"X-Mailer")) return 0; + if (!strcasecmp(msg->key,"User-Agent")) return 0; + if (!strncasecmp(msg->key,"NNTP-",5)) return 0; + if (!strncasecmp(msg->key,"X-Trace",7)) return 0; + if (!strncasecmp(msg->key,"X-Complaints",12)) return 0; + if (!strncasecmp(msg->key,"X-MSMail",9)) return 0; + if (!strncasecmp(msg->key,"X-MimeOLE",9)) return 0; + if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) return 0; + if (!strcasecmp(msg->key,"X-Origin-Date")) return 0; + if (!strncasecmp(msg->key,"X-PGP-",6)) return 0; + if (!strncasecmp(msg->key,"Resent-",7)) return 0; + if (!strcasecmp(msg->key,"X-Mailing-List")) return 0; + if (!strcasecmp(msg->key,"X-Loop")) return 0; + if (!strcasecmp(msg->key,"Precedence")) return 0; + /*if (!strcasecmp(msg->key,"")) return ;*/ + return 1; +} + + diff --git a/mbfido/scannews.h b/mbfido/scannews.h new file mode 100644 index 00000000..739a8fba --- /dev/null +++ b/mbfido/scannews.h @@ -0,0 +1,39 @@ +#ifndef _SCANNEWS_H +#define _SCANNEWS_H + +#define MAX_MSGID_LEN 196 +#define MAX_GRP_LEN 128 + +/* + * Linked list for list overview.fmt + */ +typedef struct XOVERVIEW { + struct XOVERVIEW *next; + char *header; /* dynamically alloced */ + char *field; + int fieldlen; + int full; +} Overview, *POverview; + + + +/* + * Linked list structure one for each article + */ +typedef struct LinkList { + struct LinkList *next; + char msgid[MAX_MSGID_LEN]; + long nr; + int isdupe; +} List, *PList; + +enum { RETVAL_ERROR = -1, RETVAL_OK = 0, RETVAL_NOARTICLES, RETVAL_UNEXPECTEDANS, RETVAL_VERNR, \ + RETVAL_NOAUTH, RETVAL_EMPTYKILL, RETVAL_NOXOVER }; + + +void ScanNews(void); +int do_article(FILE *); + + +#endif + diff --git a/mbfido/sendmail.c b/mbfido/sendmail.c new file mode 100644 index 00000000..a0ba3008 --- /dev/null +++ b/mbfido/sendmail.c @@ -0,0 +1,149 @@ +/***************************************************************************** + * + * File ..................: tosser/sendmail.c + * Purpose ...............: Output a netmail to one of our links. + * Last modification date : 11-Mar-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbnode.h" +#include "../lib/clcomm.h" +#include "../lib/dbmsgs.h" +#include "addpkt.h" +#include "rollover.h" +#include "sendmail.h" + + + +/* + * Start a netmail to one of our nodes in the setup. + * Return a file descriptor if success else NULL. + * Later the pack routine will add these mails to the outbound. + */ +FILE *SendMgrMail(faddr *t, int Keep, int FileAttach, char *bymgr, char *subj, char *reply) +{ + FILE *qp; + time_t Now; + fidoaddr Orig, Dest; + faddr From; + unsigned flags = M_PVT; + char ext[4]; + + From = *bestaka_s(t); + memset(&Orig, 0, sizeof(Orig)); + Orig.zone = From.zone; + Orig.net = From.net; + Orig.node = From.node; + Orig.point = From.point; + sprintf(Orig.domain, "%s", From.domain); + + memset(&Dest, 0, sizeof(Dest)); + Dest.zone = t->zone; + Dest.net = t->net; + Dest.node = t->node; + Dest.point = t->point; + sprintf(Dest.domain, "%s", t->domain); + + if (!SearchNode(Dest)) { + Syslog('m', "Can't find node %s", aka2str(Dest)); + return NULL; + } + + Syslog('-', " Netmail from %s to %s", aka2str(Orig), ascfnode(t, 0x1f)); + + Now = time(NULL) - (gmt_offset((time_t)0) * 60); + flags |= (nodes.Crash) ? M_CRASH : 0; + flags |= (FileAttach) ? M_FILE : 0; + flags |= (!Keep) ? M_KILLSENT : 0; + flags |= (nodes.Hold) ? M_HOLD : 0; + + /* + * Increase counters, update record and reload. + */ + StatAdd(&nodes.MailSent, 1L); + UpdateNode(); + SearchNode(Dest); + + memset(&ext, 0, sizeof(ext)); + if (nodes.PackNetmail) + sprintf(ext, (char *)"qqq"); + else if (nodes.Crash) + sprintf(ext, (char *)"ccc"); + else if (nodes.Hold) + sprintf(ext, (char *)"hhh"); + else + sprintf(ext, (char *)"nnn"); + + if ((qp = OpenPkt(Orig, Dest, (char *)ext)) == NULL) + return NULL; + + if (AddMsgHdr(qp, &From, t, flags, 0, Now, nodes.Sysop, tlcap(bymgr), subj)) { + fclose(qp); + return NULL; + } + + if (Dest.point) + fprintf(qp, "\001TOPT %d\r", Dest.point); + if (Orig.point) + fprintf(qp, "\001FMPT %d\r", Orig.point); + + fprintf(qp, "\001INTL %d:%d/%d %d:%d/%d\r", Dest.zone, Dest.net, Dest.node, Orig.zone, Orig.net, Orig.node); + + /* + * Add MSGID, REPLY and PID + */ + fprintf(qp, "\001MSGID: %s %08lx\r", aka2str(Orig), sequencer()); + if (reply != NULL) + fprintf(qp, "\001REPLY: %s\r", reply); + fprintf(qp, "\001PID: MBSE-FIDO %s\r", VERSION); + fprintf(qp, "\001TZUTC: %s\r", gmtoffset(Now)); + return qp; +} + + + +void CloseMail(FILE *qp, faddr *t) +{ + time_t Now; + struct tm *tm; + + putc('\r', qp); + Now = time(NULL); + tm = gmtime(&Now); + fprintf(qp, "\001Via %s @%d%02d%02d.%02d%02d%02d.02.UTC %s\r", + ascfnode(bestaka_s(t), 0x1f), tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec, VERSION); + + putc(0, qp); + fclose(qp); +} + + + diff --git a/mbfido/sendmail.h b/mbfido/sendmail.h new file mode 100644 index 00000000..16d2e401 --- /dev/null +++ b/mbfido/sendmail.h @@ -0,0 +1,10 @@ +#ifndef _SENDMAIL_H +#define _SENDMAIL_H + + +FILE *SendMgrMail(faddr *, int, int, char *, char *, char *); +void CloseMail(FILE *, faddr*); + + +#endif + diff --git a/mbfido/tic.c b/mbfido/tic.c new file mode 100644 index 00000000..422e70e8 --- /dev/null +++ b/mbfido/tic.c @@ -0,0 +1,451 @@ +/***************************************************************************** + * + * File ..................: mbfido/tic.c + * Purpose ...............: Process .tic files + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbftn.h" +#include "../lib/clcomm.h" +#include "ulock.h" +#include "ptic.h" +#include "fsort.h" +#include "pack.h" +#include "tic.h" + +#define UNPACK_FACTOR 300 + +int tic_in = 0; /* .tic files received */ +int tic_imp = 0; /* imported .tic files */ +int tic_out = 0; /* .tic files sent */ +int tic_bad = 0; /* bad .tic files */ +int tic_dup = 0; /* dupe .tic files */ + + +extern int do_unprot; +extern int do_quiet; +extern int tic_in; + + +/* + * returns: -1 = Errors. + * 0 = No files processed + * 1 = Processed file(s) + */ +int Tic() +{ + char *inbound, *fname; + DIR *dp; + struct dirent *de; + struct stat sbuf; + int i, rc = 0; + fd_list *fdl = NULL; + + IsDoing("Process .tic files"); + CompileNL = FALSE; + + if (do_unprot) { + inbound = xstrcpy(CFG.inbound); + } else { + inbound = xstrcpy(CFG.pinbound); + } + Syslog('+', "Pass: process ticfiles (%s)", inbound); + + if (!diskfree(CFG.freespace)) { + free(inbound); + return -1; + } + + if (chdir(inbound) == -1) { + WriteError("$Can't chdir(%s)", inbound); + free(inbound); + return -1; + } + + if ((dp = opendir(inbound)) == NULL) { + WriteError("$Can't opendir(%s)", inbound); + free(inbound); + return -1; + } + + while ((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && + (strncasecmp(de->d_name+11, "c", 1) == 0)) { + if ((strncasecmp(de->d_name+8, ".a", 2) == 0) || + (strncasecmp(de->d_name+8, ".c", 2) == 0) || + (strncasecmp(de->d_name+8, ".z", 2) == 0) || + (strncasecmp(de->d_name+8, ".l", 2) == 0) || + (strncasecmp(de->d_name+8, ".r", 2) == 0) || + (strncasecmp(de->d_name+8, ".0", 2) == 0)) { + if (checkspace(inbound, de->d_name, UNPACK_FACTOR)) { + if ((unpack(de->d_name)) != 0) { + WriteError("Error unpacking %s", de->d_name); + } + } else + Syslog('+', "Insufficient space to unpack file %s", de->d_name); + } + } + + rewinddir(dp); + while ((de = readdir(dp))) + if ((strlen(de->d_name) == 12) && (strncasecmp(de->d_name+8, ".tic", 4) == 0)) { + stat(de->d_name, &sbuf); + fill_fdlist(&fdl, de->d_name, sbuf.st_mtime); + } + + closedir(dp); + sort_fdlist(&fdl); + + while ((fname = pull_fdlist(&fdl)) != NULL) { + if (LoadTic(inbound, fname) == 0) + rc = 1; + if (IsSema((char *)"upsalarm")) { + rc = 0; + Syslog('+', "Detected upsalarm semafore, aborting tic processing"); + break; + } + if (!diskfree(CFG.freespace)) { + rc = 0; + break; + } + } + + if (!do_quiet) { + printf("\r"); + for (i = 0; i < 79; i++) + printf(" "); + printf("\r"); + fflush(stdout); + } + + if (rc) + packmail(); + + if (CompileNL) + CreateSema((char *)"mbindex"); + + free(inbound); + return rc; +} + + + +/* + * Returns 1 if error, 0 if ok. + */ +int LoadTic(char *inb, char *tfn) +{ + FILE *tfp; + char *Temp, *Buf, *Log = NULL, *Realname; + int i, j, rc; + fa_list *sbl = NULL; + int Kwd, DescCnt = FALSE; + + if (CFG.slow_util && do_quiet) + usleep(1); + + memset(&TIC, 0, sizeof(TIC)); + memset(&T_File, 0, sizeof(T_File)); + + sprintf(TIC.Inbound, "%s/", inb); + sprintf(TIC.FilePath, "%s/", inb); + strcpy(TIC.TicName, tfn); + + chdir(inb); + if ((tfp = fopen(tfn, "r")) == NULL) { + WriteError("$Cannot open %s", tfn); + return 1; + } + + Temp = calloc(256, sizeof(char)); + Buf = calloc(256, sizeof(char)); + Realname = calloc(PATH_MAX, sizeof(char)); + + while ((fgets(Buf, 256, tfp)) != NULL) { + + /* + * Remove all garbage from the .TIC file. + */ + Temp[0] = '\0'; + j = 0; + for (i = 0; i < strlen(Buf); i++) + if ((Buf[i] >= ' ') || (Buf[i] < 0)) { + Temp[j] = Buf[i]; + j++; + } + Temp[j] = '\0'; + + Kwd = FALSE; + + if (strncasecmp(Temp, "hatch", 5) == 0) + Kwd = TIC.Hatch = TRUE; + + if (TIC.Hatch) { + if (strncasecmp(Temp, "pth ", 4) == 0) { + sprintf(TIC.FilePath, "%s/", Temp+4); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "nomove", 6) == 0) + Kwd = TIC.NoMove = TRUE; + + if (strncasecmp(Temp, "hatchnew", 8) == 0) + Kwd = TIC.HatchNew = TRUE; + } + + if (strncasecmp(Temp, "area ", 5) == 0) { + strcpy(TIC.TicIn.Area, Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "origin ", 7) == 0) { + strcpy(TIC.TicIn.Origin, Temp+7); + strcpy(T_File.Origin, Temp+7); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "from ", 5) == 0) { + strcpy(TIC.TicIn.From, Temp+5); + strcpy(T_File.From, Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "file ", 5) == 0) { + if (TIC.Hatch) + strcpy(TIC.TicIn.OrgName, Temp+5); + else + strcpy(TIC.TicIn.OrgName, tl(Temp+5)); + sprintf(Realname, "%s", Temp+5); + strcpy(TIC.NewName, TIC.TicIn.OrgName); + strcpy(T_File.Name, TIC.TicIn.OrgName); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "fullname", 8) == 0) { + strcpy(TIC.TicIn.LName, Temp+8); + Syslog('f', "Long filename: %s", TIC.TicIn.LName); + } + + if (strncasecmp(Temp, "created ", 8) == 0) { + strcpy(TIC.TicIn.Created, Temp+8); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "magic ", 6) == 0) { + strcpy(TIC.TicIn.Magic, Temp+6); + strcpy(T_File.Magic, Temp+6); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "crc ", 4) == 0) { + TIC.Crc_Int = strtoul(Temp+4, (char **)NULL, 16); + sprintf(TIC.TicIn.Crc, "%08lX", TIC.Crc_Int); + strcpy(T_File.Crc, TIC.TicIn.Crc); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "pw ", 3) == 0) { + strcpy(TIC.TicIn.Pw, Temp+3); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "replaces ", 9) == 0) { + strcpy(TIC.TicIn.Replace, Temp+9); + strcpy(T_File.Replace, Temp+9); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "desc ", 5) == 0) { + if (!DescCnt) { + strcpy(TIC.TicIn.Desc, Temp+5); + strcpy(T_File.Desc, TIC.TicIn.Desc); + Kwd = TRUE; + DescCnt = TRUE; + } else { + Syslog('!', "More than one \"Desc\" line"); + } + } + + if (strncasecmp(Temp, "path ", 5) == 0) { + strcpy(TIC.TicIn.Path[TIC.TicIn.TotPath], Temp+5); + TIC.TicIn.TotPath++; + TIC.Aka.zone = atoi(strtok(Temp+5, ":")); + TIC.Aka.net = atoi(strtok(NULL, "/")); + TIC.Aka.node = atoi(strtok(NULL, "\0")); + for (i = 0; i < 40; i++) + if ((CFG.akavalid[i]) && + (CFG.aka[i].zone == TIC.Aka.zone) && + (CFG.aka[i].net == TIC.Aka.net) && + (CFG.aka[i].node == TIC.Aka.node) && + (!CFG.aka[i].point)) + TIC.PathErr = TRUE; + Kwd = TRUE; + } + + if (strncasecmp(Temp, "seenby ", 7) == 0) { + fill_list(&sbl, Temp+7, NULL, FALSE); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "areadesc ", 9) == 0) { + strcpy(TIC.TicIn.AreaDesc, Temp+9); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "to ", 3) == 0) { + /* + * Drop this one + */ + Kwd = TRUE; + } + + if (strncasecmp(Temp, "size ", 5) == 0) { + TIC.TicIn.Size = atoi(Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "date ", 5) == 0) { + Syslog('f', "Date: %s", Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "cost ", 5) == 0) { + TIC.TicIn.UplinkCost = atoi(Temp+5); + Kwd = TRUE; + } + + if (strncasecmp(Temp, "ldesc ", 6) == 0) { + if (TIC.TicIn.TotLDesc < 25) { + Temp[86] = '\0'; + strcpy(TIC.TicIn.LDesc[TIC.TicIn.TotLDesc], Temp+6); + TIC.TicIn.TotLDesc++; + } + Kwd = TRUE; + } + + /* + * If we didn't find a matching keyword it is a line we + * will just remember and forward if there are downlinks. + */ + if (!Kwd) { + /* + * Consider Destination keyword not as a passthru + * line and drop it. + */ + if (strncasecmp(Temp, "destination ", 12) != 0) { + if (TIC.TicIn.Unknowns < 25) { + strcpy(TIC.TicIn.Unknown[TIC.TicIn.Unknowns], Temp); + TIC.TicIn.Unknowns++; + } + } + } + } + + fclose(tfp); + + if (TIC.TicIn.TotLDesc) { + /* + * First check for a bug in Harald Harms Allfix program that + * lets Allfix forward dummy Ldesc lines with the contents: + * "Long description not available" + */ + if (strstr(TIC.TicIn.LDesc[0], "ion not avail") != NULL) { + Syslog('!', "Killing invalid Ldesc line(s)"); + TIC.TicIn.TotLDesc = 0; + } + } + if (TIC.TicIn.TotLDesc) { + T_File.TotLdesc = TIC.TicIn.TotLDesc; + for (i = 0; i <= TIC.TicIn.TotLDesc; i++) + strcpy(T_File.LDesc[i], TIC.TicIn.LDesc[i]); + } + + /* + * Show on screen what we are doing + */ + if (!do_quiet) { + colour(3, 0); + printf("\r"); + for (i = 0; i < 79; i++) + printf(" "); + printf("\rTic: %12s File: %-14s Area: %-12s ", TIC.TicName, TIC.TicIn.OrgName, TIC.TicIn.Area); + fflush(stdout); + } + + /* + * Show in logfile what we are doing + */ + Syslog('+', "Processing %s, %s area %s from %s", TIC.TicName, TIC.TicIn.OrgName, TIC.TicIn.Area, TIC.TicIn.From); + Syslog('+', "+- %s", TIC.TicIn.Created); + Log = NULL; + + if (strlen(TIC.TicIn.Replace)) { + Log = xstrcpy((char *)"Replace "); + Log = xstrcat(Log, TIC.TicIn.Replace); + } + if (strlen(TIC.TicIn.Magic)) { + if (Log != NULL) + Log = xstrcat(Log, (char *)", Magic "); + else + Log = xstrcpy((char *)"Magic "); + Log = xstrcat(Log, TIC.TicIn.Magic); + } + if (Log != NULL) { + Syslog('+', "%s", Log); + free(Log); + Log = NULL; + } + + sprintf(Temp, "%s", TIC.TicIn.From); + TIC.Aka.zone = atoi(strtok(Temp, ":")); + TIC.Aka.net = atoi(strtok(NULL, "/")); + TIC.Aka.node = atoi(strtok(NULL, "@\0")); + if (SearchFidonet(TIC.Aka.zone)) + strcpy(TIC.Aka.domain, fidonet.domain); + sprintf(Temp, "%s", TIC.TicIn.Origin); + TIC.OrgAka.zone = atoi(strtok(Temp, ":")); + TIC.OrgAka.net = atoi(strtok(NULL, "/")); + TIC.OrgAka.node = atoi(strtok(NULL, "@\0")); + if (SearchFidonet(TIC.OrgAka.zone)) + strcpy(TIC.OrgAka.domain, fidonet.domain); + free(Temp); + free(Buf); + + tic_in++; + rc = ProcessTic(sbl, Realname); + tidy_falist(&sbl); + free(Realname); + + return rc; +} + + + diff --git a/mbfido/tic.h b/mbfido/tic.h new file mode 100644 index 00000000..1b943a20 --- /dev/null +++ b/mbfido/tic.h @@ -0,0 +1,72 @@ +#ifndef _TIC_H +#define _TIC_H + + +typedef struct _tic_in { + char Area[21]; /* Area name */ + char Origin[81]; /* Origin address */ + char From[81]; /* From name */ + char OrgName[81]; /* Original filename */ + char LName[81]; /* Long filename */ + char Replace[81]; /* File to replace */ + char Created[81]; /* Created text */ + char Path[25][81]; /* Travelled path */ + int TotPath; /* Nr of pathlines */ + char Desc[256]; /* Short description */ + char Magic[21]; /* Magic alias */ + char Crc[9]; /* CRC of file */ + char Pw[21]; /* Password */ + char AreaDesc[61]; /* Area description */ + char Date[61]; /* Date field */ + long UplinkCost; /* Uplink cost */ + off_t Size; /* Size of file */ + char LDesc[25][81]; /* Long description */ + int TotLDesc; /* Total lines */ + char Unknown[25][128]; /* Unknown (passthru) lines */ + int Unknowns; /* Total of above */ + int MultiSeen; /* Multi Seenby Lines */ +} Tic_in; + + +typedef struct _TICrec { + char Inbound[PATH_MAX]; /* Inbound directory */ + char TicName[13]; /* Name of .TIC file */ + Tic_in TicIn; /* Original TIC record */ + fidoaddr OrgAka; /* Origin address */ + fidoaddr Aka; /* An address ? */ + char NewName[81]; /* New name of file */ + char File_Id[25][49]; /* Description */ + int File_Id_Ct; /* Nr of lines */ + unsigned long Crc_Int; /* Crc value */ + int KeepNum; /* Keep number of files */ + off_t FileSize; /* Size of file */ + time_t FileDate; /* Date of file */ + time_t UpLoadDate; /* Upload date of file */ + char FilePath[PATH_MAX]; /* Path to the file */ + unsigned PathErr : 1; /* If path error */ + unsigned OtherPath : 1; /* If otherpath is true */ + unsigned Hatch : 1; /* If internal hatched */ + unsigned NoMove : 1; /* No move magic */ + unsigned HatchNew : 1; /* Hatch in new areas */ + unsigned SendOrg : 1; /* Send original file */ + unsigned Charge : 1; /* Charge for this file */ + unsigned PassThru : 1; /* PassThru file */ + unsigned NewAlias : 1; /* New alias is set */ + long FileCost; /* Cost for this file */ + char BBSpath[PATH_MAX]; /* Path to import in */ + char BBSdesc[55]; /* Area description */ +} TICrec; + + +TICrec TIC; /* Global .tic record */ +struct _filerecord T_File; /* Global file handling rec.*/ + +int CompileNL; + + +int Tic(void); +int LoadTic(char *, char *); + + +#endif + diff --git a/mbfido/toberep.c b/mbfido/toberep.c new file mode 100644 index 00000000..6b4fd33f --- /dev/null +++ b/mbfido/toberep.c @@ -0,0 +1,79 @@ +/***************************************************************************** + * + * File ..................: mbfido/toberep.c + * Purpose ...............: Add a file to the To-Be-Reported database + * Last modification date : 19-Mar-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" + + +#include "toberep.h" + + +/* + * Add a file whos data is in T_File to the toberep.data file. + * The newfiles announce option will later remove these records. + */ +void Add_ToBeRep() +{ + char fname[128]; + struct _filerecord Temp; + FILE *tbr; + int Found = FALSE; + + sprintf(fname, "%s/etc/toberep.data", getenv("MBSE_ROOT")); + if ((tbr = fopen(fname, "a+")) == NULL) { + WriteError("$Can't create %s", fname); + return; + } + + fseek(tbr, 0, SEEK_SET); + while (fread(&Temp, sizeof(Temp), 1, tbr) == 1) { + if ((strcmp(Temp.Name, T_File.Name) == 0) && + (Temp.Fdate == T_File.Fdate) && + (strcmp(Temp.Echo, T_File.Echo) == 0)) + Found = TRUE; + } + + if (Found) { + Syslog('!', "File %s already in toberep.data", T_File.Name); + fclose(tbr); + return; + } + + fwrite(&T_File, sizeof(T_File), 1, tbr); + fclose(tbr); +} + + + diff --git a/mbfido/toberep.h b/mbfido/toberep.h new file mode 100644 index 00000000..e5f3cac7 --- /dev/null +++ b/mbfido/toberep.h @@ -0,0 +1,9 @@ +#ifndef _TOBEREP_H +#define _TOBEREP_H + + +void Add_ToBeRep(void); + + +#endif + diff --git a/mbfido/tosspkt.c b/mbfido/tosspkt.c new file mode 100644 index 00000000..ef9c36b6 --- /dev/null +++ b/mbfido/tosspkt.c @@ -0,0 +1,400 @@ +/***************************************************************************** + * + * File ..................: tosser/tosspkt.c + * Purpose ...............: Toss a single *.pkt file + * Last modification date : 03-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "importmsg.h" +#include "tosspkt.h" + + + +/* + * External declarations + */ +extern int do_quiet; + + + +/* + * Global variables + */ +int net_in = 0; /* Netmails received */ +int net_imp = 0; /* Netmails imported */ +int net_out = 0; /* Netmails forwarded */ +int net_bad = 0; /* Bad netmails (tracking errors */ +int echo_in = 0; /* Echomail received */ +int echo_imp = 0; /* Echomail imported */ +int echo_out = 0; /* Echomail forwarded */ +int echo_bad = 0; /* Bad echomail */ +int echo_dupe = 0; /* Dupe echomail */ +int news_in = 0; /* News received */ +int news_imp = 0; /* News imported */ +int news_out = 0; /* News posted */ +int news_bad = 0; /* Bad news */ +int news_dupe = 0; /* Dupe articles */ +int email_in = 0; /* Email received */ +int email_imp = 0; /* Email imported */ +int email_out = 0; /* Email forwarded */ +int email_bad = 0; /* Bad email */ +char *toname = NULL; /* To user */ +char *fromname = NULL; /* From user */ +char *subj = NULL; /* Message subject */ +extern char *msgid; + + +static int at_zero = 0; + +char *aread(char *, int, FILE *); +char *aread(char *s, int count, FILE *fp) +{ + int i,c,next; + + if (feof(fp)) + return(NULL); + if (s == NULL) + return NULL; + if (at_zero) + { + at_zero=0; + return NULL; + } + + for (i = 0,next = 1; (i < count-1) && next;) + switch (c=getc(fp)) { + case '\n': break; + + case '\r': s[i]='\n'; + i++; + next=0; + break; + + case 0x8d: s[i]=' '; + i++; + break; + + case '\0': at_zero=1; + next=0; + break; + + default: s[i]=c; + i++; + break; + } + s[i]='\0'; + return s; +} + + + +/* + * Toss one packet. + * + * 0 - + * 1 - Cannot open packet + * 2 - Bad packet header + * 3 - Packet is not for us + * 4 - Bad password + */ +int TossPkt(char *fn) +{ + int rc, count = 0; + static int maxrc = 0; + static faddr from, to; + FILE *pkt; + + if (!do_quiet) { + colour(10, 0); + printf("Tossing packet %s\n", fn); + } + + if ((pkt = fopen(fn, "r")) == 0) { + WriteError("$Cannot open %s", fn); + return 1; + } + + memset(&from, 0, sizeof(faddr)); + memset(&to, 0, sizeof(faddr)); + + if (((rc = getheader(&from, &to, pkt, fn)) != 0)) { + WriteError("%s, aborting", + (rc == 1)?"wrong header type": + (rc == 2)?"bad packet header": + (rc == 3)?"packet is not for us": + (rc == 4)?"bad password": + "bad packet"); + return(rc); + } + + while ((rc = getmessage(pkt, &from, &to)) == 1) { + count++; + } + Syslog('+', "Messages : %d", count); + + maxrc = rc; + if (!do_quiet) + printf("\r \r"); + + if (rc) + Syslog('+', "End, rc=%d", maxrc); + + fclose(pkt); + return maxrc; +} + + + +/* + * Process one message from message packet. + * + * 0 - no more messages + * 1 - more messages + * 2 - bad file + * 3 - bad message header + * 4 - unable to open temp file + * 5 - unexpected end of packet + * >10 - import error + */ +int getmessage(FILE *pkt, faddr *p_from, faddr *p_to) +{ + char buf[2048]; + char *orig = NULL; + char *p, *l, *r; + int tmp, rc, maxrc = 0; + static faddr f, t; + faddr *o; + int result, flags, cost; + time_t mdate = 0L; + FILE *fp; + unsigned char buffer[0x0e]; + off_t orig_off; + + subj = NULL; + toname = NULL; + fromname = NULL; + result = fread(&buffer, 1, sizeof(buffer), pkt); + if (result == 0) { + Syslog('m', "Zero bytes message, assume end of pkt"); + return 0; + } + + switch(tmp = (buffer[0x01] << 8) + buffer[0x00]) { + case 0: + if (result == 2) + return 0; + else { + Syslog('!', "Junk after logical end of packet, skipped"); + return 5; + + } + case 2: + break; + + default: + Syslog('!', "bad message type: 0x%04x",tmp); + return 2; + } + + if (result != 14) { + Syslog('!', "Unexpected end of packet"); + return 5; + } + + memset(&f, 0, sizeof(f)); + memset(&t, 0, sizeof(t)); + f.node = (buffer[0x03] << 8) + buffer[0x02]; + t.node = (buffer[0x05] << 8) + buffer[0x04]; + f.net = (buffer[0x07] << 8) + buffer[0x06]; + t.net = (buffer[0x09] << 8) + buffer[0x08]; + flags = (buffer[0x0b] << 8) + buffer[0x0a]; + cost = (buffer[0x0d] << 8) + buffer[0x0c]; + + /* + * Read the DateTime, toUserName, fromUserName and subject fields + * from the packed message. The stringlength is +1 for the right + * check. This is different then in ifmail's original code. + */ + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 20) + Syslog('!', "date too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + mdate = parsefdate(buf, NULL); + if (aread(buf, sizeof(buf)-1, pkt)) { + Syslog('!', "date not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 36) + Syslog('!', "to name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + t.name = xstrcpy(buf); + toname = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=t.name+strlen(t.name)-1) == '\n') + *p = '\0'; + Syslog('!', "to name not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 36) + Syslog('!', "from name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + f.name = xstrcpy(buf); + fromname = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=f.name+strlen(f.name)-1) == '\n') + *p = '\0'; + Syslog('!', "from name not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (aread(buf, sizeof(buf)-1, pkt)) { + if (strlen(buf) > 72) + Syslog('!', "subject too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); + subj = xstrcpy(buf); + if (aread(buf, sizeof(buf)-1, pkt)) { + if (*(p=subj+strlen(subj)-1) == '\n') + *p = '\0'; + subj = xstrcat(subj,(char *)"\\n"); + subj = xstrcat(subj,buf); + Syslog('!', "subj not null-terminated: \"%s\"",buf); + return 3; + } + } + + if (feof(pkt) || ferror(pkt)) { + Syslog('!', "Could not read message header, aborting"); + return 3; + } + + f.zone = p_from->zone; + t.zone = p_to->zone; + + if ((fp = tmpfile()) == NULL) { + WriteError("$unable to open temporary file"); + return 4; + } + orig_off = 0L; + + /* + * Read the text from the .pkt file + */ + while (aread(buf,sizeof(buf)-1,pkt)) { + + fputs(buf, fp); + + /* + * Extract info from Origin line if found. + */ + if (!strncmp(buf," * Origin:",10)) { + orig_off = ftell(fp); + p=buf+10; + while (*p == ' ') p++; + if ((l=strrchr(p,'(')) && (r=strrchr(p,')')) && (l < r)) { + *l = '\0'; + *r = '\0'; + l++; + if ((o = parsefnode(l))) { + f.point = o->point; + f.node = o->node; + f.net = o->net; + f.zone = o->zone; + if (o->domain) + f.domain=o->domain; + o->domain=NULL; + tidy_faddr(o); + } + } else + if (*(l=p+strlen(p)-1) == '\n') + *l='\0'; + for (l=p+strlen(p)-1;*l == ' ';l--) + *l='\0'; + orig = xstrcpy(p); + } + } + + rc = importmsg(p_from, &f,&t,orig,mdate,flags,cost,fp,orig_off); + if (rc) + rc+=10; + if (rc > maxrc) + maxrc = rc; + + fclose(fp); + + if(f.name) + free(f.name); + f.name=NULL; + + if(t.name) + free(t.name); + t.name=NULL; + + if(f.domain) + free(f.domain); + f.domain=NULL; + + if(t.domain) + free(t.domain); + t.domain=NULL; + + if (fromname) + free(fromname); + fromname = NULL; + + if (toname) + free(toname); + toname = NULL; + + if (subj) + free(subj); + subj = NULL; + + if (orig) + free(orig); + orig = NULL; + + if (msgid) + free(msgid); + msgid = NULL; + + if (feof(pkt) || ferror(pkt)) { + WriteError("Unexpected end of packet"); + return 5; + } + return 1; +} + + diff --git a/mbfido/tosspkt.h b/mbfido/tosspkt.h new file mode 100644 index 00000000..bd59ef48 --- /dev/null +++ b/mbfido/tosspkt.h @@ -0,0 +1,9 @@ +#ifndef _TOSSPKT_H +#define _TOSSPKT_H + + +int TossPkt(char *); +int getmessage(FILE *, faddr *, faddr *); + +#endif + diff --git a/mbfido/tracker.c b/mbfido/tracker.c new file mode 100644 index 00000000..d64cace1 --- /dev/null +++ b/mbfido/tracker.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: tosser/tracker.c + * Purpose ...............: Netmail tracker / router + * Last modification date : 12-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbnode.h" +#include "../lib/dbftn.h" +#include "tracker.h" + + +extern char nodes_fil[81]; +extern long nodes_pos; + +/* + * Netmail tracker. Return TRUE if we found a valid route. + * If we did find a route, it is returned in the route pointer. + * If not, return FALSE. The calling program must bounce the + * original message. + */ +int TrackMail(fidoaddr too, fidoaddr *route) +{ + int rc, i; + + Syslog('r', "Tracking destination %s", aka2str(too)); + + rc = GetRoute(aka2str(too) , route); + if (rc == R_NOROUTE) { + WriteError("No route to %s, not parsed", aka2str(too)); + return R_NOROUTE; + } + if (rc == R_UNLISTED) { + WriteError("No route to %s, unlisted node", aka2str(too)); + return R_UNLISTED; + } + + /* + * If local aka + */ + if (rc == R_LOCAL) + return R_LOCAL; + + /* + * Now look again if from the routing result we find a + * direct link. If so, maybe adjust something. + */ + if (SearchNode(*route)) { + Syslog('r', "Known node: %s", aka2str(nodes.Aka[0])); + Syslog('r', "Check \"too\" %s", aka2str(too)); + + if (nodes.RouteVia.zone) { + route->zone = nodes.RouteVia.zone; + route->net = nodes.RouteVia.net; + route->node = nodes.RouteVia.node; + route->point = nodes.RouteVia.point; + sprintf(route->domain, "%s", nodes.RouteVia.domain); + return R_ROUTE; + } else { + for (i = 0; i < 20; i++) + if (route->zone == nodes.Aka[i].zone) + break; + route->zone = nodes.Aka[i].zone; + route->net = nodes.Aka[i].net; + route->node = nodes.Aka[i].node; + route->point = nodes.Aka[i].point; + sprintf(route->domain, "%s", nodes.Aka[i].domain); + return R_ROUTE; + } + } + + return rc; +} + + + +int AreWeHost(faddr *); +int AreWeHost(faddr *dest) +{ + int i, j; + + /* + * First a fast run in our own zone. + */ + for (i = 0; i < 40; i++) + if (CFG.akavalid[i] && (CFG.aka[i].zone == dest->zone)) + if (CFG.aka[i].node == 0) + return i; + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (SearchFidonet(dest->zone)) + for (j = 0; j < 6; j++) + if (CFG.aka[i].zone == fidonet.zone[j]) + if (CFG.aka[i].node == 0) + return i; + + return -1; +} + + + +int AreWeHub(faddr *); +int AreWeHub(faddr *dest) +{ + int i, j; + node *nl; + faddr *fido; + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (CFG.aka[i].zone == dest->zone) { + fido = fido2faddr(CFG.aka[i]); + nl = getnlent(fido); + tidy_faddr(fido); + if (nl->addr.domain) + free(nl->addr.domain); + if (nl->type == NL_HUB) + return i; + } + + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + if (SearchFidonet(dest->zone)) + for (j = 0; j < 6; j++) + if (CFG.aka[i].zone == fidonet.zone[j]) { + fido = fido2faddr(CFG.aka[i]); + nl = getnlent(fido); + tidy_faddr(fido); + if (nl->addr.domain) + free(nl->addr.domain); + if (nl->type == NL_HUB) + return i; + } + + return -1; +} + + + +/* + * Get routing information for specified netmail address. + */ +int GetRoute(char *ftn, fidoaddr *res) +{ + node *dnlent, *bnlent; + unsigned short myregion; + faddr *dest, *best, *maddr; + fidoaddr *fido; + int me_host = -1, me_hub = -1; + int i; + fidoaddr dir; + FILE *fil; + + memset(res, 0, sizeof(fidoaddr)); + dest = parsefnode(ftn); + if (SearchFidonet(dest->zone)) { + if (dest->domain) + free(dest->domain); + dest->domain = xstrcpy(fidonet.domain); + } + best = bestaka_s(dest); + Syslog('r', "Get route for: %s", ascfnode(dest, 0xff)); + + /* + * Check if the destination is ourself. + */ + for (i = 0; i < 40; i++) { + if (CFG.akavalid[i] && (CFG.aka[i].zone == dest->zone) && + (CFG.aka[i].net == dest->net) && (CFG.aka[i].node == dest->node)) { + if (dest->point == CFG.aka[i].point) { + Syslog('+', "R: %s => Loc %s", ascfnode(dest, 0x0f), aka2str(CFG.aka[i])); + memcpy(res, &CFG.aka[i], sizeof(fidoaddr)); + tidy_faddr(best); + tidy_faddr(dest); + return R_LOCAL; + } + if (dest->point && (!CFG.aka[i].point)) { + Syslog('+', "R: %s => My point", ascfnode(dest, 0xff)); + fido = faddr2fido(dest); + memcpy(res, fido, sizeof(fidoaddr)); + free(fido); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + if (best->point) { + /* + * We are a point, so don't bother the rest of the tests, route + * to our boss. + */ + res->zone = best->zone; + res->net = best->net; + res->node = best->node; + res->point = 0; + Syslog('+', "R: %s => My boss %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + + /* + * Now test several possible setup matches. + */ + dir.zone = dest->zone; + dir.net = dest->net; + dir.node = dest->node; + dir.point = dest->point; + sprintf(dir.domain, "%s", dest->domain); + + /* + * First direct match + */ + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net) && + (dir.point == nodes.Aka[i].point)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + /* + * Again, but now for points + */ + dir.point = 0; + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + res->point = 0; + Syslog('+', "R: %s => Boss link %s", ascfnode(dest, 0x0f), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + + /* + * Check if we know the uplink, but first check if the node is listed. + */ + dnlent = (node *)malloc(sizeof(node)); + memcpy(dnlent, getnlent(dest), sizeof(node)); + if (dnlent->addr.domain) + free(dnlent->addr.domain); + + if (!(dnlent->pflag & NL_DUMMY)) { + dir.node = dnlent->upnode; + dir.net = dnlent->upnet; + if (SearchNode(dir)) { + for (i = 0; i < 20; i++) { + if ((dir.zone == nodes.Aka[i].zone) && + (dir.node == nodes.Aka[i].node) && + (dir.net == nodes.Aka[i].net)) { + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + res->point = 0; + Syslog('+', "R: %s => Uplink %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + } + + /* + * We don't know the route from direct links. We will first see + * what we are, host, hub or node. + */ + me_host = AreWeHost(dest); + if (me_host == -1) + me_hub = AreWeHub(dest); + bnlent = getnlent(best); + myregion = bnlent->region; + + /* + * This is default routing for hosts: + * 1. Out of zone and region mail goes to the myzone:myregion/0 + * 2. Out of net mail goes to host myzone:destnet/0 + * 3. Nodes without hub are my downlinks, no route. + * 4. The rest goes to the hubs. + */ + if (me_host != -1) { + sprintf(res->domain, "%s", CFG.aka[me_host].domain); + if (((myregion != dnlent->region) && (!(dnlent->pflag & NL_DUMMY))) || + (CFG.aka[me_host].zone != dest->zone)) { + res->zone = CFG.aka[me_host].zone; + res->net = myregion; + Syslog('+', "R: %s => Region %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + if (CFG.aka[me_host].net != dest->net) { + res->zone = dest->zone; + res->net = dest->net; + Syslog('+', "R: %s => Host %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + if (dnlent->upnode == 0) { + res->zone = dest->zone; + res->net = dest->net; + res->node = dest->node; + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + res->zone = CFG.aka[me_host].zone; + res->net = dnlent->upnet; + res->node = dnlent->upnode; + Syslog('+', "R: %s => Hub %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + + /* + * This is the default routing for hubs. + * 1. If the nodes hub is our own hub, it's a downlink. + * 2. Kick everything else to the host. + */ + if (me_hub != -1) { + sprintf(res->domain, "%s", CFG.aka[me_hub].domain); + if ((dnlent->upnode == CFG.aka[me_hub].node) && + (dnlent->upnet == CFG.aka[me_hub].net) && + (dnlent->addr.zone == CFG.aka[me_hub].zone)) { + res->zone = dest->zone; + res->net = dest->net; + res->node = dest->node; + res->point = dest->point; + Syslog('+', "R: %s => Dir link %s", ascfnode(dest, 0x0f), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } else { + res->zone = CFG.aka[me_hub].zone; + res->net = CFG.aka[me_hub].net; + Syslog('+', "R: %s => My host %s", ascfnode(dest, 0xff), aka2str(*res)); + free(dnlent); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + } + free(dnlent); + + /* + * Routing for normal nodes, everything goes to the hub or host. + */ + if ((me_hub == -1) && (me_host == -1)) { + if (bnlent->pflag != NL_DUMMY) { + res->zone = bnlent->addr.zone; + res->net = bnlent->upnet; + res->node = bnlent->upnode; + sprintf(res->domain, "%s", bnlent->addr.domain); + Syslog('+', "R: %s => %s", ascfnode(dest, 0xff), aka2str(*res)); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + tidy_faddr(best); + tidy_faddr(dest); + return R_ROUTE; + } + + if (bnlent->addr.domain) + free(bnlent->addr.domain); + + /* + * If the above failed, we are probably a new node without + * a nodelist entry. We will switch to plan B. + */ + if ((fil = fopen(nodes_fil, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + nodes_pos = -1; + while (fread(&nodes, nodeshdr.recsize, 1, fil) == 1) { + fseek(fil, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + for (i = 0; i < 20; i++) { + if ((nodes.Aka[i].zone) && + (nodes.Aka[i].zone == best->zone) && + (nodes.Aka[i].net == best->net)) { + maddr = fido2faddr(nodes.Aka[i]); + bnlent = getnlent(maddr); + tidy_faddr(maddr); + if (bnlent->addr.domain) + free(bnlent->addr.domain); + if ((bnlent->type == NL_HUB) || + (bnlent->type == NL_HOST)) { + fclose(fil); + memcpy(res, &nodes.Aka[i], sizeof(fidoaddr)); + Syslog('r', "R: %s => %s", ascfnode(dest, 0xff), aka2str(*res)); + tidy_faddr(best); + tidy_faddr(dest); + return R_DIRECT; + } + } + } + } + fclose(fil); + } + } + + WriteError("Routing parse error 2"); + tidy_faddr(best); + tidy_faddr(dest); + return R_NOROUTE; +} + + + +void TestRoute(char *dest) +{ + fidoaddr result; + int rc; + + + rc = GetRoute(dest, &result); + if (rc == R_NOROUTE) + printf("Route %d %23s => no route\n", rc, dest); + else if (rc == R_UNLISTED) + printf("Route %d %23s => unlisted node\n", rc, dest); + else + printf("Route %d %23s => %s\n", rc, dest, aka2str(result)); +} + + + +void TestTracker(void) +{ + colour(7, 0); + TestRoute((char *)"2:2801/16@fidonet"); + TestRoute((char *)"2:2801/16.1"); + TestRoute((char *)"2:2801/805.3"); + TestRoute((char *)"2:2801/899.1@fidonet"); + TestRoute((char *)"2:2801/890@fidonet"); + TestRoute((char *)"2:2801/1008"); + TestRoute((char *)"2:2801/21"); + TestRoute((char *)"2:2801/899@fidonet"); + TestRoute((char *)"2:2801/807"); + TestRoute((char *)"92:100/0@bibnet"); + TestRoute((char *)"92:100/5@bibnet"); + TestRoute((char *)"92:100/45"); + TestRoute((char *)"2:28/0"); + TestRoute((char *)"2:2801/1002@fidonet"); + TestRoute((char *)"2:2801/206"); + TestRoute((char *)"2:2/0@fidonet"); + TestRoute((char *)"2:2/3001"); + TestRoute((char *)"2:2801/28"); + TestRoute((char *)"2:2801/307.50"); + TestRoute((char *)"2:280/901"); + TestRoute((char *)"2:280/9"); + TestRoute((char *)"2:203/111"); + TestRoute((char *)"1:213/350"); + TestRoute((char *)"9:314/8@virnet"); + TestRoute((char *)"9:314/8.1@virnet"); +} + + diff --git a/mbfido/tracker.h b/mbfido/tracker.h new file mode 100644 index 00000000..225d34cd --- /dev/null +++ b/mbfido/tracker.h @@ -0,0 +1,16 @@ +#ifndef _TRACKER_H +#define _TRACKER_H + +#define R_NOROUTE 0 +#define R_LOCAL 1 +#define R_DIRECT 2 +#define R_ROUTE 3 +#define R_UNLISTED 4 + + +int TrackMail(fidoaddr, fidoaddr *); +int GetRoute(char *, fidoaddr *); +void TestTracker(void); + +#endif + diff --git a/mbfido/ulock.c b/mbfido/ulock.c new file mode 100644 index 00000000..bf737d74 --- /dev/null +++ b/mbfido/ulock.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * + * File ..................: mbfido/ulock.c + * Purpose ...............: Lock mbfido processing. + * Last modification date : 10-May-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "flock.h" +#include "ulock.h" + +#define UNPACK_FACTOR 300 +#define TOSS_FACTOR 120 +#define TMPNAME "TMP." +#define LCKNAME "LOCKFILE" + + +static char lockfile[81]; + +extern int do_quiet; + + +/* + * Put a lock on this program. + */ +int lockunpack(void) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/", CFG.inbound); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + WriteError("$Can't create lockfile \"%s\"", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (1) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + WriteError("$Can't open lockfile \"%s\"", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + WriteError("$Can't read old pid from \"%s\"", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + Syslog('+', "Stale lock found for pid %u", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + WriteError("$Kill for %u failed",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + Syslog('+', "mbfido already running, pid=%u", oldpid); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulockunpack(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +int checkspace(char *dir, char *fn, int factor) +{ + struct stat st; + struct statfs sfs; + + if ((stat(fn,&st) != 0) || (statfs(dir,&sfs) != 0)) { + WriteError("Cannot stat \"%s\" or statfs \"%s\", assume enough space", fn, dir); + return 1; + } + + if ((((st.st_size / sfs.f_bsize +1) * factor) / 100L) > sfs.f_bfree) { + Syslog('!', "Only %lu %lu-byte blocks left on device where %s is located", + sfs.f_bfree,sfs.f_bsize,dir); + return 0; + } + return 1; +} + + + +/* + * Unpack archive + */ +int unpack(char *fn) +{ + char newname[16]; + char *cmd = NULL, *unarc; + int rc = 0, ld; + + if (!do_quiet) { + colour(11, 0); + printf("Unpacking file %s\n", fn); + } + + if ((unarc = unpacker(fn)) == NULL) + return 1; + + if (!getarchiver(unarc)) + return 1; + + cmd = xstrcpy(archiver.munarc); + + if ((cmd == NULL) || (cmd == "")) + return -1; + + if ((ld = f_lock(fn)) == -1) { + free(cmd); + return 1; + } + + rc = execute(cmd,fn,(char *)NULL,(char*)"/dev/null",(char*)"/dev/null",(char*)"/dev/null"); + if (rc == 0) + unlink(fn); + else { + strncpy(newname,fn,sizeof(newname)-1); + strcpy(newname+8,".bad"); + rename(fn,newname); + } + + free(cmd); + funlock(ld); + return rc; +} + + + diff --git a/mbfido/ulock.h b/mbfido/ulock.h new file mode 100644 index 00000000..b91f61ab --- /dev/null +++ b/mbfido/ulock.h @@ -0,0 +1,11 @@ +#ifndef _ULOCK_H +#define _ULOCK_H + +int checkspace(char *, char *, int); +int lockunpack(void); +void ulockunpack(void); +int unpack(char *); + +#endif + + diff --git a/mbfido/utic.c b/mbfido/utic.c new file mode 100644 index 00000000..5a5462c5 --- /dev/null +++ b/mbfido/utic.c @@ -0,0 +1,262 @@ +/***************************************************************************** + * + * File ..................: mbfido/utic.c + * Purpose ...............: Utilities for tic processing + * Last modification date : 26-May-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "tic.h" +#include "mover.h" +#include "tic.h" +#include "utic.h" + + +extern int tic_bad; +extern int do_quiet; + + +char *MakeTicName() +{ + static char buf[13]; + + buf[12] = '\0'; + sprintf(buf, "%08lx.tic", sequencer()); + buf[0] = 'm'; + buf[1] = 'b'; + + return buf; +} + + + +/* + * Return day in the year, 0..365 + */ +int Day_Of_Year() +{ + time_t Now; + struct tm *Tm; + + Now = time(NULL); + Tm = localtime(&Now); + + return Tm->tm_yday; +} + + + +/* + * ReArc files in the current directory + */ +int Rearc(char *unarc) +{ + int i, j; + char temp[81], *cmd = NULL; + + Syslog('f', "Entering Rearc(%s)", unarc); + + i = 0; + while (TIC.NewName[i] != '.') + i++; + i++; + + j = 0; + for (; i < strlen(TIC.NewName); i++) { + if (TIC.NewName[i] > '9') + TIC.NewName[i] = tolower(unarc[j]); + j++; + } + + + Syslog('f' , "NewName = \"%s\"", TIC.NewName); + + if (!getarchiver(unarc)) { + return FALSE; + } + + cmd = xstrcpy(archiver.farc); + + if (cmd == NULL) { + WriteError("Rearc(): No arc command available"); + return FALSE; + } else { + sprintf(temp, "%s%s .", TIC.Inbound, TIC.NewName); + if (execute(cmd, temp, (char *)NULL, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null") == 0) { + /* MUST SET TIC.FileDate to NEW ARCHIVE */ + return TRUE; + } + WriteError("Rearc(%s) Failed", unarc); + return FALSE; + } + free(cmd); +} + + + +void DeleteVirusWork() +{ + char *buf = NULL; + char temp[81]; + + getcwd(buf, 128); + sprintf(temp, "%s/tmp", getenv("MBSE_ROOT")); + + if (chdir(temp) == 0) { + Syslog('f', "DeleteVirusWork %s/arc", temp); + system("rm -r -f arc"); + system("mkdir arc"); + } else + WriteError("$Can't chdir to %s", temp); + + chdir(buf); +} + + + +void Bad(char *format, ...) +{ + char outstr[1024]; + va_list va_ptr; + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + WriteError(outstr); + MoveBad(); + tic_bad++; +} + + + +void ReCalcCrc(char *fn) +{ + TIC.Crc_Int = file_crc(fn, CFG.slow_util && do_quiet); + sprintf(TIC.TicIn.Crc, "%08lX", TIC.Crc_Int); + strcpy(T_File.Crc, TIC.TicIn.Crc); +} + + + +int Get_File_Id() +{ + char temp[81]; + char Desc[256]; + FILE *fp; + int i, j, lines = 0; + + sprintf(temp, "%s/tmp/FILE_ID.DIZ", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) + return FALSE; + + /* + * Read no more then 25 lines. + */ + while (((fgets(Desc, 255, fp)) != NULL) && (TIC.File_Id_Ct < 25)) { + lines++; + /* + * Check if the FILE_ID.DIZ is in a normal layout. + * The layout should be max. 10 lines of max. 48 characters. + * We check at 51 characters and if the lines are longer, + * we trash the FILE_ID.DIZ file. + */ + if (strlen(Desc) > 51) { + fclose(fp); + unlink(temp); + TIC.File_Id_Ct = 0; + Syslog('f', "FILE_ID.DIZ line %d is %d chars", lines, strlen(Desc)); + Syslog('!', "Trashing illegal formatted FILE_ID.DIZ"); + return FALSE; + } + + if (strlen(Desc) > 0) { + j = 0; + for (i = 0; i < strlen(Desc); i++) { + if ((Desc[i] >= ' ') || (Desc[i] < 0)) { + TIC.File_Id[TIC.File_Id_Ct][j] = Desc[i]; + j++; + } + } + + if (j >= 48) + TIC.File_Id[TIC.File_Id_Ct][48] = '\0'; + else + TIC.File_Id[TIC.File_Id_Ct][j] = '\0'; + + TIC.File_Id_Ct++; + } + } + fclose(fp); + unlink(temp); + + /* + * Strip empty lines at end of FILE_ID.DIZ + */ + while ((strlen(TIC.File_Id[TIC.File_Id_Ct-1]) == 0) && (TIC.File_Id_Ct)) + TIC.File_Id_Ct--; + + Syslog('f', "Got %d FILE_ID.DIZ lines", TIC.File_Id_Ct); + if (TIC.File_Id_Ct) + return TRUE; + else + return FALSE; +} + + + +void UpDateAlias(char *Alias) +{ + char *path; + FILE *fp; + + Syslog('f', "UpDateAlias(%s) with %s", Alias, TIC.NewName); + + if (!strlen(CFG.req_magic)) { + WriteError("No magic filename path configured"); + return; + } + + path = xstrcpy(CFG.req_magic); + path = xstrcat(path, (char *)"/"); + path = xstrcat(path, Alias); + + if ((fp = fopen(path, "w")) == NULL) { + WriteError("$Can't create %s", path); + return; + } + fprintf(fp, "%s\n", TIC.NewName); + fclose(fp); + free(path); +} + + + diff --git a/mbfido/utic.h b/mbfido/utic.h new file mode 100644 index 00000000..f514bae2 --- /dev/null +++ b/mbfido/utic.h @@ -0,0 +1,15 @@ +#ifndef _UTIC_H +#define _UTIC_H + + +char *MakeTicName(void); +int Day_Of_Year(void); +int Rearc(char *); +void DeleteVirusWork(void); +void Bad(char *, ...); +void ReCalcCrc(char *); +int Get_File_Id(void); +void UpDateAlias(char *); + + +#endif diff --git a/mbfido/viadate.c b/mbfido/viadate.c new file mode 100644 index 00000000..df36392c --- /dev/null +++ b/mbfido/viadate.c @@ -0,0 +1,68 @@ +/***************************************************************************** + * + * File ..................: mbfido/viadate.c + * Purpose ...............: Create a Via date + * Last modification date : 20-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "viadate.h" + + + +static char *months[] = { + (char *)"Jan", (char *)"Feb", (char *)"Mar", + (char *)"Apr", (char *)"May", (char *)"Jun", + (char *)"Jul", (char *)"Aug", (char *)"Sep", + (char *)"Oct", (char *)"Nov", (char *)"Dec" +}; + + + +static char *weekday[] = { + (char *)"Sun", (char *)"Mon", (char *)"Tue", + (char *)"Wed", (char *)"Thu", (char *)"Fri", + (char *)"Sat" +}; + + + +char *viadate(void) +{ + static char buf[64]; + time_t t; + struct tm *ptm; + + time(&t); + ptm = localtime(&t); + sprintf(buf,"%s %s %d %d at %02d:%02d", weekday[ptm->tm_wday],months[ptm->tm_mon], + ptm->tm_mday,ptm->tm_year+1900,ptm->tm_hour,ptm->tm_min); + return buf; +} + diff --git a/mbfido/viadate.h b/mbfido/viadate.h new file mode 100644 index 00000000..7dc0c2c0 --- /dev/null +++ b/mbfido/viadate.h @@ -0,0 +1,9 @@ +#ifndef _VIADATE_H +#define _VIADATE_H + + +char *viadate(void); + + +#endif + diff --git a/mbmon/Makefile.am b/mbmon/Makefile.am new file mode 100644 index 00000000..6009cdb4 --- /dev/null +++ b/mbmon/Makefile.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . +noinst_PROGRAMS = mbmon +mbmon_SOURCES = mutil.c mbmon.c common.c mutil.h mbmon.h common.h + +mbmon_LDADD = ../lib/libmemwatch.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmon $(bindir) + diff --git a/mbmon/Makefile.in b/mbmon/Makefile.in new file mode 100644 index 00000000..9cceb016 --- /dev/null +++ b/mbmon/Makefile.in @@ -0,0 +1,353 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +noinst_PROGRAMS = mbmon +mbmon_SOURCES = mutil.c mbmon.c common.c mutil.h mbmon.h common.h + +mbmon_LDADD = ../lib/libmemwatch.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbmon_OBJECTS = mutil.o mbmon.o common.o +mbmon_DEPENDENCIES = ../lib/libmemwatch.a +mbmon_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbmon_SOURCES) +OBJECTS = $(mbmon_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbmon/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbmon: $(mbmon_OBJECTS) $(mbmon_DEPENDENCIES) + @rm -f mbmon + $(LINK) $(mbmon_LDFLAGS) $(mbmon_OBJECTS) $(mbmon_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbmon + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +common.o: common.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h +mbmon.o: mbmon.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h mutil.h +mutil.o: mutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h common.h mutil.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbmon $(bindir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbmon/common.c b/mbmon/common.c new file mode 100644 index 00000000..2c8d60f1 --- /dev/null +++ b/mbmon/common.c @@ -0,0 +1,918 @@ +/***************************************************************************** + * + * File ..................: mbmon/common.c + * Purpose ...............: Common utilities + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include +#include "common.h" + + +pid_t mypid; /* Original parent pid if child */ +unsigned long lcrc = 0, tcrc = 1; /* CRC value of logstring */ +int lcnt = 0; /* Same message counter */ +static char *pbuff = NULL; +static int sock = -1; /* TCP/IP socket */ + +struct sockaddr_un clntaddr; /* Client socket address */ +struct sockaddr_un servaddr; /* Server socket address */ +struct sockaddr_un from; /* From socket address */ +int fromlen; +static char spath[108]; /* Server socket path */ +static char cpath[108]; /* Client socket path */ + + + + +void InitClient(char *user) +{ + sprintf(cpath, "%s/tmp/mbmon%d", getenv("MBSE_ROOT"), getpid()); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Store my pid in case a child process is forked and wants to do + * some communications with the mbsed server. + */ + mypid = getpid(); + if (socket_connect(user) == -1) { + printf("PANIC: cannot access socket\n"); + exit(1); + } +} + + + +void ExitClient(int errcode) +{ + if (socket_shutdown(mypid) == -1) + printf("PANIC: unable to shutdown socket\n"); + fflush(stdout); + fflush(stdin); + + if (pbuff) + free(pbuff); + + unlink(cpath); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(errcode); +} + + + +void SockS(const char *format, ...) +{ + char *out; + va_list va_ptr; + + out = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + socket_receive(); + + free(out); +} + + + +char *SockR(const char *format, ...) +{ + static char buf[SS_BUFSIZE]; + char *out; + va_list va_ptr; + + memset(&buf, 0, SS_BUFSIZE); + out = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(out, format, va_ptr); + va_end(va_ptr); + + if (socket_send(out) == 0) + sprintf(buf, "%s", socket_receive()); + + free(out); + return buf; +} + + + +void Syslog(int level, const char *format, ...) +{ + char *outstr; + va_list va_ptr; + int i; + + outstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + for (i = 0; i < strlen(outstr); i++) + if (outstr[i] == '\r' || outstr[i] == '\n') + outstr[i] = ' '; + + tcrc = StringCRC32(outstr); + if (tcrc == lcrc) { + lcnt++; + free(outstr); + return; + } else { + lcrc = tcrc; + if (lcnt) { + lcnt++; + SockS("ALOG:5,mbmon.log,mbmon,%d,+,Last message repeated %d times;", mypid, lcnt); + } + lcnt = 0; + } + + SockS("ALOG:5,mbmon.log,mbmon,%d,+,%s;", mypid, outstr); + free(outstr); +} + + + +void IsDoing(const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(64, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + SockS("ADOI:2,%d,%s;", mypid, outputstr); + free(outputstr); +} + + + +static time_t nop = 0; + +/* + * This function can be called very often but will only send once a minute + * a NOP to the server. This is a simple solution to keep server trafic low. + */ +void Nopper(void) +{ + time_t now; + + now = time(NULL); + if (((time_t)now - (time_t)nop) > 60) { + nop = now; + SockS("GNOP:1,%d;", mypid); + } +} + + + +/************************************************************************ + * + * Connect to Unix Datagram socket, return -1 if error or socket no. + */ + +int socket_connect(char *user) +{ + int s; + static char buf[SS_BUFSIZE]; + char tty[18]; + + if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) { + perror("mbmon"); + printf("Unable to create Unix Datagram socket\n"); + return -1; + } + + memset(&clntaddr, 0, sizeof(clntaddr)); + clntaddr.sun_family = AF_UNIX; + strcpy(clntaddr.sun_path, cpath); + + if (bind(s, &clntaddr, sizeof(clntaddr)) < 0) { + close(s); + perror("mbmon"); + printf("Can't bind socket %s\n", cpath); + return -1; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + sprintf(servaddr.sun_path, "%s", (char *)spath); + + /* + * Now that we have an connection, we gather + * information to tell the server who we are. + */ + if (isatty(1) && (ttyname(1) != NULL)) { + strcpy(tty, ttyname(1)); + if (strchr(tty, 'p')) + strcpy(tty, index(tty, 'p')); + else if (strchr(tty, 't')) + strcpy(tty, index(tty, 't')); + else if (strchr(tty, 'c')) + strcpy(tty, index(tty, 'c')); + } else { + strcpy(tty, "-"); + } + sock = s; + + /* + * Send the information to the server. + */ + sprintf(buf, "AINI:5,%d,%s,%s,mbmon,localhost;", getpid(), tty, user); + if (socket_send(buf) != 0) { + sock = -1; + return -1; + } + + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) != 0) { + printf("AINI not acknowledged by the server\n"); + sock = -1; + return -1; + } + + return s; +} + + + +/* + * Send data via Unix Datagram socket + */ +int socket_send(char *buf) +{ + if (sock == -1) + return -1; + + if (sendto(sock, buf, strlen(buf), 0, (struct sockaddr *) & servaddr, sizeof(servaddr)) != strlen(buf)) { + printf("Socket send failed error %d\n", errno); + return -1; + } + + return 0; +} + + + +/* + * Return an empty buffer if somthing went wrong, else the complete + * dataline is returned. + */ +char *socket_receive(void) +{ + static char buf[SS_BUFSIZE]; + int rlen; + + memset((char *)&buf, 0, SS_BUFSIZE); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, SS_BUFSIZE, 0, &from, &fromlen); + if (rlen == -1) { + perror("recv"); + printf("Error reading socket\n"); + memset((char *)&buf, 0, SS_BUFSIZE); + return buf; + } + return buf; +} + + + +/*************************************************************************** + * + * Shutdown the socket, first send the server the close command so this + * application will be removed from the servers active clients list. + * There must be a parameter with the pid so that client applications + * where the shutdown will be done by a child process is able to give + * the parent pid as an identifier. + */ + +int socket_shutdown(pid_t pid) +{ + static char buf[SS_BUFSIZE]; + + if (sock == -1) + return 0; + + sprintf(buf, "ACLO:1,%d;", pid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "107:0;", 6) != 0) { + printf("Shutdown not acknowledged by the server\n"); + printf("Got \"%s\"\n", buf); + } + } + + if (shutdown(sock, 1) == -1) { + perror("mbmon"); + printf("Cannot shutdown socket\n"); + return -1; + } + + sock = -1; + return 0; +} + + + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +unsigned long crc32tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + + +/* Calculate the CRC of a string. */ + +unsigned long str_crc32(char *str) +{ + unsigned long crc; + + for (crc=0L; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +unsigned long StringCRC32(char *str) +{ + unsigned long crc; + + for (crc = 0xffffffff; *str; str++) + crc = crc32tab[((int)crc^(*str)) & 0xff] ^ ((crc>>8) & 0x00ffffff); + return crc; +} + + + +int rawset = FALSE; + + +/* + * Sets raw mode and saves the terminal setup + */ +void Setraw() +{ + if (ioctl(ttyfd, TCGETA, &tbuf) == -1) { + perror("TCGETA Failed"); + exit(1); /* ERROR - could not set get tty ioctl */ + } + + tbufsav = tbuf; + tbuf.c_iflag &= ~(INLCR | ICRNL | IUCLC | ISTRIP | IXON ); + /* + * Map CRNL modes strip control characters and flow control + */ + tbuf.c_oflag &= ~OPOST; /* Don't do ouput character translation */ + tbuf.c_lflag &= ~(ICANON | ECHO); /* No canonical input and no echo */ + tbuf.c_cc[VMIN] = 1; /* Receive 1 character at a time */ + tbuf.c_cc[VTIME] = 0; /* No time limit per character */ + + if (ioctl(ttyfd, TCSETAF, &tbuf) == -1) { + perror("TCSETAF failed"); + exit(1); /* ERROR - could not set tty ioctl */ + } + + rawset = TRUE; +} + + + +/* + * Unsets raw mode and returns state of terminal + */ +void Unsetraw() +{ + /* + * Only unset the mode if it is set to raw mode + */ + if (rawset == TRUE) { + if (ioctl(ttyfd, TCSETAF, &tbufsav) == -1) { + perror("TCSETAF Normal Failed"); + exit(1); /* ERROR - could not save original tty ioctl */ + } + } + rawset = FALSE; +} + + + +/* + * Wait for a character for a maximum of wtime * 10 mSec. + */ +int Waitchar(unsigned char *ch, int wtime) +{ + int i, rc = -1; + + for (i = 0; i < wtime; i++) { + rc = read(ttyfd, ch, 1); + if (rc == 1) + return rc; + usleep(10000); + } + return rc; +} + + + +int Escapechar(unsigned char *ch) +{ + int rc; + unsigned char c; + + /* + * Escape character, if nothing follows within + * 50 mSec, the user really pressed . + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + if (*ch == '[') { + /* + * Start of CSI sequence. If nothing follows, + * return immediatly. + */ + if ((rc = Waitchar(ch, 5)) == -1) + return rc; + + /* + * Test for the most important keys. Note + * that only the cursor movement keys are + * guaranteed to work with PC-clients. + */ + c = *ch; + if (c == 'A') + c = KEY_UP; + if (c == 'B') + c = KEY_DOWN; + if (c == 'C') + c = KEY_RIGHT; + if (c == 'D') + c = KEY_LEFT; + if ((c == '1') || (c == 'H') || (c == 0)) + c = KEY_HOME; + if ((c == '4') || (c == 'K') || (c == 101) || (c == 144)) + c = KEY_END; + if (c == '2') + c = KEY_INS; + if (c == '3') + c = KEY_DEL; + if (c == '5') + c = KEY_PGUP; + if (c == '6') + c = KEY_PGDN; + memcpy(ch, &c, sizeof(unsigned char)); + return rc; + } + return -1; +} + + + +/* + * Returns the offset from your location to UTC. So in the MET timezone + * this returns -60 (wintertime). People in the USA get positive results. + */ +long gmt_offset(time_t now) +{ + struct tm ptm; + struct tm gtm; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + return offset; +} + + + +/* + * Returns the TZUTC string, note that the sign is opposite from the + * function above. + */ +char *gmtoffset(time_t now) +{ + static char buf[6]="+0000"; + char sign; + int hr, min; + long offset; + + offset = gmt_offset(now); + + if (offset <= 0) { + sign = '+'; + offset = -offset; + } else + sign = '-'; + + hr = offset / 60L; + min = offset % 60L; + + if (sign == '-') + sprintf(buf, "%c%02d%02d", sign, hr, min); + else + sprintf(buf, "%02d%02d", hr, min); + + return(buf); +} + + + +char *str_time(time_t total) +{ + static char buf[10]; + int h, m; + + memset(&buf, 0, sizeof(buf)); + + /* + * 0 .. 59 seconds + */ + if (total < (time_t)60) { + sprintf(buf, "%2d.00s", (int)total); + return buf; + } + + /* + * 1:00 .. 59:59 minutes:seconds + */ + if (total < (time_t)3600) { + h = total / 60; + m = total % 60; + sprintf(buf, "%2d:%02d ", h, m); + return buf; + } + + /* + * 1:00 .. 23:59 hours:minutes + */ + if (total < (time_t)86400) { + h = (total / 60) / 60; + m = (total / 60) % 60; + sprintf(buf, "%2d:%02dm", h, m); + return buf; + } + + /* + * 1/00 .. 30/23 days/hours + */ + if (total < (time_t)2592000) { + h = (total / 3600) / 24; + m = (total / 3600) % 24; + sprintf(buf, "%2d/%02dh", h, m); + return buf; + } + + sprintf(buf, "N/A "); + return buf; +} + + + +char *t_elapsed(time_t start, time_t end) +{ + return str_time(end - start); +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = malloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = malloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + +char *padleft(char *str, int size, char pad) +{ + static char stri[256]; + static char temp[256]; + + strcpy(stri, str); + memset(temp, pad, (long)size); + temp[size] = '\0'; + if (strlen(stri) <= size) + memmove(temp, stri, (long)strlen(stri)); + else + memmove(temp, stri, (long)size); + return temp; +} + + + +void Striplf(char *String) +{ + int i; + + for(i = 0; i < strlen(String); i++) { + if(*(String + i) == '\0') + break; + if(*(String + i) == '\n') + *(String + i) = '\0'; + } +} + + + +/* + * Changes ansi background and foreground color + */ +void colour(int fg, int bg) +{ + int att=0, fore=37, back=40; + + if (fg<0 || fg>31 || bg<0 || bg>7) { + printf("ANSI: Illegal colour specified: %i, %i\n", fg, bg); + return; + } + + printf("["); + if ( fg > 15) { + printf("5;"); + fg-=16; + } + if (fg > 7) { + att=1; + fg=fg-8; + } + + if (fg==0) fore=30; + else if (fg==1) fore=34; + else if (fg==2) fore=32; + else if (fg==3) fore=36; + else if (fg==4) fore=31; + else if (fg==5) fore=35; + else if (fg==6) fore=33; + else fore=37; + + if (bg==1) back=44; + else if (bg==2) back=42; + else if (bg==3) back=46; + else if (bg==4) back=41; + else if (bg==5) back=45; + else if (bg==6) back=43; + else if (bg==7) back=47; + else back=40; + + printf("%d;%d;%dm", att, fore, back); +} + + + +void clear() +{ + colour(LIGHTGRAY, BLACK); + printf(ANSI_HOME); + printf(ANSI_CLEAR); +} + + + +/* + * Moves cursor to specified position + */ +void locate(int y, int x) +{ + if (y > LINES || x > COLS) { + printf("ANSI: Invalid screen coordinates: %i, %i\n", y, x); + return; + } + printf("\x1B[%i;%iH", y, x); +} + + + +/* + * curses compatible functions + */ +void mvprintw(int y, int x, const char *format, ...) +{ + char *outputstr; + va_list va_ptr; + + outputstr = calloc(2048, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(outputstr, format, va_ptr); + va_end(va_ptr); + + locate(y, x); + printf(outputstr); + free(outputstr); +} + + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/mbmon/common.h b/mbmon/common.h new file mode 100644 index 00000000..33a2d7b1 --- /dev/null +++ b/mbmon/common.h @@ -0,0 +1,97 @@ +#ifndef _COMMON_H +#define _COMMON_H + + +#pragma pack(1) + +#define MBSE_SS(x) (x)?(x):"(null)" +#define SS_BUFSIZE 2048 + + +/* + * Returned function keys + */ +#define KEY_BACKSPACE 8 +#define KEY_LINEFEED 10 +#define KEY_ENTER 13 +#define KEY_ESCAPE 27 +#define KEY_RUBOUT 127 +#define KEY_UP 200 +#define KEY_DOWN 201 +#define KEY_LEFT 202 +#define KEY_RIGHT 203 +#define KEY_HOME 204 +#define KEY_END 205 +#define KEY_INS 206 +#define KEY_DEL 207 +#define KEY_PGUP 208 +#define KEY_PGDN 209 + + +#define LINES 24 +#define COLS 80 + + +/* + * ANSI colors + */ +#define BLACK 0 +#define BLUE 1 +#define GREEN 2 +#define CYAN 3 +#define RED 4 +#define MAGENTA 5 +#define BROWN 6 +#define LIGHTGRAY 7 +#define DARKGRAY 8 +#define LIGHTBLUE 9 +#define LIGHTGREEN 10 +#define LIGHTCYAN 11 +#define LIGHTRED 12 +#define LIGHTMAGENTA 13 +#define YELLOW 14 +#define WHITE 15 + +#define ANSI_CLEAR "\x1B[2J" +#define ANSI_HOME "\x1B[H" + +extern char SigName[32][16]; + + + +int ttyfd; /* Filedescriptor for raw mode */ +struct termio tbuf, tbufsav; /* Structure for raw mode */ + + +void InitClient(char *); +void ExitClient(int); +void SockS(const char *, ...); +char *SockR(const char *, ...); +void Syslog(int, const char *, ...); +void IsDoing(const char *, ...); +void Nopper(void); +int socket_connect(char *); +int socket_send(char *); +char *socket_receive(void); +int socket_shutdown(pid_t); +unsigned long str_crc32(char *str); +unsigned long StringCRC32(char *); +long gmt_offset(time_t); +char *gmtoffset(time_t); +char *str_time(time_t); +char *t_elapsed(time_t, time_t); +void Setraw(void); /* Set raw mode */ +void Unsetraw(void); /* Unset raw mode */ +int Waitchar(unsigned char *, int); /* Wait n * 10mSec for char */ +int Escapechar(unsigned char *); /* Escape sequence test */ +char *xstrcpy(char *); +char *padleft(char *str, int size, char pad); +void Striplf(char *String); +void colour(int, int); +void clear(void); +void locate(int, int); +void mvprintw(int, int, const char *, ...); + + +#endif + diff --git a/mbmon/mbmon.c b/mbmon/mbmon.c new file mode 100644 index 00000000..ebb9dae8 --- /dev/null +++ b/mbmon/mbmon.c @@ -0,0 +1,451 @@ +/***************************************************************************** + * + * File ..................: mbmon/mbmon.c + * Purpose ...............: Monitor Program + * Last modification date : 29-Jun-2001 + * Todo ..................: Trace logfiles + * Chat with user via server + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "common.h" +#include "mutil.h" + + +extern char *version; +extern char *copyright; + + + +static void die(int onsig) +{ + signal(onsig, SIG_IGN); + screen_stop(); + if (onsig && (onsig <= NSIG)) + Syslog('?', "$Finished on signal %s", SigName[onsig]); + else + Syslog(' ', "Normally finished"); + ExitClient(0); +} + + + +void ShowSysinfo(void) +{ + int ch; + char buf[128], *cnt; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "5. SHOW BBS SYSTEM INFO"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Total calls"); + mvprintw( 8, 6, "2. Pots calls"); + mvprintw( 9, 6, "3. ISDN calls"); + mvprintw(10, 6, "4. Network calls"); + mvprintw(11, 6, "5. Local calls"); + mvprintw(12, 6, "6. Date started"); + mvprintw(13, 6, "7. Last caller"); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("View System Info"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + sprintf(buf, "GSYS:1,%d;", getpid()); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:7,", 6) == 0) { + cnt = strtok(buf, ","); + mvprintw( 7,26, "%s", strtok(NULL, ",")); + mvprintw( 8,26, "%s", strtok(NULL, ",")); + mvprintw( 9,26, "%s", strtok(NULL, ",")); + mvprintw(10,26, "%s", strtok(NULL, ",")); + mvprintw(11,26, "%s", strtok(NULL, ",")); + mvprintw(12,26, "%s", strtok(NULL, ",")); + mvprintw(13,26, "%s", strtok(NULL, ";")); + fflush(stdout); + } + } + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void ShowLastcaller(void) +{ + int records, ch, i, y, o; + char buf[128], *cnt; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 6, "6. SHOW BBS LASTCALLERS"); + set_color(YELLOW, RED); + mvprintw( 6, 1, "Nr Username Location Level Device Time Mins Calls Speed Actions"); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("View Lastcallers"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + records = 0; + sprintf(buf, "GLCC:0;"); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:1,", 6) == 0) { + cnt = strtok(buf, ","); + records = atoi(strtok(NULL, ";")); + } + } + + if (records) { + y = 7; + if (records > 10) + o = records -10; + else + o = 1; + set_color(CYAN, BLACK); + for (i = o; i <= records; i++) { + sprintf(buf, "GLCR:1,%d;", i); + if (socket_send(buf) == 0) { + sprintf(buf, "%s", socket_receive()); + if (strncmp(buf, "100:9,", 6) == 0) { + cnt = strtok(buf, ","); + mvprintw(y, 1, "%2d", i); + mvprintw(y, 4, "%s", strtok(NULL, ",")); + mvprintw(y,19, "%s", strtok(NULL, ",")); + mvprintw(y,32, "%s", strtok(NULL, ",")); + mvprintw(y,38, "%s", strtok(NULL, ",")); + mvprintw(y,45, "%s", str_time(atoi(strtok(NULL, ",")))); + mvprintw(y,52, "%s", strtok(NULL, ",")); + mvprintw(y,57, "%s", strtok(NULL, ",")); + mvprintw(y,63, "%s", strtok(NULL, ",")); + mvprintw(y,73, "%s", strtok(NULL, ";")); + y++; + } + } + } + } + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void system_moni(void) +{ + int ch, y, eof; + char *cnt; + char buf[128]; + time_t start, now; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1. SERVER CLIENTS"); + set_color(YELLOW, RED); + mvprintw( 7, 1, "Pid tty user program city doing time "); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + IsDoing("System Monitor"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + eof = 0; + set_color(LIGHTGRAY, BLACK); + + for (y = 8; y <= LINES - 5; y++) { + if (y == 8) + sprintf(buf, "GMON:1,1;"); + else + sprintf(buf, "GMON:1,0;"); + if (eof == 0) { + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + locate(y, 1); + clrtoeol(); + if (strncmp(buf, "100:0;", 6) == 0) { + /* + * There's no more information + */ + eof = 1; + } else { + cnt = strtok(buf, ","); + mvprintw(y, 1, (char *)"%.5s", strtok(NULL, ",")); + mvprintw(y, 7, (char *)"%.6s", strtok(NULL, ",")); + mvprintw(y,14, (char *)"%.16s", strtok(NULL, ",")); + mvprintw(y,31, (char *)"%.8s", strtok(NULL, ",")); + mvprintw(y,40, (char *)"%.15s", strtok(NULL, ",")); + mvprintw(y,56, (char *)"%.18s", strtok(NULL, ",")); + start = atoi(strtok(NULL, ";")); + now = time(NULL); + mvprintw(y,75, (char *)"%s", t_elapsed(start, now)); + } + } + } else { + /* + * If no valid data, clear line + */ + locate(y, 1); + clrtoeol(); + } + } /* for () */ + + ch = testkey(LINES - 4, COLS / 2 + 8); + } while (ch == '\0'); +} + + + +void system_stat(void) +{ + int ch; + char buf[256]; + char *cnt; + time_t now; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "2. SERVER STATISTICS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "First date started"); + mvprintw( 7,62, "BBS Open"); + mvprintw( 8, 6, "Last date started"); + mvprintw( 8,62, "ZMH"); + mvprintw( 9, 6, "Total server starts"); + mvprintw( 9,62, "Internet"); + mvprintw(10, 6, "Connected clients"); + mvprintw(10,62, "Running"); + mvprintw(11,62, "Load avg"); + mvprintw(12,30, "Total Today"); + hor_lin(13,30,8); + hor_lin(13,45,8); + mvprintw(14, 6, "Client connects"); + mvprintw(15, 6, "Peak connections"); + mvprintw(16, 6, "Protocol syntax errors"); + mvprintw(17, 6, "Communication errors"); + mvprintw(19, 6, "Next sequence number"); + mvprintw(19,62, "Press any key"); + IsDoing("System Statistics"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + sprintf(buf, "GSTA:1,%d;", getpid()); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + set_color(LIGHTGRAY, BLACK); + cnt = strtok(buf, ","); + now = atoi(strtok(NULL, ",")); + mvprintw(7, 30, "%s", ctime(&now)); + now = atoi(strtok(NULL, ",")); + mvprintw(8, 30, "%s", ctime(&now)); + cnt = strtok(NULL, ","); + mvprintw(9, 30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(10,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(14,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(15,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(16,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(17,30, (char *)"%s ", strtok(NULL, ",")); + mvprintw(14,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(15,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(16,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(17,45, (char *)"%s ", strtok(NULL, ",")); + mvprintw(7,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(8,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(9,72, "%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(10,72,"%s", atoi(strtok(NULL, ",")) == 1?"Yes":"No "); + mvprintw(11,72, "%s ", strtok(NULL, ",")); + mvprintw(19,30, (char *)"%s", strtok(NULL, ";")); + } + + ch = testkey(19,76); + } while (ch == '\0'); +} + + + +void disk_stat(void) +{ + int ch, i; + char buf[1024]; + char *cnt, *type, *fs, *p; + unsigned long last[10]; + unsigned long size, used, perc; + char sign; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "3. FILESYSTEM USAGE"); + set_color(YELLOW, RED); + mvprintw( 7, 1, " Size MB Used MB Perc. FS-Type Mountpoint "); + set_color(CYAN, BLACK); + mvprintw(LINES - 2, 6, "Press any key"); + IsDoing("Filesystem Usage"); + + do { + show_date(LIGHTGRAY, BLACK, 0, 0); + + sprintf(buf, "GDST:1,%d;", getpid()); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + set_color(LIGHTGRAY, BLACK); + cnt = strtok(buf, ":"); + cnt = strtok(NULL, ",;"); + if (atoi(cnt)) { + for (i = 0; i < atoi(cnt); i++) { + p = strtok(NULL, " "); + size = atoi(p); + p = strtok(NULL, " "); + used = size - atoi(p); + perc = (used * 100) / size; + sign = ' '; + fs = strtok(NULL, " "); + type = strtok(NULL, ",;"); + if (used > last[i]) + sign = '^'; + if (used < last[i]) + sign = 'v'; + if (last[i] == 0) + sign = ' '; + last[i] = used; + set_color(CYAN, BLACK); + mvprintw(i+8, 1, "%8lu %8lu ", + size, used); + set_color(WHITE, BLACK); + printf("%c ", sign); + set_color(CYAN, BLACK); + if (strstr(type, "iso") == NULL) { + if (perc >= 95) + set_color(LIGHTRED, BLACK); + else if (perc >= 80) + set_color(YELLOW, BLACK); + } + printf("%3lu", perc); + putchar('%'); + set_color(CYAN, BLACK); + printf(" %-8s %-40s", type, fs); + } + locate(i+8, 1); + clrtoeol(); + } + } + + ch = testkey(LINES - 2, 20); + } while (ch == '\0'); +} + + + +void soft_info(void) +{ + clr_index(); + set_color(YELLOW, BLACK); + center_addstr( 7, (char *)"MBSE BBS"); + set_color(WHITE, BLACK); + center_addstr( 9, (char *)"(c) Michiel Broek"); + set_color(YELLOW, BLACK); + center_addstr(11, (char *)"Made in the Netherlands"); + set_color(LIGHTGREEN, BLACK); + center_addstr(LINES -8, (char *)"This is free software; released under the terms of the GNU General"); + center_addstr(LINES -7, (char *)"Public License as published by the Free Software Foundation."); + set_color(CYAN, BLACK); + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +int main(int argc, char *argv[]) +{ + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * Find out who is on the keyboard or automated the keyboard. + */ + pw = getpwuid(getuid()); + InitClient(pw->pw_name); + Syslog(' ', "Started by %s", pw->pw_name); + + /* + * Setup several signals so when the program terminate's it + * will properly close. + */ + signal(SIGINT, (void (*))die); + signal(SIGBUS, (void (*))die); + signal(SIGSEGV,(void (*))die); + signal(SIGTERM,(void (*))die); + signal(SIGKILL,(void (*))die); + + screen_start((char *)"MBmon"); + + for (;;) { + + IsDoing("Browsing Menu"); + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "0. MBSE BBS MONITOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. View Server Clients"); + mvprintw( 8, 6, "2. View Server Statistics"); + mvprintw( 9, 6, "3. View Filesystem Usage"); + mvprintw(10, 6, "4. View System Logfiles"); + mvprintw(11, 6, "5. View BBS System Information"); + mvprintw(12, 6, "6. View BBS Lastcallers List"); + mvprintw(13, 6, "7. View Software Information"); + + switch(select_menu(7)) { + case 0: + die(0); + break; + case 1: + system_moni(); + break; + case 2: + system_stat(); + break; + case 3: + disk_stat(); + break; + case 5: + ShowSysinfo(); + break; + case 6: + ShowLastcaller(); + break; + case 7: + soft_info(); + break; + } + } +} + diff --git a/mbmon/mbmon.h b/mbmon/mbmon.h new file mode 100644 index 00000000..596d9e24 --- /dev/null +++ b/mbmon/mbmon.h @@ -0,0 +1,14 @@ +#ifndef _MBMON_H +#define _MBMON_H + +static void die(int); +void ShowSysinfo(void); +void ShowLastcaller(void); +void system_moni(void); +void system_stat(void); +void disk_stat(void); +void soft_info(void); + + +#endif + diff --git a/mbmon/mutil.c b/mbmon/mutil.c new file mode 100644 index 00000000..bd578c67 --- /dev/null +++ b/mbmon/mutil.c @@ -0,0 +1,548 @@ +/***************************************************************************** + * + * File ..................: mutil.c + * Purpose ...............: Utilities + * Last modification date : 25-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "common.h" +#include "mutil.h" + + +unsigned char readkey(int y, int x, int fg, int bg) +{ + int rc = -1, i; + unsigned char ch = 0; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + i = 0; + while (rc == -1) { + if ((i % 10) == 0) + show_date(fg, bg, 0, 0); + + locate(y, x); + fflush(stdout); + rc = Waitchar(&ch, 5); + if ((rc == 1) && (ch != KEY_ESCAPE)) + break; + + if ((rc == 1) && (ch == KEY_ESCAPE)) + rc = Escapechar(&ch); + + if (rc == 1) + break; + i++; + Nopper(); + } + + Unsetraw(); + close(ttyfd); + + return ch; +} + + + +unsigned char testkey(int y, int x) +{ + int rc; + unsigned char ch = 0; + + Nopper(); + locate(y, x); + fflush(stdout); + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + rc = Waitchar(&ch, 100); + if (rc == 1) { + if (ch == KEY_ESCAPE) + rc = Escapechar(&ch); + } + + Unsetraw(); + close(ttyfd); + + if (rc == 1) + return ch; + else + return '\0'; +} + + + +void show_field(int y, int x, char *str, int length, int fill) +{ + mvprintw(y, x, padleft(str, length, fill)); +} + + +int insertflag = 0; + +void newinsert(int i, int fg, int bg) +{ + insertflag = i; + set_color(YELLOW, RED); + if (insertflag != 0) { + mvprintw(2,36," INS "); + } else { + mvprintw(2,36," OVR "); + } + set_color(fg, bg); +} + + + + +char *edit_field(int y, int x, int w, int p, char *s_) +{ + int i, charok, first, curpos; + static char s[256]; + unsigned int ch; + + memset((char *)s, 0, 256); + sprintf(s, "%s", s_); + curpos = 0; + first = 1; + newinsert(1, YELLOW, BLUE); + + do { + set_color(YELLOW, BLUE); + show_field(y, x, s, w, '_'); + locate(y, x + curpos); + do { + ch = readkey(y, x + curpos, YELLOW, BLUE); + set_color(YELLOW, BLUE); + + /* + * Test if the pressed key is a valid key. + */ + charok = 0; + if ((ch >= ' ') && (ch <= '~')) { + switch(p) { + case '!': + ch = toupper(ch); + charok = 1; + break; + case 'X': + charok = 1; + break; + case '9': + if (ch == ' ' || ch == '-' || ch == ',' || + ch == '.' || isdigit(ch)) + charok = 1; + break; + case 'U': + ch = toupper(ch); + if (isupper(ch)) + charok = 1; + break; + default: + putchar(7); + break; + } + } + + } while (charok == 0 && ch != KEY_ENTER && ch != KEY_LINEFEED && + ch != KEY_DEL && ch != KEY_INS && ch != KEY_HOME && + ch != KEY_LEFT && ch != KEY_RIGHT && ch != KEY_ESCAPE && + ch != KEY_BACKSPACE && ch != KEY_RUBOUT && ch != KEY_END); + + + if (charok == 1) { + if (first == 1) { + first = 0; + memset((char *)s, 0, 256); + curpos = 0; + } + if (curpos < w) { + if (insertflag == 1) { + /* + * Insert mode + */ + if (strlen(s) < w) { + if (curpos < strlen(s)) { + for (i = strlen(s); i >= curpos; i--) + s[i+1] = s[i]; + } + s[curpos] = ch; + if (curpos < w) + curpos++; + } else { + putchar(7); + } + } else { + /* + * Overwrite mode + */ + s[curpos] = ch; + if (curpos < w) + curpos++; + } + } else { + /* + * The field is full + */ + putchar(7); + } + } /* if charok */ + + first = 0; + switch (ch) { + case KEY_HOME: + curpos = 0; + break; + case KEY_END: + curpos = strlen(s); + break; + case KEY_LEFT: + if (curpos > 0) + curpos--; + else + putchar(7); + break; + case KEY_RIGHT: + if (curpos < strlen(s)) + curpos++; + else + putchar(7); + break; + case KEY_INS: + if (insertflag == 1) + newinsert(0, YELLOW, BLUE); + else + newinsert(1, YELLOW, BLUE); + break; + case KEY_BACKSPACE: + if (strlen(s) > 0) { + if (curpos >= strlen(s)) { + curpos--; + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + case KEY_RUBOUT: + case KEY_DEL: + if (strlen(s) > 0) { + if ((curpos) == (strlen(s) -1)) { + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + } + } while ((ch != KEY_ENTER) && (ch != KEY_LINEFEED) && (ch != KEY_ESCAPE)); + + set_color(LIGHTGRAY, BLUE); + mvprintw(2,36, " "); + set_color(LIGHTGRAY, BLACK); + return s; +} + + + +/* + * Select menu, max is the highest item to pick. Returns zero if + * "-" (previous level) is selected. + */ +int select_menu(int max) +{ + static char *menu=(char *)"-"; + char help[80]; + int pick; + + sprintf(help, "Select menu item (1..%d) or ^\"-\"^ for previous level.", max); + showhelp(help); + + /* + * Loop forever until it's right. + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 3, '9', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + return 0; + + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + return pick; + + working(2, 0, 0); + working(0, 0, 0); + } +} + + + +void clrtoeol() +{ + int i; + + printf("\r"); + for (i = 0; i < COLS; i++) + putchar(' '); + printf("\r"); + fflush(stdout); +} + + + +void hor_lin(int y, int x, int len) +{ + int i; + + locate(y, x); + for (i = 0; i < len; i++) + putchar('-'); + fflush(stdout); +} + + + +static int old_f = -1; +static int old_b = -1; + +void set_color(int f, int b) +{ + if ((f != old_f) || (b != old_b)) { + old_f = f; + old_b = b; + colour(f, b); + fflush(stdout); + } +} + + + +static time_t lasttime; + +/* + * Show the current date & time in the second status row + */ +void show_date(int fg, int bg, int y, int x) +{ + time_t now; + char *p; + + time(&now); + if (now != lasttime) { + lasttime = now; + set_color(LIGHTGREEN, BLUE); + p = ctime(&now); + Striplf(p); + mvprintw(1, 44, (char *)"%s TZUTC %s", p, gmtoffset(now)); + p = asctime(gmtime(&now)); + Striplf(p); + mvprintw(2, 44, (char *)"%s UTC", p); + if (y && x) + locate(y, x); + set_color(fg, bg); + } +} + + + +void center_addstr(int y, char *s) +{ + mvprintw(y, (COLS / 2) - (strlen(s) / 2), s); +} + + + +/* + * Curses and screen initialisation. + */ +void screen_start(char *name) +{ + int i; + + /* + * Overwrite screen the first time, if user had it black on white + * it will change to white on black. clear() won't do the trick. + */ + set_color(LIGHTGRAY, BLUE); + locate(1, 1); + for (i = 0; i < LINES; i++) { + if (i == 3) + colour(LIGHTGRAY, BLACK); + clrtoeol(); + if (i < LINES) + printf("\n"); + } + fflush(stdout); + + set_color(WHITE, BLUE); + locate(1, 1); + printf((char *)"%s for MBSE BBS version %s", name, VERSION); + set_color(YELLOW, BLUE); + locate(2, 1); + printf((char *)"(c) Copyright Michiel Broek"); + set_color(LIGHTGRAY, BLACK); + show_date(LIGHTGRAY, BLACK, 0, 0); + fflush(stdout); +} + + + +/* + * Screen deinit + */ +void screen_stop() +{ + set_color(LIGHTGRAY, BLACK); + clear(); + fflush(stdout); +} + + + +/* + * Message at the upperright window about actions + */ +void working(int txno, int y, int x) +{ + int i; + + /* + * If txno not 0 there will be something written. The + * reversed attributes for mono, or white on red for + * color screens is set. The cursor is turned off and + * original cursor position is saved. + */ + show_date(LIGHTGRAY, BLACK, 0, 0); + + if (txno != 0) + set_color(YELLOW, RED); + else + set_color(LIGHTGRAY, BLACK); + + switch (txno) { + case 0: mvprintw(4, 66, (char *)" "); + break; + case 1: mvprintw(4, 66, (char *)"Working . . ."); + break; + case 2: mvprintw(4, 66, (char *)">>> ERROR <<<"); + for (i = 1; i <= 5; i++) { + putchar(7); + fflush(stdout); + usleep(150000); + } + usleep(550000); + break; + case 3: mvprintw(4, 66, (char *)"Form inserted"); + putchar(7); + fflush(stdout); + sleep(1); + break; + case 4: mvprintw(4, 66, (char *)"Form deleted "); + putchar(7); + fflush(stdout); + sleep(1); + break; + } + + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + if (y && x) + locate(y, x); + fflush(stdout); +} + + + +/* + * Clear the middle window + */ +void clr_index() +{ + int i; + + set_color(LIGHTGRAY, BLACK); + for (i = 3; i <= (LINES - 1); i++) { + locate(i, 1); + clrtoeol(); + } +} + + + +/* + * Show help at the bottom of the screen. + */ +void showhelp(char *T) +{ + int f, i, x, forlim; + + f = FALSE; + locate(LINES-1, 1); + set_color(WHITE, RED); + clrtoeol(); + x = 0; + forlim = strlen(T); + + for (i = 0; i < forlim; i++) { + if (T[i] == '^') { + if (f == FALSE) { + f = TRUE; + set_color(YELLOW, RED); + } else { + f = FALSE; + set_color(WHITE, RED); + } + } else { + putchar(T[i]); + x++; + } + } + set_color(LIGHTGRAY, BLACK); + fflush(stdout); +} + + diff --git a/mbmon/mutil.h b/mbmon/mutil.h new file mode 100644 index 00000000..2772d449 --- /dev/null +++ b/mbmon/mutil.h @@ -0,0 +1,22 @@ +#ifndef _MUTIL_H +#define _MUTIL_H + +unsigned char readkey(int, int, int, int); +unsigned char testkey(int, int); +void show_field(int, int, char *, int, int); +void newinsert(int, int, int); +char *edit_field(int, int, int, int, char *); +int select_menu(int); +void clrtoeol(void); +void hor_lin(int, int, int); +void set_color(int, int); +void show_date(int, int, int, int); +void center_addstr(int y, char *s); +void screen_start(char *); +void screen_stop(void); +void working(int, int, int); +void clr_index(void); +void showhelp(char *); + +#endif + diff --git a/mbsebbs/Makefile.am b/mbsebbs/Makefile.am new file mode 100644 index 00000000..8fec03e6 --- /dev/null +++ b/mbsebbs/Makefile.am @@ -0,0 +1,61 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . +noinst_PROGRAMS = mbsebbs mball mblang mbchat mbfbgen mbstat mbtoberep mbuser mbuseradd mbpasswd + +mbsebbs_SOURCES = bank.c bbslist.c chat.c file.c funcs.c funcs4.c mail.c menu.c \ +misc.c pinfo.c nextuser.c oneline.c page.c pwcheck.c fsedit.c \ +bye.c change.c mbsebbs.c safe.c timeout.c user.c timecheck.c \ +exitinfo.c filesub.c lineedit.c offline.c language.c msgutil.c \ +newuser.c pop3.c email.c \ +bank.h bbslist.h chat.h file.h funcs.h funcs4.h mail.h menu.h \ +misc.h pinfo.h nextuser.h oneline.h page.h pwcheck.h fsedit.h \ +bye.h change.h mbsebbs.h safe.h timeout.h user.h timecheck.h \ +exitinfo.h filesub.h lineedit.h offline.h language.h msgutil.h \ +newuser.h pop3.h email.h statetbl.h + +mball_SOURCES = mball.c mball.h + +mblang_SOURCES = mblang.c + +mbchat_SOURCES = mbchat.c + +mbfbgen_SOURCES = mbfbgen.c + +mbstat_SOURCES = mbstat.c mbstat.h + +mbtoberep_SOURCES = mbtoberep.c + +mbuser_SOURCES = mbuser.c mbuser.h + +mbuseradd_SOURCES = mbuseradd.c mbuseradd.h + +mbpasswd_SOURCES = mbpasswd.c commonio.c pwio.c shadowio.c sgetpwent.c \ +xmalloc.c myname.c rad64.c salt.c getdef.c encrypt.c \ +mbpasswd.h commonio.h pwio.h shadowio.h sgetpwent.h \ +xmalloc.h myname.h rad64.h salt.h getdef.h encrypt.h + +mbsebbs_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mball_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mblang_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbchat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfbgen_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbstat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbuser_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 6711 mbsebbs $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mball $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mblang $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbchat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfbgen $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbstat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbtoberep $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuser $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuseradd $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbpasswd $(bindir) + diff --git a/mbsebbs/Makefile.in b/mbsebbs/Makefile.in new file mode 100644 index 00000000..5536c14f --- /dev/null +++ b/mbsebbs/Makefile.in @@ -0,0 +1,633 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . +noinst_PROGRAMS = mbsebbs mball mblang mbchat mbfbgen mbstat mbtoberep mbuser mbuseradd mbpasswd + +mbsebbs_SOURCES = bank.c bbslist.c chat.c file.c funcs.c funcs4.c mail.c menu.c misc.c pinfo.c nextuser.c oneline.c page.c pwcheck.c fsedit.c bye.c change.c mbsebbs.c safe.c timeout.c user.c timecheck.c exitinfo.c filesub.c lineedit.c offline.c language.c msgutil.c newuser.c pop3.c email.c bank.h bbslist.h chat.h file.h funcs.h funcs4.h mail.h menu.h misc.h pinfo.h nextuser.h oneline.h page.h pwcheck.h fsedit.h bye.h change.h mbsebbs.h safe.h timeout.h user.h timecheck.h exitinfo.h filesub.h lineedit.h offline.h language.h msgutil.h newuser.h pop3.h email.h statetbl.h + + +mball_SOURCES = mball.c mball.h + +mblang_SOURCES = mblang.c + +mbchat_SOURCES = mbchat.c + +mbfbgen_SOURCES = mbfbgen.c + +mbstat_SOURCES = mbstat.c mbstat.h + +mbtoberep_SOURCES = mbtoberep.c + +mbuser_SOURCES = mbuser.c mbuser.h + +mbuseradd_SOURCES = mbuseradd.c mbuseradd.h + +mbpasswd_SOURCES = mbpasswd.c commonio.c pwio.c shadowio.c sgetpwent.c xmalloc.c myname.c rad64.c salt.c getdef.c encrypt.c mbpasswd.h commonio.h pwio.h shadowio.h sgetpwent.h xmalloc.h myname.h rad64.h salt.h getdef.h encrypt.h + + +mbsebbs_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a ../lib/libmbinet.a +mball_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mblang_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbchat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbfbgen_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbstat_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mbuser_LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbsebbs_OBJECTS = bank.o bbslist.o chat.o file.o funcs.o funcs4.o \ +mail.o menu.o misc.o pinfo.o nextuser.o oneline.o page.o pwcheck.o \ +fsedit.o bye.o change.o mbsebbs.o safe.o timeout.o user.o timecheck.o \ +exitinfo.o filesub.o lineedit.o offline.o language.o msgutil.o \ +newuser.o pop3.o email.o +mbsebbs_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a \ +../lib/libmbinet.a +mbsebbs_LDFLAGS = +mball_OBJECTS = mball.o +mball_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mball_LDFLAGS = +mblang_OBJECTS = mblang.o +mblang_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mblang_LDFLAGS = +mbchat_OBJECTS = mbchat.o +mbchat_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbchat_LDFLAGS = +mbfbgen_OBJECTS = mbfbgen.o +mbfbgen_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbfbgen_LDFLAGS = +mbstat_OBJECTS = mbstat.o +mbstat_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbstat_LDFLAGS = +mbtoberep_OBJECTS = mbtoberep.o +mbtoberep_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbtoberep_LDFLAGS = +mbuser_OBJECTS = mbuser.o +mbuser_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libdbase.a +mbuser_LDFLAGS = +mbuseradd_OBJECTS = mbuseradd.o +mbuseradd_LDADD = $(LDADD) +mbuseradd_DEPENDENCIES = +mbuseradd_LDFLAGS = +mbpasswd_OBJECTS = mbpasswd.o commonio.o pwio.o shadowio.o sgetpwent.o \ +xmalloc.o myname.o rad64.o salt.o getdef.o encrypt.o +mbpasswd_LDADD = $(LDADD) +mbpasswd_DEPENDENCIES = +mbpasswd_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbsebbs_SOURCES) $(mball_SOURCES) $(mblang_SOURCES) $(mbchat_SOURCES) $(mbfbgen_SOURCES) $(mbstat_SOURCES) $(mbtoberep_SOURCES) $(mbuser_SOURCES) $(mbuseradd_SOURCES) $(mbpasswd_SOURCES) +OBJECTS = $(mbsebbs_OBJECTS) $(mball_OBJECTS) $(mblang_OBJECTS) $(mbchat_OBJECTS) $(mbfbgen_OBJECTS) $(mbstat_OBJECTS) $(mbtoberep_OBJECTS) $(mbuser_OBJECTS) $(mbuseradd_OBJECTS) $(mbpasswd_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbsebbs/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbsebbs: $(mbsebbs_OBJECTS) $(mbsebbs_DEPENDENCIES) + @rm -f mbsebbs + $(LINK) $(mbsebbs_LDFLAGS) $(mbsebbs_OBJECTS) $(mbsebbs_LDADD) $(LIBS) + +mball: $(mball_OBJECTS) $(mball_DEPENDENCIES) + @rm -f mball + $(LINK) $(mball_LDFLAGS) $(mball_OBJECTS) $(mball_LDADD) $(LIBS) + +mblang: $(mblang_OBJECTS) $(mblang_DEPENDENCIES) + @rm -f mblang + $(LINK) $(mblang_LDFLAGS) $(mblang_OBJECTS) $(mblang_LDADD) $(LIBS) + +mbchat: $(mbchat_OBJECTS) $(mbchat_DEPENDENCIES) + @rm -f mbchat + $(LINK) $(mbchat_LDFLAGS) $(mbchat_OBJECTS) $(mbchat_LDADD) $(LIBS) + +mbfbgen: $(mbfbgen_OBJECTS) $(mbfbgen_DEPENDENCIES) + @rm -f mbfbgen + $(LINK) $(mbfbgen_LDFLAGS) $(mbfbgen_OBJECTS) $(mbfbgen_LDADD) $(LIBS) + +mbstat: $(mbstat_OBJECTS) $(mbstat_DEPENDENCIES) + @rm -f mbstat + $(LINK) $(mbstat_LDFLAGS) $(mbstat_OBJECTS) $(mbstat_LDADD) $(LIBS) + +mbtoberep: $(mbtoberep_OBJECTS) $(mbtoberep_DEPENDENCIES) + @rm -f mbtoberep + $(LINK) $(mbtoberep_LDFLAGS) $(mbtoberep_OBJECTS) $(mbtoberep_LDADD) $(LIBS) + +mbuser: $(mbuser_OBJECTS) $(mbuser_DEPENDENCIES) + @rm -f mbuser + $(LINK) $(mbuser_LDFLAGS) $(mbuser_OBJECTS) $(mbuser_LDADD) $(LIBS) + +mbuseradd: $(mbuseradd_OBJECTS) $(mbuseradd_DEPENDENCIES) + @rm -f mbuseradd + $(LINK) $(mbuseradd_LDFLAGS) $(mbuseradd_OBJECTS) $(mbuseradd_LDADD) $(LIBS) + +mbpasswd: $(mbpasswd_OBJECTS) $(mbpasswd_DEPENDENCIES) + @rm -f mbpasswd + $(LINK) $(mbpasswd_LDFLAGS) $(mbpasswd_OBJECTS) $(mbpasswd_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbsebbs + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +bank.o: bank.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h bank.h funcs4.h language.h funcs.h timeout.h \ + timecheck.h exitinfo.h +bbslist.o: bbslist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h bbslist.h \ + funcs.h funcs4.h language.h +bye.o: bye.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h funcs.h language.h bye.h +change.o: change.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h change.h \ + funcs.h funcs4.h language.h misc.h pwcheck.h timeout.h \ + exitinfo.h bye.h +chat.o: chat.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h chat.h funcs.h funcs4.h language.h misc.h \ + exitinfo.h +commonio.o: commonio.c ../config.h commonio.h +email.o: email.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/msgtext.h ../lib/msg.h ../lib/common.h \ + ../lib/clcomm.h ../lib/mbinet.h exitinfo.h language.h mail.h \ + timeout.h msgutil.h funcs4.h email.h +encrypt.o: encrypt.c ../config.h encrypt.h +exitinfo.o: exitinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs.h \ + funcs4.h language.h oneline.h misc.h bye.h timeout.h \ + timecheck.h exitinfo.h +file.o: file.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h filesub.h file.h funcs.h funcs4.h language.h \ + misc.h timeout.h exitinfo.h change.h +filesub.o: filesub.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h filesub.h \ + funcs.h language.h funcs4.h misc.h timeout.h exitinfo.h \ + change.h +fsedit.o: fsedit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/ansi.h ../lib/common.h ../lib/clcomm.h \ + mail.h funcs4.h language.h timeout.h pinfo.h fsedit.h +funcs.o: funcs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/msgtext.h ../lib/msg.h \ + ../lib/clcomm.h funcs.h language.h funcs4.h oneline.h misc.h \ + bye.h timeout.h timecheck.h exitinfo.h mail.h email.h +funcs4.o: funcs4.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h ../lib/msg.h \ + funcs4.h misc.h timeout.h language.h +getdef.o: getdef.c ../config.h getdef.h +language.o: language.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs4.h \ + language.h +lineedit.o: lineedit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h mail.h \ + funcs4.h language.h timeout.h lineedit.h +mail.o: mail.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/msgtext.h ../lib/clcomm.h ../lib/msg.h mail.h funcs.h \ + funcs4.h language.h misc.h timeout.h oneline.h exitinfo.h \ + lineedit.h fsedit.h filesub.h msgutil.h pop3.h email.h +mball.o: mball.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/mbse.h \ + ../lib/records.h ../lib/common.h ../lib/dbcfg.h ../lib/clcomm.h \ + mball.h +mbchat.o: mbchat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h +mbfbgen.o: mbfbgen.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h +mblang.o: mblang.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h +mbpasswd.o: mbpasswd.c ../config.h encrypt.h rad64.h myname.h xmalloc.h \ + pwio.h shadowio.h mbpasswd.h +mbsebbs.o: mbsebbs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/msg.h \ + mbsebbs.h user.h funcs.h funcs4.h language.h menu.h misc.h \ + bye.h timeout.h +mbstat.o: mbstat.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbstat.h +mbtoberep.o: mbtoberep.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h +mbuser.o: mbuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/dbcfg.h mbuser.h +mbuseradd.o: mbuseradd.c ../config.h mbuseradd.h +menu.o: menu.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h oneline.h mail.h bbslist.h change.h bank.h \ + chat.h file.h funcs.h funcs4.h misc.h nextuser.h safe.h \ + timeout.h menu.h page.h pinfo.h bye.h timecheck.h exitinfo.h \ + language.h offline.h email.h +misc.o: misc.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h funcs.h funcs4.h language.h misc.h timeout.h \ + exitinfo.h +msgutil.o: msgutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h \ + ../lib/msgtext.h ../lib/msg.h oneline.h msgutil.h +myname.o: myname.c ../config.h +newuser.o: newuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h funcs4.h \ + pwcheck.h newuser.h language.h timeout.h change.h bye.h +nextuser.o: nextuser.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/ansi.h ../lib/clcomm.h ../lib/common.h \ + nextuser.h funcs.h funcs4.h language.h timeout.h +offline.o: offline.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/mbse.h \ + ../lib/records.h ../lib/bluewave.h ../lib/common.h \ + ../lib/clcomm.h ../lib/msgtext.h ../lib/msg.h mail.h funcs.h \ + funcs4.h language.h file.h filesub.h exitinfo.h timeout.h \ + msgutil.h pop3.h offline.h +oneline.o: oneline.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h oneline.h \ + funcs.h funcs4.h language.h +page.o: page.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h funcs.h funcs4.h chat.h page.h timeout.h mail.h \ + language.h +pinfo.o: pinfo.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h funcs4.h +pop3.o: pop3.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h ../lib/mbinet.h ../lib/msgtext.h ../lib/msg.h \ + msgutil.h pop3.h +pwcheck.o: pwcheck.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h pwcheck.h \ + funcs4.h timeout.h +pwio.o: pwio.c ../config.h sgetpwent.h commonio.h pwio.h +rad64.o: rad64.c ../config.h rad64.h +safe.o: safe.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h exitinfo.h funcs.h funcs4.h misc.h safe.h \ + timeout.h language.h +salt.o: salt.c ../config.h rad64.h getdef.h +sgetpwent.o: sgetpwent.c ../config.h sgetpwent.h +shadowio.o: shadowio.c ../config.h commonio.h shadowio.h +timecheck.o: timecheck.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/clcomm.h ../lib/common.h timecheck.h \ + funcs.h funcs4.h misc.h bye.h exitinfo.h language.h +timeout.o: timeout.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/mbse.h ../lib/structs.h \ + ../lib/records.h ../lib/common.h ../lib/clcomm.h ../lib/msg.h \ + timeout.h funcs.h funcs4.h bye.h filesub.h language.h +user.o: user.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/mbse.h ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h timeout.h user.h pwcheck.h funcs.h funcs4.h \ + misc.h bye.h file.h mail.h change.h menu.h exitinfo.h \ + language.h offline.h statetbl.h email.h newuser.h +xmalloc.o: xmalloc.c ../config.h xmalloc.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 6711 mbsebbs $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mball $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mblang $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbchat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbfbgen $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbstat $(bindir) + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbtoberep $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuser $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbuseradd $(bindir) + $(INSTALL) -s -g root -o root -m 6711 mbpasswd $(bindir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbsebbs/bank.c b/mbsebbs/bank.c new file mode 100644 index 00000000..75913214 --- /dev/null +++ b/mbsebbs/bank.c @@ -0,0 +1,576 @@ +/***************************************************************************** + * + * File ..................: bbs/bank.c + * Purpose ...............: Time/Bytes Bank + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "bank.h" +#include "funcs4.h" +#include "language.h" +#include "funcs.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" + + +/* + * internal function prototypes + */ +int BankMenu(void); +void AddAccount(void); +void Deposit(void); +void Withdraw(void); +void DepositTime(void); +void WithdrawTime(void); + +void DepositBytes(void); +void WithdrawBytes(void); + +FILE *pBank; +int usernum = 0; +long bankset; + + + +/* + * Timebank, called from the menu system. + */ +void Bank() +{ + int FoundName = FALSE; + int Loop = TRUE; + char *temp, temp1[81]; + + DisplayFile((char *)"bank"); + temp = calloc(PATH_MAX, sizeof(char)); + + while(Loop) { + FoundName = FALSE; + usernum = 0; + WhosDoingWhat(TIMEBANK); + + sprintf(temp, "%s/etc/bank.data", getenv("MBSE_ROOT")); + if ((pBank = fopen(temp, "r+")) == NULL) { + /* Create a new database */ + pBank = fopen(temp, "a+"); + bankhdr.hdrsize = sizeof(bankhdr); + bankhdr.recsize = sizeof(bank); + fwrite(&bankhdr, sizeof(bankhdr), 1, pBank); + fclose(pBank); + Syslog('-', "Created %s", temp); + AddAccount(); + if ((pBank = fopen(temp, "r+")) == NULL) { + WriteError("Unable to open %s", temp); + free(temp); + return; + } + } + + fread(&bankhdr, sizeof(bankhdr), 1, pBank); + fseek(pBank, bankhdr.hdrsize, 0); + while (fread(&bank, bankhdr.recsize, 1, pBank) == 1) { + if((strcmp(bank.Name, exitinfo.sUserName)) == 0) { + FoundName = TRUE; + break; + } else + usernum++; + } /* End of while */ + + fclose(pBank); + + if(!FoundName) + AddAccount(); + + if ((pBank = fopen(temp, "r+")) == NULL) + AddAccount(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + if (fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fread(&bank, bankhdr.recsize, 1, pBank); + + sprintf(temp1, "%s", (char *) GetDateDMY()); + if ((strcmp(temp1, bank.Date)) != 0) { + bank.TimeWithdraw = 0; + bank.KByteWithdraw = 0; + bank.TimeDeposit = 0; + bank.KByteDeposit = 0; + sprintf(bank.Date, "%s", (char *) GetDateDMY()); + } + + Loop = BankMenu(); + } + free(temp); +} + + + +int BankMenu() +{ + int i; + + clear(); + /* MBSE BBS System Bank */ + language(4, 7, 11); + colour(15, 0); + sLine(); + /* Bank Account: */ + language(3, 0, 12); + poutCR(15, 0, bank.Name); + colour(15, 0); + sLine(); + + /* Time in account */ + language(10, 0, 13); + colour(15, 0); + printf("%d\n", bank.TimeBalance); + + /* Bytes in account */ + language(10, 0, 14); + colour(15, 0); + printf("%d\n", bank.KByteBalance); + + /* Time deposited today */ + language(10, 0, 15); + colour(15, 0); + printf("%d\n", bank.TimeDeposit); + + /* Bytes deposited today */ + language(10, 0, 16); + colour(15, 0); + printf("%d\n", bank.KByteDeposit); + + /* Time withdrawn today */ + language(10, 0, 17); + colour(15, 0); + printf("%d\n", bank.TimeWithdraw); + + /* Bytes withdrawn today */ + language(10, 0, 18); + colour(15, 0); + printf("%d\n", bank.KByteWithdraw); + + colour(15, 0); + sLine(); + TimeCheck(); + /* (D)eposit, (W)ithdraw, (Q)uit */ + language(12, 0, 19); + Enter(2); + + /* Bank > */ + language(15, 0, 20); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(19, 0)) + Deposit(); + else + if (i == Keystroke(19, 1)) + Withdraw(); + else + if (i == Keystroke(19, 2)) + return FALSE; + + return TRUE; +} + + + +void AddAccount() +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/bank.data", getenv("MBSE_ROOT")); + + if ((pBank = fopen(temp, "a+")) == NULL) + WriteError("Can't open %s for updating", temp); + else { + memset(&bank, 0, sizeof(bank)); + strcpy(bank.Name, exitinfo.sUserName); + sprintf(bank.Date, "%s", (char *) GetDateDMY()); + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + } + free(temp); +} + + + +void Deposit() +{ + int i; + + /* (T)ime, (B)ytes, (Q)uit : */ + language(3, 0, 21); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(21, 0)) + DepositTime(); + else + if (i == Keystroke(21, 1)) + DepositBytes(); +} + + + +void Withdraw() +{ + int i; + + /* (T)ime, (B)ytes, (Q)uit : */ + language(3, 0, 21); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(21, 0)) + WithdrawTime(); + else + if (i == Keystroke(21, 1)) + WithdrawBytes(); +} + + + +void DepositTime() +{ + int x; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + fflush(stdin); + + if(exitinfo.iTimeLeft <= 5) { + Enter(2); + /* You must have at least 5 minutes remaining to deposit */ + language(12, 0, 22); + Enter(2); + Pause(); + free(temp); + return; + } + + Enter(1); + /* How much time. Minutes available to you is */ + language(15, 0, 23); + printf("%d: ", exitinfo.iTimeLeft - 5); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.TimeDeposit += x; + bank.TimeBalance += x; + + if(bank.TimeDeposit > CFG.iMaxTimeDeposit) { + colour(10, 0); + Enter(1); + /* You have tried to deposit more than the maximum limit today. */ + language(10, 0, 24); + Enter(1); + + /* Maximum allowed minutes to deposit per day: */ + language(12, 0, 25); + printf("%d.\n\n", CFG.iMaxTimeDeposit); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(bank.TimeBalance > CFG.iMaxTimeBalance) { + Enter(1); + /* You have exeeded your account balance. */ + language(10, 0, 26); + /* Maximum allowable minutes in bank account is: */ + language(12, 0, 27); + printf("%d\n", CFG.iMaxTimeBalance); + /* You are allowed to deposit: */ + language(14, 0, 28); + printf("%d\n\n", CFG.iMaxTimeBalance - (bank.TimeBalance - x) ); + Pause(); + fclose(pBank); + free(temp); + return; + } + + Time2Go -= (x * 60); + TimeCheck(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + + free(temp); +} + + + +void WithdrawTime() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + /* How much time. Minutes available to you is */ + Enter(1); + language(15, 0, 23); + printf("%d: ", bank.TimeBalance); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + + bank.TimeWithdraw += x; + bank.TimeBalance -= x; + + if(bank.TimeWithdraw > CFG.iMaxTimeWithdraw) { + Enter(1); + /* You have tried to withdraw more than the maximum limit today. */ + language(10, 0, 29); + /* Maximum allowed to withdraw per day: */ + language(12, 0, 30); + printf("%d.\n\n", CFG.iMaxTimeWithdraw); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(x > bank.TimeBalance + x) { + Enter(1); + /* You have tried to withdraw more time than is in your bank account. */ + language(10, 0, 31); + /* Current bank balance: */ + language(10, 0, 32); + printf("%d.\n\n", bank.TimeBalance + x); + Pause(); + fclose(pBank); + free(temp); + return; + } + + Time2Go += (x * 60); + TimeCheck(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + + +void DepositBytes() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + if(exitinfo.DownloadKToday <= 5) { + Enter(2); + /* You must have at least 5 bytes remaining to deposit */ + language(12, 0, 22); + Enter(2); + Pause(); + free(temp); + return; + } + + Enter(1); + /* Bytes available: */ + language(15, 0, 36); + printf("%lu: ", exitinfo.DownloadKToday); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.KByteDeposit += x; + bank.KByteBalance += x; + + if(bank.KByteDeposit > CFG.iMaxByteDeposit * 1000) { + Enter(1); + /* You have tried to deposit more than the maximum limit today. */ + language(10, 0, 25); + Enter(1); + colour(12, 0); + /* Maximum allowed kilobytes to deposit per day: */ + language(12, 0, 33); + printf("%d.\n\n", CFG.iMaxByteDeposit); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(bank.KByteBalance > CFG.iMaxByteBalance * 1000) { + Enter(1); + /* You have exeeded your account balance. */ + language(10, 0, 34); + Enter(1); + /* Maximum allowable kilobytes in bank account is: */ + language(12, 0, 35); + printf("%d\n", CFG.iMaxByteBalance); + colour(14, 0); + /* You are allowed to deposit: */ + language(14, 0, 28); + printf("%d\n\n", CFG.iMaxByteBalance - (bank.KByteBalance - x) ); + Pause(); + fclose(pBank); + free(temp); + return; + } + + exitinfo.DownloadKToday -= x; + WriteExitinfo(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + + +void WithdrawBytes() +{ + char *temp; + int x; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + + Enter(1); + /* How many bytes. Bytes available to you is */ + language(15, 0, 36); + printf("%d: ", bank.KByteBalance); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) { + free(temp); + return; + } + + x = atoi(temp); + bank.KByteWithdraw += x; + bank.KByteBalance -= x; + + if(bank.KByteWithdraw > CFG.iMaxByteWithdraw * 1000) { + Enter(1); + /* You have tried to withdraw more than the maximum limit today. */ + language(10, 0, 29); + Enter(1); + colour(12, 0); + /* Maximum allowed to withdraw per day: */ + language(12, 0, 30); + printf("%d bytes.\n\n", CFG.iMaxByteWithdraw); + Pause(); + fclose(pBank); + free(temp); + return; + } + + if(x > bank.KByteBalance + x) { + Enter(1); + /* You have tried to withdraw more time than is in your bank account. */ + language(10, 0, 31); + Enter(1); + colour(12, 0); + /* Current bank balance: */ + language(12, 0, 32); + printf("%d.\n\n", bank.KByteBalance + x); + Pause(); + fclose(pBank); + free(temp); + return; + } + + exitinfo.DownloadKToday += x; + WriteExitinfo(); + + bankset = bankhdr.hdrsize + (usernum * bankhdr.recsize); + + if(fseek(pBank, bankset, 0) != 0) + WriteError("Can't move pointer there."); + + fwrite(&bank, sizeof(bank), 1, pBank); + fclose(pBank); + free(temp); +} + + diff --git a/mbsebbs/bank.h b/mbsebbs/bank.h new file mode 100644 index 00000000..2239fc91 --- /dev/null +++ b/mbsebbs/bank.h @@ -0,0 +1,7 @@ +#ifndef _BANK_H +#define _BANK_H + +void Bank(void); + +#endif + diff --git a/mbsebbs/bbslist.c b/mbsebbs/bbslist.c new file mode 100644 index 00000000..aaf27517 --- /dev/null +++ b/mbsebbs/bbslist.c @@ -0,0 +1,708 @@ +/***************************************************************************** + * + * File ..................: bbs/bbslist.c + * Purpose ...............: Handle BBS lists + * Last modification date : 28-Jun-2001 + * ToDo ..................: Add use of new fields + * Verify check at logon + * Intro New BBS at logon + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "bbslist.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" + + + +void BBS_Add(void) +{ + FILE *pBBSList; + char *sFileName; + char *temp; + + sFileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "a+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(temp); + free(sFileName); + return; + } + + if (ftell(pBBSList) == 0) { + /* + * The file looks new created, add header + */ + bbshdr.hdrsize = sizeof(bbshdr); + bbshdr.recsize = sizeof(bbs); + fwrite(&bbshdr, sizeof(bbshdr), 1, pBBSList); + } + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + /* Adding BBS */ + printf(" %s", (char *) Language(300)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+--------------+\n"); + /* Adding BBS */ + printf("\t\t\t\t| %s |\n", (char *) Language(300)); + printf("\t\t\t\t+--------------+\n\n"); + } + + memset(&bbs, 0, sizeof(bbs)); + + while (TRUE) { + /* BBS Name: */ + pout(15, 0, (char *) Language(301)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.BBSName, 40); + + if((strlen(bbs.BBSName)) > 3) + break; + else { + Enter(1); + pout(12, 0, (char *) Language(302)); + Enter(2); + Pause(); + free(temp); + free(sFileName); + return; + } + } + + while (TRUE) { + /* Phone Number: */ + pout(15, 0, (char *) Language(303)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Phone[0], 20); + + if((strlen(bbs.Phone[0])) > 3) + break; + } + + while (TRUE) { + /* Sysop Name: */ + pout(15, 0, (char *) Language(304)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getname(bbs.Sysop, 35); + + if((strlen(bbs.Sysop)) > 3) + break; + } + + while (TRUE) { + /* BBS Software: */ + pout(15, 0, (char *) Language(305)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Software, 19); + + if((strlen(bbs.Software)) >= 2) + break; + } + + while (TRUE) { + /* Storage (Gigabyte): */ + pout(15, 0, (char *) Language(306)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getnum(temp, 8); + + if ((strlen(temp)) > 0) { + bbs.Storage = atoi(temp); + break; + } + } + + while (TRUE) { + /* Speeds: */ + pout(15, 0, (char *) Language(307)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Speeds[0], 40); + + if((strlen(bbs.Speeds[0])) > 2) + break; + } + + Enter(1); + /* Would you like to add a extended discription? [Y/n]: */ + pout(15, 0, (char *) Language(308)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((toupper(temp[0]) == Keystroke(308, 0)) || (strcmp(temp, "") == 0)) { + colour(14, 0); + /* Please a enter discription for */ + printf("\n%s%s (2 Lines)\n", (char *) Language(309), bbs.BBSName); + pout(15, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Desc[0], 71); + pout(15, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(bbs.Desc[1], 71); + } + + printf("\n"); + Syslog('+', "User added BBS to list"); + + sprintf(bbs.UserName,"%s", exitinfo.sUserName); + sprintf(bbs.DateOfEntry,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + sprintf(bbs.Verified,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + bbs.Available = TRUE; + + fwrite(&bbs, sizeof(bbs), 1, pBBSList); + fclose(pBBSList); + free(temp); + free(sFileName); +} + + + +void BBS_List(void) +{ + FILE *pBBSList; + int recno = 0; + char *sFileName; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("BBSList: Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + printf(" %s", (char *) Language(310)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+---------------+\n"); + /* BBS Listing */ + printf("\t\t\t\t| %s |\n", (char *) Language(310)); + printf("\t\t\t\t+---------------+\n\n"); + } + + /* # BBS Name Number Software Gigabyte Speed*/ + colour(15, 0); + printf("%s\n", Language(311)); + colour(12, 0); + sLine(); + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) { + if ((bbs.Available)) { + colour(15, 0); + printf("%-5d", recno); + + colour(10, 0); + bbs.BBSName[22] = '\0'; + printf("%-23s", bbs.BBSName); + + colour(11, 0); + bbs.Phone[0][14] = '\0'; + printf("%-15s", bbs.Phone[0]); + + colour(14, 0); + bbs.Software[15] = '\0'; + printf("%-16s", bbs.Software); + + colour(13, 0); + printf("%-11d", bbs.Storage); + + colour(8, 0); + bbs.Speeds[0][9] = '\0'; + printf("%s\n", bbs.Speeds[0]); + } + recno++; + } + colour(12, 0); + sLine(); + fclose(pBBSList); + free(sFileName); + Pause(); +} + + + +void BBS_Search(void) +{ + FILE *pBBSList; + int recno = 0; + int iFoundBBS = FALSE; + char *sFileName; + char *Name; + char *sTemp; + long offset; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("BBSList: Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + Name = calloc(30, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c ", 177, 177); + colour(15, 0); + printf("%s", (char *) Language(312)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t\t+--------------------+\n"); + /* Search for a BBS */ + printf("\t\t\t\t | %s |\n", (char *) Language(312)); + printf("\t\t\t\t +--------------------+\n\n"); + } + + while (TRUE) { + /* Please enter 3 letters of BBS to search for: */ + pout(15, 0, (char *) Language(313)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 29); + + if((strcmp(Name,"")) == 0) { + fflush(stdin); + fclose(pBBSList); + free(sFileName); + free(sTemp); + free(Name); + return; + } + + if((strlen(Name)) > 2) + break; + else { + Enter(1); + /* I need at least 3 letters ...*/ + pout(12, 0, (char *) Language(314)); + Enter(2); + } + } + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) { + if((strstr(tl(bbs.BBSName), tl(Name)) != NULL)) { + tlf(bbs.BBSName); + colour(14, 0); + /* BBS Name: */ + printf("\n%s%s\n\n", (char *) Language(301), bbs.BBSName); + /* View this BBS? [Y/n]: */ + pout(15, 0, (char *) Language(315)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(sTemp, 80); + if ((toupper(sTemp[0]) == Keystroke(315, 0)) || (strcmp(sTemp,"") == 0)) { + iFoundBBS = TRUE; + break; + } else + recno++; + } else { + recno++; + } + } + + if(!iFoundBBS) { + Enter(1); + /* Could not find the BBS Listed ... */ + pout(12, 0, (char *) Language(316)); + Enter(2); + fclose(pBBSList); + Pause(); + free(sFileName); + free(Name); + free(sTemp); + return; + } + + offset = bbshdr.hdrsize + (recno * bbshdr.recsize); + if(fseek(pBBSList, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, bbshdr.recsize, 1, pBBSList); + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t%c%c ", 177, 177); + colour(15, 0); + /* Search for a BBS */ + printf("%s", (char *) Language(312)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,219); + printf("\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t+--------------------+\n"); + /* Search for a BBS */ + printf("\t\t\t| %s |\n", (char *) Language(312)); + printf("\t\t\t+--------------------+\n\n"); + } + + /* # BBS Name Number Software Storage Speed */ + colour(15, 0); + printf("%s\n", Language(311)); + + colour(12, 0); + sLine(); + + colour(15, 0); + printf("%-5d", recno); + + colour(10, 0); + bbs.BBSName[22] = '\0'; + printf("%-23s", bbs.BBSName); + + colour(11, 0); + bbs.Phone[0][14] = '\0'; + printf("%-15s", bbs.Phone[0]); + + colour(14, 0); + bbs.Software[15] = '\0'; + printf("%-16s", bbs.Software); + + colour(13, 0); + printf("%-11d", bbs.Storage); + + colour(8, 0); + bbs.Speeds[0][9] = '\0'; + printf("%s\n", bbs.Speeds[0]); + + colour(12, 0); + sLine(); + fclose(pBBSList); + Pause(); + free(sFileName); + free(sTemp); + free(Name); +} + + + +void BBS_Show(void) +{ + FILE *pBBSList; + int recno = 0; + int nrecno = 0; + long int offset; + char *sFileName; + char srecno[10]; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSList = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + free(sFileName); + fread(&bbshdr, sizeof(bbshdr), 1, pBBSList); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t%c%c ", 177, 177); + colour(15, 0); + /* Show a BBS */ + printf("%s", (char *) Language(317)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177,177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220,219); + } else { + printf("\n\t\t\t+--------------+\n"); + /* Show a BBS */ + printf("\t\t\t| %s |\n", (char *) Language(317)); + printf("\t\t\t+--------------+\n\n"); + } + + Enter(1); + /* Please enter number to list: */ + pout(15, 0, (char *) Language(318)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 9); + + if((strcmp(srecno,"")) == 0) + return; + + recno = atoi(srecno); + nrecno = recno; + recno = 0; + + while (fread(&bbs, bbshdr.recsize, 1, pBBSList) == 1) + recno++; + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, (char *) Language(319)); + Enter(2); + fclose(pBBSList); + Pause(); + return; + } else { + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if(fseek(pBBSList, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, bbshdr.recsize, 1, pBBSList); + + colour(12, 0); + sLine(); + + /* Record : */ + pout(15, 0, (char *) Language(320)); + colour(10, 0); + printf("%d\n", nrecno); + + /* BBS Name : */ + pout(15, 0, (char *) Language(321)); + colour(10, 0); + printf("%s\n", bbs.BBSName); + + /* Number : */ + pout(15, 0, (char *) Language(322)); + colour(10, 0); + printf("%s\n", bbs.Phone[0]); + + /* Software : */ + pout(15, 0, (char *) Language(323)); + colour(10, 0); + printf("%s\n", bbs.Software); + + /* Storage : */ + pout(15, 0, (char *) Language(324)); + colour(10, 0); + printf("%d\n", bbs.Storage); + + /* Speeds : */ + pout(15, 0, (char *) Language(325)); + colour(10, 0); + printf("%s\n", bbs.Speeds[0]); + + /* Sysop Name : */ + pout(15, 0, (char *) Language(326)); + colour(10, 0); + printf("%s\n", bbs.Sysop); + + if((strcmp(bbs.Desc[0],"")) != 0) { + pout(15, 0, (char *)" Description : "); + colour(13, 0); + bbs.Desc[0][62] = '\0'; + printf("%s\n", bbs.Desc[0]); + } + if((strcmp(bbs.Desc[1],"")) != 0) { + pout(15, 0, (char *)" : "); + colour(13, 0); + bbs.Desc[1][62] = '\0'; + printf("%s\n", bbs.Desc[1]); + } + + colour(12, 0); + sLine(); + + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + pout(15, 0, (char *)"Sysop extra information\n"); + colour(12, 0); + sLine(); + + /* Available : */ + pout(15, 0, (char *) Language(327)); + colour(10, 0); + printf("%d\n", bbs.Available); + + /* Date of Entry : */ + pout(15, 0, (char *) Language(328)); + colour(10, 0); + printf("%s\n", bbs.DateOfEntry); + + /* Entry Name : */ + pout(15, 0, (char *) Language(329)); + colour(10, 0); + printf("%s\n", bbs.UserName); + + colour(12, 0); + sLine(); + } + Pause(); + } + fclose(pBBSList); +} + + + +void BBS_Delete(void) +{ + FILE *pBBSLine; + int recno = 0; + long int offset; + int nrecno = 0; + char srecno[7]; + char *sFileName; + char stemp[50]; + char sUser[35]; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/bbslist.data", getenv("MBSE_ROOT")); + + if((pBBSLine = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + free(sFileName); + fread(&bbshdr, sizeof(bbshdr),1 , pBBSLine); + + if(exitinfo.GraphMode) { + colour(9, 0); + printf("\n\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177); + printf("\t\t\t\t%c%c", 177, 177); + colour(15, 0); + /* Delete BBS */ + printf(" %s", (char *) Language(330)); + colour(9, 0); + printf("%c%c %c\n", 177, 177, 219); + printf("\t\t\t\t%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c %c\n", 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 219); + printf("\t\t\t\t %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n\n", 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 219); + } else { + printf("\n\t\t\t\t+--------------+\n"); + /* Delete BBS */ + printf("\t\t\t\t| %s |\n", (char *) Language(330)); + printf("\t\t\t\t+--------------+\n\n"); + } + + Enter(1); + /* Please enter number to delete: */ + pout(15, 0, (char *) Language(331)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 9); + + if((strcmp(srecno,"")) == 0) + return; + + recno = atoi(srecno); + nrecno = recno; + recno = 0; + + while (fread(&bbs, bbshdr.recsize, 1, pBBSLine) == 1) + recno++; + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, (char *) Language(319)); + Enter(2); + fclose(pBBSLine); + Pause(); + return; + } else { + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if (fseek(pBBSLine, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + + fread(&bbs, sizeof(bbs), 1, pBBSLine); + + /* Convert Record Int to string, so we can print to logfiles */ + sprintf(stemp,"%d", nrecno); + + /* Print UserName to String, so we can compare for deletion */ + sprintf(sUser,"%s", exitinfo.sUserName); + + if((strcmp(sUser, bbs.UserName)) != 0) { + if((!SYSOP) && (exitinfo.Security.level < CFG.sysop_access)) { + /* Record */ /* does not belong to you.*/ + printf("\n%s%s %s\n\n", (char *) Language(332), stemp, (char *) Language(333)); + Syslog('!', "User tried to delete somebody else's bbslist record: %s", stemp); + return; + } + } + + if ((bbs.Available == FALSE)) { + colour(12, 0); + /* Record */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('!', "User tried to mark an already marked bbslist record: %s", stemp); + } else { + bbs.Available = FALSE; + colour(10, 0); + /* Record: */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(335)); + Syslog('+', "User marked bbslist record for deletion: %s", stemp); + colour(15, 2); + /* The Sysop will purge the list once he has *//* seen you have marked a record for deletion. */ + printf("%s\n%s\n\n", (char *) Language(336), (char *) Language(337)); + Pause(); + } + + offset = bbshdr.hdrsize + (nrecno * bbshdr.recsize); + if(fseek(pBBSLine, offset, 0) != 0) + WriteError("Can't move pointer there. %s",sFileName); + fwrite(&bbs, sizeof(bbs), 1, pBBSLine); + } + + fclose(pBBSLine); +} + + diff --git a/mbsebbs/bbslist.h b/mbsebbs/bbslist.h new file mode 100644 index 00000000..fe80e356 --- /dev/null +++ b/mbsebbs/bbslist.h @@ -0,0 +1,11 @@ +#ifndef _BBSLIST_H +#define _BBSLIST_H + +void BBS_Add(void); +void BBS_List(void); +void BBS_Show(void); +void BBS_Delete(void); +void BBS_Search(void); + +#endif + diff --git a/mbsebbs/bye.c b/mbsebbs/bye.c new file mode 100644 index 00000000..7df8f496 --- /dev/null +++ b/mbsebbs/bye.c @@ -0,0 +1,164 @@ +/***************************************************************************** + * + * File ..................: bbs/bye.c + * Purpose ...............: Hangup functions + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs.h" +#include "language.h" +#include "bye.h" + + +extern pid_t mypid; +extern time_t t_start; +int do_mailout = FALSE; + + +void Good_Bye(int onsig) +{ + FILE *pUsrConfig, *pExitinfo; + char *temp; + long offset; + time_t t_end; + + IsDoing("Hangup"); + temp = calloc(PATH_MAX, sizeof(char)); + Syslog('+', "Good_Bye()"); + + if (onsig != SIGHUP) + DisplayFile((char *)"goodbye"); + + if (do_mailout) + CreateSema((char *)"mailout"); + + + /* + * Update the users database record. + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"r+b")) != NULL) { + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + if ((pExitinfo = fopen(temp,"rb")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + + usrconfig = exitinfo; + fclose(pExitinfo); + + usrconfig.iLastFileArea = iAreaNumber; + if (!iAreaNumber) + WriteError("Setting filearea to zero"); + usrconfig.iHangUps++; + + /* If time expired, do not say say successful logoff */ + if(!iExpired) + Syslog('+', "User successfully logged off BBS"); + + usrconfig.iLastMsgArea = iMsgAreaNumber; + + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if(fseek(pUsrConfig, offset, 0) != 0) { + WriteError("Can't move pointer in file %s", temp); + ExitClient(1); + } + + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + } + } + + time(&t_end); + Syslog(' ', "MBSEBBS finished in %s", t_elapsed(t_start, t_end)); + + /* + * Start shutting down this session + */ + socket_shutdown(mypid); + sprintf(temp, "%s/tmp/mbsebbs%d", getenv("MBSE_ROOT"), getpid()); + unlink(temp); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + unlink(temp); + free(temp); + unlink("taglist"); + + /* + * Flush all data to the user, wait 5 seconds to + * be sure the user received all data, this program + * and parent are also finished. + */ + colour(7, 0); + fflush(stdout); + fflush(stdin); + sleep(5); + + Unsetraw(); + Free_Language(); + free(pTTY); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(onsig); +} + + + +void Quick_Bye(int onsig) +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + Syslog('+', "Quick_Bye"); + socket_shutdown(mypid); + sprintf(temp, "%s/tmp/mbsebbs%d", getenv("MBSE_ROOT"), getpid()); + unlink(temp); + free(temp); + + colour(7, 0); + fflush(stdout); + fflush(stdin); + sleep(3); + + Free_Language(); + free(pTTY); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); +} + + + diff --git a/mbsebbs/bye.h b/mbsebbs/bye.h new file mode 100644 index 00000000..816a0cf6 --- /dev/null +++ b/mbsebbs/bye.h @@ -0,0 +1,8 @@ +#ifndef _BYE_H +#define _BYE_H + +void Quick_Bye(int); +void Good_Bye(int); + +#endif + diff --git a/mbsebbs/change.c b/mbsebbs/change.c new file mode 100644 index 00000000..b7886d9b --- /dev/null +++ b/mbsebbs/change.c @@ -0,0 +1,817 @@ +/***************************************************************************** + * + * File ..................: bbs/change.c + * Purpose ...............: Change user settings + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "change.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "pwcheck.h" +#include "timeout.h" +#include "exitinfo.h" +#include "bye.h" + + +int Chg_Language(int NewMode) +{ + FILE *pLang; + int iLang, iFoundLang = FALSE; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + if (!NewMode) + ReadExitinfo(); + + while(TRUE) { + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if(( pLang = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("\nFATAL: Can't open language file\n\n"); + Pause(); + free(temp); + Quick_Bye(0); + } + fread(&langhdr, sizeof(langhdr), 1, pLang); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select your preferred language */ + printf("\n%s\n\n", (char *) Language(378)); + + iLang = 6; + colour(9,0); + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) + if (lang.Available) { + colour(13, 0); + printf("(%s)", lang.LangKey); + colour(8,0); + printf(" %c ", 46); + colour(3,0); + printf("%-29s ", lang.Name); + + iLang++; + if ((iLang % 2) == 0) + printf("\n"); + } + Enter(1); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select language: */ + printf("\n%s", (char *) Language(379)); + + fflush(stdout); + alarm_on(); + iLang = toupper(Getone()); + + printf("%c", iLang); + + fseek(pLang, langhdr.hdrsize, 0); + + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) { + strcpy(lang.LangKey,tu(lang.LangKey)); + if ((lang.LangKey[0] == iLang) && (lang.Available)) { + strcpy(CFG.current_language, lang.Filename); + iFoundLang = TRUE; + break; + } + } + + fclose(pLang); + + if(!iFoundLang) { + Enter(2); + /* Invalid selection, please try again! */ + pout(10, 0, (char *) Language(265)); + Enter(2); + } else { + exitinfo.iLanguage = iLang; + strcpy(CFG.current_language, lang.Filename); + Free_Language(); + InitLanguage(); + + colour(10, 0); + /* Language now set to" */ + printf("\n\n%s%s\n\n", (char *) Language(380), lang.Name); + + if (!NewMode) { + Syslog('+', "Changed language to %s", lang.Name); + WriteExitinfo(); + Pause(); + } + break; + } + } + + free(temp); + Enter(1); + return iLang; +} + + + +void Chg_Password() +{ + unsigned long crc, crctmp; + char *temp1, *temp2; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + DisplayFile((char *)"password"); + + Enter(1); + /* Old password: */ + language(15, 0, 120); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + Getpass(temp1); + crctmp = StringCRC32(tu(temp1)); + + if (exitinfo.iPassword == crctmp) { + while (TRUE) { + Enter(1); + /* New password: */ + language(9, 0, 121); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + Getpass(temp1); + if((strlen(temp1)) >= CFG.password_length) { + Enter(1); + /* Confirm new password: */ + language(9, 0, 122); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getpass(temp2); + if(( strcmp(temp1,temp2)) != 0) { + /* Passwords do not match! */ + Enter(2); + language(12, 0, 123); + Enter(1); + } else { + fflush(stdout); + fflush(stdin); + crc = StringCRC32(tu(temp1)); + break; + } + } else { + colour(12, 0); + /* Your password must contain at least %d characters! Try again.*/ + printf("\n%s%d %s\n\n", (char *) Language(42), CFG.password_length, (char *) Language(43)); + } + } + + Syslog('+', "%s/bin/mbpasswd -n %s ******", getenv("MBSE_ROOT"), exitinfo.Name); + sprintf(temp1, "%s/bin/mbpasswd -n %s %s", getenv("MBSE_ROOT"), exitinfo.Name, temp2); + if (system(temp1) != 0) { + WriteError("Failed to set new Unix password"); + } else { + exitinfo.iPassword = crc; + memset(&exitinfo.Password, 0, sizeof(exitinfo.Password)); + sprintf(exitinfo.Password, "%s", temp2); + Enter(1); + /* Password Change Successful */ + language(10, 0, 124); + Syslog('+', "User changed his password"); + WriteExitinfo(); + } + } else { + Enter(1); + /* Old password incorrect! */ + language(12, 0, 125); + } + + free(temp1); + free(temp2); + Enter(2); + Pause(); +} + + + +/* + * Function will allow a user to change his handle + */ +void Chg_Handle() +{ + char *Handle, *temp; + + Handle = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + ReadExitinfo(); + Syslog('+', "Old handle \"%s\"", exitinfo.sHandle); + + while (TRUE) { + Enter(1); + /* Enter a handle (Enter to Quit): */ + pout(9, 0, (char *) Language(412)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getname(temp, 34); + + if((strcmp(temp, "")) == 0) { + free(Handle); + free(temp); + return; + } + + strcpy(Handle, tl(temp)); + + if (CheckHandle(Handle)) + pout(12, 0, (char *)"\nThat handle is already been used\n"); + else + if (CheckName(Handle)) + pout(12, 0, (char *)"\nThat name is already been used\n"); + else + if((strcmp(Handle, "sysop")) == 0) + pout(12, 0, (char *)"\nYou cannot use Sysop as a handle\n"); + else { + if(strcmp(temp, "") != 0) { + Setup(exitinfo.sHandle, temp); + pout(10, 0, (char *)"\nHandle Changed!\n\n"); + Syslog('+', "New handle \"%s\"", exitinfo.sHandle); + break; + } + } + } + + WriteExitinfo(); + free(temp); + free(Handle); +} + + + +/* + * Toggle hotkeys + */ +void Chg_Hotkeys() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.HotKeys) { + exitinfo.HotKeys = FALSE; + /* Hotkeys are now OFF */ + pout(10, 0, (char *) Language(146)); + } else { + exitinfo.HotKeys = TRUE; + /* Hotkeys are now ON */ + pout(10, 0, (char *) Language(145)); + } + + Enter(2); + sleep(2); + Syslog('+', "Hotkeys changed to %s", exitinfo.HotKeys?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle Mail Check + */ +void Chg_MailCheck() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.MailScan) { + exitinfo.MailScan = FALSE; + /* New Mail check is now OFF */ + pout(10, 0, (char *) Language(367)); + } else { + exitinfo.MailScan = TRUE; + /* New Mail check is now ON */ + pout(10, 0, (char *) Language(366)); + } + + Enter(2); + sleep(2); + Syslog('+', "New Mail Check changed to %s", exitinfo.MailScan ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle New Files Check + */ +void Chg_FileCheck() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.ieFILE) { + exitinfo.ieFILE = FALSE; + /* New Files check is now OFF */ + pout(10, 0, (char *) Language(371)); + } else { + exitinfo.ieFILE = TRUE; + /* New Files check is now ON */ + pout(10, 0, (char *) Language(370)); + } + + Enter(2); + sleep(2); + Syslog('+', "Check New Files changed to %s", exitinfo.ieFILE ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Toggle Fullscreen Editor + */ +void Chg_FsMsged() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.FsMsged) { + exitinfo.FsMsged = FALSE; + /* Fullscreen Editor is now OFF */ + pout(10, 0, (char *) Language(373)); + } else { + exitinfo.FsMsged = TRUE; + /* Fullscreen Editor is now ON */ + pout(10, 0, (char *) Language(372)); + } + + Enter(2); + sleep(2); + Syslog('+', "Fullscreen Editor changed to %s", exitinfo.FsMsged ?"True":"False"); + WriteExitinfo(); +} + + + +/* + * Function to toggle DoNotDisturb Flag + */ +void Chg_Disturb() +{ + ReadExitinfo(); + colour(10, 0); + + if(exitinfo.DoNotDisturb) { + exitinfo.DoNotDisturb = FALSE; + /* Do not disturb turned OFF */ + printf("\n%s\n", (char *) Language(416)); + } else { + exitinfo.DoNotDisturb = TRUE; + /* Do not disturb turned ON */ + printf("\n%s\n", (char *) Language(417)); + } + + Syslog('+', "Do not disturb now %s", exitinfo.DoNotDisturb?"True":"False"); + UserSilent(exitinfo.DoNotDisturb); + sleep(2); + WriteExitinfo(); +} + + + +void Chg_Location() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old location \"%s\"", exitinfo.sLocation); + + while (TRUE) { + /* Old Location: */ + Enter(1); + /* Old location: */ + pout(15, 0, (char *) Language(73)); + colour(9, 0); + printf("%s\n", exitinfo.sLocation); + Enter(1); + /* Please enter your location: */ + pout(14, 0, (char *) Language(49)); + + if(CFG.iCapLocation) { + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetnameNE(temp, 24); + } else { + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + if((strcmp(temp, "")) == 0) + break; + + if(( strlen(temp)) < CFG.CityLen) { + Enter(1); + /* Please enter a longer location (min */ + colour(12, 0); + printf("%s%d)", (char *) Language(74), CFG.CityLen); + Enter(1); + } else { + Setup(exitinfo.sLocation,temp); + break; + } + } + + Syslog('+', "New location \"%s\"", exitinfo.sLocation); + WriteExitinfo(); +} + + + +/* + * Toggle Graphics + */ +void Chg_Graphics() +{ + ReadExitinfo(); + Enter(2); + + if (exitinfo.GraphMode) { + exitinfo.GraphMode = FALSE; + /* Ansi Mode turned OFF */ + pout(15, 0, (char *) Language(76)); + } else { + exitinfo.GraphMode = TRUE; + /* Ansi Mode turned ON */ + pout(15, 0, (char *) Language(75)); + } + + Syslog('+', "Graphics mode now %s", exitinfo.GraphMode?"On":"Off"); + Enter(2); + TermInit(exitinfo.GraphMode); + WriteExitinfo(); + sleep(2); +} + + + +void Chg_VoicePhone() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old voice phone \"%s\"", exitinfo.sVoicePhone); + + while (TRUE) { + Enter(1); + /* Please enter you Voice Number */ + pout(10, 0, (char *) Language(45)); + Enter(1); + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetPhone(temp, 16); + + if (strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + pout(12, 0, (char *) Language(47)); + Enter(1); + } else { + strcpy(exitinfo.sVoicePhone, temp); + break; + } + } + + Syslog('+', "New voice phone \"%s\"", exitinfo.sVoicePhone); + WriteExitinfo(); +} + + + +void Chg_DataPhone() +{ + char temp[81]; + + ReadExitinfo(); + Syslog('+', "Old data phone \"%s\"", exitinfo.sDataPhone); + + while (1) { + Enter(1); + /* Please enter you Data Number */ + pout(10, 0, (char *) Language(48)); + Enter(1); + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + GetPhone(temp, 16); + + if( strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + pout(12, 0, (char *) Language(47)); + Enter(1); + } else { + strcpy(exitinfo.sDataPhone, temp); + break; + } + } + + Syslog('+', "New data phone \"%s\"", exitinfo.sDataPhone); + WriteExitinfo(); +} + + + +void Chg_News() +{ + ReadExitinfo(); + + if (exitinfo.ieNEWS) { + exitinfo.ieNEWS = FALSE; + /* News bulletins turned OFF */ + printf("\n\n%s\n\n", (char *) Language(79)); + } else { + exitinfo.ieNEWS = TRUE; + /* News bulletins turned ON */ + printf("\n\n%s\n\n", (char *) Language(78)); + } + + Syslog('+', "News bullentins now %s", exitinfo.ieNEWS?"True":"False"); + sleep(2); + WriteExitinfo(); +} + + + +void Chg_ScreenLen() +{ + char *temp; + + ReadExitinfo(); + temp = calloc(81, sizeof(char)); + Syslog('+', "Old screenlen %d", exitinfo.iScreenLen); + fflush(stdin); + + Enter(1); + /* Please enter your Screen Length? [24]: */ + pout(13, 0, (char *) Language(64)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + Getnum(temp, 2); + + if((strcmp(temp, "")) == 0) { + exitinfo.iScreenLen = 24; + printf("\n%s\n\n", (char *) Language(80)); + } else { + exitinfo.iScreenLen = atoi(temp); + printf("\n%s%d\n\n", (char *) Language(81), exitinfo.iScreenLen); + } + + Syslog('+', "New screenlen %d", exitinfo.iScreenLen); + WriteExitinfo(); + Pause(); + free(temp); +} + + + +/* + * Check users Date of Birth, if it is ok, we calculate his age. + */ +int Test_DOB(char *DOB) +{ + int tyear, year, month, day; + char temp[40], temp1[40]; + + /* First check length of string */ + if (strlen(DOB) != 10) { + Syslog('!', "Date format length %d characters", strlen(DOB)); + /* Please enter the correct date format */ + language(14, 0, 83); + return FALSE; + } + /* + * Split the date into pieces + */ + strcpy(temp1, DOB); + strcpy(temp, strtok(temp1, "-")); + day = atoi(temp); + strcpy(temp, strtok(NULL, "-")); + month = atoi(temp); + strcpy(temp, strtok(NULL, "")); + year = atoi(temp); + tyear = l_date->tm_year + 1900; + + if (((tyear - year) < 10) || ((tyear - year) > 95)) { + Syslog('!', "DOB: Year error: %d", tyear - year); + return FALSE; + } + if ((month < 1) || (month > 12)) { + Syslog('!', "DOB: Month error: %d", month); + return FALSE; + } + if ((day < 1) || (day > 31)) { + Syslog('!', "DOB: Day error: %d", day); + return FALSE; + } + + UserAge = tyear - year; + if ((l_date->tm_mon + 1) < month) + UserAge--; + if (((l_date->tm_mon + 1) == month) && (l_date->tm_mday < day)) + UserAge--; + Syslog('B', "DOB: Users age %d year", UserAge); + return TRUE; +} + + + +void Chg_DOB() +{ + char *temp; + + temp = calloc(81, sizeof(char)); + + ReadExitinfo(); + Syslog('+', "Old DOB %s", exitinfo.sDateOfBirth); + + while (TRUE) { + Enter(1); + /* Please enter your Date of Birth DD-MM-YYYY: */ + pout(3, 0, (char *) Language(56)); + colour(CFG.InputColourF, CFG.InputColourB); + GetDate(temp, 10); + if (Test_DOB(temp)) { + Setup(exitinfo.sDateOfBirth, temp); + break; + } + } + + Syslog('+', "New DOB %s", exitinfo.sDateOfBirth); + WriteExitinfo(); + free(temp); +} + + + + +/* + * Change default protocol. + */ +void Chg_Protocol() +{ + FILE *pProtConfig; + int iProt, iFoundProt = FALSE; + int precno = 0; + char *temp; + char Prot[2]; + + temp = calloc(PATH_MAX, sizeof(char)); + ReadExitinfo(); + Syslog('+', "Old protocol %s", sProtName); + + while(TRUE) { + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + + if ((pProtConfig = fopen(temp, "r")) == NULL) { + WriteError("$Can't open %s", temp); + /* Protocol: Can't open protocol file. */ + printf("\n%s\n\n", (char *) Language(262)); + Pause(); + free(temp); + fclose(pProtConfig); + return; + } + fread(&PROThdr, sizeof(PROThdr), 1, pProtConfig); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Select your preferred protocol */ + printf("\n%s\n\n", (char *) Language(263)); + + colour(9,0); + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) + if (PROT.Available && Access(exitinfo.Security, PROT.Level)) + printf("(%s) %-20s Efficiency %3d %%\n", PROT.ProtKey, PROT.ProtName, PROT.Efficiency); + + colour(CFG.HiliteF, CFG.HiliteB); + printf("\n%s", (char *) Language(264)); + + fflush(stdout); + alarm_on(); + iProt = toupper(Getone()); + + printf("%c", iProt); + sprintf(Prot, "%c", iProt); + + fseek(pProtConfig, PROThdr.hdrsize, 0); + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) { + if ((strncmp(PROT.ProtKey, Prot, 1) == 0) && + PROT.Available && Access(exitinfo.Security, PROT.Level)) { + strcpy(sProtName, PROT.ProtName); + strcpy(sProtUp, PROT.ProtUp); + strcpy(sProtDn, PROT.ProtDn); + strcpy(sProtAdvice, PROT.Advice); + uProtBatch = PROT.Batch; + uProtBidir = PROT.Bidir; + iProtEfficiency = PROT.Efficiency; + iFoundProt = TRUE; + } else + precno++; + } + + fclose(pProtConfig); + + if (iProt == 13) { + free(temp); + return; + } else + if (!iFoundProt) { + Enter(2); + pout(10, 0, (char *) Language(265)); + Enter(2); + /* Loop for new attempt */ + } else { + Setup(exitinfo.sProtocol, sProtName); + colour(10,0); + /* Protocol now set to: */ + printf("\n\n%s%s\n\n", (char *) Language(266), sProtName); + Pause(); + break; + } + } + + Syslog('+', "New protocol %s", sProtName); + WriteExitinfo(); + free(temp); +} + + + +void Set_Protocol(char *Protocol) +{ + FILE *pProtConfig; + int precno = 0; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + + if(( pProtConfig = fopen(temp, "rb")) == NULL) { + WriteError("$Can't open %s", temp); + /* Protocol: Can't open protocol file. */ + printf("\n%s\n\n", (char *) Language(262)); + Pause(); + free(temp); + return; + } + + fread(&PROThdr, sizeof(PROThdr), 1, pProtConfig); + + while (fread(&PROT, PROThdr.recsize, 1, pProtConfig) == 1) { + if ((strcmp(PROT.ProtName, Protocol)) == 0) { + tlf(sProtName); + strcpy(sProtName, PROT.ProtName); + strcpy(sProtUp, PROT.ProtUp); + strcpy(sProtDn, PROT.ProtDn); + strcpy(sProtAdvice, PROT.Advice); + uProtBatch = PROT.Batch; + uProtBidir = PROT.Bidir; + iProtEfficiency = PROT.Efficiency; + } else + precno++; + } + + free(temp); + fclose(pProtConfig); +} + + + diff --git a/mbsebbs/change.h b/mbsebbs/change.h new file mode 100644 index 00000000..04b0bd8d --- /dev/null +++ b/mbsebbs/change.h @@ -0,0 +1,26 @@ +#ifndef _CHANGE_H +#define _CHANGE_H + + +int Chg_Language(int); /* Change language */ +void Chg_Password(void); /* Change BBS Password */ +void Chg_Handle(void); /* Change Handle */ +void Chg_Hotkeys(void); /* Toggle Hotkeys */ +void Chg_Disturb(void); /* Toggle "Do not disturb" */ +void Chg_MailCheck(void); /* Toggle New Mail Check */ +void Chg_FileCheck(void); /* Toggle New Files Check */ +void Chg_FsMsged(void); /* Toggle Fullscreen Editor */ +void Chg_Location(void); /* Change location */ +void Chg_Graphics(void); /* Toggle graphics */ +void Chg_VoicePhone(void); /* Change voicephone */ +void Chg_DataPhone(void); /* Change dataphone */ +void Chg_News(void); /* Toggle News Bulletins */ +void Chg_ScreenLen(void); /* Change screen len */ +int Test_DOB(char *); /* Test of Date of Birth is valid */ +void Chg_DOB(void); /* Change Date of Birth */ +void Chg_Protocol(void); /* Change default transfer protocol. */ +void Set_Protocol(char *); /* Set default protocol */ + + +#endif + diff --git a/mbsebbs/chat.c b/mbsebbs/chat.c new file mode 100644 index 00000000..1f359d28 --- /dev/null +++ b/mbsebbs/chat.c @@ -0,0 +1,194 @@ +/***************************************************************************** + * + * File ..................: bbs/chat.c + * Purpose ...............: Sysop to user chat utility + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "chat.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "exitinfo.h" + + + +#define DEVICE "/tmp/chatdev" + + + + +void Chat(void) +{ + FILE *pGetDev, *pLog, *pBusy, *pChat; + int ch; + int iLetter = 0; + char sDevice[20]; + char *sLog = NULL; + char temp[81] = ""; + + if(CFG.iAutoLog) + sLog = calloc(56, sizeof(char)); + + WhosDoingWhat(SYSOPCHAT); + + clear(); + + if((pGetDev = fopen(DEVICE,"r")) == NULL) + WriteError("Can't open file:", DEVICE); + else { + fscanf(pGetDev, "%19s", sDevice); + fclose(pGetDev); + } + + if(( pChat = fopen(sDevice,"w")) == NULL) + perror("Error"); + + /* + * Check to see if it must load a external chat program + * Check the length of the chat program is greater than Zero + * Check if user has execute permisson on the chat program + */ + if(!CFG.iExternalChat || (strlen(CFG.sExternalChat) < 1) || \ + (access(CFG.sExternalChat, X_OK) != 0)) { + if ((pBusy = fopen("/tmp/.BusyChatting", "w")) == NULL) + WriteError("Unable to open BusyChatting file", "/tmp/.BusyChatting"); + else { + fprintf(pBusy, "%s", pTTY); + fclose(pBusy); + } + + sprintf(temp, "/tmp/.chat.%s", pTTY); + if(( pBusy = fopen(temp, "w")) == NULL) + WriteError("Unable to open chat.tty file", temp); + else + fclose(pBusy); + + colour(10, 0); + printf("%s\n\r", (char *) Language(59)); + fflush(stdout); + Setraw(); + + sleep(2); + + Syslog('+', "Sysop chat started"); + + fprintf(pChat, "%s is ready ... \n\r",exitinfo.sUserName); + + while (1) { + ch = getc(stdin); + ch &= '\377'; + /* The next statement doesn't work, the chat will start again */ + if (ch == '\007') { + Syslog('+', "Sysop chat ended - User exited chat"); + unlink("/tmp/chatdev"); + sprintf(temp, "/tmp/.chat.%s", pTTY); + unlink(temp); + unlink("/tmp/.BusyChatting"); + Unsetraw(); + break; + } + putchar(ch); + putc(ch, pChat); + + if(CFG.iAutoLog) { + if(ch != '\b') + iLetter++; /* Count the letters user presses for logging */ + sprintf(sLog, "%s%c", sLog, ch); + } + + if (ch == '\n') { + ch = '\r'; + putchar(ch); + putc(ch, pChat); + } + + if (ch == '\r') { + ch = '\n'; + putchar(ch); + putc(ch, pChat); + } + + if (ch == '\b') { + ch = ' '; + putchar(ch); + putc(ch, pChat); + ch = '\b'; + putchar(ch); + putc(ch, pChat); + + if(CFG.iAutoLog) + sLog[--iLetter] = '\0'; + } + + /* Check if log chat is on and if so log chat to disk */ + if(CFG.iAutoLog) { + if(iLetter >= 55 || ch == '\n') { + iLetter = 0; + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), CFG.chat_log); + if(( pLog = fopen(temp, "a+")) != NULL) { + fflush(pLog); + fprintf(pLog, "%s [%s]: %s\n", exitinfo.sUserName, (char *) GetLocalHM(), sLog); + fclose(pLog); + strcpy(sLog, ""); + } + } + } + + if(access("/tmp/chatdev", R_OK) != 0) { + colour(10, 0); + printf("\n\n\n%s\n\n\r", (char *) Language(60)); + Syslog('+', "Sysop chat ended"); + sprintf(temp, "/tmp/.chat.%s", pTTY); + unlink(temp); + unlink("/tmp/.BusyChatting"); + Unsetraw(); + Pause(); + break; + } + } + /* End of ExternalChat Check */ + } else { + system(CFG.sExternalChat); + printf("\n\n"); + Pause(); + } + + if(CFG.iAutoLog) + free(sLog); + + fclose(pChat); +} + + diff --git a/mbsebbs/chat.h b/mbsebbs/chat.h new file mode 100644 index 00000000..766333be --- /dev/null +++ b/mbsebbs/chat.h @@ -0,0 +1,8 @@ +#ifndef _CHAT_H +#define _CHAT_H + +void Chat(void); /* Chat Function */ + +#endif + + diff --git a/mbsebbs/commonio.c b/mbsebbs/commonio.c new file mode 100644 index 00000000..3c3fa706 --- /dev/null +++ b/mbsebbs/commonio.c @@ -0,0 +1,746 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/commonio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 07-Feb-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SHADOW_PASSWORD +#include +#endif +#include "commonio.h" + +/* local function prototypes */ +static int check_link_count (const char *); +static int do_lock_file (const char *, const char *); +static FILE *fopen_set_perms (const char *, const char *, const struct stat *); +static int create_backup (const char *, FILE *); +static void free_linked_list (struct commonio_db *); +static void add_one_entry (struct commonio_db *, struct commonio_entry *); +static int name_is_nis (const char *); +static int write_all (const struct commonio_db *); +static struct commonio_entry *find_entry_by_name (struct commonio_db *, const char *); + + +static int check_link_count(const char *file) +{ + struct stat sb; + + if (stat(file, &sb) != 0) + return 0; + + if (sb.st_nlink != 2) + return 0; + + return 1; +} + + +static int do_lock_file(const char *file, const char *lock) +{ + int fd; + int pid; + int len; + int retval; + char buf[32]; + + if ((fd = open(file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) + return 0; + + pid = getpid(); + snprintf(buf, sizeof buf, "%d", pid); + len = strlen(buf) + 1; + if (write (fd, buf, len) != len) { + close(fd); + unlink(file); + return 0; + } + close(fd); + + if (link(file, lock) == 0) { + retval = check_link_count(file); + unlink(file); + return retval; + } + + if ((fd = open(lock, O_RDWR)) == -1) { + unlink(file); + errno = EINVAL; + return 0; + } + len = read(fd, buf, sizeof(buf) - 1); + close(fd); + if (len <= 0) { + unlink(file); + errno = EINVAL; + return 0; + } + buf[len] = '\0'; + if ((pid = strtol(buf, (char **) 0, 10)) == 0) { + unlink(file); + errno = EINVAL; + return 0; + } + if (kill(pid, 0) == 0) { + unlink(file); + errno = EEXIST; + return 0; + } + if (unlink(lock) != 0) { + unlink(file); + return 0; + } + + retval = 0; + if (link(file, lock) == 0 && check_link_count(file)) + retval = 1; + + unlink(file); + return retval; +} + + + +static FILE *fopen_set_perms(const char *name, const char *mode, const struct stat *sb) +{ + FILE *fp; + int mask; + + mask = umask(0777); + fp = fopen(name, mode); + umask(mask); + if (!fp) + return NULL; + +#ifdef HAVE_FCHMOD + if (fchmod(fileno(fp), sb->st_mode & 0777)) + goto fail; +#else + if (chmod(name, sb->st_mode & 0777)) + goto fail; +#endif + +#ifdef HAVE_FCHOWN + if (fchown(fileno(fp), sb->st_uid, sb->st_gid)) + goto fail; +#else + if (chown(name, sb->st_mode)) + goto fail; +#endif + return fp; + +fail: + fclose(fp); + unlink(name); + return NULL; +} + + + +static int create_backup(const char *backup, FILE *fp) +{ + struct stat sb; + struct utimbuf ub; + FILE *bkfp; + int c, mask; + + if (fstat(fileno(fp), &sb)) + return -1; + + mask = umask(077); + bkfp = fopen(backup, "w"); + umask(mask); + if (!bkfp) + return -1; + + /* TODO: faster copy, not one-char-at-a-time. --marekm */ + rewind(fp); + while ((c = getc(fp)) != EOF) { + if (putc(c, bkfp) == EOF) + break; + } + if (c != EOF || fflush(bkfp)) { + fclose(bkfp); + return -1; + } + if (fclose(bkfp)) + return -1; + + ub.actime = sb.st_atime; + ub.modtime = sb.st_mtime; + utime(backup, &ub); + return 0; +} + + + +static void free_linked_list(struct commonio_db *db) +{ + struct commonio_entry *p; + + while (db->head) { + p = db->head; + db->head = p->next; + + if (p->line) + free(p->line); + + if (p->entry) + db->ops->free(p->entry); + + free(p); + } + db->tail = NULL; +} + + + +int commonio_setname(struct commonio_db *db, const char *name) +{ + strcpy(db->filename, name); + return 1; +} + + + +int commonio_present(const struct commonio_db *db) +{ + return (access(db->filename, F_OK) == 0); +} + + + +int commonio_lock(struct commonio_db *db) +{ + char file[1024]; + char lock[1024]; + + if (db->locked) + return 1; + + snprintf(file, sizeof file, "%s.%ld", db->filename, (long) getpid()); + snprintf(lock, sizeof lock, "%s.lock", db->filename); + if (do_lock_file(file, lock)) { + db->locked = 1; + return 1; + } + return 0; +} + + + +int commonio_lock_first(struct commonio_db *db) +{ +#ifdef HAVE_LCKPWDF + /* + * When locking several files, *_lock_first() is called + * for the first one, and *_lock() for the others. + * If lckpwdf() is available, call it here (it may block + * for up to 15 seconds), and if it succeeds, call + * *_lock() once (no retries, it should always succeed). + */ + + if (lckpwdf() == -1) + return 0; /* failure */ + + if (!commonio_lock(db)) { + ulckpwdf(); + return 0; /* failure */ + } + + return 1; /* success */ +#else + int i; + + /* + * No lckpwdf() - do it the old way. + */ +#ifndef LOCK_TRIES +#define LOCK_TRIES 15 +#endif + for (i = 1; i < LOCK_TRIES; i++) { + if (commonio_lock(db)) + return 1; /* success */ + + sleep(1); + } + + /* + * Retry the last time... + */ + return commonio_lock(db); +#endif /* !HAVE_LCKPWDF */ +} + + + +int commonio_unlock(struct commonio_db *db) +{ + char lock[1024]; + + if (db->isopen) { + db->readonly = 1; + if (!commonio_close(db)) + return 0; + } + if (db->locked) { + db->locked = 0; + snprintf(lock, sizeof lock, "%s.lock", db->filename); + unlink(lock); + return 1; + } + return 0; +} + + + +static void add_one_entry(struct commonio_db *db, struct commonio_entry *p) +{ + p->next = NULL; + p->prev = db->tail; + if (!db->head) + db->head = p; + if (db->tail) + db->tail->next = p; + db->tail = p; +} + + + +static int name_is_nis(const char *n) +{ + return (n[0] == '+' || n[0] == '-'); +} + + +/* + * New entries are inserted before the first NIS entry. Order is preserved + * when db is written out. + */ +#ifndef KEEP_NIS_AT_END +#define KEEP_NIS_AT_END 1 +#endif + +#if KEEP_NIS_AT_END +/* prototype */ +static void add_one_entry_nis (struct commonio_db *, struct commonio_entry *); + +static void add_one_entry_nis(struct commonio_db *db, struct commonio_entry *new) +{ + struct commonio_entry *p; + + for (p = db->head; p; p = p->next) { + if (name_is_nis(p->entry ? db->ops->getname(p->entry) : p->line)) { + new->next = p; + new->prev = p->prev; + if (p->prev) + p->prev->next = new; + else + db->head = new; + p->prev = new; + return; + } + } + add_one_entry(db, new); +} +#endif /* KEEP_NIS_AT_END */ + + + +int commonio_open(struct commonio_db *db, int mode) +{ + char buf[8192]; + char *cp; + char *line; + struct commonio_entry *p; + void *entry; + int flags = mode; + + mode &= ~O_CREAT; + + if (db->isopen || (mode != O_RDONLY && mode != O_RDWR)) { + errno = EINVAL; + return 0; + } + db->readonly = (mode == O_RDONLY); + if (!db->readonly && !db->locked) { + errno = EACCES; + return 0; + } + + db->head = db->tail = db->cursor = NULL; + db->changed = 0; + + db->fp = fopen(db->filename, db->readonly ? "r" : "r+"); + + /* + * If O_CREAT was specified and the file didn't exist, it will be + * created by commonio_close(). We have no entries to read yet. --marekm + */ + if (!db->fp) { + if ((flags & O_CREAT) && errno == ENOENT) { + db->isopen++; + return 1; + } + return 0; + } + + while (db->ops->fgets(buf, sizeof buf, db->fp)) { + if ((cp = strrchr(buf, '\n'))) + *cp = '\0'; + + if (!(line = strdup(buf))) + goto cleanup; + + if (name_is_nis(line)) { + entry = NULL; + } else if ((entry = db->ops->parse(line))) { + entry = db->ops->dup(entry); + if (!entry) + goto cleanup_line; + } + + p = (struct commonio_entry *) malloc(sizeof *p); + if (!p) + goto cleanup_entry; + + p->entry = entry; + p->line = line; + p->changed = 0; + + add_one_entry(db, p); + } + + db->isopen++; + return 1; + +cleanup_entry: + if (entry) + db->ops->free(entry); +cleanup_line: + free(line); +cleanup: + free_linked_list(db); + fclose(db->fp); + db->fp = NULL; + errno = ENOMEM; + return 0; +} + + + +static int write_all(const struct commonio_db *db) +{ + const struct commonio_entry *p; + void *entry; + + for (p = db->head; p; p = p->next) { + if (p->changed) { + entry = p->entry; + if (db->ops->put(entry, db->fp)) + return -1; + } else if (p->line) { + if (db->ops->fputs(p->line, db->fp) == EOF) + return -1; + if (putc('\n', db->fp) == EOF) + return -1; + } + } + return 0; +} + + + +int commonio_close(struct commonio_db *db) +{ + char buf[1024]; + int errors = 0; + struct stat sb; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->isopen = 0; + + if (!db->changed || db->readonly) { + fclose(db->fp); + db->fp = NULL; + goto success; + } + + if (db->fp) { + if (fstat(fileno(db->fp), &sb)) { + fclose(db->fp); + db->fp = NULL; + goto fail; + } + + /* + * Create backup file. + */ + snprintf(buf, sizeof buf, "%s-", db->filename); + + if (create_backup(buf, db->fp)) + errors++; + + if (fclose(db->fp)) + errors++; + + if (errors) { + db->fp = NULL; + goto fail; + } + } else { + /* + * Default permissions for new [g]shadow files. + * (passwd and group always exist...) + */ + sb.st_mode = 0400; + sb.st_uid = 0; + sb.st_gid = 0; + } + + snprintf(buf, sizeof buf, "%s+", db->filename); + + db->fp = fopen_set_perms(buf, "w", &sb); + if (!db->fp) + goto fail; + + if (write_all(db)) + errors++; + + if (fflush(db->fp)) + errors++; +#ifdef HAVE_FSYNC + if (fsync(fileno(db->fp))) + errors++; +#else + sync(); +#endif + if (fclose(db->fp)) + errors++; + + db->fp = NULL; + + if (errors) { + unlink(buf); + goto fail; + } + + if (rename(buf, db->filename)) + goto fail; + +success: + free_linked_list(db); + return 1; + +fail: + free_linked_list(db); + return 0; +} + + + +static struct commonio_entry * find_entry_by_name(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + void *ep; + + for (p = db->head; p; p = p->next) { + ep = p->entry; + if (ep && strcmp(db->ops->getname(ep), name) == 0) + break; + } + return p; +} + + + +int commonio_update(struct commonio_db *db, const void *entry) +{ + struct commonio_entry *p; + void *nentry; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + if (!(nentry = db->ops->dup(entry))) { + errno = ENOMEM; + return 0; + } + p = find_entry_by_name(db, db->ops->getname(entry)); + if (p) { + db->ops->free(p->entry); + p->entry = nentry; + p->changed = 1; + db->cursor = p; + + db->changed = 1; + return 1; + } + /* not found, new entry */ + p = (struct commonio_entry *) malloc(sizeof *p); + if (!p) { + db->ops->free(nentry); + errno = ENOMEM; + return 0; + } + + p->entry = nentry; + p->line = NULL; + p->changed = 1; + +#if KEEP_NIS_AT_END + add_one_entry_nis(db, p); +#else + add_one_entry(db, p); +#endif + + db->changed = 1; + return 1; +} + + + +void commonio_del_entry(struct commonio_db *db, const struct commonio_entry *p) +{ + if (p == db->cursor) + db->cursor = p->next; + + if (p->prev) + p->prev->next = p->next; + else + db->head = p->next; + + if (p->next) + p->next->prev = p->prev; + else + db->tail = p->prev; + + db->changed = 1; +} + + + +int commonio_remove(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen || db->readonly) { + errno = EINVAL; + return 0; + } + p = find_entry_by_name(db, name); + if (!p) { + errno = ENOENT; + return 0; + } + + commonio_del_entry(db, p); + + if (p->line) + free(p->line); + + if (p->entry) + db->ops->free(p->entry); + + return 1; +} + + + +const void * commonio_locate(struct commonio_db *db, const char *name) +{ + struct commonio_entry *p; + + if (!db->isopen) { + errno = EINVAL; + return NULL; + } + p = find_entry_by_name(db, name); + if (!p) { + errno = ENOENT; + return NULL; + } + db->cursor = p; + return p->entry; +} + + + +int commonio_rewind(struct commonio_db *db) +{ + if (!db->isopen) { + errno = EINVAL; + return 0; + } + db->cursor = NULL; + return 1; +} + + + +const void * commonio_next(struct commonio_db *db) +{ + void *entry; + + if (!db->isopen) { + errno = EINVAL; + return 0; + } + if (db->cursor == NULL) + db->cursor = db->head; + else + db->cursor = db->cursor->next; + + while (db->cursor) { + entry = db->cursor->entry; + if (entry) + return entry; + + db->cursor = db->cursor->next; + } + return NULL; +} + diff --git a/mbsebbs/commonio.h b/mbsebbs/commonio.h new file mode 100644 index 00000000..14b98f50 --- /dev/null +++ b/mbsebbs/commonio.h @@ -0,0 +1,108 @@ +#ifndef _COMMONIO_H +#define _COMMONIO_H + + + +/* + * Linked list entry. + */ +struct commonio_entry { + char *line; + int changed; + void *entry; /* struct passwd, struct spwd, ... */ + struct commonio_entry *prev, *next; +}; + + + +/* + * Operations depending on database type: passwd, group, shadow etc. + */ +struct commonio_ops { + /* + * Make a copy of the object (for example, struct passwd) + * and all strings pointed by it, in malloced memory. + */ + void * (*dup) (const void *); + + /* + * free() the object including any strings pointed by it. + */ + void (*free) (void *); + + /* + * Return the name of the object (for example, pw_name + * for struct passwd). + */ + const char * (*getname) (const void *); + + /* + * Parse a string, return object (in static area - + * should be copied using the dup operation above). + */ + void * (*parse) (const char *); + + /* + * Write the object to the file (this calls putpwent() + * for struct passwd, for example). + */ + int (*put) (const void *, FILE *); + + /* + * fgets and fputs (can be replaced by versions that + * understand line continuation conventions). + */ + char * (*fgets) (char *, int, FILE *); + int (*fputs) (const char *, FILE *); +}; + + + +/* + * Database structure. + */ +struct commonio_db { + /* + * Name of the data file. + */ + char filename[1024]; + + /* + * Operations from above. + */ + struct commonio_ops *ops; + + /* + * Currently open file stream. + */ + FILE *fp; + + /* + * Head, tail, current position in linked list. + */ + struct commonio_entry *head, *tail, *cursor; + + /* + * Various flags. + */ + int changed, isopen, locked, readonly; +}; + + + +int commonio_setname (struct commonio_db *, const char *); +int commonio_present (const struct commonio_db *); +int commonio_lock (struct commonio_db *); +int commonio_lock_first (struct commonio_db *); +int commonio_open (struct commonio_db *, int); +const void *commonio_locate (struct commonio_db *, const char *); +int commonio_update (struct commonio_db *, const void *); +int commonio_remove (struct commonio_db *, const char *); +int commonio_rewind (struct commonio_db *); +const void *commonio_next (struct commonio_db *); +int commonio_close (struct commonio_db *); +int commonio_unlock (struct commonio_db *); +void commonio_del_entry (struct commonio_db *, const struct commonio_entry *); + +#endif + diff --git a/mbsebbs/email.c b/mbsebbs/email.c new file mode 100644 index 00000000..259bd067 --- /dev/null +++ b/mbsebbs/email.c @@ -0,0 +1,1041 @@ +/***************************************************************************** + * + * File ..................: bbs/email.c + * Purpose ...............: Internet email + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "exitinfo.h" +#include "language.h" +#include "mail.h" +#include "timeout.h" +#include "msgutil.h" +#include "funcs4.h" +#include "email.h" + + +extern unsigned long LastNum; +extern int Kludges; +extern FILE *qf; +extern char *Message[]; +extern int Line; +extern int do_mailout; + + + +/* + * Internal prototypes + */ +int HasNoEmail(void); +int Export_a_Email(unsigned long); +int EmailPanel(void); +void Reply_Email(int); +int Save_Email(int); + + + +int HasNoEmail(void) +{ + if (exitinfo.Email) + return FALSE; + + colour(15, 0); + printf("\nYou have no e-mail access\n\n"); + sleep(3); + return TRUE; +} + + + +/* + * Show message header screen top for reading messages. + */ +void ShowEmailHdr(void) +{ + static char Buf1[35], Buf2[35], Buf3[81]; + struct tm *tm; + + Buf1[0] = '\0'; + Buf2[0] = '\0'; + Buf3[0] = '\0'; + + clear(); + colour(1,7); + printf(" %-70s", sMailbox); + + colour(4,7); + printf("#%-5lu\n", Msg.Id); + + /* Date : */ + pout(14, 0, (char *) Language(206)); + colour(10, 0); + tm = gmtime(&Msg.Written); + printf("%02d-%02d-%d %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, + tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec); + colour(12, 0); + if (Msg.Local) printf(" Local"); + if (Msg.Intransit) printf(" Transit"); + if (Msg.Private) printf(" Priv."); + if (Msg.Received) printf(" Rcvd"); + if (Msg.Sent) printf(" Sent"); + if (Msg.KillSent) printf(" KillSent"); + if (Msg.ArchiveSent) printf(" ArchiveSent"); + if (Msg.Hold) printf(" Hold"); + if (Msg.Crash) printf(" Crash"); + if (Msg.Immediate) printf(" Imm."); + if (Msg.Direct) printf(" Dir"); + if (Msg.Gate) printf(" Gate"); + if (Msg.FileRequest) printf(" Freq"); + if (Msg.FileAttach) printf(" File"); + if (Msg.TruncFile) printf(" TruncFile"); + if (Msg.KillFile) printf(" KillFile"); + if (Msg.ReceiptRequest) printf(" RRQ"); + if (Msg.ConfirmRequest) printf(" CRQ"); + if (Msg.Orphan) printf(" Orphan"); + if (Msg.Encrypt) printf(" Crypt"); + if (Msg.Compressed) printf(" Comp"); + if (Msg.Escaped) printf(" 7bit"); + if (Msg.ForcePU) printf(" FPU"); + if (Msg.Localmail) printf(" Localmail"); + if (Msg.Netmail) printf(" Netmail"); + if (Msg.Echomail) printf(" Echomail"); + if (Msg.News) printf(" News"); + if (Msg.Email) printf(" E-mail"); + if (Msg.Nodisplay) printf(" Nodisp"); + if (Msg.Locked) printf(" LCK"); + if (Msg.Deleted) printf(" Del"); + printf("\n"); + + /* From : */ + pout(14,0, (char *) Language(209)); + colour(10, 0); + printf("%s\n", Msg.From); + + /* To : */ + pout(14,0, (char *) Language(208)); + colour(10, 0); + printf("%s\n", Msg.To); + + /* Subject : */ + pout(14,0, (char *) Language(210)); + colour(10, 0); + printf("%s\n", Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + colour(14, 1); + if (Msg.Reply) + sprintf(Buf1, "\"+\" %s %lu", (char *)Language(211), Msg.Reply); + if (Msg.Original) + sprintf(Buf2, " \"-\" %s %lu", (char *)Language(212), Msg.Original); + sprintf(Buf3, "%s%s ", Buf1, Buf2); + colour(14, 1); + printf("%78s \n", Buf3); +} + + + + +/* + * Export a email to file in the users home directory. + */ +int Export_a_Email(unsigned long Num) +{ + char *p; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + Syslog('+', "Export email %d in area %s", Num, sMailbox); + + /* + * The area data is already set, so we can do the next things + */ + if (EmailBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMailpath)) { + WriteError("Error open JAM base %s", sMailpath); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + + /* + * Export the message text to the file in the users home/wrk directory. + * Create the filename as _.msg The message is + * written in M$DOS format. + */ + p = calloc(PATH_MAX, sizeof(char)); + sprintf(p, "%s/%s/wrk/%s_%lu.msg", CFG.bbs_usersdir, exitinfo.Name, sMailbox, Num); + if ((qf = fopen(p, "w")) != NULL) { + free(p); + p = NULL; + if (Msg_Read(Num, 80)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if (p[0] == '\001') { + if (Kludges) { + p[0] = 'a'; + fprintf(qf, "^%s\r\n", p); + } + } else + fprintf(qf, "%s\r\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + free(p); + } + Msg_Close(); + + /* + * Report the result. + */ + colour(CFG.TextColourF, CFG.TextColourB); + printf("\n\n%s", (char *) Language(46)); + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s_%lu.msg\n\n", sMailbox, Num); + Pause(); + return TRUE; +} + + + +/* + * Save the message to disk. + */ +int Save_Email(int IsReply) +{ + int i; + char *p, *temp; + unsigned long crc = -1; + long id; + FILE *fp; + + if (Line < 2) + return TRUE; + + if (!Open_Msgbase(sMailpath, 'w')) { + return FALSE; + } + + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Written = Msg.Arrived; + Msg.Local = TRUE; + Msg.Netmail = TRUE; + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * Add header lines + */ + sprintf(temp, "\001Date: %s", rfcdate(Msg.Written)); + MsgText_Add2(temp); + sprintf(temp, "\001From: %s", Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001Subject: %s", Msg.Subject); + MsgText_Add2(temp); + sprintf(temp, "\001Sender: %s", Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001To: %s", Msg.To); + MsgText_Add2(temp); + MsgText_Add2((char *)"\001MIME-Version: 1.0"); + MsgText_Add2((char *)"\001Content-Type: text/plain"); + MsgText_Add2((char *)"\001Content-Transfer-Encoding: 8bit"); + sprintf(temp, "\001X-Mailreader: MBSE BBS %s", VERSION); + MsgText_Add2(temp); + p = calloc(81, sizeof(char)); + id = sequencer(); + sprintf(p, "<%08lx@%s>", id, CFG.sysdomain); + sprintf(temp, "\001Message-id: %s", p); + MsgText_Add2(temp); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(CFG.EmailFidoAka), id); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + free(p); + sprintf(temp, "\001PID: MBSE-BBS %s", VERSION); + MsgText_Add2(temp); + + if (IsReply) { + sprintf(temp, "\001In-reply-to: %s", Msg.Replyid); + MsgText_Add2(temp); + crc = -1; + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + } else + Msg.ReplyCRC = 0xffffffff; + + + /* + * Add message text + */ + for (i = 1; i < Line; i++) { + MsgText_Add2(Message[i]); + } + + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + /* + * Save if to disk + */ + Msg_AddMsg(); + Msg_UnLock(); + + ReadExitinfo(); + exitinfo.iPosted++; + WriteExitinfo(); + + do_mailout = TRUE; + + Syslog('+', "Email (%ld) to \"%s\", \"%s\", in mailbox", Msg.Id, Msg.To, Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Saving message to disk */ + printf("\n%s(%ld)\n\n", (char *) Language(202), Msg.Id); + fflush(stdout); + sleep(2); + + /* + * Add quick mailscan info + */ + sprintf(temp, "%s/tmp/netmail.jam", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s/%s/mailbox %lu\n", CFG.bbs_usersdir, exitinfo.Name, Msg.Id); + fclose(fp); + } + + free(temp); + Msg_Close(); + + return TRUE; +} + + + +int Read_a_Email(unsigned long Num) +{ + char *p = NULL, *fn; + lastread LR; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + + /* + * The area data is already set, so we can do the next things + */ + if (EmailBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMailpath)) { + WriteError("Error open JAM base %s", sMailpath); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + ShowEmailHdr(); + + /* + * Fill Quote file in case the user wants to reply. Note that line + * wrapping is set lower then normal message read, to create room + * for the Quote> strings at the start of each line. + */ + fn = calloc(PATH_MAX, sizeof(char)); + sprintf(fn, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(fn, "w")) != NULL) { + if (Msg_Read(Num, 75)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if (p[0] == '\001') { + /* + * While doing this, store the original Message-id in case + * a reply will be made. + */ + if (strncasecmp(p, "\001Message-id: ", 13) == 0) { + sprintf(Msg.Msgid, "%s", p+13); + Syslog('m', "Stored Msgid \"%s\"", Msg.Msgid); + } + if (Kludges) { + p[0] = 'a'; + fprintf(qf, "^%s\n", p); + } + } else + fprintf(qf, "%s\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + free(fn); + + /* + * Show message text + */ + colour(CFG.TextColourF, CFG.TextColourB); + if (Msg_Read(Num, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if (p[0] == '\001') { + if (Kludges) { + colour(7, 0); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, TRUE)) + break; + } + } else { + colour(CFG.TextColourF, CFG.TextColourB); + if (strchr(p, '>') != NULL) + if ((strlen(p) - strlen(strchr(p, '>'))) < 10) + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, TRUE)) + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * Set the Received status on this message. + */ + if (!Msg.Received) { + Syslog('m', "Marking message received"); + Msg.Received = TRUE; + Msg.Read = time(NULL) - (gmt_offset((time_t)0) * 60); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Num); + Msg_UnLock(); + } + } + + /* + * Update lastread pointer. + */ + if (Msg_Lock(30L)) { + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = Num; + if (Num > LR.HighReadMsg) + LR.HighReadMsg = Num; + if (LR.HighReadMsg > EmailBase.Highest) + LR.HighReadMsg = EmailBase.Highest; + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = Num; + LR.HighReadMsg = Num; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append lastread"); + } + free(p); + Msg_UnLock(); + } + + Msg_Close(); + return TRUE; +} + + + +/* + * The panel bar under the message while email reading + */ +int EmailPanel(void) +{ + int input; + + WhosDoingWhat(READ_POST); + + colour(15, 4); + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port */ + printf("%s", (char *) Language(214)); + if (exitinfo.Security.level >= CFG.sysop_access) + printf(", (!)"); + printf(": "); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + + if (input == '!') { + if (exitinfo.Security.level >= CFG.sysop_access) { + if (Kludges) + Kludges = FALSE; + else + Kludges = TRUE; + Read_a_Email(LastNum); + } + } else if (input == Keystroke(214, 0)) { /* (A)gain */ + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 4)) { /* (P)ost */ + Write_Email(); + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 2)) { /* (L)ast */ + if (LastNum > EmailBase.Lowest) + LastNum--; + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 3)) { /* (R)eply */ + Reply_Email(TRUE); + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 5)) { /* (Q)uit */ + /* Quit */ + printf("%s\n", (char *) Language(189)); + return FALSE; + } else if (input == Keystroke(214, 7)) { /* e(X)port */ + Export_a_Email(LastNum); + Read_a_Email(LastNum); + } else if (input == '+') { + if (Msg.Reply) + LastNum = Msg.Reply; + Read_a_Email(LastNum); + } else if (input == '-') { + if (Msg.Original) + LastNum = Msg.Original; + Read_a_Email(LastNum); + } else if (input == Keystroke(214, 6)) { /* (D)elete */ +// Delete_EmailNum(LastNum); + if (LastNum < EmailBase.Highest) { + LastNum++; + Read_a_Email(LastNum); + } else { + return FALSE; + } + } else { + /* Next */ + pout(15, 0, (char *) Language(216)); + if (LastNum < EmailBase.Highest) + LastNum++; + else + return FALSE; + Read_a_Email(LastNum); + } + return TRUE; +} + + + +/* + * Read e-mail, called from the menus + */ +void Read_Email(void) +{ + char *temp; + unsigned long Start; + lastread LR; + + if (HasNoEmail()) + return; + + colour(CFG.TextColourF, CFG.TextColourB); + /* Message area \"%s\" contains %lu messages. */ + printf("\n%s\"%s\" %s%lu %s", (char *) Language(221), sMailbox, (char *) Language(222), EmailBase.Total, (char *) Language(223)); + + /* + * Check for lastread pointer, suggest lastread number for start. + */ + Start = EmailBase.Lowest; + if (Msg_Open(sMailpath)) { + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = 1; + Msg_Close(); + /* + * If we already have read the last message, the pointer is + * higher then HighMsgNum, we set it at HighMsgNum to prevent + * errors and read that message again. + */ + if (Start > EmailBase.Highest) + Start = EmailBase.Highest; + } + + colour(15, 0); + /* Please enter a message between */ + printf("\n%s(%lu - %lu)", (char *) Language(224), EmailBase.Lowest, EmailBase.Highest); + /* Message number [ */ + printf("\n%s%lu]: ", (char *) Language(225), Start); + + temp = calloc(128, sizeof(char)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((strcmp(temp, "")) != 0) + Start = atoi(temp); + free(temp); + + if (!Read_a_Email(Start)) + return; + + if (EmailBase.Total == 0) + return; + + while(EmailPanel()) {} +} + + + +/* + * Reply message, in Msg.From and Msg.Subject must be the + * name to reply to and the subject. + */ +void Reply_Email(int IsReply) +{ + int i, j, x; + char to[65]; + char from[65]; + char subj[72]; + char msgid[81]; + char replyto[81]; + char replyaddr[81]; + char *tmp, *buf; + char qin[9]; + faddr *Dest = NULL; + + sprintf(from, "%s", Msg.To); + sprintf(to, "%s", Msg.From); + sprintf(replyto, "%s", Msg.ReplyTo); + sprintf(replyaddr, "%s", Msg.ReplyAddr); + + if (strncasecmp(Msg.Subject, "Re:", 3) && IsReply) { + sprintf(subj, "Re: %s", Msg.Subject); + } else { + sprintf(subj, "%s", Msg.Subject); + } + Syslog('m', "Reply msg to %s, subject %s", to, subj); + Syslog('m', "Msgid was %s", Msg.Msgid); + sprintf(msgid, "%s", Msg.Msgid); + + x = 0; + Line = 1; + WhosDoingWhat(READ_POST); + clear(); + colour(1,7); + printf(" %-71s", sMailbox); + colour(4,7); + printf("#%-5lu", EmailBase.Highest + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + sLine(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + Msg_New(); + + sprintf(Msg.Replyid, "%s", msgid); + sprintf(Msg.ReplyTo, "%s", replyto); + sprintf(Msg.ReplyAddr, "%s", replyaddr); + + /* From : */ + pout(14, 0, (char *) Language(209)); + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use fidonet.org style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, ascinode(Dest, 0x2f), exitinfo.sUserName); + } else + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From); + Enter(1); + Syslog('b', "Setting From: %s", Msg.From); + + /* To : */ + sprintf(Msg.To, "%s", to); + pout(14, 0, (char *) Language(208)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.To); + Enter(1); + + /* Enter to keep Subject. */ + pout(12, 0, (char *) Language(219)); + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(210)); + sprintf(Msg.Subject, "%s", subj); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.Subject); + + x = strlen(subj); + fflush(stdout); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrP(subj, 50, x); + fflush(stdout); + + if (strlen(subj)) + strcpy(Msg.Subject, subj); + tlf(Msg.Subject); + + Msg.Private = TRUE; + Enter(1); + +// Check_Attach(); + + /* + * Quote original message now, format the original users + * initials into qin. If its a name@system.dom the use the + * first 8 characters of the name part. + */ + sprintf(Message[1], "%s wrote to %s:", to, from); + memset(&qin, 0, sizeof(qin)); + if (strchr(to, '@')) { + tmp = xstrcpy(strtok(to, "@")); + tmp[8] = '\0'; + sprintf(qin, "%s", tmp); + free(tmp); + } else { + x = TRUE; + j = 0; + for (i = 0; i < strlen(to); i++) { + if (x) { + qin[j] = to[i]; + j++; + x = FALSE; + } + if (to[i] == ' ' || to[i] == '.') + x = TRUE; + if (j == 6) + break; + } + } + + Line = 2; + tmp = calloc(128, sizeof(char)); + buf = calloc(128, sizeof(char)); + + sprintf(tmp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(tmp, "r")) != NULL) { + while ((fgets(buf, 128, qf)) != NULL) { + Striplf(buf); + sprintf(Message[Line], "%s> %s", (char *)qin, buf); + Line++; + if (Line == TEXTBUFSIZE) + break; + } + fclose(qf); + } else + WriteError("$Can't read %s", tmp); + + free(buf); + free(tmp); + + if (Edit_Msg()) + Save_Email(IsReply); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +void Write_Email(void) +{ + faddr *Dest = NULL; + int i; + char *orgbox; + + if (HasNoEmail()) + return; + + orgbox = xstrcpy(sMailbox); + SetEmailArea((char *)"mailbox"); + + WhosDoingWhat(READ_POST); + clear(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + + Msg_New(); + + colour(9, 0); + /* Posting message in area: */ + printf("\n%s\"%s\"\n", (char *) Language(156), "mailbox"); + + Enter(1); + /* From : */ + pout(14, 0, (char *) Language(157)); + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use fidonet.org style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, ascinode(Dest, 0x2f), exitinfo.sUserName); + } else + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Msg.From); + Syslog('b', "Setting From: %s", Msg.From); + + Enter(1); + /* To : */ + pout(14, 0, (char *) Language(158)); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrU(Msg.To, 63); + + if ((strcmp(Msg.To, "")) == 0) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + SetEmailArea(orgbox); + return; + } + + /* Subject : */ + pout(14, 0, (char *) Language(161)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Msg.Subject, 65, 0); + tlf(Msg.Subject); + + if((strcmp(Msg.Subject, "")) == 0) { + Enter(1); + /* Abort Message [y/N] ?: */ + pout(3, 0, (char *) Language(162)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(162, 0)) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + SetEmailArea(orgbox); + return; + } + } + + Msg.Private = TRUE; + + if (Edit_Msg()) { + Save_Email(FALSE); + } + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + + SetEmailArea(orgbox); +} + + + +void QuickScan_Email(void) +{ + int FoundMsg = FALSE; + long i; + + iLineCount = 2; + WhosDoingWhat(READ_POST); + + if (EmailBase.Total == 0) { + Enter(1); + /* There are no messages in this area. */ + pout(15, 0, (char *) Language(205)); + Enter(3); + sleep(3); + return; + } + + clear(); + /* # From To Subject */ + poutCR(14, 1, (char *) Language(220)); + + if (Msg_Open(sMailpath)) { + for (i = EmailBase.Lowest; i <= EmailBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + + colour(15, 0); + printf("%-6lu", Msg.Id); + colour(3, 0); + printf("%s ", padleft(Msg.From, 20, ' ')); + + colour(2, 0); + printf("%s ", padleft(Msg.To, 20, ' ')); + colour(5, 0); + printf("%s", padleft(Msg.Subject, 31, ' ')); + printf("\n"); + FoundMsg = TRUE; + if (LC(1)) + break; + } + } + Msg_Close(); + } + + if(!FoundMsg) { + Enter(1); + /* There are no messages in this area. */ + pout(10, 0, (char *) Language(205)); + Enter(2); + sleep(3); + } + + iLineCount = 2; + Pause(); +} + + + +void Trash_Email(void) +{ + if (HasNoEmail()) + return; +} + + + +void Choose_Mailbox(char *Option) +{ + char *temp; + + if (HasNoEmail()) + return; + + if (strlen(Option)) { + if (!strcmp(Option, "M+")) { + if (!strcmp(sMailbox, "mailbox")) + SetEmailArea((char *)"archive"); + else if (!strcmp(sMailbox, "archive")) + SetEmailArea((char *)"trash"); + else if (!strcmp(sMailbox, "trash")) + SetEmailArea((char *)"mailbox"); + } + if (!strcmp(Option, "M-")) { + if (!strcmp(sMailbox, "mailbox")) + SetEmailArea((char *)"trash"); + else if (!strcmp(sMailbox, "trash")) + SetEmailArea((char *)"archive"); + else if (!strcmp(sMailbox, "archive")); + SetEmailArea((char *)"mailbox"); + } + Syslog('+', "Emailarea: %s", sMailbox); + return; + } + + clear(); + Enter(1); + /* Message areas */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(231)); + Enter(2); + + pout(15, 0, (char *)" 1"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(467)); printf("\n"); + pout(15, 0, (char *)" 2"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(468)); printf("\n"); + pout(15, 0, (char *)" 3"); pout(9, 0, (char *)" . "); pout(3, 0, (char *) Language(469)); printf("\n"); + + pout(CFG.MoreF, CFG.MoreB, (char *) Language(470)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + temp = calloc(81, sizeof(char)); + GetstrC(temp, 7); + + switch (atoi(temp)) { + case 1: SetEmailArea((char *)"mailbox"); + break; + case 2: SetEmailArea((char *)"archive"); + break; + case 3: SetEmailArea((char *)"trash"); + break; + } + + Syslog('+', "Emailarea: %s", sMailbox); + free(temp); +} + + + +void SetEmailArea(char *box) +{ + if (!exitinfo.Email) + return; + + sprintf(sMailpath, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, box); + sprintf(sMailbox, "%s", box); + + /* + * Get information from the message base + */ + if (Msg_Open(sMailpath)) { + EmailBase.Lowest = Msg_Lowest(); + EmailBase.Highest = Msg_Highest(); + EmailBase.Total = Msg_Number(); + Msg_Close(); + } else + WriteError("Error open JAM %s", sMailpath); +} + + + diff --git a/mbsebbs/email.h b/mbsebbs/email.h new file mode 100644 index 00000000..81bc9d1f --- /dev/null +++ b/mbsebbs/email.h @@ -0,0 +1,15 @@ +#ifndef _EMAIL_H +#define _EMAIL_H + +void ShowEmailHdr(void); +int Read_a_Email(unsigned long); +void Read_Email(void); +void Write_Email(void); +void QuickScan_Email(void); +void Trash_Email(void); +void Choose_Mailbox(char *); +void SetEmailArea(char *); + + +#endif + diff --git a/mbsebbs/encrypt.c b/mbsebbs/encrypt.c new file mode 100644 index 00000000..f4d4069c --- /dev/null +++ b/mbsebbs/encrypt.c @@ -0,0 +1,142 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/encrypt.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-May-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1990 - 1993, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#ifdef _XOPEN_CRYPT +#include +#endif +#include "encrypt.h" + +#ifdef MD5_CRYPT +extern char *md5_crypt(); +#endif + + +char *pw_encrypt(const char *clear, const char *salt) +{ + static char cipher[128]; + char *cp; +#ifdef SW_CRYPT + static int count; +#endif + +#ifdef MD5_CRYPT + /* + * If the salt string from the password file or from crypt_make_salt() + * begins with the magic string, use the new algorithm. + */ + if (strncmp(salt, "$1$", 3) == 0) + return md5_crypt(clear, salt); +#endif + +#ifdef SW_CRYPT + /* + * Copy over the salt. It is always the first two + * characters of the string. + */ + + cipher[0] = salt[0]; + cipher[1] = salt[1]; + cipher[2] = '\0'; + + /* + * Loop up to ten times on the cleartext password. + * This is because the input limit for passwords is + * 80 characters. + * + * The initial salt is that provided by the user, or the + * one generated above. The subsequent salts are gotten + * from the first two characters of the previous encrypted + * block of characters. + */ + + for (count = 0;count < 10;count++) { + cp = crypt (clear, salt); + if (strlen(cp) != 13) + return cp; + strcat (cipher, cp + 2); + salt = cipher + 11 * count + 2; + + if (strlen (clear) > 8) + clear += 8; + else + break; + } +#else + cp = crypt (clear, salt); + if (strlen(cp) != 13) + return cp; /* nonstandard crypt() in libc, better bail out */ + strcpy (cipher, cp); + +#ifdef DOUBLESIZE + if (strlen (clear) > 8) { + cp = crypt (clear + 8, salt); + strcat (cipher, cp + 2); + } +#endif /* DOUBLESIZE */ +#endif /* SW_CRYPT */ + return cipher; +} + + diff --git a/mbsebbs/encrypt.h b/mbsebbs/encrypt.h new file mode 100644 index 00000000..48feaa89 --- /dev/null +++ b/mbsebbs/encrypt.h @@ -0,0 +1,9 @@ +#ifndef _ENCRYPT_H +#define _ENCRYPT_H + + +char *pw_encrypt(const char *, const char *); + + +#endif + diff --git a/mbsebbs/exitinfo.c b/mbsebbs/exitinfo.c new file mode 100644 index 00000000..4f66be3e --- /dev/null +++ b/mbsebbs/exitinfo.c @@ -0,0 +1,404 @@ +/***************************************************************************** + * + * File ..................: bbs/exitinfo.c + * Purpose ...............: Exitinfo functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "oneline.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" + + + +/* + * Copy usersrecord into ~/tmp/.bbs-exitinfo.tty + */ +void InitExitinfo() +{ + FILE *pUsrConfig, *pExitinfo; + char *temp; + long offset; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + + if ((pUsrConfig = fopen(temp,"r+b")) == NULL) { + WriteError("$Can't open %s for writing", temp); + free(temp); + return; + } + + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if(fseek(pUsrConfig, offset, 0) != 0) { + WriteError("$Can't move pointer in %s", temp); + free(temp); + Good_Bye(1); + } + + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + + exitinfo = usrconfig; + fclose(pUsrConfig); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + mkdirs(temp); + if ((pExitinfo = fopen(temp, "w+b")) == NULL) + WriteError("$Can't open %s for writing", temp); + else { + fwrite(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function will re-read users file in memory, so the latest information + * is available to other functions + */ +void ReadExitinfo() +{ + FILE *pExitinfo; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + mkdirs(temp); + if(( pExitinfo = fopen(temp,"r+b")) == NULL) + InitExitinfo(); + else { + fflush(stdin); + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function will rewrite userinfo from memory, so the latest information + * is available to other functions + */ +void WriteExitinfo() +{ + FILE *pExitinfo; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/tmp/.bbs-exitinfo.%s", getenv("MBSE_ROOT"), pTTY); + if(( pExitinfo = fopen(temp,"w+b")) == NULL) + WriteError("$WriteExitinfo() failed"); + else { + fwrite(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + fclose(pExitinfo); + } + free(temp); +} + + + +/* + * Function to display what users are currently On-Line and what they + * are busy doing + */ +void WhosOn(char *OpData) +{ + FILE *pExitinfo; + DIR *Directory; + char *Heading, *Underline, *temp, *tmp, *device; + struct dirent *Dir; + int i, x; + + Underline = calloc(81, sizeof(char)); + Heading = calloc(81, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + tmp = calloc(PATH_MAX, sizeof(char)); + + WhosDoingWhat(WHOSON); + + clear(); + + Enter(1); + colour(15, 0); + sprintf(Heading, "%s%s", (char *) Language(414), CFG.bbs_name); + Center(Heading); + x = strlen(Heading); + + for(i = 0; i < x; i++) + sprintf(Underline, "%s%c", Underline, exitinfo.GraphMode ? 196 : 45); + + colour(12, 0); + Center(Underline); + + printf("\n"); + + pout(10, 0, (char *) Language(415)); + Enter(1); + + colour(2, 0); + fLine(79); + + sprintf(tmp, "%s/tmp", getenv("MBSE_ROOT")); + if ((Directory = opendir(tmp)) != NULL) + while ((Dir = readdir( Directory )) != NULL) + if((strstr(Dir->d_name, ".bbs-exitinfo.")) != NULL) { + sprintf(temp, "%s/%s", tmp, Dir->d_name); + if(( pExitinfo = fopen(temp, "rb")) != NULL) { + fread(&exitinfo, sizeof(exitinfo), 1, pExitinfo); + + colour(11, 0); + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(exitinfo.sHandle, "") != 0 && *(exitinfo.sHandle) != ' ')) + printf("%-30s", exitinfo.sHandle); + else + printf("%-30s", exitinfo.sUserName); + } else + printf("%-30s", exitinfo.sUserName); + + colour(9, 0); + if((device = strstr(Dir->d_name, "tty")) != NULL) + printf("%-9s", device); + else + printf("%-9s", "None"); + + colour(15, 0); + + /* Browseng */ + if(exitinfo.iStatus == BROWSING) + printf("%-15s", (char *) Language(418)); + + /* Downloading */ + else if(exitinfo.iStatus == DOWNLOAD) + printf("%-15s", (char *) Language(419)); + + /* Uploading */ + else if(exitinfo.iStatus == UPLOAD) + printf("%-15s", (char *) Language(420)); + + /* Msg Section */ + else if(exitinfo.iStatus == READ_POST) + printf("%-15s", (char *) Language(421)); + + /* External Door */ + else if(exitinfo.iStatus == DOOR) + printf("%-15s", (char *) Language(422)); + + /* Chatting */ + else if(exitinfo.iStatus == SYSOPCHAT) + printf("%-15s", (char *) Language(423)); + + /* Listing Files */ + else if(exitinfo.iStatus == FILELIST) + printf("%-15s", (char *) Language(424)); + + /* Banking Door */ + else if(exitinfo.iStatus == TIMEBANK) + printf("%-15s", (char *) Language(426)); + + /* Safe Door */ + else if(exitinfo.iStatus == SAFE) + printf("%-15s", (char *) Language(427)); + + /* WhosOn List */ + else if(exitinfo.iStatus == WHOSON) + printf("%-15s", (char *) Language(428)); + + /* Idle */ + else + printf("%s", (char *) Language(429)); + + colour(12, 0); + printf("%-25s\n", exitinfo.sLocation); + + fclose(pExitinfo); + } + } + closedir(Directory); + + ReadExitinfo(); + + colour(2, 0); + fLine(79); + + free(tmp); + free(temp); + free(Underline); + free(Heading); + + printf("\n"); +} + + + +/* + * Function will update users file and and update exitinfo.iStatus + */ +void WhosDoingWhat(int iStatus) +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + ReadExitinfo(); + exitinfo.iStatus = iStatus; + WriteExitinfo(); + + switch(iStatus) { + case BROWSING: + strcpy(temp, "Browsing Menus"); + break; + + case DOWNLOAD: + strcpy(temp, "Downloading"); + break; + + case UPLOAD: + strcpy(temp, "Uploading"); + break; + + case READ_POST: + strcpy(temp, "Read/post Messages"); + break; + + case DOOR: + strcpy(temp, "External Door"); + break; + + case SYSOPCHAT: + strcpy(temp, "Sysop Chat"); + break; + + case FILELIST: + strcpy(temp, "List Files"); + break; + + case TIMEBANK: + strcpy(temp, "Time Bank"); + break; + + case SAFE: + strcpy(temp, "Safe Cracker"); + break; + + case WHOSON: + strcpy(temp, "View Whoson List"); + break; + + case OLR: + strcpy(temp, "Offline Reader"); + break; + } + IsDoing(temp); + + free(temp); +} + + + +/* + * Function will allow a user to send a on-line message to another user + * It will prompt the user for the username. The message is sent thru + * mbsed, from the resonse message we can see if we succeeded. + */ +void SendOnlineMsg(char *OpData) +{ + static char buf[128]; + char *User, *String; + + User = calloc(36, sizeof(char)); + String = calloc(77, sizeof(char)); + WhosOn(OpData); + + /* Please enter username to send message to: */ + pout(3, 0, (char *) Language(430)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(User, 35); + if (!strcmp(User, "")) { + free(User); + free(String); + return; + } + + /* Please enter message to send (Max 76 Characters) */ + pout(10, 0, (char *)Language(433)); + pout(10, 0, (char *)"\n> "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(String, 76); + + if ((strcmp(String, "")) != 0) { + buf[0] = '\0'; + sprintf(buf, "CSPM:3,%s,%s,%s;", strcmp(OpData, "/H") != 0 ? exitinfo.sUserName : \ + strcmp(exitinfo.sHandle, "") == 0 ? exitinfo.sUserName : \ + exitinfo.sHandle, User, String); + + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + + if (strncmp(buf, "100:1,3;", 8) == 0) { + /* Sorry, there is no user on */ + printf("\n%s %s\n\n", (char *) Language(431), User); + } + if (strncmp(buf, "100:1,2;", 8) == 0) { + printf("\nNo more room in users message buffer\n\n"); + } + if (strncmp(buf, "100:1,1;", 8) == 0) { + colour(12, 0); + /* doesn't wish to be disturbed */ + printf("\n%s %s\n", User, (char *) Language(432)); + } + if (strncmp(buf, "100:0;", 6) == 0) { + printf("Message Sent!\n"); + Syslog('+', "Online msg to %s: \"%s\"", User, String); + } + } + } + + free(User); + free(String); + Pause(); +} + + diff --git a/mbsebbs/exitinfo.h b/mbsebbs/exitinfo.h new file mode 100644 index 00000000..a4269031 --- /dev/null +++ b/mbsebbs/exitinfo.h @@ -0,0 +1,13 @@ +#ifndef _EXITINFO_H +#define _EXITINFO_H + +void InitExitinfo(void); /* Create exitinfo */ +void ReadExitinfo(void); /* Read Users Config in Memory */ +void WriteExitinfo(void); /* Write Users config from memory */ +void WhosOn(char *); /* What users are currently online */ +void WhosDoingWhat(int); /* Update what user is doing */ +void SendOnlineMsg(char *); /* Send On-Line Message to User */ + + +#endif + diff --git a/mbsebbs/file.c b/mbsebbs/file.c new file mode 100644 index 00000000..dab8d70d --- /dev/null +++ b/mbsebbs/file.c @@ -0,0 +1,2167 @@ +/***************************************************************************** + * + * File ..................: bbs/file.c + * Purpose ...............: All the file functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "filesub.h" +#include "file.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" +#include "change.h" + + + +extern long arecno; /* File area number in xxxScan() functions */ +int Strlen = 0; +int FileRecno = 0; + + + +/* + * Show filelist from current area, called from the menu. + */ +void File_List() +{ + FILE *pFile; + int FileCount = 0; + unsigned FileBytes = 0; + _Tag T; + + iLineCount = 0; + WhosDoingWhat(FILELIST); + + Syslog('+', "Listing File Area # %d", iAreaNumber); + + if(Access(exitinfo.Security, area.LTSec) == FALSE) { + colour(14, 0); + /* You don't have enough security to list this area */ + printf("\n%s\n", (char *) Language(236)); + Pause(); + return; + } + + InitTag(); + + if ((pFile = OpenFileBase(iAreaNumber, FALSE)) == NULL) + return; + + clear(); + Header(); + if (iLC(2) == 1) { + fclose(pFile); + return; + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + T.Area = iAreaNumber; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + + if (ShowOneFile() == 1) { + fclose(pFile); + return; + } + + if(file.Deleted) + /* D E L E T E D */ /* Uploaded by: */ + printf("%-15s %s [%ld] %s%s\n", file.Name, (char *) Language(239), file.TimesDL, (char *) Language(238), file.Uploader); + + if(file.Missing) + /* M I S S I N G */ /* Uploaded by: */ + printf("%-15s %s [%ld] %s%s\n", file.Name, (char *) Language(240), file.TimesDL, (char *) Language(238), file.Uploader); + + FileCount++; /* Increase File Counter by 1 */ + FileBytes += file.Size; /* Increase File Byte Count */ + } + + Mark(); + + colour(11,0); + /* Total Files: */ + printf("\n%s%d / %d bytes\n\n", (char *) Language(242), FileCount, FileBytes); + + iLineCount = 0; + fclose(pFile); + Pause(); +} + + + +/* + * Download files already tagged, called from the menu. + */ +void Download(void) +{ + FILE *tf, *fp, *fd; + int i, err, Count = 0; + int OldArea; + char *symTo, *symFrom; + char *temp; + long Size = 0, CostSize = 0; + time_t ElapstimeStart, ElapstimeFin, iTime; + long iTransfer = 0; + + Enter(2); + OldArea = iAreaNumber; + WhosDoingWhat(DOWNLOAD); + unlink("./tag/filedesc.txt"); + + if ((tf = fopen("taglist", "r+")) == NULL) { + /* No files marked for download. */ + pout(12, 0, (char *) Language(258)); + Enter(2); + Pause(); + return; + } + + symTo = calloc(PATH_MAX, sizeof(char)); + symFrom = calloc(PATH_MAX, sizeof(char)); + colour(13, 0); + /* Checking your marked downloads, please wait... */ + printf("%s\n\n", (char *) Language(255)); + + ReadExitinfo(); + while (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + if (Tag.Active) { + + SetFileArea(Tag.Area); + + /* + * Check password for selected file + */ + memset(&file, 0, sizeof(file)); + if ((fp = OpenFileBase(Tag.Area, FALSE)) != NULL) { + + while (fread(&file, sizeof(file), 1, fp) == 1) { + if (strcmp(file.Name, Tag.File) == 0) + break; + } + fclose(fp); + } + + if (strcmp(file.Name, Tag.File) == 0) { + Syslog('b', "Found file %s in area %d", file.Name, Tag.Area); + if ((file.Deleted) || (file.Missing)) { + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(248)); + /* Sorry that file is unavailable for download */ + printf("%s (%s)\n", (char *) Language(248), file.Name); + Tag.Active = FALSE; + } + + } + + if (Tag.Active) { + /* + * Create/Append file description list while we're + * busy checking. If the users doesn't want it we + * can unlink it aftwerwards. We also insert CR + * characters to please the poor DOS (M$oft) users. + */ + sprintf(symTo, "./tag/filedesc.%ld", exitinfo.Downloads % 256); + if ((fd = fopen(symTo, "a")) != NULL) { + fprintf(fd, "%s\r\n", file.Name); + for (i = 0; i < 25; i++) { + if (strlen(file.Desc[i]) > 1) + fprintf(fd, " %s\r\n", file.Desc[i]); + } + fprintf(fd, "\r\n"); + fclose(fd); + } + + /* + * Make a symlink to the users download dir. + * First unlink, in case there was an old one. + */ + chdir("./tag"); + unlink(Tag.File); + sprintf(symFrom, "%s", Tag.File); + sprintf(symTo, "%s/%s", sAreaPath, Tag.File); + if (symlink(symTo, symFrom)) { + WriteError("$Can't create symlink %s %s %d", symTo, symFrom, errno); + Tag.Active = FALSE; + } + Home(); + } + + if (!Tag.Active) { + /* + * Update the download active flag in the + * taglist + */ + fseek(tf, - sizeof(Tag), SEEK_CUR); + fwrite(&Tag, sizeof(Tag), 1, tf); + } else { + /* + * Count file and sizes. + */ + Count++; + Size += file.Size; + if ((!file.Free) && (!area.Free)) + CostSize += file.Size; + + } + } + } + + /* + * If anything left to download... + */ + if (!Count) { + fclose(tf); + SetFileArea(OldArea); + unlink("taglist"); + /* No files marked for download */ + pout(12, 0, (char *) Language(258)); + Enter(2); + Pause(); + free(symTo); + free(symFrom); + return; + } + + colour(14, 0); + /* You have */ /* files( */ /* bytes) marked for download */ + printf("%s %d %s%ld %s\n\n", (char *) Language(249), Count, (char *) Language(280), Size, (char *) Language(281)); + + /* + * If user has no default protocol, make sure he has one. + */ + if (!ForceProtocol()) { + SetFileArea(OldArea); + free(symTo); + free(symFrom); + return; + } + + if (!CheckBytesAvailable(CostSize)) { + SetFileArea(OldArea); + free(symTo); + free(symFrom); + return; + } + + Pause(); + + clear(); + /* File(s) : */ + pout(14, 0, (char *) Language(349)); printf("%d\n", Count); + /* Size : */ + pout( 3, 0, (char *) Language(350)); printf("%lu\n", Size); + /* Protocol : */ + pout( 3, 0, (char *) Language(351)); printf("%s\n", sProtName); + + Syslog('+', "Download tagged files start"); + + printf("%s\n\n", sProtAdvice); + fflush(stdout); + fflush(stdin); + + /* HERE WE SHOULD MAKE A DIFFERENCE BETWEEN BATCHING AND NON + * BATCHING PROTOCOLS. + */ + + /* + * Wait a while before download + */ + sleep(2); + time(&ElapstimeStart); + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s ./tag/*", sProtDn); + Syslog('+', "Download command %s", temp); + + /* + * Transfer the files. Set the Client/Server time at the maximum + * time the user has plus 10 minutes. The overall timer 10 seconds + * less. Not a nice but working solution. + */ + alarm_set(((exitinfo.iTimeLeft + 10) * 60) - 10); + Altime((exitinfo.iTimeLeft + 10) * 60); + if ((err = system(temp)) != 0) { + /* + * Only log the error, we might have sent some files + * instead of nothing. + */ + perror(""); + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("Download error %d, prot: %s", err, sProtDn); + } + Altime(0); + alarm_off(); + alarm_on(); + fflush(stdout); + fflush(stdin); + free(temp); + time(&ElapstimeFin); + + /* + * Get time from Before Download and After Download to get + * download time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + /* + * Checking the successfull sent files, they are missing from + * the ./tag directory. Failed files are still there. + */ + colour(11, 0); + /* Updating download counters, please wait ... */ + printf("\r%s\n\n", (char *) Language(352)); + fflush(stdout); + Count = Size = 0; + + if ((tf = fopen("taglist", "r+")) != NULL) { + + while (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + + if (Tag.Active) { + + sprintf(symTo, "./tag/%s", Tag.File); + /* + * If symlink is gone the file is sent. + */ + if ((access(symTo, R_OK)) != 0) { + Syslog('+', "File %s from area %d sent ok", Tag.File, Tag.Area); + Tag.Active = FALSE; + fseek(tf, - sizeof(Tag), SEEK_CUR); + fwrite(&Tag, sizeof(Tag), 1, tf); + + /* + * Update the download counter and the + * last download date. + */ + SetFileArea(Tag.Area); + if ((fp = OpenFileBase(Tag.Area, TRUE)) != NULL) { + while (fread(&file, sizeof(file), 1, fp) == 1) { + if (strcmp(file.Name, Tag.File) == 0) + break; + } + Size += file.Size; + file.TimesDL++; + time(&file.LastDL); + fseek(fp, - sizeof(file), SEEK_CUR); + fwrite(&file, sizeof(file), 1, fp); + fclose(fp); + Count++; + } + } else { + Syslog('+', "Failed to sent %s from area %d", Tag.File, Tag.Area); + } + } + } + + } + + /* + * Work out transfer rate in seconds by dividing the + * Size of the File by the amount of time it took to download + * the file. + */ + iTransfer = Size / iTime; + Syslog('+', "Download time %ld seconds (%lu cps), %d files", iTime, iTransfer, Count); + + + /* + * Update the users record. + */ + ReadExitinfo(); + + exitinfo.Downloads += Count; /* Increase download counter */ + exitinfo.DownloadK += (Size / 1024); /* Increase amount download today */ + + /* + * Minus the amount downloaded today from downloadktoday + * if less than zero, it won't let the user download anymore. + */ + exitinfo.DownloadKToday -= (Size / 1024); + exitinfo.iTransferTime = iTransfer; + + WriteExitinfo(); + Pause(); + SetFileArea(OldArea); + free(symTo); + free(symFrom); +} + + + +/* + * Show Raw directory + */ +void File_RawDir(char *OpData) +{ + DIR *dirp; + char *FileName, *temp; + int iFileCount = 0; + int LineCount = 2; + int iBytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if((strcmp(OpData, "/F")) == 0) + strcpy(temp, sAreaPath); + else + strcpy(temp, OpData); + + if ((dirp = opendir(temp)) == NULL) { + clear(); + WriteError("$RawDir: Can't open dir: %s", temp); + printf("\nCan't open directory for raw listing!\n\n"); + Pause(); + } else { + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Filename Size Date */ + printf("%s\n", (char *) Language(261)); + fLine(42); + + while ((dp = readdir( dirp )) != NULL ) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + + if (*(dp->d_name) != '.') { + iFileCount++; + if(stat(FileName,&statfile) != 0) + printf("Can't stat file %s\n",FileName); + iBytes += statfile.st_size; + + colour(14,0); + printf("%-20s", dp->d_name); + + colour(13,0); + printf("%-12ld", statfile.st_size); + + colour(10,0); + printf("%-10s\n", StrDateDMY(statfile.st_mtime)); + + LineCount++; + if (LineCount == exitinfo.iScreenLen) { + Pause(); + LineCount = 0; + } + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + fLine(42); + /* Total Files: */ /* Bytes */ + printf("%s %d, %d %s\n\n", (char *) Language(242), iFileCount, iBytes, (char *) Language(354)); + + Pause(); + closedir(dirp); + } + free(temp); + free(FileName); +} + + + +/* + * Search for keyword, called from menu. + */ +int KeywordScan() +{ + FILE *pAreas, *pFile; + int i, z, y, Found, Count = 0; + char *Name; + char *tmpname; + char *BigDesc; + char temp[81]; + _Tag T; + unsigned long OldArea; + + + Name = calloc(81, sizeof(char)); + tmpname = calloc(81, sizeof(char)); + BigDesc = calloc(1230, sizeof(char)); + OldArea = iAreaNumber; + + iLineCount = 2; /* Reset Line Counter to Zero */ + arecno = 1; /* Reset Area Number to One */ + + Enter(2); + /* Enter keyword to use for Search: */ + pout(11, 0, (char *) Language(267)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 80); + + if((strcmp(Name, "")) == 0) + return 0; + + strcpy(tmpname, tl(Name)); + strcpy(Name, ""); + y = strlen(tmpname); + for (z = 0; z < y; z++) { + if (tmpname[z] != '*') { + sprintf(temp, "%c", tmpname[z]); + strcat(Name, temp); + } + } + Syslog('+', "KeywordScan(): \"%s\"", Name); + + clear(); + /* File search by keyword */ + pout(15, 0, (char *) Language(268)); + Enter(1); + InitTag(); + + for(i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL) { + + Nopper(); + Found = FALSE; + Sheader(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + for(i = 0; i < 25; i++) + sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i)); + + if ((strstr(file.Name,Name) != NULL) || (strstr(tl(BigDesc), Name) != NULL)) { + + if (!Found) { + Enter(2); + if (iLC(2) == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + Count++; + if (ShowOneFile() == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + strcpy(BigDesc, ""); /* Clear BigDesc */ + + } /* while */ + + fclose(pFile); + if (Found) { + Enter(2); + if (iLC(2) == 1) { + free(BigDesc); + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End check for LTSec */ + } /* if access */ + arecno++; /* Go to next file area */ + } /* End of Main */ + + Syslog('+', "Found %d files", Count); + free(BigDesc); + free(Name); + free(tmpname); + fclose(pAreas); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + SetFileArea(OldArea); + return 1; +} + + + +/* + * Search for a file, called from the menu. + */ +int FilenameScan() +{ + FILE *pAreas, *pFile; + int z, y, Found, Count = 0; + char *Name; + char *tmpname; + char temp[81]; + _Tag T; + unsigned long OldArea; + + Name = calloc(81, sizeof(char)); + tmpname = calloc(81, sizeof(char)); + OldArea = iAreaNumber; + + iLineCount = 2; /* Reset Line Counter to Zero */ + arecno = 1; /* Reset Area Number to One */ + + Enter(2); + /* Accepts wildcards such as : *.zip, *.gz, .tar */ + pout(15, 0, (char *) Language(269)); + Enter(1); + /* : *.zip is the same as .zip */ + pout(15, 0, (char *) Language(270)); + + Enter(2); + /* Enter filename to search for : */ + pout(11, 0, (char *) Language(271)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Name, 80); + + if ((strcmp(Name, "")) == 0) { + free(tmpname); + free(Name); + return 0; + } + + /* + * If there is a file extension, strip it off, it are mostly + * archiver extensions, and who knows what we're using as + * archiver. + */ + if (strchr(Name, '.') != NULL) + strcpy(tmpname, strtok(Name, ".")); + else + strcpy(tmpname, tl(Name)); + strcpy(Name, ""); + y = strlen(tmpname); + for(z = 0; z < y; z++) { + if(tmpname[z] != '*') { + sprintf(temp, "%c", tmpname[z]); + strcat(Name, temp); + } + } + Syslog('+', "FilenameScan(): \"%s\"", Name); + + clear(); + /* File Search by Filename */ + pout(15, 0, (char *) Language(272)); + Enter(1); + InitTag(); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL) { + + Found = FALSE; + Sheader(); + Nopper(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + strcpy(tmpname, tl(file.Name)); + if ((strstr(tmpname, Name)) != NULL) { + if (!Found) { + Enter(2); + if (iLC(2) == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + Count++; + if (ShowOneFile() == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End of while */ + + fclose(pFile); + if (Found) { + Enter(2); + if (iLC(2) == 1) { + free(Name); + free(tmpname); + SetFileArea(OldArea); + return 1; + } + } + + } /* End Check for LTSec */ + } /* if access */ + arecno++; /* Go to next file area */ + + } /* End of Main */ + + Syslog('+', "Found %d files", Count); + fclose(pAreas); + free(Name); + free(tmpname); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + SetFileArea(OldArea); + return 1; +} + + + +/* + * Scan for new files, called from menu. + */ +int NewfileScan(int AskStart) +{ + FILE *pAreas, *pFile; + long ifDate, itDate; + char *temp, *Date; + int Found, Count = 0; + _Tag T; + + Date = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + iLineCount = 2; + arecno = 1; /* Reset Area Number to One */ + + if (AskStart) { + Enter(2); + /* Search for new since your last call [Y/n]: */ + pout(11, 0, (char *) Language(273)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + + if (toupper(Getone()) == Keystroke(273, 1)) { + Enter(1); + /* Enter new date to search for [DD-MM-YYYY]: */ + pout(2, 0, (char *) Language(274)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetDate(temp, 10); + } else + strcpy(temp, LastLoginDate); + } else + strcpy(temp, LastLoginDate); + + Syslog('+', "NewfileScan() since %s", temp); + clear(); + /* File Search by Date */ + pout(15, 0, (char *) Language(275)); + Enter(2); + + Date[0] = temp[6]; /* Swap the date around */ + Date[1] = temp[7]; /* Instead of DD-MM-YYYY */ + Date[2] = temp[8]; /* Let it equal YYYYMMDD */ + Date[3] = temp[9]; /* Swap the date around */ + Date[4] = temp[3]; /* Swap the date around */ + Date[5] = temp[4]; /* because when you convert */ + Date[6] = temp[0]; /* a string to an int you */ + Date[7] = temp[1]; /* loose the front Zero */ + Date[8] = '\0'; /* making the number smaller */ + itDate = atol(Date); + + InitTag(); + + if ((pAreas = OpenFareas(FALSE)) == NULL) + return 0; + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && + (strlen(area.Password) == 0) && (area.New)) { + + if ((pFile = OpenFileBase(arecno, FALSE)) != NULL ) { + + Sheader(); + Found = FALSE; + Nopper(); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + strcpy(temp, StrDateDMY(file.UploadDate)); /* Realloc Space for Date */ + Date[0] = temp[6]; /* Swap the date around */ + Date[1] = temp[7]; /* Instead of DD-MM-YYYY */ + Date[2] = temp[8]; /* Let it equal YYYYMMDD */ + Date[3] = temp[9]; /* Swap the date around */ + Date[4] = temp[3]; /* Swap the date around */ + Date[5] = temp[4]; /* because when you convert */ + Date[6] = temp[0]; /* a string to an int you */ + Date[7] = temp[1]; /* loose the front Zero */ + Date[8] = '\0'; /* making the number smaller */ + /* and invalid to this cause */ + ifDate = atol(Date); + + if(ifDate >= itDate) { + if (!Found) { + printf("\n\n"); + if (iLC(2) == 1) { + free(Date); + free(temp); + return 1; + } + Found = TRUE; + } + + T.Area = arecno; + T.Active = FALSE; + T.Cost = file.Cost; + T.Size = file.Size; + sprintf(T.File, "%s", file.Name); + SetTag(T); + + Count++; + if (ShowOneFile() == 1) { + free(Date); + free(temp); + return 1; + } + + } /* End of if */ + } /* End of while */ + + fclose(pFile); + + /* + * Add 2 blank lines after found files. + */ + if (Found) { + printf("\n\n"); + if (iLC(2) == 1) { + free(Date); + free(temp); + return 1; + } + } + + } /* End of open filebase */ + + } /* End of check new files scan */ + arecno++; /* Go to next file area */ + + } /* End of Main */ + + if (Count) + Syslog('+', "Found %d new files", Count); + fclose(pAreas); + printf("\n"); + if (Count) + Mark(); + else + Pause(); + + free(temp); + free(Date); + return 1; +} + + + +/* + * Upload a file. + */ +int Upload() +{ + char File[81], temp[81]; + int Area, x = 0; + int i, err; + unsigned long OldArea; + time_t ElapstimeStart, ElapstimeFin, iTime; + DIR *dirp; + struct dirent *dp; + struct stat statfile; + char *arc; + + + WhosDoingWhat(UPLOAD); + + /* + * Select default protocol if users hasn't any. + */ + if (!ForceProtocol()) + return 0; + + Enter(1); + Area = OldArea = iAreaNumber; + + /* + * If there is a special upload area for the current area + * then select it. + */ + if (area.Upload) + Area = area.Upload; + SetFileArea(Area); + + /* + * Only ask for a filename for non-batching protocols, + * ie. the stone age Xmodem for example. + */ + if (!uProtBatch) { + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if((strcmp(File, "")) == 0) + return 0; + + if (*(File) == '.' || *(File) == '*' || *(File) == ' ' || *(File) == '/') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + Strlen = strlen(File); + Strlen--; + + if (*(File + Strlen) == '.' || *(File + Strlen) == '/' || *(File + Strlen) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + if ((!strcmp(File, "files.bbs")) || (!strcmp(File, "00index")) || (strstr(File, (char *)".html"))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Syslog('!', "Attempted to upload %s", File); + Pause(); + return 0; + } + + for (i = 0; i < strlen(File); i++) + printf("%d ", File[i]); + + /* + * Check for a space in filename being uploaded + */ + if ((strchr(File, 32)) != NULL) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return 0; + } + + /* MOET IN ALLE AREAS ZOEKEN */ + if (area.Dupes) { + x = CheckFile(File, Area); + if(x) { + Enter(1); + /* The file already exists on the system */ + pout(15, 3, (char *) Language(282)); + Enter(2); + SetFileArea(OldArea); + Pause(); + return 0; + } + } + SetFileArea(OldArea); + } + + SetFileArea(Area); + Syslog('+', "Upload area is %d %s", Area, area.Name); + + /* + * Check upload access for the real upload directory. + */ + if (!Access(exitinfo.Security, area.UPSec)) { + colour(CFG.HiliteF, CFG.HiliteB); + /* You do not have enough access to upload to this area */ + printf("\n%s\n\n", (char *) Language(278)); + SetFileArea(OldArea); + Pause(); + return 0; + } + + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now ...*/ + printf("\n\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + SetFileArea(OldArea); + return 0; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file(s). Set the Client/Server time to 2 hours. + * This is not a nice solution, at least it works and prevents + * that the bbs will hang. + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + /* + * Log any errors + */ + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n\n\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get time from Before Upload and After Upload to get + * upload time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('b', "Transfer time %ld", iTime); + + if ((dirp = opendir(".")) == NULL) { + WriteError("$Upload: can't open ./upl"); + Home(); + SetFileArea(OldArea); + return 1; + } + + Syslog('b', "Start checking uploaded files"); + pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"\n\nChecking your upload(s)\n\n"); + + while ((dp = readdir(dirp)) != NULL) { + + if (*(dp->d_name) != '.') { + stat(dp->d_name, &statfile); + Syslog('+', "Uploaded \"%s\", %ld bytes", dp->d_name, statfile.st_size); + + if ((arc = GetFileType(dp->d_name)) == NULL) { + /* + * If the filetype is unknown, it is probably + * a textfile or so. Import it direct. + */ + Syslog('b', "Unknown file type"); + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + } else { + /* + * We figured out the type of the uploaded file. + */ + Syslog('b', "File type is %s", arc); + + /* + * MS-DOS executables are handled direct. + */ + if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) { + if (!ScanDirect(dp->d_name)) + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + } else { + switch(ScanArchive(dp->d_name, arc)) { + + case 0: + ImportFile(dp->d_name, Area, TRUE, iTime, statfile.st_size); + break; + + case 1: + break; + + case 2: + break; + + case 3: + /* + * No valid unarchiver found, just import + */ + ImportFile(dp->d_name, Area, FALSE, iTime, statfile.st_size); + break; + } + } + } + } + } + closedir(dirp); + + Home(); + SetFileArea(OldArea); + Pause(); + return 1; +} + + + +/* + * Function will download a specific file + */ +int DownloadDirect(char *Name, int Wait) +{ + int err, rc; + char *symTo, *symFrom; + char *temp; + long Size; + time_t ElapstimeStart, ElapstimeFin, iTime; + long iTransfer = 0; + + if ((Size = file_size(Name)) == -1) { + WriteError("No file %s", Name); + colour(CFG.HiliteF, CFG.HiliteB); + printf("File not found\n\n"); + Pause(); + } + + /* + * Make a symlink to the users tmp dir. + */ + symTo = calloc(PATH_MAX, sizeof(char)); + symFrom = calloc(PATH_MAX, sizeof(char)); + sprintf(symFrom, "%s/%s/tmp%s", CFG.bbs_usersdir, exitinfo.Name, strrchr(Name, '/')); + sprintf(symTo, "%s", Name); + + if (symlink(symTo, symFrom)) { + WriteError("$Can't create symlink %s %s", symTo, symFrom); + free(symTo); + free(symFrom); + return FALSE; + } + + /* + * If user has no default protocol, make sure he has one. + */ + if (!ForceProtocol()) { + unlink(symFrom); + free(symTo); + free(symFrom); + return FALSE; + } + + WhosDoingWhat(DOWNLOAD); + ReadExitinfo(); + + clear(); + /* File(s) : */ + pout(14, 0, (char *) Language(349)); printf("%s\n", symFrom); + /* Size : */ + pout( 3, 0, (char *) Language(350)); printf("%lu\n", Size); + /* Protocol : */ + pout( 3, 0, (char *) Language(351)); printf("%s\n", sProtName); + + Syslog('+', "Download direct start %s", Name); + + printf("%s\n\n", sProtAdvice); + fflush(stdout); + fflush(stdin); + + /* + * Wait a while before download + */ + sleep(2); + time(&ElapstimeStart); + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s %s", sProtDn, symFrom); + Syslog('+', "Download command %s", temp); + + /* + * Transfer the file. Set the Client/Server time at the maximum + * time the user has plus 10 minutes. The overall timer 10 seconds + * less. + */ + alarm_set(((exitinfo.iTimeLeft + 10) * 60) - 10); + Altime((exitinfo.iTimeLeft + 10) * 60); + if ((err = system(temp)) != 0) { + /* + * Only log the error, we might have sent some files + * instead of nothing. + */ + perror(""); + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("Download error %d, prot: %s", err, sProtDn); + } + Altime(0); + alarm_off(); + alarm_on(); + fflush(stdout); + fflush(stdin); + free(temp); + time(&ElapstimeFin); + + /* + * Get time from Before Download and After Download to get + * download time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + if ((access(symFrom, R_OK)) != 0) { + + /* + * Work out transfer rate in seconds by dividing the + * Size of the File by the amount of time it took to download + * the file. + */ + iTransfer = Size / iTime; + Syslog('+', "Download ok, time %ld seconds (%lu cps)", iTime, iTransfer); + + /* + * Update the users record. The file is free, so only statistics. + */ + ReadExitinfo(); + exitinfo.Downloads++; /* Increase download counter */ + exitinfo.iTransferTime = iTransfer; + WriteExitinfo(); + rc = TRUE; + } else { + Syslog('+', "Download failed to sent file"); + unlink(symFrom); + rc = FALSE; + } + if (Wait) + Pause(); + free(symTo); + free(symFrom); + return rc; +} + + + +/* + * Function will list users home directory + */ +void List_Home() +{ + DIR *dirp; + char *FileName, *temp; + int iFileCount = 0; + int iBytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + iLineCount = 2; + clear(); + sprintf(temp, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name); + + if ((dirp = opendir(temp)) == NULL) { + WriteError("$List_Home: Can't open dir: %s", temp); + /* Can't open directory for listing: */ + printf("\n%s\n\n", (char *) Language(290)); + Pause(); + } else { + colour(1, 7); + /* Home directory listing for */ + printf(" %s", (char *) Language(291)); + colour(4, 7); + printf("%-51s\n", exitinfo.sUserName); + + while ((dp = readdir( dirp )) != NULL ) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + /* + * Check first letter of file for a ".", do not display hidden files + * This includes the current directory and parent directory . & .. + */ + if (*(dp->d_name) != '.') { + iFileCount++; + if(stat(FileName, &statfile) != 0) + WriteError("$Can't stat file %s",FileName); + iBytes += statfile.st_size; + + colour(14,0); + printf("%-20s", dp->d_name); + + colour(13,0); + printf("%-12ld", statfile.st_size); + + colour(10,0); + printf("%s ", StrDateDMY(statfile.st_mtime)); + + colour(11,0); + printf("%s", StrTimeHMS(statfile.st_mtime)); + + printf("\n"); + } + if (iLC(1) == 1) + return; + } + + colour(11,0); + /* Total Files: */ /* Bytes */ + printf("\n\n%s%d / %d %s\n", (char *) Language(242), iFileCount, iBytes, (char *) Language(354)); + + Pause(); + closedir(dirp); + } + + free(temp); + free(FileName); +} + + + +/* + * Delete files from home directory + */ +void Delete_Home() +{ + char *temp, *temp1; + int i; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/%s/wrk/", CFG.bbs_usersdir, exitinfo.Name); + + Enter(1); + /* Please enter filename to delete: */ + pout(9, 0, (char *) Language(292)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp1, 80); + + + if(strcmp(temp1, "") == 0) { + free(temp); + free(temp1); + return; + } + + if(temp1[0] == '.') { + Enter(1); + /* Sorry you may not delete hidden files ...*/ + pout(12, 0, (char *) Language(293)); + } else { + strcat(temp, temp1); + + if ((access(temp, R_OK)) == 0) { + colour(10, 0); + /* Delete file: */ /* Are you Sure? [Y/n]: */ + printf("\n%s %s, %s", (char *) Language(368), temp1, (char *) Language(369)); + fflush(stdout); + i = toupper(Getone()); + + if (i == Keystroke(368, 0) || i == 13) { + i = unlink(temp); + + if (i == -1) { + Enter(1); + /* Unable to delete file ... */ + pout(12, 0, (char *) Language(294)); + } else { + Syslog('+', "Delete %s from homedir", temp1); + } + } else { + Enter(2); + /* Aborting ... */ + pout(8, 0, (char *) Language(116)); + } + } else { + Enter(1); + /* Invalid filename, please try again ... */ + pout(12, 0, (char *) Language(295)); + } + + } + + free(temp); + free(temp1); + printf("\n"); + Pause(); +} + + + +/* + * Function allows user to download from his/her home directory + * but still does all the necessary checks + */ +int Download_Home() +{ + char *temp, *File; + struct stat statfile; + int rc; + + File = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + WhosDoingWhat(DOWNLOAD); + + colour(14,0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if(( strcmp(File, "")) == 0) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, Aborting. */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(File); + free(temp); + return FALSE; + } + + if( *(File) == '/' || *(File) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(temp); + return FALSE; + } + + /* + * Get path for users home directory + */ + sprintf(temp, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File); + + if (stat(temp, &statfile) != 0) { + Enter(1); + /* File does not exist, please try again ...*/ + pout(12, 0, (char *) Language(296)); + Enter(2); + Pause(); + free(File); + free(temp); + return FALSE; + } + + rc = DownloadDirect(temp, TRUE); + + free(File); + free(temp); + return rc; +} + + + +/* + * Function will upload to users home directory + */ +int Upload_Home() +{ + DIR *dirp; + struct dirent *dp; + char *File, *sFileName, *temp, *arc; + time_t ElapstimeStart, ElapstimeFin, iTime; + int err; + struct stat statfile; + + WhosDoingWhat(UPLOAD); + if (!ForceProtocol()) + return 0; + + File = calloc(PATH_MAX, sizeof(char)); + sFileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if (!uProtBatch) { + + Enter(1); + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if((strcmp(File, "")) == 0) { + free(File); + free(sFileName); + free(temp); + return 0; + } + + if(File[0] == '.' || File[0] == '*' || File[0] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(sFileName); + free(temp); + return 0; + } + + Strlen = strlen(File); + Strlen--; + + if(File[Strlen] == '.' || File[Strlen] == '/' || File[Strlen] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(sFileName); + free(temp); + return 0; + } + + } + + clear(); + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now ...*/ + printf("\n\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + free(File); + free(sFileName); + free(temp); + return 0; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file(s). Set the Client/Server time to 2 hours. + * This is not a nice solution, at least it works and prevents + * that the bbs will hang. + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + /* + * Log any errors + */ + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n\n\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get time from Before Upload and After Upload to get + * upload time, if the time is zero, it will be one. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('b', "Transfer time %ld", iTime); + + if ((dirp = opendir(".")) == NULL) { + WriteError("$Upload: can't open ./upl"); + Home(); + free(File); + free(sFileName); + free(temp); + return 1; + } + + Syslog('b', "Start checking uploaded files"); + pout(CFG.UnderlineColourF, CFG.UnderlineColourB, (char *)"\n\nChecking your upload(s)\n\n"); + + while ((dp = readdir(dirp)) != NULL) { + + if (*(dp->d_name) != '.') { + stat(dp->d_name, &statfile); + Syslog('+', "Uploaded \"%s\", %ld bytes", dp->d_name, statfile.st_size); + + if ((arc = GetFileType(dp->d_name)) == NULL) { + /* + * If the filetype is unknown, it is probably + * a textfile or so. Import it direct. + */ + Syslog('b', "Unknown file type"); + ImportHome(dp->d_name); + } else { + /* + * We figured out the type of the uploaded file. + */ + Syslog('b', "File type is %s", arc); + + /* + * MS-DOS executables are handled direct. + */ + if ((strcmp("EXE", arc) == 0) || (strcmp("COM", arc) == 0)) { + if (!ScanDirect(dp->d_name)) + ImportHome(dp->d_name); + } else { + switch(ScanArchive(dp->d_name, arc)) { + + case 0: + ImportHome(dp->d_name); + break; + + case 1: + break; + + case 2: + break; + + case 3: + /* + * No valid unarchiver found, just import + */ + ImportHome(dp->d_name); + break; + } + } + } + } + } + closedir(dirp); + Home(); + + ReadExitinfo(); + exitinfo.Uploads++; + WriteExitinfo(); + + Pause(); + free(File); + free(sFileName); + free(temp); + return 1; +} + + + +/* + * Select filearea, called from menu. + */ +void FileArea_List(char *Option) +{ + FILE *pAreas; + int iAreaCount = 6, Recno = 1; + int iOldArea, iAreaNum = 0; + int iGotArea = FALSE; /* Flag to check if user typed in area */ + long offset; + char *temp; + + /* + * Save old area, incase he picks a invalid area + */ + iOldArea = iAreaNumber; + if ((pAreas = OpenFareas(FALSE)) == NULL) + return; + + /* + * Count howmany records there are + */ + fseek(pAreas, 0, SEEK_END); + iAreaNum = (ftell(pAreas) - areahdr.hdrsize) / areahdr.recsize; + + /* + * If there are menu options, select area direct. + */ + if (strlen(Option) != 0) { + + if (strcmp(Option, "F+") == 0) + while(TRUE) { + iAreaNumber++; + if (iAreaNumber > iAreaNum) + iAreaNumber = 1; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer here"); + } + + fread(&area, areahdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) + break; + } + + if (strcmp(Option, "F-") == 0) + while(TRUE) { + iAreaNumber--; + if (iAreaNumber < 1) + iAreaNumber = iAreaNum; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer here"); + } + + fread(&area, areahdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available) && (strlen(area.Password) == 0)) + break; + } + SetFileArea(iAreaNumber); + Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc); + fclose(pAreas); + return; + } + + /* + * Interactive mode + */ + clear(); + Enter(1); + /* File Areas */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(298)); + Enter(2); + temp = calloc(81, sizeof(char)); + + fseek(pAreas, areahdr.hdrsize, 0); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + if ((Access(exitinfo.Security, area.LTSec)) && (area.Available)) { + area.Name[31] = '\0'; + + colour(15,0); + printf("%5d", Recno); + + colour(9,0); + printf(" %c ", 46); + + colour(3,0); + printf("%-31s", area.Name); + + iAreaCount++; + + if ((iAreaCount % 2) == 0) + printf("\n"); + else + printf(" "); + } + + Recno++; + + if ((iAreaCount / 2) == exitinfo.iScreenLen) { + /* More (Y/n/=/Area #): */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(207)); + /* + * Ask user for Area or enter to continue + */ + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 7); + + if (toupper(*(temp)) == Keystroke(207, 1)) + break; + + if ((strcmp(temp, "")) != 0) { + iGotArea = TRUE; + break; + } + + iAreaCount = 2; + } + } + + /* + * If user type in area above during area listing + * don't ask for it again + */ + if (!iGotArea) { + Enter(1); + /* Select Area: */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + /* + * Check if user pressed ENTER + */ + if((strcmp(temp, "")) == 0) { + fclose(pAreas); + return; + } + + iAreaNumber = atoi(temp); + + /* + * Do a check in case user enters a negative value + */ + if (iAreaNumber < 1) + iAreaNumber = 1; + + offset = areahdr.hdrsize + ((iAreaNumber - 1) * areahdr.recsize); + if(fseek(pAreas, offset, 0) != 0) + printf("Can't move pointer there."); + else + fread(&area, areahdr.recsize, 1, pAreas); + + /* + * Do a check if area is greater or less number than allowed, + * security access level, is oke, and the area is active. + */ + if (iAreaNumber > iAreaNum || iAreaNumber < 1 || + (Access(exitinfo.Security, area.LTSec) == FALSE) || + (strlen(area.Name) == 0)) { + Enter(1); + /* Invalid area specified - Please try again ...*/ + pout(12, 0, (char *) Language(233)); + Enter(2); + Pause(); + fclose(pAreas); + iAreaNumber = iOldArea; + SetFileArea(iAreaNumber); + free(temp); + return; + } + + SetFileArea(iAreaNumber); + Syslog('+', "File area %lu %s", iAreaNumber, sAreaDesc); + + /* + * Check if file area has a password, if it does ask user for it + */ + if((strlen(area.Password)) > 2) { + Enter(2); + /* Please enter Area Password: */ + pout(15, 0, (char *) Language(299)); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 20); + + if((strcmp(temp, area.Password)) != 0) { + Enter(1); + /* Password is incorrect */ + pout(15, 0, (char *) Language(234)); + Enter(2); + Syslog('!', "Incorrect File Area # %d password given: %s", iAreaNumber, temp); + SetFileArea(iOldArea); + } else { + Enter(1); + /* Password is correct */ + pout(15, 0, (char *) Language(235)); + Enter(2); + } + Pause(); + } + + free(temp); + fclose(pAreas); +} + + + +/* + * Show filelist from current area, called from the menu. + */ +void Copy_Home() +{ + FILE *pFile; + char *File, *temp1, *temp2; + int err, Found = FALSE; + + File = calloc(81, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + + colour(14,0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + if ((strcmp(File, "")) == 0) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, Aborting. */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if (*(File) == '/' || *(File) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if(Access(exitinfo.Security, area.DLSec) == FALSE) { + colour(14, 0); + printf("\n%s\n", (char *) Language(236)); + Pause(); + free(File); + free(temp1); + free(temp2); + return; + } + + if ((pFile = OpenFileBase(iAreaNumber, FALSE)) == NULL) { + free(File); + free(temp1); + free(temp2); + return; + } + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + + if (strcmp(File, file.Name) == 0) { + + Found = TRUE; + if (((file.Size + Quota()) > (CFG.iQuota * 1048576))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* You have not enough diskspace free to copy this file */ + printf("%s\n", (char *) Language(279)); + Syslog('+', "Copy homedir, not enough quota"); + } else { + sprintf(temp1, "%s/%s", area.Path, File); + sprintf(temp2, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, File); + colour(CFG.TextColourF, CFG.TextColourB); + /* Start copy: */ + printf("%s%s ", (char *) Language(289), File); + fflush(stdout); + + Syslog('b', "Copy from : %s", temp1); + Syslog('b', "Copy to : %s", temp2); + + if ((err = file_cp(temp1, temp2))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Failed! */ + printf("%s\n", (char *) Language(353)); + WriteError("Copy %s to homedir failed, code %d", File, err); + } else { + /* Ok */ + printf("%s\n", (char *) Language(200)); + Syslog('+', "Copied %s from area %d to homedir", File, iAreaNumber); + } + } + } + } + fclose(pFile); + + if (!Found) { + colour(CFG.HiliteF, CFG.HiliteB); + /* File does not exist, please try again ... */ + printf("%s\n", (char *) Language(296)); + } + + Pause(); + free(File); + free(temp1); + free(temp2); +} + + + +/* + * Edit the list of tagged files. + */ +void EditTaglist() +{ + FILE *tf; + int i, x, Fg, Count; + char *temp; + + if ((tf = fopen("taglist", "r+")) == NULL) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No files tagged. */ + printf("\n%s\n\n", (char *) Language(361)); + Pause(); + return; + } + + temp = calloc(81, sizeof(char)); + + while (TRUE) { + clear(); + fseek(tf, 0, SEEK_SET); + Count = 0; + colour(CFG.HiliteF, CFG.HiliteB); + /* # Area Active File Size Cost */ + printf("%s\n", (char *) Language(355)); + colour(10, 0); + fLine(48); + + while ((fread(&Tag, sizeof(Tag), 1, tf) == 1)) { + Count++; + + if (Tag.Active) + Fg = 15; + else + Fg = 7; + + colour(Fg, 0); + printf("%3d ", Count); + + Fg--; + colour(Fg, 0); + printf("%5ld ", Tag.Area); + + Fg--; + colour(Fg, 0); + if (Tag.Active) + /* Yes */ + printf("%-6s ", (char *) Language(356)); + else + /* No */ + printf("%-6s ", (char *) Language(357)); + + Fg--; + colour(Fg, 0); + printf("%-14s", Tag.File); + + Fg--; + colour(Fg, 0); + printf(" %8ld", Tag.Size); + + Fg--; + colour(Fg, 0); + printf(" %5d\n", Tag.Cost); + } + colour(10, 0); + fLine(48); + + colour(15, 4); + /* (T)oggle active, (E)rase all, (ENTER) to continue: */ + printf("\n%s", (char *) Language(358)); + fflush(stdout); + fflush(stdin); + + i = toupper(Getone()); + colour(CFG.CRColourF, CFG.CRColourB); + + if (i == Keystroke(358, 0)) { + /* Enter file number, 1.. */ + printf("\n\n%s%d ", (char *) Language(359), Count); + fflush(stdout); + fflush(stdin); + + GetstrC(temp, 5); + x = atoi(temp); + + if ((x > 0) && (x <= Count)) { + if (fseek(tf, (x - 1) * sizeof(Tag), SEEK_SET) == 0) { + if (fread(&Tag, sizeof(Tag), 1, tf) == 1) { + if (Tag.Active) + Tag.Active = FALSE; + else + Tag.Active = TRUE; + + fseek(tf,(x - 1) * sizeof(Tag), SEEK_SET); + fwrite(&Tag, sizeof(Tag), 1, tf); + } + } + } + } + + if (i == Keystroke(358, 1)) { + fclose(tf); + unlink("taglist"); + free(temp); + return; + } + + if ((i == '\r') || (i == '\n')) { + fclose(tf); + free(temp); + return; + } + } +} + + + +/* + * View a file in the current area. + */ +void ViewFile() +{ +} + + diff --git a/mbsebbs/file.h b/mbsebbs/file.h new file mode 100644 index 00000000..14021785 --- /dev/null +++ b/mbsebbs/file.h @@ -0,0 +1,24 @@ +#ifndef _FILE_H +#define _FILE_H + + +void File_RawDir(char *); /* Raw Directory List of a Directory */ +void File_List(void); /* List files in current Area */ +void Download(void); /* Tagged file download */ +int DownloadDirect(char *, int);/* Download a file direct */ +int KeywordScan(void); /* Search a file on a keyword */ +int FilenameScan(void); /* Search a file on filenames */ +int NewfileScan(int); /* Scan for new files */ +int Upload(void); /* Upload a file. */ +void FileArea_List(char *); /* Select file area */ +void SetFileArea(unsigned long);/* Select new area and load globals */ +void EditTaglist(void); /* Edit download taglist */ +void List_Home(void); /* List users home directory */ +void Delete_Home(void); /* Delete file from home directory */ +int Download_Home(void); /* Allows user to download from home dir */ +int Upload_Home(void); /* Allows user to upload to home directory */ +void Copy_Home(void); /* Copy a file to home directory */ +void ViewFile(void); /* View a file in the current area. */ + +#endif + diff --git a/mbsebbs/filesub.c b/mbsebbs/filesub.c new file mode 100644 index 00000000..48af87f3 --- /dev/null +++ b/mbsebbs/filesub.c @@ -0,0 +1,1099 @@ +/***************************************************************************** + * + * File ..................: bbs/filesub.c + * Purpose ...............: All the file sub functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "filesub.h" +#include "funcs.h" +#include "language.h" +#include "funcs4.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" +#include "change.h" + + + +long arecno = 1; /* Area record number */ +int Hcolor = 9; /* Color of area line in xxxScan() functions */ + + +/* + * Variables for file tagging + */ +int Tagnr; +_Tag Tagbuf[100]; + + + +/* + * Reset the tag ringbuffer. + */ +void InitTag() +{ + int i; + + Tagnr = 0; + + for (i = 0; i < 100; i++) { + memset(&Tagbuf[i], 0, sizeof(_Tag)); + } +} + + + +/* + * Add a file in the tag ringbuffer. + */ +void SetTag(_Tag tag) +{ + if (Tagnr < 99) + Tagnr++; + else + Tagnr = 1; + + Tagbuf[Tagnr] = tag; +} + + + +int ForceProtocol() +{ + /* + * If user has no default protocol, make sure he has one. + */ + if (strcmp(sProtName, "") == 0) { + Chg_Protocol(); + + /* + * If the user didn't pick a protocol, quit. + */ + if (strcmp(sProtName, "") == 0) { + return FALSE; + } + } + return TRUE; +} + + + +/* + * Get string, no newline afterwards. + */ +void GetstrD(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 6"); + return; + } + Setraw(); + strcpy(sStr, ""); + + alarm_on(); + while (ch != 13) { + ch = Readkey(); + + if (((ch == 8) || (ch == KEY_DEL) || (ch == 127)) && (iPos > 0)) { + printf("\b \b"); + fflush(stdout); + sStr[--iPos]='\0'; + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + fflush(stdout); + } else + ch=07; + } + } + + Unsetraw(); + close(ttyfd); +} + + + +/* + * Open FileDataBase. + */ +FILE *OpenFileBase(unsigned long Area, int Write) +{ + FILE *pFile; + char *FileBase; + + FileBase = calloc(PATH_MAX, sizeof(char)); + sprintf(FileBase,"%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), Area); + + if (Write) + pFile = fopen(FileBase, "r+"); + else + pFile = fopen(FileBase, "r"); + + if (pFile == NULL) { + WriteError("$Can't open file: %s", FileBase); + /* Can't open file database for this area */ + printf("%s\n\n", (char *) Language(237)); + sleep(2); + } + free(FileBase); + return pFile; +} + + + +/* + * Open the fareas.data file for read or R/W and read the headerrecord. + * The filepointer is at the start of the first record. + */ +FILE *OpenFareas(int Write) +{ + FILE *pAreas; + char *FileArea; + + FileArea = calloc(PATH_MAX, sizeof(char)); + sprintf(FileArea, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if (Write) + pAreas = fopen(FileArea, "r+"); + else + pAreas = fopen(FileArea, "r"); + + if (pAreas == NULL) { + WriteError("$Can't open FileBase %s", FileArea); + /* FATAL: Unable to open areas database */ + printf("%s\n\n", (char *) Language(243)); + sleep(2); + } else + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + free(FileArea); + return pAreas; +} + + + +/* + * Pageheader for filelistings + */ +void Header() +{ + colour(4, 7); + printf(" Area "); + + colour(4, 7); + printf("%-5d ", iAreaNumber); + + colour(1,7); + printf("%-65s\n", sAreaDesc); + + colour(15,0); + fLine(79); +} + + + +/* + * Searchheader for areas during xxxxScan(). + */ +void Sheader() +{ + colour(Hcolor, 0); + printf("\r %-4ld", arecno); + + colour(9, 0); + printf(" ... "); + + colour(Hcolor, 0); + printf("%-40s", area.Name); + fflush(stdout); + + if (Hcolor < 15) + Hcolor++; + else + Hcolor = 9; +} + + + +/* + * Blank current line without newline. + */ +void Blanker(int count) +{ + int i; + + for (i = 0; i < count; i++) + printf("\b"); + + for (i = 0; i < count; i++) + printf(" "); + + printf("\r"); + fflush(stdout); +} + + + +/* + * Mark one or more files for download by putting them into the "taglist" + * in the users homedirectory. Check against dupe tags. + */ +void Mark() +{ + char *temp; + FILE *fp; + int i, Found; + int Count, Size; + + temp = calloc(81, sizeof(char)); + + /* + * First count the already tagged files. + */ + Count = Size = 0; + if ((fp = fopen("taglist", "r")) != NULL) { + while (fread(&Tag, sizeof(Tag), 1, fp) == 1) { + if (Tag.Active) { + Count++; + Size += (Tag.Size / 1024); + } + } + fclose(fp); + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Marked: */ + printf("%s%d, %dK; ", (char *) Language(360), Count, Size); + + /* Mark file number of press to stop */ + printf("%s", (char *) Language(7)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrD(temp, 10); + Blanker(strlen(Language(7)) + strlen(temp)); + + if (strlen(temp) == 0) { + free(temp); + return; + } + + i = atoi(temp); + + if ((i > 0) && (i < 100)) { + if ((Tagbuf[i].Area) && (strlen(Tagbuf[i].File))) { + if (Access(exitinfo.Security, area.DLSec)) { + if ((fp = fopen("taglist", "a+")) != NULL) { + + fseek(fp, 0, SEEK_SET); + Found = FALSE; + while (fread(&Tag, sizeof(Tag), 1, fp) == 1) + if ((Tag.Area == Tagbuf[i].Area) && (strcmp(Tag.File, Tagbuf[i].File) == 0)) { + Found = TRUE; + Syslog('b', "Tagbuf[i].File already tagged"); + } + + if (!Found) { + memset(&Tag, 0, sizeof(Tag)); + Tag = Tagbuf[i]; + Tag.Active = TRUE; + fwrite(&Tag, sizeof(Tag), 1, fp); + Syslog('+', "Tagged file %s from area %d", Tag.File, Tag.Area); + } + + fclose(fp); + } + } else { + colour(12, 0); + /* You do not have enough access to download from this area. */ + printf("%s", (char *) Language(244)); + fflush(stdout); + sleep(3); + Blanker(strlen(Language(244))); + } + } + } + + free(temp); +} + + + +/* + * More prompt, returns 1 if user decides not to look any further. + */ +int iLC(int Lines) +{ + int x, z; + + x = strlen(Language(131)); + iLineCount += Lines; + + if ((iLineCount >= exitinfo.iScreenLen) && (iLineCount < 1000)) { + iLineCount = 0; + + while(TRUE) { + /* More (Y/n/=) M=Mark */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(131)); + + fflush(stdout); + alarm_on(); + z = toupper(Getone()); + Blanker(x); + + if (z == Keystroke(131, 1)) { + printf("\n"); + return 1; + } + + if (z == Keystroke(131, 2)) { + iLineCount = 1000; + return 0; + } + + if ((z == Keystroke(131, 0)) || (z == '\r') || (z == '\n')) { + return 0; + } + + if (z == Keystroke(131, 3)) { + Mark(); + } + } + } + return 0; +} + + + +/* + * Show one file, return 1 if user wants to stop, 0 to show next file. + */ +int ShowOneFile() +{ + int y, z, fg, bg; + + if ((!file.Deleted) && (!file.Missing)) { + + colour(7, 0); + printf(" %02d ", Tagnr); + + colour(CFG.FilenameF, CFG.FilenameB); + if(strlen(file.Name) < 25) + printf("%-15s", file.Name); + else { + printf("%-75s", file.Name); + if (iLC(1) == 1) + return 1; + } + + colour(CFG.FilesizeF, CFG.FilesizeB); + if(strlen(file.Name) < 25) + printf("%10lu ", file.Size); + else + printf("%25lu ", file.Size); + + colour(CFG.FiledateF, CFG.FiledateB); + printf("%-10s ", StrDateDMY(file.UploadDate)); + + colour(12, 0); + if(file.TimesDL < 10) + printf(" "); + + if(file.TimesDL < 100) + printf(" "); + + if(file.TimesDL < 1000) + printf(" "); + + if(file.TimesDL > 9999) + file.TimesDL = 9999; + + printf("[%ld] ", file.TimesDL); + + if((strcmp(file.Uploader, "")) == 0) + strcpy(file.Uploader, "SysOp"); + + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s%s\n", (char *) Language(238), file.Uploader); + + if (iLC(1) == 1) + return 1; + + for(z = 0; z <= 25; z++) { + if ((y = strlen(file.Desc[z])) > 1) { + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) { + /* + * Color formatted description lines. + */ + if (file.Desc[z][3] > '9') + fg = (int)file.Desc[z][3] - 55; + else + fg = (int)file.Desc[z][3] - 48; + bg = (int)file.Desc[z][2] - 48; + colour(fg, bg); + printf(" %s\n",file.Desc[z]+4); + } else { + colour(CFG.FiledescF, CFG.FiledescB); + printf(" %s\n",file.Desc[z]); + } + + if (iLC(1) == 1) + return 1; + } + } + } + return 0; +} + + + +int CheckBytesAvailable(long CostSize) +{ + if((exitinfo.DownloadKToday <= 0) || ((CostSize / 1024) > exitinfo.DownloadKToday)) { + + /* You do not have enough bytes to download \" */ + pout(12, 0, (char *) Language(252)); + Enter(1); + Syslog('+', "Not enough bytes to download %ld", CostSize); + + colour(15, 0); + /* You must upload before you can download. */ + pout(12, 0, (char *) Language(253)); + Enter(2); + + colour(14, 0); + /* Kilobytes currently available: */ + printf("%s%lu Kbytes.\n\n", (char *) Language(254), exitinfo.DownloadKToday); + + Pause(); + return FALSE; + } + + return TRUE; +} + + + +/* + * Change back to users homedir. + */ +void Home() +{ + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s", CFG.bbs_usersdir, exitinfo.Name); + chdir(temp); + free(temp); +} + + + +/* + * Scan a .COM or .EXE file in users upload directory. + */ +int ScanDirect(char *fn) +{ + FILE *fp; + int err, Found = FALSE; + char *temp, *temp1; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + sprintf(temp1, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp1, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + + sprintf(temp1, "%s %s %s >/dev/null", virscan.scanner, virscan.options, temp); + colour(CFG.TextColourF, CFG.TextColourB); + /* Scanning */ /* with */ + printf("%s %s %s %s ", (char *) Language(132), fn, (char *) Language(133), virscan.comment); + fflush(stdout); + Syslog('b', "%s ", temp1); + + if ((err = system(temp1))) { + Syslog('?', "VIRUS ALERT: Result %d", err); + colour(CFG.HiliteF, CFG.HiliteB); + /* Possible VIRUS found! */ + printf("%s\n", (char *) Language(199)); + Found = TRUE; + } else + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + } + fclose(fp); + } + + free(temp); + free(temp1); + return Found; +} + + + +/* + * Scan archive using users ./tmp directory. + * Return codes: + * 0 - All seems well + * 1 - Error unpacking archive + * 2 - Possible virus found + * 3 - Not a known archive format. + */ +int ScanArchive(char *fn, char *ftype) +{ + FILE *fp; + int err, Found = FALSE; + char *temp; + char *cwd = NULL; + + + /* + * First search for the right archiver program + */ + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return 3; + } + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((strcmp(ftype, archiver.name) == 0) && (archiver.available)) { + break; + } + } + fclose(fp); + if ((strcmp(ftype, archiver.name)) || (!archiver.available)) { + free(temp); + return 3; + } + + Syslog('b', "Archiver %s", archiver.comment); + + cwd = getcwd(cwd, 80); + Syslog('b', "Current directory is %s", cwd); + + sprintf(temp, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + if (chdir(temp)) { + WriteError("$Can't chdir(%s)", temp); + free(temp); + return 1; + } + + colour(CFG.TextColourF, CFG.TextColourB); + /* Unpacking archive */ + printf("%s %s ", (char *) Language(201), fn); + fflush(stdout); + sprintf(temp, "%s %s/%s >/dev/null", archiver.funarc, cwd, fn); + Syslog('b', "Unarc %s", temp); + + if ((err = system(temp))) { + WriteError("$Failed %s", temp); + system("rm -f -r *"); + chdir(cwd); + free(cwd); + colour(CFG.HiliteF, CFG.HiliteB); + /* ERROR */ + printf("%s\n", (char *) Language(217)); + fflush(stdout); + return 1; + } + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + + sprintf(temp, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fp); + + while (fread(&virscan, virscanhdr.recsize, 1, fp) == 1) { + + sprintf(temp, "%s %s * >/dev/null", virscan.scanner, virscan.options); + colour(CFG.TextColourF, CFG.TextColourB); + /* Scanning */ /* with */ + printf("%s %s %s %s ", (char *) Language(132), fn, (char *) Language(133), virscan.comment); + fflush(stdout); + Syslog('b', "%s ", temp); + + if ((err = system(temp))) { + Syslog('?', "VIRUS ALERT: Result %d", err); + colour(CFG.HiliteF, CFG.HiliteB); + /* Possible VIRUS found! */ + printf("%s\n", (char *) Language(199)); + Found = TRUE; + } else + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + } + fclose(fp); + } + + system("rm -f -r *"); + chdir(cwd); + free(cwd); + free(temp); + + if (Found) + return 2; + else + return 0; +} + + + +/* + * Try to find out the type of uploaded file. + */ +char *GetFileType(char *fn) +{ + unsigned char buf[8], dbuf[80]; + FILE *fp; + int i; + + if ((fp = fopen(fn, "r")) == NULL) { + WriteError("$Can't open file %s", fn); + return NULL; + } + + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) { + WriteError("$Can't read head of file %s", fn); + return NULL; + } + + fclose(fp); + dbuf[0] = '\0'; + + for (i = 0; i < sizeof(buf); i++) + if ((buf[i] >= ' ') && (buf[i] <= 127)) + sprintf((char*)dbuf+strlen(dbuf), " %c", buf[i]); + else + sprintf((char*)dbuf+strlen(dbuf), " %02x", buf[i]); + + Syslog('b', "file head: %s", dbuf); + + /* + * Various expected uploads. Not that the standard MS-DOS archivers + * must return the exact format, ie "ZIP" for PKZIP. These strings + * are tested against the archivers database. Others that aren't + * compressed files are not important, they just pop up in your + * logfiles. + */ + if (memcmp(buf, "PK\003\004", 4) == 0) return (char *)"ZIP"; + if (*buf == 0x1a) return (char *)"ARC"; + if (memcmp(buf+2, "-l", 2) == 0) return (char *)"LZH"; + if (memcmp(buf, "ZOO", 3) == 0) return (char *)"ZOO"; + if (memcmp(buf, "`\352", 2) == 0) return (char *)"ARJ"; + if (memcmp(buf, "Rar!", 4) == 0) return (char *)"RAR"; + if (memcmp(buf, "MZ", 2) == 0) return (char *)"EXE"; + if (memcmp(buf, "\000\000\001\263", 4) == 0) return (char *)"MPEG"; + if (memcmp(buf, "MOVI", 4) == 0) return (char *)"MOVI"; + if (memcmp(buf, "\007\007\007", 3) == 0) return (char *)"CPIO"; + if (memcmp(buf, "\351,\001JAM", 6) == 0) return (char *)"JAM"; + if (memcmp(buf, "SQSH", 4) == 0) return (char *)"SQSH"; + if (memcmp(buf, "UC2\0x1a", 4) == 0) return (char *)"UC2"; + if (memcmp(buf, ".snd", 4) == 0) return (char *)"SND"; + if (memcmp(buf, "MThd", 4) == 0) return (char *)"MID"; + if (memcmp(buf, "RIFF", 4) == 0) return (char *)"WAV"; + if (memcmp(buf, "EMOD", 4) == 0) return (char *)"MOD"; + if (memcmp(buf, "MTM", 3) == 0) return (char *)"MTM"; + if (memcmp(buf, "#/bin/", 6) == 0) return (char *)"UNIX script"; + if (memcmp(buf, "\037\235", 2) == 0) return (char *)"Compressed data"; + if (memcmp(buf, "\037\213", 2) == 0) return (char *)"gzip compress"; + if (memcmp(buf, "\177ELF", 4) == 0) return (char *)"ELF"; + if (memcmp(buf, "%!", 2) == 0) return (char *)"PostScript"; + if (memcmp(buf, "GIF8", 4) == 0) return (char *)"GIF"; + if (memcmp(buf, "\377\330\377\340", 4) == 0) return (char *)"JPEG"; + if (memcmp(buf, "\377\330\377\356", 4) == 0) return (char *)"JPG"; + if (memcmp(buf, "BM", 2) == 0) return (char *)"Bitmap"; + if (memcmp(buf, "%PDF", 4) == 0) return (char *)"PDF"; + if (memcmp(buf, "THNL", 4) == 0) return (char *)"ThumbNail"; + if ((memcmp(buf, "", 6) == 0) || + (memcmp(buf, "", 6) == 0)) return (char *)"HTML"; + + /* + * .COM formats. Should cover about 2/3 of COM files. + */ + if ((*buf == 0xe9) || (*buf == 0x8c) || + (*buf == 0xeb) || (*buf == 0xb8)) return (char *)"COM"; + + return NULL; +} + + + +/* + * Import file in area. Returns TRUE if successfull. + */ +int ImportFile(char *fn, int Area, int fileid, time_t iTime, off_t Size) +{ + char *temp, *temp1; + int i, x; + char *token; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s", area.Path, fn); + sprintf(temp1, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + + Syslog('b', "Move %s to %s", temp1, temp); + if ((file_mv(temp1, temp))) { + WriteError("$Can't move %s to %s", fn, area.Path); + } else { + if (Addfile(fn, Area, fileid)) { + + ReadExitinfo(); + + /* + * If Size is equal to Zero, don't increase file counters else + * Increase file counters if any other size + */ + if (Size) { + exitinfo.Uploads++; + exitinfo.UploadK += (Size / 1024); + exitinfo.UploadKToday += (Size / 1024); + Syslog('b', "Uploads %d, Kb %d, Kb today %d", exitinfo.Uploads, + exitinfo.UploadK, exitinfo.UploadKToday); + + /* + * Give back the user his bytes from the upload + * Work out byte ratio, then give time back to user + */ + strcpy(temp, CFG.sByteRatio); + token = strtok(temp, ":"); + i = atoi(token); + token = strtok(NULL, "\0"); + x = atoi(token); + Size *= i / x; + /* You have */ /* extra download KBytes. */ + printf("%s %ld %s\n", (char *) Language(249), Size / 1024, (char *) Language(250)); + + exitinfo.DownloadKToday += (Size / 1024); + Syslog('b', "DownloadKToday %d", exitinfo.DownloadKToday); + } + + /* + * Give back the user his time that he used to upload + * Work out time ratio, then give time back to user + * Ratio 3:1, Upload time: times by 3 / 1 + */ + strcpy(temp, CFG.sTimeRatio); + token = strtok(temp, ":"); + i = atoi(token); + token = strtok(NULL, "\0"); + x = atoi(token); + + iTime *= i / x; + iTime /= 60; /* Divide Seconds by 60 to give minutes */ + /* You have */ /* extra minutes. */ + printf("%s %ld %s\n", (char *) Language(249), iTime, (char *) Language(259)); + + exitinfo.iTimeLeft += iTime; + + WriteExitinfo(); + return TRUE; + } + } + + free(temp); + free(temp1); + return FALSE; +} + + + +/* + * Add file to the FileDataBase. If fileid is true, then try to + * get the filedescription from FILE_ID.DIZ if it is in the + * archive, else the user must supply the description. + * Returns TRUE is successfull. + */ +int Addfile(char *File, int AreaNum, int fileid) +{ + FILE *id, *pFileDB, *pPrivate; + int err, iDesc = 1, iPrivate = FALSE, GotId = FALSE; + char *Filename, *temp1; + char *Desc[26]; + struct stat statfile; + int i; + char temp[81]; + + Filename = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + + sprintf(Filename, "%s/%s", area.Path, File); + + if ((pFileDB = OpenFileBase(AreaNum, TRUE)) != NULL) { + /* + * Do a physical check of file to see if it exists + * if it fails it will return a zero which will not + * increase his uploads stats + */ + if(stat(Filename, &statfile) != 0) { + + colour(10, 0); + /* Upload was unsuccessful for: */ + printf("\n%s%s\n\n", (char *) Language(284), File); + + fclose(pFileDB); + free(Filename); + free(temp1); + return FALSE; + } + + memset(&file, 0, sizeof(file)); + strcpy(file.Name, File); + sprintf(temp1,"%ld",statfile.st_size); + file.Size = atoi(temp1); + file.FileDate = statfile.st_mtime; + strcpy(file.Uploader, exitinfo.sUserName); + time(&file.UploadDate); + + if(area.PwdUP) { + colour(9,0); + /* Do you want to password protect your upload ? [y/N]: */ + printf("\n%s", (char *) Language(285)); + fflush(stdout); + + if (toupper(Getone()) == Keystroke(285, 0)) { + colour(10, 0); + /* REMEMBER: Passwords are "CaSe SeNsITiVe!" */ + printf("\n%s\n", (char *) Language(286)); + colour(14,0); + /* Password: */ + printf("%s", (char *) Language(8)); + fflush(stdout); + fflush(stdin); + GetstrC(file.Password, 20); + } + } + + if (fileid) { + /* + * The right unarchiver is still in memory, + * get the FILE_ID.DIZ if it exists. + */ + sprintf(temp, "%s %s/%s FILE_ID.DIZ >/dev/null", archiver.iunarc, area.Path, File); + Syslog('b', "%s", temp); + if ((err = system(temp))) { + WriteError("$Unpack error %s", temp); + } else { + Syslog('+', "Found FILE_ID.DIZ"); + GotId = TRUE; + colour(CFG.TextColourF, CFG.TextColourB); + /* Found FILE_ID.DIZ in */ + printf("%s %s\n", (char *) Language(257), File); + fflush(stdout); + } + } + + if (GotId) { + if ((id = fopen("FILE_ID.DIZ", "r")) != NULL) { + /* + * Import FILE_ID.DIZ, format to max. 25 + * lines, 48 chars width. + */ + while ((fgets(temp1, 256, id)) != NULL) { + if (iDesc < 26) { + Striplf(temp1); + temp1[48] = '\0'; + strcpy(file.Desc[iDesc - 1], temp1); + } + iDesc++; + } + } + fclose(id); + unlink("FILE_ID.DIZ"); + } else { + /* + * Ask the user for a description. + */ + for (i = 0; i < 26; i++) + *(Desc + i) = (char *) calloc(49, sizeof(char)); + + colour(12,0); + /* Please enter description of file */ + printf("\n%s %s\n\n", (char *) Language(287), File); + while (TRUE) { + colour(10,0); + printf("%2d> ", iDesc); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + + GetstrC(*(Desc + iDesc), 48); + + if((strcmp(*(Desc + iDesc), "")) == 0) + break; + + iDesc++; + + if(iDesc >= 26) + break; + } + + for(i = 1; i < iDesc; i++) + strcpy(file.Desc[i - 1], Desc[i]); + + for (i = 0; i < 26; i++) + free(Desc[i]); + } + + fseek(pFileDB, 0, SEEK_END); + fwrite(&file, sizeof(file), 1, pFileDB); + fclose(pFileDB); + + sprintf(temp, "%s/log/uploads.log", getenv("MBSE_ROOT")); + if ((pPrivate = fopen(temp, "a+")) == NULL) + WriteError("$Can't open %s", temp); + else { + iPrivate = TRUE; + fprintf(pPrivate, "****************************************************"); + fprintf(pPrivate, "\nUser : %s", file.Uploader); + fprintf(pPrivate, "\nFile : %s", file.Name); + fprintf(pPrivate, "\nSize : %lu", file.Size); + fprintf(pPrivate, "\nUpload Date : %s\n\n", StrDateDMY(file.UploadDate)); + + for(i = 0; i < iDesc - 1; i++) + fprintf(pPrivate, "%2d: %s\n", i, file.Desc[i]); + + fclose(pPrivate); + } + + Enter(1); + /* Your upload time has been returned to you. Thank you for your upload! */ + pout(10, 0, (char *) Language(288)); + Enter(1); + } + + free(Filename); + free(temp1); + return TRUE; +} + + + +/* + * Set file area number, set global area description and path. + */ +void SetFileArea(unsigned long AreaNum) +{ + FILE *pArea; + long offset; + + memset(&area, 0, sizeof(area)); + + if ((pArea = OpenFareas(FALSE)) == NULL) + return; + + offset = areahdr.hdrsize + ((AreaNum - 1) * areahdr.recsize); + if (fseek(pArea, offset, 0) != 0) { + WriteError("$Seek error in fareas.data, area %ld", AreaNum); + return; + } + + fread(&area, areahdr.recsize, 1, pArea); + strcpy(sAreaDesc, area.Name); + strcpy(sAreaPath, area.Path); + iAreaNumber = AreaNum; + fclose(pArea); +} + + + +unsigned long Quota() +{ + DIR *dirp; + char *FileName, *temp; + unsigned long Bytes = 0; + struct dirent *dp; + struct stat statfile; + + FileName = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/%s/wrk", CFG.bbs_usersdir, exitinfo.Name); + + if ((dirp = opendir(temp)) == NULL) { + WriteError("$Can't open dir %s", temp); + } else { + while ((dp = readdir(dirp)) != NULL) { + sprintf(FileName, "%s/%s", temp, dp->d_name); + + if (*(dp->d_name) != '.') + if (stat(FileName, &statfile) == 0) + Bytes += statfile.st_size; + } + + closedir(dirp); + } + + free(FileName); + free(temp); + return Bytes; +} + + + +void ImportHome(char *fn) +{ + char *temp1, *temp2; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + sprintf(temp1, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + sprintf(temp2, "%s/%s/upl/%s", CFG.bbs_usersdir, exitinfo.Name, fn); + + Syslog('+', "Move %s to home, result %d", fn, file_mv(temp2, temp1)); + free(temp1); + free(temp2); +} + + diff --git a/mbsebbs/filesub.h b/mbsebbs/filesub.h new file mode 100644 index 00000000..bcc2ee16 --- /dev/null +++ b/mbsebbs/filesub.h @@ -0,0 +1,28 @@ +#ifndef _FILESUB_H +#define _FILESUB_H + + +FILE *OpenFileBase(unsigned long Area, int); +FILE *OpenFareas(int); +int ForceProtocol(void); +int CheckBytesAvailable(long); +int iLC(int); +void Header(void); +void Sheader(void); +int ShowOneFile(void); +int Addfile(char *, int, int); +void InitTag(void); +void SetTag(_Tag); +void Blanker(int); +void GetstrD(char *, int); +void Mark(void); +int UploadB_Home(char *); +char *GetFileType(char *); +void Home(void); +int ScanDirect(char *); +int ScanArchive(char *, char *); +int ImportFile(char *, int, int, time_t, off_t); +unsigned long Quota(void); +void ImportHome(char *); + +#endif diff --git a/mbsebbs/fsedit.c b/mbsebbs/fsedit.c new file mode 100644 index 00000000..ecd0887c --- /dev/null +++ b/mbsebbs/fsedit.c @@ -0,0 +1,753 @@ +/***************************************************************************** + * + * File ..................: bbs/fsedit.c + * Purpose ...............: FullScreen Message editor. + * Last modification date : 23-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/ansi.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mail.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" +#include "pinfo.h" +#include "fsedit.h" + + +extern int Line; /* Number of lines + 1 */ +extern char *Message[]; /* TEXTBUFSIZE lines of 80 chars */ + +int Row; /* Current row on screen */ +int Col; /* Current column in text and on screen */ +int TopVisible; /* First visible line of text */ +int InsMode; /* Insert mode */ +int CurRow; /* Current row in buffer */ + + + +void Show_Ins(void); +void Show_Ins(void) +{ + locate(1, 70); + colour(YELLOW, BLUE); + if (InsMode) + printf("INS"); + else + printf("OVR"); + fflush(stdout); +} + + + +void Top_Help(void); +void Top_Help() +{ + locate(1,1); + colour(YELLOW, BLUE); + printf("%s", padleft((char *)"Press ESC for menu, other keys is edit text", 80, ' ')); + Show_Ins(); +} + + + +void Top_Menu(void); +void Top_Menu(void) +{ + locate(1,1); + colour(WHITE, RED); + printf("%s", padleft((char *)"(A)bort (H)elp (S)ave - Any other key is continue edit", 80, ' ')); + fflush(stdout); +} + + + +void Ls(int, int); +void Ls(int a, int y) +{ + locate(y, 10); + printf("%c ", a ? 179 : '|'); +} + + + +void Rs(int); +void Rs(int a) +{ + colour(LIGHTGREEN, BLUE); + printf("%c", a ? 179 : '|'); +} + + + +void Ws(int, int); +void Ws(int a, int y) +{ + int i; + + Ls(a, y); + for (i = 0; i < 57; i++) + printf(" "); + Rs(a); +} + + + +void Hl(int, int, char *); +void Hl(int a, int y, char *txt) +{ + Ls(a, y); + colour(WHITE, BLUE); + printf("%s", padleft(txt, 57, ' ')); + Rs(a); +} + + + +void Full_Help(void); +void Full_Help(void) +{ + int a, i; + + a = exitinfo.GraphMode; + + colour(LIGHTGREEN, BLUE); + + /* Top row */ + locate(1, 10); + printf("%c", a ? 213 : '+'); + for (i = 0; i < 58; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 184 : '+'); + + Ws(a, 2); + + Ls(a, 3); + colour(YELLOW, BLUE); + printf("%s", padleft((char *)" Editor Help", 57, ' ')); + Rs(a); + + Ws(a, 4); + Hl(a, 5, (char *)"Ctrl-S or LeftArrow - Cursor left"); + Hl(a, 6, (char *)"Ctrl-D or RightArrow - Cursor right"); + Hl(a, 7, (char *)"Ctrl-E or UpArrow - Cursor up"); + Hl(a, 8, (char *)"Ctrl-X or DownArrow - Cursor down"); + Hl(a, 9, (char *)"Ctrl-V or Insert - Insert or Overwrite"); + Hl(a, 10, (char *)"Ctrl-N - Insert line"); + Hl(a, 11, (char *)"Ctrl-Y - Delete line"); + Ws(a, 12); + Hl(a, 13, (char *)"Ctrl-L - Refresh screen"); + Hl(a, 14, (char *)"Ctrl-R - Read from file"); + Ws(a, 15); + + locate(16,10); + printf("%c", a ? 212 : '+'); + for (i = 0; i < 58; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 190 : '+'); + fflush(stdout); +} + + + +void Setcursor(void); +void Setcursor(void) +{ + CurRow = Row + TopVisible - 1; + locate(Row + 1, Col); + fflush(stdout); +} + + + +void Beep(void); +void Beep(void) +{ + printf("\007"); + fflush(stdout); +} + + + +/* + * Refresh and rebuild screen in editing mode. + */ +void Refresh(void); +void Refresh(void) +{ + int i, j = 2; + + clear(); + Top_Help(); + locate(j,1); + colour(CFG.TextColourF, CFG.TextColourB); + + for (i = 1; i <= Line; i++) { + if ((i >= TopVisible) && (i < (TopVisible + exitinfo.iScreenLen -1))) { + locate(j, 1); + j++; + printf("%s", Message[i]); + } + } + Setcursor(); +} + + + +void Debug(void); +void Debug(void) +{ + Syslog('B', "Col=%d Row=%d TopVisible=%d Lines=%d CurRow=%d Len=%d", + Col, Row, TopVisible, Line, Row+TopVisible-1, strlen(Message[Row+TopVisible-1])); +} + + + +void GetstrLC(char *, int); +void GetstrLC(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + printf("\n"); +} + + + +int Fs_Edit() +{ + unsigned char ch; + int i, Changed = FALSE; + char *filname, *tmpname; + FILE *fd; + + Syslog('b', "Entering FullScreen editor"); + clear(); + fflush(stdout); + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + WriteError("$Can't open tty"); + return FALSE; + } + Setraw(); + InsMode = TRUE; + TopVisible = 1; + Col = 1; + Row = 1; + Refresh(); + Debug(); + + while (TRUE) { + Nopper(); + alarm_on(); + ch = Readkey(); + CurRow = Row + TopVisible - 1; + + switch (ch) { + case KEY_ENTER: + Syslog('B', "Enter pressed: Col=%d CurRow=%d Line=%d", Col, CurRow, Line); + Debug(); + if (Col == 1) { + Syslog('B', "Enter at beginning of line"); + for (i = Line; i >= CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "-Moving row %d to %d", i, i+1); + Syslog('B', ":%s", Message[i]); + } + Message[i+1][0] = '\0'; + Syslog('B', "-Clearing row %d", i+1); + } else { + for (i = Line; i > CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "-Moving row %d to %d", i, i+1); + } + Message[CurRow+1][0] = '\0'; + Syslog('B', "-Clearing row %d", CurRow+1); + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "Enter in middle of line"); + for (i = Col-1; i <= strlen(Message[CurRow]); i++) { + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], Message[CurRow][i]); + } + Message[CurRow][Col-1] = '\0'; + } else { + Syslog('B', "Enter at end of line"); + } + } + Line++; + Row++; + Col = 1; + if (Row < (exitinfo.iScreenLen -1)) { + CurRow++; + } else { + Syslog('B', "Scroll down by ENTER"); + Row -= 12; + TopVisible += 12; + } + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + break; + + case ('N' - 64): /* Insert line, scroll down */ + Syslog('B', "Insert line"); + Debug(); + for (i = Line; i >= CurRow; i--) + sprintf(Message[i+1], "%s", Message[i]); + Message[CurRow][0] = '\0'; + Line++; + Col = 1; + Refresh(); + Debug(); + Changed = TRUE; + break; + + case ('Y' - 64): /* Erase line, scroll up */ + Syslog('B', "Erase line"); + Debug(); + if (Line == CurRow) { + Syslog('B', "Erasing last line"); + if (Line > 1) { + Message[CurRow][0] = '\0'; + Line--; + if ((Row == 1) && (TopVisible > 12)) { + Row += 12; + TopVisible -= 12; + } else + Row--; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } else + Beep(); + } else { + Syslog('B', "Erasing line in the middle"); + for (i = CurRow; i < Line; i++) { + sprintf(Message[i], "%s", Message[i+1]); + } + Message[i+1][0] = '\0'; + Line--; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } + break; + + case KEY_UP: + case ('E' - 64): + Syslog('B', "Cursor up"); + if (Row > 1) { + Row--; + CurRow--; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Setcursor(); + Debug(); + } else { + if (TopVisible > 12) { + Syslog('B', "Scroll up"); + TopVisible -= 12; + Row += 12; + Refresh(); + Setcursor(); + Debug(); + } else + Beep(); + } + break; + + case KEY_DOWN: + case ('X' - 64): + Syslog('B', "Cursor down"); + Debug(); + if (Row < (Line - TopVisible + 1)) { + if (Row < (exitinfo.iScreenLen -1)) { + Row++; + CurRow++; + if (Col > strlen(Message[CurRow]) + 1) + Col = strlen(Message[CurRow]) + 1; + Setcursor(); + Debug(); + } else { + Syslog('B', "Scroll down"); + Row -= 12; + TopVisible += 12; + Refresh(); + Setcursor(); + Debug(); + } + } else + Beep(); + break; + + case KEY_LEFT: + case ('S' - 64): + Syslog('B', "Cursor left"); + if (Col > 1) { + Col--; + Setcursor(); + Debug(); + } else + Beep(); + break; + + case KEY_RIGHT: + case ('D' - 64): + if (Col <= strlen(Message[CurRow])) { + Col++; + Setcursor(); + Debug(); + } else + Beep(); + break; + + case KEY_DEL: + Syslog('b', "DEL key"); + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "DEL in middle of line"); + Debug(); + Setcursor(); + for (i = Col; i <= strlen(Message[CurRow]); i++) { + Syslog('B', "i=%d", i); + Message[CurRow][i-1] = Message[CurRow][i]; + printf("%c", Message[CurRow][i]); + } + printf(" \b"); + Message[i-1] = '\0'; + Setcursor(); + } else + Beep(); + + /* + * Trap the extra code so it isn't + * inserted in the text + */ + ch = Readkey(); + break; + + case KEY_BACKSPACE: + case KEY_RUBOUT: + Syslog('B', "BS at Col=%d Row=%d CurRow=%d", Col, Row, CurRow); + if (Col == 1 && CurRow == 1) { + Syslog('B', "BS on first character in message"); + Beep(); + } else if (Col == 1) { + if (strlen(Message[CurRow-1]) + strlen(Message[CurRow]) < 75) { + Col = strlen(Message[CurRow-1]) + 1; + strcat(Message[CurRow-1], Message[CurRow]); + for ( i = CurRow; i < Line; i++) + sprintf(Message[i], "%s", Message[i+1]); + Message[i+1][0] = '\0'; + Line--; + Row--; + CurRow--; + Refresh(); + Setcursor(); + Debug(); + Changed = TRUE; + } else Beep(); + } else { + if (Col == strlen(Message[CurRow]) + 1) { + Syslog('B', "BS at end of line"); + Debug(); + printf("\b \b"); + fflush(stdout); + Col--; + Message[CurRow][Col-1] = '\0'; + Changed = TRUE; + } else { + Syslog('B', "BS in middle of line"); + Debug(); + Col--; + Setcursor(); + for (i = Col; i < strlen(Message[CurRow]); i++) { + Syslog('B', "i=%d", i); + Message[CurRow][i-1] = Message[CurRow][i]; + printf("%c", Message[CurRow][i]); + } + printf(" \b"); + Message[CurRow][strlen(Message[CurRow])] = '\0'; + Setcursor(); + Changed = TRUE; + } + } + break; + + case KEY_INS: + case ('V' - 64): + if (InsMode) + InsMode = FALSE; + else + InsMode = TRUE; + Show_Ins(); + colour(CFG.TextColourF, CFG.TextColourB); + Setcursor(); + Syslog('B', "InsertMode now %s", InsMode ? "True" : "False"); + /* + * Trap the extra code so it isn't + * inserted in the text + */ + ch = Readkey(); + break; + + case ('L' - 64): /* Refresh screen */ + Syslog('B', "Refresh()"); + Refresh(); + Debug(); + break; + + case ('R' - 64): /* Read from file */ + Syslog('b', "Read from file"); + + tmpname = calloc(PATH_MAX, sizeof(char)); + filname = calloc(PATH_MAX, sizeof(char)); + + colour(14, 0); + /* Please enter filename: */ + printf("\n%s", (char *) Language(245)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrLC(filname, 80); + + if ((strcmp(filname, "") == 0)) { + colour(CFG.HiliteF, CFG.HiliteB); + /* No filename entered, aborting */ + printf("\n\n%s\n", (char *) Language(246)); + Pause(); + free(filname); + free(tmpname); + Refresh(); + Debug(); + break; + } + + if (*(filname) == '/' || *(filname) == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename */ + printf("\n\n%s\n", (char *) Language(247)); + Pause(); + free(tmpname); + free(filname); + Refresh(); + Debug(); + break; + } + + sprintf(tmpname, "%s/%s/wrk/%s", CFG.bbs_usersdir, exitinfo.Name, filname); + if ((fd = fopen(tmpname, "r")) == NULL) { + WriteError("$Can't open %s", tmpname); + colour(CFG.HiliteF, CFG.HiliteB); + /* File does not exist, please try again */ + printf("\n\n%s\n", (char *) Language(296)); + Pause(); + } else { + while ((fgets(filname, 80, fd)) != NULL) { + for (i = 0; i < strlen(filname); i++) { + if (*(filname + i) == '\0') + break; + if (*(filname + i) == '\n') + *(filname + i) = '\0'; + if (*(filname + i) == '\r') + *(filname + i) = '\0'; + } + /* + * Make sure that any tear or origin lines are + * made invalid. + */ + if (strncmp(filname, (char *)"--- ", 4) == 0) + filname[1] = 'v'; + if (strncmp(filname, (char *)" * Origin:", 10) == 0) + filname[1] = '+'; + sprintf(Message[Line], "%s", filname); + Line++; + } + fclose(fd); + Changed = TRUE; + Syslog('+', "Inserted file %s", tmpname); + } + + free(tmpname); + free(filname); + Refresh(); + Debug(); + Col = 1; + Setcursor(); + break; + + case KEY_ESCAPE: /* Editor menu */ + Syslog('B', "Escape pressed"); + Top_Menu(); + + ch = toupper(Readkey()); + if (ch == 'A' || ch == 'S') { + Syslog('B', "%s message (%c)", (ch == 'S' && Changed) ? "Saving" : "Aborting", ch); + Unsetraw(); + close(ttyfd); + Debug(); + clear(); + fflush(stdout); + for (i = 1; i <= Line; i++) + Syslog('B', "%3d \"%s\"", i, Message[i]); + if (ch == 'S' && Changed) { + Syslog('+', "Message saved"); + return TRUE; + } else { + Syslog('+', "Message aborted"); + return FALSE; + } + } + + if (ch == 'H') { + Syslog('B', "User wants help"); + Full_Help(); + ch = Readkey(); + Refresh(); + } else + Top_Help(); + + colour(CFG.TextColourF, CFG.TextColourB); + Setcursor(); + break; + + default: + if (ch > 31 && ch < 127) { + /* + * Normal printable characters + */ + Debug(); + if (Col == strlen(Message[CurRow]) + 1) { + /* + * Append to line + */ + if (Col < 79) { + Col++; + sprintf(Message[CurRow], "%s%c", Message[CurRow], ch); + printf("%c", ch); + fflush(stdout); + Changed = TRUE; + } else { + /* + * Do simple word wrap + */ + for (i = Line; i > CurRow; i--) { + sprintf(Message[i+1], "%s", Message[i]); + Syslog('B', "[WW]-Moving row %d to %d", i, i+1); + } + Message[CurRow+1][0] = '\0'; + Syslog('B', "[WW]-Clearing row %d", CurRow+1); + Col = 74; + while (Message[CurRow][Col] != ' ' && i != 0) + Col--; + Col++; + if (Col <= strlen(Message[CurRow])) { + Syslog('B', "[WW]-Move end of line %d to new row %d", CurRow, CurRow+1); + for (i = Col; i <= strlen(Message[CurRow]); i++) { + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], Message[CurRow][i]); + } + Message[CurRow][Col-1] = '\0'; + } + sprintf(Message[CurRow+1], "%s%c", Message[CurRow+1], ch); + Line++; + Row++; + Col = strlen(Message[CurRow+1])+1; + Refresh(); + Debug(); + Changed = TRUE; + } + } else { + /* + * Insert or overwrite + */ + Syslog('b', "%s in line", InsMode ? "Insert" : "Overwrite"); + if (InsMode) { + if (strlen(Message[CurRow]) < 80) { + for (i = strlen(Message[CurRow]); i > (Col-1); i--) { + Syslog('B', "(i+1=%d)[%c] = (i=%d)[%c]", i+1, Message[CurRow][i+1], i, Message[CurRow][i]); + Message[CurRow][i+1] = Message[CurRow][i]; + } + Message[CurRow][Col-1] = ch; + Col++; + locate(Row + 1, 1); + printf(Message[CurRow]); + Setcursor(); + Changed = TRUE; + } else { + Beep(); + } + } else { + Message[CurRow][Col-1] = ch; + printf("%c", ch); + fflush(stdout); + Col++; + Changed = TRUE; + } + } + } else + Syslog('b', "Pressed %d (unsupported)", ch); + } + } + + WriteError("FsEdit(): Impossible to be here"); + Unsetraw(); + close(ttyfd); + return FALSE; +} + + diff --git a/mbsebbs/fsedit.h b/mbsebbs/fsedit.h new file mode 100644 index 00000000..f4909be9 --- /dev/null +++ b/mbsebbs/fsedit.h @@ -0,0 +1,7 @@ +#ifndef _FSEDIT_H +#define _FSEDIT_H + +int Fs_Edit(void); /* The fullscreen message editor */ + +#endif + diff --git a/mbsebbs/funcs.c b/mbsebbs/funcs.c new file mode 100644 index 00000000..bd9ac9cc --- /dev/null +++ b/mbsebbs/funcs.c @@ -0,0 +1,1031 @@ +/***************************************************************************** + * + * File ..................: bbs/funcs.c + * Purpose ...............: Misc functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "language.h" +#include "funcs4.h" +#include "oneline.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" +#include "timecheck.h" +#include "exitinfo.h" +#include "mail.h" +#include "email.h" + + +extern long ActiveMsgs; +extern time_t t_start; + + + +/* + * Security Access Check + */ +int Access(securityrec us, securityrec ref) +{ + Syslog('B', "User %5d %08lx %08lx", us.level, us.flags, ~us.flags); + Syslog('B', "Ref. %5d %08lx %08lx", ref.level, ref.flags, ref.notflags); + + if (us.level < ref.level) + return FALSE; + + if ((ref.notflags & ~us.flags) != ref.notflags) + return FALSE; + + if ((ref.flags & us.flags) != ref.flags) + return FALSE; + + return TRUE; +} + + + +void UserList(char *OpData) +{ + FILE *pUsrConfig; + int LineCount = 2; + int iFoundName = FALSE; + int iNameCount = 0; + char *Name, *sTemp, *User; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + Name = calloc(37, sizeof(char)); + sTemp = calloc(81, sizeof(char)); + User = calloc(81, sizeof(char)); + + clear(); + /* User List */ + language(15, 0, 126); + Enter(1); + LineCount = 1; + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp, "rb")) == NULL) { + WriteError("UserList: Can't open file: %s", temp); + return; + } + fread(&uhdr, sizeof(uhdr), 1, pUsrConfig); + + /* Enter Username search string or (Enter) for all users: */ + language(15, 0, 127); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetstrC(Name,35); + clear(); + + /* Name Location Last On Calls */ + language(15, 0, 128); + Enter(1); + + colour(2, 0); + fLine(79); + + colour(3, 0); + while (fread(&u, uhdr.recsize, 1, pUsrConfig) == 1) { + if ((strcmp(Name,"")) != 0) { + if((strcmp(OpData, "/H")) == 0) + sprintf(User, "%s", u.sHandle); + else + sprintf(User, "%s", u.sUserName); + + if ((strstr(tl(User), tl(Name)) != NULL)) { + if ((!u.Hidden) && (!u.Deleted)) { + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(u.sHandle, "") != 0 && *(u.sHandle) != ' ')) + printf("%-25s", u.sHandle); + else + printf("%-25s", u.sUserName); + } else + printf("%-25s", u.sUserName); + + printf("%-30s%-14s%-11d", u.sLocation, StrDateDMY(u.tLastLoginDate), u.iTotalCalls); + iFoundName = TRUE; + LineCount++; + iNameCount++; + } + } + } else + if ((!u.Hidden) && (!u.Deleted) && (strlen(u.sUserName) > 0)) { + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(u.sHandle, "") != 0 && *(u.sHandle) != ' ')) + printf("%-25s", u.sHandle); + else + printf("%-25s", u.sUserName); + } else + printf("%-25s", u.sUserName); + + printf("%-30s%-14s%-11d", u.sLocation, StrDateDMY(u.tLastLoginDate), u.iTotalCalls); + iFoundName = TRUE; + LineCount++; + iNameCount++; + Enter(1); + } + + if (LineCount >= exitinfo.iScreenLen - 2) { + LineCount = 0; + Pause(); + colour(3, 0); + } + } + + if(!iFoundName) { + language(3, 0, 129); + Enter(1); + } + + fclose(pUsrConfig); + + colour(2, 0); + fLine(79); + + free(temp); + free(Name); + free(sTemp); + free(User); + + Pause(); +} + + + +void TimeStats() +{ + clear(); + ReadExitinfo(); + + colour(15, 0); + /* TIME STATISTICS for */ + printf("\n%s%s ", (char *) Language(134), exitinfo.sUserName); + /* on */ + printf("%s %s\n", (char *) Language(135), (char *) logdate()); + + colour(12, 0); + fLine(79); + + printf("\n"); + + colour(10, 0); + + /* Current Time */ + printf("%s %s\n", (char *) Language(136), (char *) GetLocalHMS()); + + /* Current Date */ + printf("%s %s\n\n", (char *) Language(137), (char *) GLCdateyy()); + + /* Connect time */ + printf("%s %d %s\n", (char *) Language(138), exitinfo.iConnectTime, (char *) Language(471)); + + /* Time used today */ + printf("%s %d %s\n", (char *) Language(139), exitinfo.iTimeUsed, (char *) Language(471)); + + /* Time remaining today */ + printf("%s %d %s\n", (char *) Language(140), exitinfo.iTimeLeft, (char *) Language(471)); + + /* Daily time limit */ + printf("%s %d %s\n", (char *) Language(141), exitinfo.iTimeUsed + exitinfo.iTimeLeft, (char *) Language(471)); + + printf("\n"); + Pause(); +} + + + +char *Gdate(time_t, int); +char *Gdate(time_t tt, int Y2K) +{ + static char GLC[15]; + struct tm *tm; + + tm = localtime(&tt); + if (Y2K) + sprintf(GLC, "%02d-%02d-%04d", tm->tm_mon +1, tm->tm_mday, tm->tm_year + 1900); + else + sprintf(GLC, "%02d-%02d-%02d", tm->tm_mon +1, tm->tm_mday, tm->tm_year % 100); + + return (GLC); +} + + + +char *Rdate(char *, int); +char *Rdate(char *ind, int Y2K) +{ + static char GLC[15]; + + memset(&GLC, 0, sizeof(GLC)); + GLC[0] = ind[3]; + GLC[1] = ind[4]; + GLC[2] = '-'; + GLC[3] = ind[0]; + GLC[4] = ind[1]; + GLC[5] = '-'; + if (Y2K) { + GLC[6] = ind[6]; + GLC[7] = ind[7]; + GLC[8] = ind[8]; + GLC[9] = ind[9]; + } else { + GLC[6] = ind[8]; + GLC[7] = ind[9]; + } + + return GLC; +} + + + +/* + * Function will run a external program or door + */ +void ExtDoor(char *Program, int NoDoorsys, int Y2Kdoorsys, int Comport) +{ + char *String, *String1; + int i, rc; + char *temp1; + FILE *fp; + + temp1 = calloc(PATH_MAX, sizeof(char)); + String = calloc(81, sizeof(char)); + + WhosDoingWhat(DOOR); + + if((strstr(Program, "/A")) != NULL) { + colour(3, 0); + if((String = strstr(Program, "/T=")) != NULL) { + String1 = String + 3; + printf("\n%s", String1); + } else + printf("\nPlease enter filename: "); + + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp1, 80); + + strreplace(Program, (char *)"/A", temp1); + + for(i = 0; i < strlen(Program); i++) { + if(*(Program + i) == '\0') + break; + if(*(Program + i) == '/') + *(Program + i) = '\0'; + } + } + + free(String); + Syslog('+', "Door: %s", Program); + ReadExitinfo(); + alarm_set((exitinfo.iTimeLeft * 60) - 10); + Altime((exitinfo.iTimeLeft * 60)); + + /* + * Always remove the old door.sys first. + */ + sprintf(temp1, "%s/%s/door.sys", CFG.bbs_usersdir, exitinfo.Name); + unlink(temp1); + + /* + * Write door.sys in users homedirectory + */ + if (!NoDoorsys) { + if ((fp = fopen(temp1, "w+")) == NULL) { + WriteError("$Can't create %s", temp1); + } else { + if (Comport) { + fprintf(fp, "COM1\r\n"); /* COM port */ + fprintf(fp, "115200\r\n");/* Effective baudrate */ + + } else { + fprintf(fp, "COM0\r\n");/* COM port */ + fprintf(fp, "0\r\n"); /* Effective baudrate */ + } + fprintf(fp, "8\r\n"); /* Databits */ + fprintf(fp, "1\r\n"); /* Node number */ + if (Comport) + fprintf(fp, "115200\r\n");/* Locked baudrate */ + else + fprintf(fp, "%ld\r\n", ttyinfo.portspeed); /* Locked baudrate */ + fprintf(fp, "Y\r\n"); /* Screen display */ + fprintf(fp, "N\r\n"); /* Printer on */ + fprintf(fp, "Y\r\n"); /* Page bell */ + fprintf(fp, "Y\r\n"); /* Caller alarm */ + fprintf(fp, "%s\r\n", exitinfo.sUserName); + fprintf(fp, "%s\r\n", exitinfo.sLocation); + fprintf(fp, "%s\r\n", exitinfo.sVoicePhone); + fprintf(fp, "%s\r\n", exitinfo.sDataPhone); + fprintf(fp, "%s\r\n", exitinfo.Password); + fprintf(fp, "%d\r\n", exitinfo.Security.level); + fprintf(fp, "%d\r\n", exitinfo.iTotalCalls); + fprintf(fp, "%s\r\n", Gdate(exitinfo.tLastLoginDate, Y2Kdoorsys)); + fprintf(fp, "%d\r\n", exitinfo.iTimeLeft * 60); + fprintf(fp, "%d\r\n", exitinfo.iTimeLeft); + fprintf(fp, "GR\r\n"); /* ANSI graphics */ + fprintf(fp, "%d\r\n", exitinfo.iScreenLen); + fprintf(fp, "N\r\n"); /* User mode, always N */ + fprintf(fp, "\r\n"); /* Always blank */ + fprintf(fp, "\r\n"); /* Always blank */ + fprintf(fp, "%s\r\n", Rdate(exitinfo.sExpiryDate, Y2Kdoorsys)); + fprintf(fp, "%d\r\n", grecno); /* Users recordnumber */ + fprintf(fp, "%s\r\n", exitinfo.sProtocol); + fprintf(fp, "%ld\r\n", exitinfo.Uploads); + fprintf(fp, "%ld\r\n", exitinfo.Downloads); + fprintf(fp, "%ld\r\n", LIMIT.DownK); + fprintf(fp, "%ld\r\n", LIMIT.DownK); + fprintf(fp, "%s\r\n", Rdate(exitinfo.sDateOfBirth, Y2Kdoorsys)); + fprintf(fp, "\r\n"); /* Path to userbase */ + fprintf(fp, "\r\n"); /* Path to messagebase */ + fprintf(fp, "%s\r\n", CFG.sysop_name); + fprintf(fp, "%s\r\n", exitinfo.sHandle); + fprintf(fp, "none\r\n"); /* Next event time */ + fprintf(fp, "Y\r\n"); /* Error free connect. */ + fprintf(fp, "N\r\n"); /* Always N */ + fprintf(fp, "Y\r\n"); /* Always Y */ + fprintf(fp, "7\r\n"); /* Default textcolor */ + fprintf(fp, "0\r\n"); /* Always 0 */ + fprintf(fp, "%s\r\n", Gdate(exitinfo.tLastLoginDate, Y2Kdoorsys)); + fprintf(fp, "%s\r\n", StrTimeHM(t_start)); + fprintf(fp, "%s\r\n", LastLoginTime); + fprintf(fp, "32768\r\n"); /* Always 32768 */ + fprintf(fp, "%d\r\n", exitinfo.DownloadsToday); + fprintf(fp, "%ld\r\n", exitinfo.UploadK); + fprintf(fp, "%ld\r\n", exitinfo.DownloadK); + fprintf(fp, "%s\r\n", exitinfo.sComment); + fprintf(fp, "0\r\n"); /* Always 0 */ + fprintf(fp, "%d\r\n", exitinfo.iPosted); + fclose(fp); + } + } + + clear(); + printf("Loading ...\n\n"); + rc = execute((char *)"/bin/sh", (char *)"-c", Program, NULL, NULL, NULL); + + Altime(0); + alarm_off(); + alarm_on(); + Syslog('+', "Door end, rc=%d", rc); + + free(temp1); + printf("\n\n"); + Pause(); +} + + + +/* + * Function will display textfile in either ansi or ascii and + * display control codes if they exist. + * Returns Success if it can display the requested file + */ +int DisplayFile(char *filename) +{ + FILE *pFileName; + long iSec = 0; + char *sFileName, *tmp, *tmp1; + char newfile[PATH_MAX]; + int i, x; + + sFileName = calloc(16385, sizeof(char)); + tmp = calloc(PATH_MAX, sizeof(char)); + tmp1 = calloc(PATH_MAX, sizeof(char)); + + /* + * Open the file in the following search order: + * 1 - if GraphMode -> users language .ans + * 2 - if GraphMode -> default language .ans + * 3 - users language .asc + * 4 - default language .asc + * 5 - Abort, there is no file to show. + */ + pFileName = NULL; + if (exitinfo.GraphMode) { + sprintf(newfile, "%s/%s.ans", lang.TextPath, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + sprintf(newfile, "%s/%s.ans", CFG.bbs_txtfiles, filename); + pFileName = fopen(newfile, "rb"); + } + } + if (pFileName == NULL) { + sprintf(newfile, "%s/%s.asc", lang.TextPath, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + sprintf(newfile, "%s/%s.asc", CFG.bbs_txtfiles, filename); + if ((pFileName = fopen(newfile, "rb")) == NULL) { + free(sFileName); + free(tmp); + free(tmp1); + return FALSE; + } + } + } + + Syslog('B', "Displayfile %s", newfile); + + while (!feof(pFileName)) { + i = fread(sFileName, sizeof(char), 16384, pFileName); + + for(x = 0; x < i; x++) { + switch(*(sFileName + x)) { + case '': + ControlCodeU(sFileName[++x]); + break; + + case '': + ControlCodeF(sFileName[++x]); + break; + + case ' ': + ControlCodeK(sFileName[++x]); + break; + + case '': + fflush(stdout); + fflush(stdin); + alarm_on(); + Getone(); + break; + + case '': + /* + * This code will allow you to specify a security level + * in front of the text, ie ^B32000^Bthis is a test^B + * will print this is a test only if you have security + * above 32000. Only one set of control chars per line. + * You cannot have multiple securitys etc + */ + x++; + strcpy(tmp1, ""); + while (*(sFileName + x) != '') { + sprintf(tmp, "%c", *(sFileName + x)); + strcat(tmp1, tmp); + x++; + } + x++; + iSec = atoi(tmp1); + while ((x <= i) && (*(sFileName + x) != '')) { + if (exitinfo.Security.level >= iSec) + printf("%c", *(sFileName + x)); + x++; + } + break; + + case '': + fflush(stdout); + sleep(1); + break; + + default: + printf("%c", *(sFileName + x)); + + } /* switch */ + } /* for */ + } /* while !eof */ + + fclose(pFileName); + free(sFileName); + free(tmp); + free(tmp1); + return TRUE; +} + + + +int DisplayFileEnter(char *File) +{ + int rc; + + rc = DisplayFile(File); + Enter(1); + /* Press ENTER to continue */ + language(13, 0, 436); + fflush(stdout); + fflush(stdin); + alarm_on(); + Getone(); + return rc; +} + + + +int CheckFile(char *File, int iArea) +{ + FILE *pFileB; + int iFile = FALSE; + char *sFileArea; + + sFileArea = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileArea,"%s/fdb/fdb%d.dta", getenv("MBSE_ROOT"), iArea); + + if(( pFileB = fopen(sFileArea,"r+")) == NULL) { + mkdir(sFileArea, 755); + return FALSE; + } + + while ( fread(&file, sizeof(file), 1, pFileB) == 1) { + if((strcmp(tl(file.Name), tl(File))) == 0) { + iFile = TRUE; + fclose(pFileB); + return TRUE; + } + + } + + fclose(pFileB); + free(sFileArea); + + if(!iFile) + return FALSE; + return 1; +} + + + +void ControlCodeF(int ch) +{ + /* Update user info */ + ReadExitinfo(); + + switch (toupper(ch)) { + case '!': + printf(exitinfo.sProtocol); + break; + case 'A': + printf("%ld", exitinfo.Uploads); + break; + + case 'B': + printf("%ld", exitinfo.Downloads); + break; + + case 'C': + printf("%lu", exitinfo.DownloadK); + break; + + case 'D': + printf("%lu", exitinfo.UploadK); + break; + + case 'E': + printf("%lu", exitinfo.DownloadK + exitinfo.UploadK); + break; + + case 'F': + printf("%lu", LIMIT.DownK); + break; + + case 'G': + printf("%d", exitinfo.iTransferTime); + break; + + case 'H': + printf("%d", iAreaNumber); + break; + + case 'I': + printf(sAreaDesc); + break; + + case 'J': + printf("%u", LIMIT.DownF); + break; + + case 'K': + printf("%s", LIMIT.Description); + break; + + default: + printf(" "); + } +} + + + +void ControlCodeU(int ch) +{ + /* + * Update user info + */ + TimeCheck(); + ReadExitinfo(); + + switch (toupper(ch)) { + case 'A': + printf("%s", exitinfo.sUserName); + break; + + case 'B': + printf(exitinfo.sLocation); + break; + + case 'C': + printf(exitinfo.sVoicePhone); + break; + + case 'D': + printf(exitinfo.sDataPhone); + break; + + case 'E': + printf(LastLoginDate); + break; + + case 'F': + printf("%s %s", StrDateDMY(exitinfo.tFirstLoginDate), StrTimeHMS(exitinfo.tFirstLoginDate)); + break; + + case 'G': + printf(LastLoginTime); + break; + + case 'H': + printf("%d", exitinfo.Security.level); + break; + + case 'I': + printf("%d", exitinfo.iTotalCalls); + break; + + case 'J': + printf("%d", exitinfo.iTimeUsed); + break; + + case 'K': + printf("%d", exitinfo.iConnectTime); + break; + + case 'L': + printf("%d", exitinfo.iTimeLeft); + break; + + case 'M': + printf("%d", exitinfo.iScreenLen); + break; + + case 'N': + printf(FirstName); + break; + + case 'O': + printf(LastName); + break; + + case 'Q': + printf("%s", exitinfo.ieNEWS ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'P': + printf("%s", exitinfo.GraphMode ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'R': + printf("%s", exitinfo.HotKeys ? (char *) Language(147) : (char *) Language(148)); + break; + + case 'S': + printf("%d", exitinfo.iTimeUsed + exitinfo.iTimeLeft); + break; + + case 'T': + printf(exitinfo.sDateOfBirth); + break; + + case 'U': + printf("%d", exitinfo.iPosted); + break; + + case 'X': + printf(lang.Name); + break; + + case 'Y': + printf(exitinfo.sHandle); + break; + + case 'Z': + printf("%s", exitinfo.DoNotDisturb ? (char *) Language(147) : (char *) Language(148)); + break; + + case '1': + printf("%s", exitinfo.MailScan ? (char *) Language(147) : (char *) Language(148)); + break; + + case '2': + printf("%s", exitinfo.ieFILE ? (char *) Language(147) : (char *) Language(148)); + break; + + case '3': + printf("%s", exitinfo.FsMsged ? (char *) Language(147) : (char *) Language(148)); + break; + + default: + printf(" "); + } +} + + + +void ControlCodeK(int ch) +{ + FILE *pCallerLog; + char sDataFile[PATH_MAX]; + lastread LR; + + switch (toupper(ch)) { + case 'A': + printf("%s", (char *) GetDateDMY()); + break; + + case 'B': + printf("%s", (char *) GetLocalHMS()); + break; + + case 'C': + printf("%s", (char *) GLCdate()); + break; + + case 'D': + printf("%s", (char *) GLCdateyy()); + break; + + case 'E': + printf("%d", Speed() ); + break; + + case 'F': + printf("%s", LastCaller); + break; + + case 'G': + printf("%d", TotalUsers()); + break; + + case 'H': + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + if((pCallerLog = fopen(sDataFile, "rb")) != NULL) { + fread(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + printf("%ld", SYSINFO.SystemCalls); + fclose(pCallerLog); + } + break; + + case 'I': + printf("%d", iMsgAreaNumber + 1); + break; + + case 'J': + printf(sMsgAreaDesc); + break; + + case 'K': + printf("%s", Oneliner_Get()); + break; + + case 'L': + SetMsgArea(iMsgAreaNumber); + printf("%ld", MsgBase.Total); + break; + + case 'M': + LR.UserID = grecno; + if (Msg_Open(sMsgAreaBase)) { + if (Msg_GetLastRead(&LR) == TRUE) { + if (LR.HighReadMsg > MsgBase.Highest) + LR.HighReadMsg = MsgBase.Highest; + printf("%ld", LR.HighReadMsg); + } else + printf("?"); + Msg_Close(); + } + break; + + case 'N': + printf("%s", sMailbox); + break; + + case 'O': + SetEmailArea(sMailbox); + printf("%ld", EmailBase.Total); + break; + + case 'P': + sprintf(sDataFile, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, sMailbox); + LR.UserID = grecno; + if (Msg_Open(sDataFile)) { + if (Msg_GetLastRead(&LR) == TRUE) { + if (LR.HighReadMsg > EmailBase.Highest) + LR.HighReadMsg = EmailBase.Highest; + printf("%ld", LR.HighReadMsg); + } else + printf("?"); + Msg_Close(); + } + break; + + default: + printf(" "); + + } +} + + + +/* + * View a textfile. + */ +void ViewTextFile(char *Textfile) +{ + FILE *fp; + int iLine = 0; + char *temp, *temp1; + char sPrompt[] = "\n(More (Y/n/=): "; + int i, x, z; + + x = strlen(sPrompt); + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp = calloc(81, sizeof(char)); + + sprintf(temp1, "%s", Textfile); + + if(( fp = fopen (temp1, "r")) != NULL) { + while (fgets(temp, 80, fp) != NULL) { + printf("%s", temp); + ++iLine; + if(iLine >= exitinfo.iScreenLen && iLine < 1000) { + iLine = 0; + pout(CFG.MoreF, CFG.MoreB, sPrompt); + + fflush(stdout); + z = Getone(); + switch(z) { + + case 'n': + case 'N': + printf("\n"); + break; + + case '=': + iLine = 1000; + } + for(i = 0; i < x; i++) + printf("\b"); + for(i = 0; i < x; i++) + printf(" "); + printf("\r"); + } + } + fclose(fp); + } + + Pause(); + free(temp1); + free(temp); +} + + + +/* + * Function will make log entry in users logfile + * Understands @ for Fileareas and ^ for Message Areas + */ +void LogEntry(char *Log) +{ + char *Entry, *temp; + int i; + + Entry = calloc(256, sizeof(char)); + temp = calloc(1, sizeof(char)); + + for(i = 0; i < strlen(Log); i++) { + if(*(Log + i) == '@') + strcat(Entry, sAreaDesc); + else + if(*(Log + i) == '^') + strcat(Entry, sMsgAreaDesc); + else { + sprintf(temp, "%c", *(Log + i)); + strcat(Entry, temp); + } + } + + Syslog('+', Entry); + free(Entry); + free(temp); +} + + + +/* + * Function will take two date strings in the following format DD-MM-YYYY and + * swap them around in the following format YYYYMMDD + * ie. 01-02-1995 will become 19950201 so that the leading Zeros are not in + * the beginning as leading Zeros will fall away if you try compare the + * two with a if statement (Millenium proof). + */ +void SwapDate(char *Date3, char *Date4) +{ + char *temp2, *temp3; + + temp2 = calloc(10, sizeof(char)); + temp3 = calloc(10, sizeof(char)); + Date1 = calloc(10, sizeof(char)); + Date2 = calloc(10, sizeof(char)); + + temp2[0] = Date3[6]; + temp2[1] = Date3[7]; + temp2[2] = Date3[8]; + temp2[3] = Date3[9]; + temp2[4] = Date3[3]; + temp2[5] = Date3[4]; + temp2[6] = Date3[0]; + temp2[7] = Date3[1]; + temp2[8] = '\0'; + + temp3[0] = Date4[6]; + temp3[1] = Date4[7]; + temp3[2] = Date4[8]; + temp3[3] = Date4[9]; + temp3[4] = Date4[3]; + temp3[5] = Date4[4]; + temp3[6] = Date4[0]; + temp3[7] = Date4[1]; + temp3[8] = '\0'; + + strcpy(Date1, temp2); + strcpy(Date2, temp3); + + free(temp2); + free(temp3); +} + + + +/* + * Function returns total number of bbs users + */ +int TotalUsers() +{ + FILE *pUsrConfig; + int ch = 0; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( pUsrConfig = fopen(temp,"rb")) == NULL) + WriteError("ControlCodeK: Can't open users file %s for reading", temp); + else { + fread(&uhdr, sizeof(uhdr), 1, pUsrConfig); + + while (fread(&u, uhdr.recsize, 1, pUsrConfig) == 1) + if ((!u.Deleted) && (strlen(u.sUserName) > 0)) + ch++; + + fclose(pUsrConfig); + } + free(temp); + + return ch; +} + + + diff --git a/mbsebbs/funcs.h b/mbsebbs/funcs.h new file mode 100644 index 00000000..a6e5c7e5 --- /dev/null +++ b/mbsebbs/funcs.h @@ -0,0 +1,23 @@ +/* funcs.h */ + +#ifndef _FUNCS_H +#define _FUNCS_H + +int Access(securityrec, securityrec); /* Check security access */ +void UserList(char *); /* Get complete users list */ +void TimeStats(void); /* Get users Time Statistics */ +void ExtDoor(char *, int, int, int); /* Run external door */ +int DisplayFile(char *); /* Display .ans/.asc textfile */ +int DisplayFileEnter(char *); /* Display .ans/.asc wait for Enter*/ +int CheckFile(char *, int); /* Check for Dupe file in Database */ +void ControlCodeF(int); /* Check Control Codes in File */ +void ControlCodeU(int); /* Check Control Codes in File */ +void ControlCodeK(int); /* Check Control Codes in File */ +void ViewTextFile(char *); /* View text file */ +void LogEntry(char *); /* Create log entry in logfile */ +void SwapDate(char *, char *); /* Swap two Date strings around */ +int TotalUsers(void); /* Returns total numbers of users */ + + +#endif + diff --git a/mbsebbs/funcs4.c b/mbsebbs/funcs4.c new file mode 100644 index 00000000..ee2e7945 --- /dev/null +++ b/mbsebbs/funcs4.c @@ -0,0 +1,1051 @@ +/***************************************************************************** + * + * File ..................: bbs/funcs4.c + * Purpose ...............: Misc functions, also for some utils. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "../lib/msg.h" +#include "funcs4.h" +#include "misc.h" +#include "timeout.h" +#include "language.h" + + +extern pid_t mypid; /* Original pid */ + + + +void UserSilent(int flag) +{ + SockS("ADIS:2,%d,%d;", mypid, flag); +} + + + +/* + * Check BBS open status, return FALSE if the bbs is closed. + * Display the reason why to the user. + */ +int CheckStatus() +{ + static char buf[81]; + + sprintf(buf, "SBBS:0;"); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:2,0", 7) == 0) + return TRUE; + if ((strncmp(buf, "100:2,2", 7) == 0) && (!ttyinfo.honor_zmh)) + return TRUE; + buf[strlen(buf) -1] = '\0'; + printf("\n\n\007*** %s ***\n\n\n", buf+8); + fflush(stdout); + } + return FALSE; +} + + + +/* + * Get a character string with cursor position + */ +void GetstrP(char *sStr, int iMaxLen, int Position) +{ + unsigned char ch = 0; + int iPos = Position; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 1"); + return; + } + Setraw(); + + alarm_on(); + + while (ch != KEY_ENTER) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == KEY_BACKSPACE) || (ch == KEY_DEL) || (ch == KEY_RUBOUT)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxLen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a character string + */ +void GetstrC(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * get a string, don't allow spaces (for Unix accounts) + */ +void GetstrU(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos] = '\0'; + } else + putchar('\007'); + } + + if (ch > 32 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a phone number, only allow digits, + and - characters. + */ +void GetPhone(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 5"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == '+')) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a number, allow digits, spaces, minus sign, points and comma's + */ +void Getnum(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 5"); + return; + } + Setraw(); + + strcpy(sStr, ""); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if ((ch >= '0' && ch <= '9') || (ch == '-') || (ch == ' ') \ + || (ch == ',') || (ch == '.')) { + + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * This function gets the date from the user checking the length and + * putting two minus signs in the right places + */ +void GetDate(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 4"); + return; + } + Setraw(); + + alarm_on(); + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) + printf("\b \b"); + else + putchar('\007'); + + if (iPos == 3 || iPos == 6) { + printf("\b \b"); + --iPos; + } + + sStr[--iPos]='\0'; + } + + if (ch >= '0' && ch <= '9') { + if (iPos < iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + if (iPos == 2 || iPos == 5) { + printf("-"); + sprintf(sStr, "%s-", sStr); + iPos++; + } + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a string, capitalize only if set in config. + */ +void Getname(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0, iNewPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 2"); + return; + } + Setraw(); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if (ch > 31 && (ch < 127)) { + if (iPos < iMaxlen) { + iPos++; + if (iPos == 1 && CFG.iCapUserName) + ch = toupper(ch); + + if (ch == 32) { + iNewPos = iPos; + iNewPos++; + } + + if (iNewPos == iPos && CFG.iCapUserName) + ch = toupper(ch); + else + if (CFG.iCapUserName) + ch = tolower(ch); + + if (iPos == 1 && CFG.iCapUserName) + ch = toupper(ch); + + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Get a Fidonet style username, always capitalize. + */ +void GetnameNE(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0, iNewPos = 0; + + fflush(stdout); + + strcpy(sStr, ""); + + if ((ttyfd = open ("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 2"); + return; + } + Setraw(); + alarm_on(); + + while (ch != 13) { + + fflush(stdout); + ch = Readkey(); + + if ((ch == 8) || (ch == KEY_DEL) || (ch == 127)) { + if (iPos > 0) { + printf("\b \b"); + sStr[--iPos]='\0'; + } else + putchar('\007'); + } + + if (ch > 31 && ch < 127) { + if (iPos < iMaxlen) { + iPos++; + + if (iPos == 1) + ch = toupper(ch); + + if (ch == 32) { + iNewPos = iPos; + iNewPos++; + } + + if (iNewPos == iPos) + ch = toupper(ch); + else + ch = tolower(ch); + + if (iPos == 1) + ch = toupper(ch); + + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + } else + putchar('\007'); + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Function will Scan Users Database for existing phone numbers. If + * found, it will write a log entry to the logfile. The user WILL NOT + * be notified about the same numbers + */ +int TelephoneScan(char *Number, char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(81, sizeof(char)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( fp = fopen(temp,"rb")) != NULL) { + fread(&uhdr, sizeof(uhdr), 1, fp); + + while (fread(&u, uhdr.recsize, 1, fp) == 1) { + if (strcasecmp(u.sUserName, Name) != 0) + if ((strlen(u.sVoicePhone) && (strcmp(u.sVoicePhone, Number) == 0)) || + (strlen(u.sDataPhone) && (strcmp(u.sDataPhone, Number) == 0))) { + Status = TRUE; + Syslog('b', "Dupe phones ref: \"%s\" voice: \"%s\" data: \"%s\"", + Number, u.sVoicePhone, u.sDataPhone); + Syslog('+', "Uses the same telephone number as %s", u.sUserName); + } + } + fclose(fp); + } + + free(temp); + return Status; +} + + + +void Pause() +{ + int i, x; + char *string; + + string = malloc(81); + + /* Press (Enter) to continue: */ + sprintf(string, "\r%s", (char *) Language(375)); + colour(CFG.CRColourF, CFG.CRColourB); + printf(string); + + do { + fflush(stdout); + fflush(stdin); + alarm_on(); + i = Getone(); + } while ((i != '\r') && (i != '\n')); + + x = strlen(string); + for(i = 0; i < x; i++) + printf("\b"); + for(i = 0; i < x; i++) + printf(" "); + for(i = 0; i < x; i++) + printf("\b"); + fflush(stdout); + + free(string); +} + + + +/* + * Function to check if UserName exists and returns a 0 or 1 + */ +int CheckName(char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp, *temp1; + struct userhdr ushdr; + struct userrec us; + + temp = calloc(81, sizeof(char)); + temp1 = calloc(81, sizeof(char)); + + strcpy(temp1, tl(Name)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp,"rb")) != NULL) { + fread(&ushdr, sizeof(ushdr), 1, fp); + + while (fread(&us, ushdr.recsize, 1, fp) == 1) { + strcpy(temp, tl(us.sUserName)); + + if((strcmp(temp, temp1)) == 0) { + Status = TRUE; + break; + } + } + fclose(fp); + } + + free(temp); + free(temp1); + return Status; +} + + + +/* + * This function returns the date in the following format: + * DD-Mon HH:MM:SS (Day-Month Time) + * The users language is used. + */ +char *logdate() +{ + static char Logdate[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + sprintf(Logdate,"%02d-%s %02d:%02d:%02d", l_date->tm_mday, GetMonth(l_date->tm_mon+1), + l_date->tm_hour, l_date->tm_min, l_date->tm_sec); + return(Logdate); +} + + + +/* + * Function will ask user to create a unix login + * Name cannot be longer than 8 characters + */ +char *NameGen(char *FidoName) +{ + char *sUserName; + struct passwd *pw; + + sUserName = calloc(10, sizeof(char)); + + Syslog('+', "NameGen(%s)", FidoName); + setpwent(); + while ((strcmp(sUserName, "") == 0 || (pw = getpwnam(sUserName)) != NULL) || (strlen(sUserName) < 3)) { + colour(12, 0); + printf("\n%s\n\n", (char *) Language(381)); + colour(15, 0); + /* Please enter a login name (Maximum 8 characters) */ + printf("\n%s\n", (char *) Language(383)); + /* ie. John Doe, login = jdoe */ + printf("%s\n", (char *) Language(384)); + colour(10, 0); + /* login > */ + printf("%s", (char *) Language(385)); + fflush(stdout); + fflush(stdin); + GetstrU(sUserName, 7); + + setpwent(); + if (pw = getpwnam(tl(sUserName)), pw != NULL) { + /* That login name already exists, please choose another one. */ + colour(12, 0); + printf("\n%s\n", (char *) Language(386)); + setpwent(); + } + } + return tl(sUserName); +} + + + +/* + * Function will create the users name in the passwd file + */ +char *NameCreate(char *Name, char *Comment, char *Password) +{ + char *PassEnt; + + PassEnt = calloc(256, sizeof(char)); + + /* + * Call mbuseradd, this is a special setuid root program to create + * unix acounts and home directories. + */ + sprintf(PassEnt, "%s/bin/mbuseradd %d %s \"%s\" %s", + getenv("MBSE_ROOT"), getgid(), Name, Comment, CFG.bbs_usersdir); + Syslog('+', "%s", PassEnt); + fflush(stdout); + fflush(stdin); + + if (system(PassEnt) != 0) { + WriteError("Failed to create unix account"); + free(PassEnt); + ExitClient(1); + } + sprintf(PassEnt, "%s/bin/mbpasswd -f %s %s", getenv("MBSE_ROOT"), Name, Password); + Syslog('+', "%s/bin/mbpasswd -f %s ******", getenv("MBSE_ROOT"), Name); + if (system(PassEnt) != 0) { + WriteError("Failed to set unix password"); + free(PassEnt); + ExitClient(1); + } + + colour(14, 0); + /* Your "Unix Account" is created, you may use it the next time you call */ + printf("\n%s\n", (char *) Language(382)); + Syslog('+', "Created Unix account %s for %s", Name, Comment); + + free(PassEnt); + return Name; +} + + + +/* + * Function will check and create a home directory for the user if + * needed. It will also change into the users home directory when + * they login. + */ +char *ChangeHomeDir(char *Name, int Mailboxes) +{ + char *temp; + static char temp1[PATH_MAX]; + + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * set umask bits to zero's then reset with mkdir + */ + umask(000); + + /* + * First check to see if users home directory exists + * else try create directory, as set in CFG.bbs_usersdir + */ + if ((access(CFG.bbs_usersdir, R_OK)) != 0) { + WriteError("$FATAL: Access to %s failed", CFG.bbs_usersdir); + free(temp); + ExitClient(1); + } + + sprintf(temp1, "%s/%s", CFG.bbs_usersdir, Name); + + /* + * Then check to see if users directory exists in the home dir + */ + if ((access(temp1, R_OK)) != 0) { + WriteError("$FATAL: Users homedir %s doesn't exist", temp1); + free(temp); + ExitClient(1); + } + + /* + * Change to users home directory + */ + if (chdir(temp1) != 0) { + WriteError("$FATAL: Can't change to users home dir, aborting: %s", temp1); + free(temp); + ExitClient(1); + } + setenv("HOME", temp1, 1); + + /* + * Check subdirectories, create them if they don't exist. + */ + sprintf(temp, "%s/wrk", temp1); + CheckDir(temp); + sprintf(temp, "%s/tag", temp1); + CheckDir(temp); + sprintf(temp, "%s/upl", temp1); + CheckDir(temp); + sprintf(temp, "%s/tmp", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu/run", temp1); + CheckDir(temp); + sprintf(temp, "%s/.dosemu/tmp", temp1); + CheckDir(temp); + umask(007); + + /* + * Check users private emailboxes + */ + if (Mailboxes) { + sprintf(temp, "%s/mailbox", temp1); + if (Msg_Open(temp)) + Msg_Close(); + sprintf(temp, "%s/archive", temp1); + if (Msg_Open(temp)) + Msg_Close(); + sprintf(temp, "%s/trash", temp1); + if (Msg_Open(temp)) + Msg_Close(); + } + + free(temp); + return temp1; +} + + + +void CheckDir(char *dir) +{ + if ((access(dir, R_OK) != 0)) { + Syslog('+', "Creating %s", dir); + if (mkdir(dir, 0770)) + WriteError("$Can't create %s", dir); + } +} + + + +/* + * Function will check /etc/passwd for users fidonet login name. + * This will allow users to login in with there full name instead of + * their login name, to cut out confusion between unix accounts + * and normal bbs logins. + */ +int Check4UnixLogin(char *UsersName) +{ + unsigned UID = -1; /* Set to -1 incase user is not found */ + struct passwd *pw; + + while ((pw = getpwent())) { + #ifdef linux + if(strcmp(pw->pw_gecos, UsersName) == 0) { + #else + if(strcmp(pw->pw_comment, UsersName) == 0) { + #endif + UID = pw->pw_uid; + break; + } + } + + return UID; +} + + + +/* + * Function to check if User Handle exists and returns a 0 or 1 + */ +int CheckHandle(char *Name) +{ + FILE *fp; + int Status = FALSE; + char *temp, *temp1; + struct userhdr uhdr; + struct userrec u; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + strcpy(temp1, tl(Name)); + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if(( fp = fopen(temp,"rb")) != NULL) { + fread(&uhdr, sizeof(uhdr), 1, fp); + + while (fread(&u, uhdr.recsize, 1, fp) == 1) { + strcpy(temp, tl(u.sHandle)); + + if((strcmp(temp, temp1)) == 0) { + Status = TRUE; + break; + } + } + free(temp); + free(temp1); + fclose(fp); + } + + return Status; +} + + + +/* + * Function will check for unwanted user names + */ +int BadNames(char *Username) +{ + FILE *fp; + short iFoundName = FALSE; + char *temp, *String, *User; + + temp = calloc(PATH_MAX, sizeof(char)); + String = calloc(81, sizeof(char)); + User = calloc(81, sizeof(char)); + + strcpy(User, tl(Username)); + + sprintf(temp, "%s/etc/badnames.ctl", getenv("MBSE_ROOT")); + if(( fp = fopen(temp, "r")) != NULL) { + while((fgets(String, 80, fp)) != NULL) { + strcpy(String, tl(String)); + Striplf(String); + if((strstr(User, String)) != NULL) { + printf("\nSorry that name is not acceptable on this system\n"); + iFoundName = TRUE; + break; + } + } + fclose(fp); + } + + free(temp); + free(String); + free(User); + return iFoundName; +} + + + +/* + * Function will find where MBSE is located on system and load + * the file $MBSE_ROOT/etc/config.data in memory. + */ +void FindMBSE() +{ + FILE *pDataFile; + static char p[81]; + char *FileName; + struct passwd *pw; + + FileName = calloc(PATH_MAX, sizeof(char)); + + /* + * Check if the environment is set, if not, then we create the + * environment from the passwd file. + */ + if (getenv("MBSE_ROOT") == NULL) { + pw = getpwnam("mbse"); + memset(&p, 0, sizeof(p)); + sprintf(p, "MBSE_ROOT=%s", pw->pw_dir); + putenv(p); + } + + if (getenv("MBSE_ROOT") == NULL) { + printf("FATAL ERROR: Environment variable MBSE_ROOT not set\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + sprintf(FileName, "%s/etc/config.data", getenv("MBSE_ROOT")); + + if(( pDataFile = fopen(FileName, "rb")) == NULL) { + printf("FATAL ERROR: Can't open %s for reading!\n", FileName); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your environment variable MBSE_ROOT is set to the BBS Path!\n"); + free(FileName); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + fread(&CFG, sizeof(CFG), 1, pDataFile); + free(FileName); + fclose(pDataFile); +} + + + +/* + * Returns Mmm in the users language. + */ +char *GetMonth(int Month) +{ + static char month[10]; + + switch (Month) { + case 1: + strcpy(month, *(mLanguage + 398)); + break; + case 2: + strcpy(month, *(mLanguage + 399)); + break; + case 3: + strcpy(month, *(mLanguage + 400)); + break; + case 4: + strcpy(month, *(mLanguage + 401)); + break; + case 5: + strcpy(month, *(mLanguage + 402)); + break; + case 6: + strcpy(month, *(mLanguage + 403)); + break; + case 7: + strcpy(month, *(mLanguage + 404)); + break; + case 8: + strcpy(month, *(mLanguage + 405)); + break; + case 9: + strcpy(month, *(mLanguage + 406)); + break; + case 10: + strcpy(month, *(mLanguage + 407)); + break; + case 11: + strcpy(month, *(mLanguage + 408)); + break; + case 12: + strcpy(month, *(mLanguage + 409)); + break; + default: + strcpy(month, "Unknown"); + } + + return(month); +} + + + +/* Returns DD-Mmm-YYYY */ +char *GLCdateyy() +{ + static char GLcdateyy[15]; + char ntime[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + + sprintf(GLcdateyy,"%02d-", + l_date->tm_mday); + + sprintf(ntime,"-%02d", l_date->tm_year+1900); + strcat(GLcdateyy, GetMonth(l_date->tm_mon+1)); + strcat(GLcdateyy,ntime); + + return(GLcdateyy); +} + + diff --git a/mbsebbs/funcs4.h b/mbsebbs/funcs4.h new file mode 100644 index 00000000..fa1238d8 --- /dev/null +++ b/mbsebbs/funcs4.h @@ -0,0 +1,31 @@ +#ifndef _FUNCS4_H +#define _FUNCS4_H + +void UserSilent(int); /* Update users silent flag info */ +int CheckStatus(void); /* Check BBS open status */ +void GetstrU(char *, int); /* Get string, forbid spaces */ +void GetstrP(char *, int, int); /* Get string with cursor position */ +void GetstrC(char *, int); /* Get string, length, clear string */ +void Getnum(char *, int); /* Get only numbers from user */ +void Getname(char *, int); /* Get name & convert every 1st char to U/C */ +void GetnameNE(char *, int); /* Get name & convert every 1st char to U/C */ +void GetDate(char *, int); /* Get users birth date and check */ +void GetPhone(char *, int); /* Get telephone number */ +int TelephoneScan(char *, char *);/* Scans for Duplicate User Phone Numbers */ +void Pause(void); /* Puts Pause on Screen and halts screen */ +int CheckName(char *); /* Check if user name exists */ +char *logdate(void); /* Returns DD-Mon HH:MM:SS */ +char *NameGen(char *); /* Get and test for unix login */ +char *NameCreate(char *, char *, char *);/* Create users login in passwd file */ +char *ChangeHomeDir(char *, int); /* Change and Create Users Home Directories */ +void CheckDir(char *); /* Check and create directory */ +int Check4UnixLogin(char *); /* Check Passwd File for Users Login */ +int CheckHandle(char *); /* Check if user handle exists */ +int BadNames(char *); /* Check for Unwanted user names */ +void FindMBSE(void); /* Load Configuration file in memory */ +char *GLCdateyy(void); /* Returns current date DD-Mmm-YYYY */ +char *GetMonth(int); /* Returns Mmm */ + + +#endif + diff --git a/mbsebbs/getdef.c b/mbsebbs/getdef.c new file mode 100644 index 00000000..6940c34a --- /dev/null +++ b/mbsebbs/getdef.c @@ -0,0 +1,393 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/getdef.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 27-Jun-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1991 - 1994, Julianne Frances Haugh and Chip Rosenthal + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#include +#include +#include +#include "getdef.h" + + +/* + * A configuration item definition. + */ + +struct itemdef { + const char *name; /* name of the item */ + char *value; /* value given, or NULL if no value */ +}; + +/* + * This list *must* be sorted by the "name" member. + */ + +#define NUMDEFS (sizeof(def_table)/sizeof(def_table[0])) +static struct itemdef def_table[] = { + { "CHFN_AUTH", NULL }, + { "CHFN_RESTRICT", NULL }, + { "CONSOLE", NULL }, + { "CONSOLE_GROUPS", NULL }, +#ifdef HAVE_LIBCRACK + { "CRACKLIB_DICTPATH", NULL }, +#endif + { "CREATE_HOME", NULL }, + { "DEFAULT_HOME", NULL }, + { "DIALUPS_CHECK_ENAB", NULL }, + { "ENVIRON_FILE", NULL }, + { "ENV_HZ", NULL }, + { "ENV_PATH" , NULL }, + { "ENV_SUPATH", NULL }, + { "ENV_TZ", NULL }, + { "ERASECHAR", NULL }, + { "FAILLOG_ENAB", NULL }, + { "FAIL_DELAY", NULL }, + { "FTMP_FILE", NULL }, + { "GID_MAX", NULL }, + { "GID_MIN", NULL }, + { "HUSHLOGIN_FILE", NULL }, + { "ISSUE_FILE", NULL }, + { "KILLCHAR", NULL }, + { "LASTLOG_ENAB", NULL }, + { "LOGIN_RETRIES", NULL }, + { "LOGIN_STRING", NULL }, + { "LOGIN_TIMEOUT", NULL }, + { "LOG_OK_LOGINS", NULL }, + { "LOG_UNKFAIL_ENAB", NULL }, + { "MAIL_CHECK_ENAB", NULL }, + { "MAIL_DIR", NULL }, + { "MAIL_FILE", NULL }, + { "MD5_CRYPT_ENAB", NULL }, + { "MOTD_FILE", NULL }, + { "NOLOGINS_FILE", NULL }, + { "NOLOGIN_STR", NULL }, + { "OBSCURE_CHECKS_ENAB", NULL }, + { "PASS_ALWAYS_WARN", NULL }, + { "PASS_CHANGE_TRIES", NULL }, + { "PASS_MAX_DAYS", NULL }, + { "PASS_MAX_LEN", NULL }, + { "PASS_MIN_DAYS", NULL }, + { "PASS_MIN_LEN", NULL }, + { "PASS_WARN_AGE", NULL }, + { "PORTTIME_CHECKS_ENAB", NULL }, + { "QMAIL_DIR", NULL }, + { "QUOTAS_ENAB", NULL }, + { "SULOG_FILE", NULL }, + { "SU_NAME", NULL }, + { "SU_WHEEL_ONLY", NULL }, + { "SYSLOG_SG_ENAB", NULL }, + { "SYSLOG_SU_ENAB", NULL }, + { "TTYGROUP", NULL }, + { "TTYPERM", NULL }, + { "TTYTYPE_FILE", NULL }, + { "UID_MAX", NULL }, + { "UID_MIN", NULL }, + { "ULIMIT", NULL }, + { "UMASK", NULL }, + { "USERDEL_CMD", NULL }, + { "USERGROUPS_ENAB", NULL }, +}; + +#ifndef LOGINDEFS +#define LOGINDEFS "/etc/login.defs" +#endif + +static char def_fname[] = LOGINDEFS; /* login config defs file */ +static int def_loaded = 0; /* are defs already loaded? */ + + +/* local function prototypes */ +static struct itemdef *def_find (const char *); +static void def_load (void); + + +/* + * getdef_str - get string value from table of definitions. + * + * Return point to static data for specified item, or NULL if item is not + * defined. First time invoked, will load definitions from the file. + */ + +char *getdef_str(const char *item) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + return ((d = def_find(item)) == NULL ? (char *)NULL : d->value); +} + + +/* + * getdef_bool - get boolean value from table of definitions. + * + * Return TRUE if specified item is defined as "yes", else FALSE. + */ + +int getdef_bool(const char *item) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return 0; + + return (strcmp(d->value, "yes") == 0); +} + + +/* + * getdef_num - get numerical value from table of definitions + * + * Returns numeric value of specified item, else the "dflt" value if + * the item is not defined. Octal (leading "0") and hex (leading "0x") + * values are handled. + */ + +int getdef_num(const char *item, int dflt) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return dflt; + + return (int) strtol(d->value, (char **)NULL, 0); +} + + +/* + * getdef_long - get long integer value from table of definitions + * + * Returns numeric value of specified item, else the "dflt" value if + * the item is not defined. Octal (leading "0") and hex (leading "0x") + * values are handled. + */ + +long getdef_long(const char *item, long dflt) +{ + struct itemdef *d; + + if (!def_loaded) + def_load(); + + if ((d = def_find(item)) == NULL || d->value == NULL) + return dflt; + + return strtol(d->value, (char **)NULL, 0); +} + +/* + * def_find - locate named item in table + * + * Search through a sorted table of configurable items to locate the + * specified configuration option. + */ + +static struct itemdef *def_find(const char *name) +{ + int min, max, curr, n; + + /* + * Invariant - desired item in range [min:max]. + */ + + min = 0; + max = NUMDEFS-1; + + /* + * Binary search into the table. Relies on the items being + * sorted by name. + */ + + while (min <= max) { + curr = (min+max)/2; + + if (! (n = strcmp(def_table[curr].name, name))) + return &def_table[curr]; + + if (n < 0) + min = curr+1; + else + max = curr-1; + } + + /* + * Item was never found. + */ + + fprintf(stderr, "mbpasswd: configuration error - unknown item '%s' (notify administrator)\r\n", name); + syslog(LOG_CRIT, "unknown configuration item `%s'", name); + return (struct itemdef *) NULL; +} + +/* + * def_load - load configuration table + * + * Loads the user-configured options from the default configuration file + */ + +static void def_load(void) +{ + int i; + FILE *fp; + struct itemdef *d; + char buf[BUFSIZ], *name, *value, *s; + + /* + * Open the configuration definitions file. + */ + + if ((fp = fopen(def_fname, "r")) == NULL) { + syslog(LOG_CRIT, "cannot open login definitions %s [%m]", def_fname); + return; + } + + /* + * Go through all of the lines in the file. + */ + + while (fgets(buf, sizeof(buf), fp) != NULL) { + + /* + * Trim trailing whitespace. + */ + + for (i = strlen(buf)-1 ; i >= 0 ; --i) { + if (!isspace(buf[i])) + break; + } + buf[++i] = '\0'; + + /* + * Break the line into two fields. + */ + + name = buf + strspn(buf, " \t"); /* first nonwhite */ + if (*name == '\0' || *name == '#') + continue; /* comment or empty */ + + s = name + strcspn(name, " \t"); /* end of field */ + if (*s == '\0') + continue; /* only 1 field?? */ + + *s++ = '\0'; + value = s + strspn(s, " \"\t"); /* next nonwhite */ + *(value + strcspn(value, "\"")) = '\0'; + + /* + * Locate the slot to save the value. If this parameter + * is unknown then "def_find" will print an err message. + */ + + if ((d = def_find(name)) == NULL) + continue; + + /* + * Save off the value. + */ + + if ((d->value = strdup(value)) == NULL) { + fprintf(stderr, "mbpasswd: Could not allocate space for config info.\n"); + syslog(LOG_ERR, "could not allocate space for config info"); + break; + } + } + (void) fclose(fp); + + /* + * Set the initialized flag. + */ + + ++def_loaded; +} + +#ifdef CKDEFS +int main(int argc, char **argv) +{ + int i; + char *cp; + struct itemdef *d; + + def_load (); + + for (i = 0 ; i < NUMDEFS ; ++i) { + if ((d = def_find(def_table[i].name)) == NULL) + printf("error - lookup '%s' failed\n", def_table[i].name); + else + printf("%4d %-24s %s\n", i+1, d->name, d->value); + } + for (i = 1;i < argc;i++) { + if (cp = getdef_str (argv[1])) + printf ("%s `%s'\n", argv[1], cp); + else + printf ("%s not found\n", argv[1]); + } + exit(0); +} +#endif diff --git a/mbsebbs/getdef.h b/mbsebbs/getdef.h new file mode 100644 index 00000000..ac6c5489 --- /dev/null +++ b/mbsebbs/getdef.h @@ -0,0 +1,10 @@ +#ifndef _GETDEF_H +#define _GETDEF_H + +/* getdef.c */ +int getdef_bool(const char *); +long getdef_long(const char *, long); +int getdef_num(const char *, int); +char *getdef_str(const char *); + +#endif /* _GETDEF_H */ diff --git a/mbsebbs/language.c b/mbsebbs/language.c new file mode 100644 index 00000000..4dcf50a3 --- /dev/null +++ b/mbsebbs/language.c @@ -0,0 +1,169 @@ +/***************************************************************************** + * + * File ..................: bbs/language.c + * Purpose ...............: Language functions. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs4.h" +#include "language.h" + + + + +/* + * Function will print text in language file + * Forground Colour, Background Colour, Record Number + */ +void language(int fg, int bg, int lRecord) +{ + pout(fg, bg, *(mLanguage + lRecord)); +} + + + +/* + * Function will return line for output + */ +char *Language(int lRecord) +{ + /* + * Return language string + */ + return (*(mLanguage + lRecord)); +} + + + +int Keystroke(int lRecord, int Pos) +{ + char temp[30]; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%s", *(mKeystroke + lRecord)); + + if ((Pos < 0) || (Pos > strlen(temp))) { + WriteError("Keystroke(%d, %d): Range Error", lRecord, Pos); + return '\0'; + } else { + return temp[Pos]; + } +} + + + +/* + * Function will set up the necessary language paths and names + */ +void Set_Language(int iLanguage) +{ + FILE *pLang; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + + if ((pLang = fopen(temp, "rb")) == NULL) { + WriteError("Language: Can't open file: %s", temp); + printf("\nLanguage: Can't open language file\n\n"); + free(temp); + Pause(); + return; + } + + fread(&langhdr, sizeof(langhdr), 1, pLang); + while (fread(&lang, langhdr.recsize, 1, pLang) == 1) { + if ((lang.LangKey[0] == iLanguage) && (lang.Available)) { + strcpy(CFG.current_language, lang.Filename); + break; + } + } + + free(temp); + fclose(pLang); +} + + + +/* + * Function will initialize language variables and load them into + * memory for speed + */ +void InitLanguage() +{ + FILE *pLang; + int iLang = 0; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp, "%s/etc/%s", getenv("MBSE_ROOT"), CFG.current_language); + if ((pLang = fopen(temp, "rb")) == NULL) { + WriteError("$FATAL: Can't open %s", temp); + ExitClient(1); + } + + while (fread(&ldata, sizeof(ldata), 1, pLang) == 1) { + *(mLanguage + iLang) = (char *) calloc(strlen(ldata.sString) + 1, sizeof(char)); + *(mKeystroke + iLang) = (char *) calloc(strlen(ldata.sKey) + 1, sizeof(char)); + strcpy(mLanguage[iLang], ldata.sString); + strcpy(mKeystroke[iLang], ldata.sKey); + iLang++; + + if(iLang >= LANG) { + printf("FATAL: Language file has to many lines in it"); + ExitClient(1); + } + } + + fclose(pLang); + Syslog('b', "%d language lines read (%s)", iLang, CFG.current_language); + free(temp); +} + + + +void Free_Language() +{ + int i; + + for (i = 0; i < LANG; i++) { + if (*(mLanguage + i)) + free(*(mLanguage + i)); + if (*(mKeystroke + i)) + free(*(mKeystroke + i)); + } +} + + + diff --git a/mbsebbs/language.h b/mbsebbs/language.h new file mode 100644 index 00000000..07c19bd6 --- /dev/null +++ b/mbsebbs/language.h @@ -0,0 +1,13 @@ +#ifndef _LANGUAGE_H +#define _LANGUAGE_H + + +void language(int, int, int); /* Print language text */ +int Keystroke(int, int); /* Return keystroke */ +void InitLanguage(void); /* Initialize Language */ +char *Language(int); /* Return line for output */ +void Set_Language(int); /* Set Language Variables Up */ +void Free_Language(void); /* Free language memory */ + +#endif + diff --git a/mbsebbs/lineedit.c b/mbsebbs/lineedit.c new file mode 100644 index 00000000..c52d6ac7 --- /dev/null +++ b/mbsebbs/lineedit.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: bbs/lineedit.c + * Purpose ...............: Message line editor. + * Last modification date : 06-Jul-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mail.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" +#include "lineedit.h" + + +extern int Line; +extern char *Message[]; + + +/* + * Internal prototypes + */ +void Line_Edit_Append(void); /* Append lines */ +void Line_Edit_Delete(void); /* Delete lines */ +void Line_Edit_Edit(void); /* Edit lines */ +void Line_Edit_Insert(void); /* Insert lines */ +void Line_Edit_Replace(void); /* Replace lines */ +void Line_Edit_Text(void); /* Edit (replace) text in line */ +void Line_Edit_Center(void); /* Center a line */ + + + + +void Line_Edit_Append() +{ + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(3, 0, (char *) Language(166)); + Enter(1); + return; + } + + while (TRUE) { + colour(10, 0); + printf("%-2d : ", Line); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Message[Line], 72, 0); + + if((strcmp(Message[Line], "")) == 0) + return; + + Line++; + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(12, 0, (char *) Language(166)); + Enter(1); + return; + } + } +} + + + +void Line_Edit_Delete() +{ + int i, start, end = 0, total; + int Loop; + char temp[81]; + + while (TRUE) { + colour(10, 0); + /* Delete starting at line */ + printf("\n\n%s#(1 - %d): ", (char *) Language(176), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(177)); + Enter(1); + return; + } + + start = atoi(temp); + colour(10, 0); + if(start > (Line - 1) ) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)", (char *) Language(178), (Line - 1) ); + else + break; + } + + while (TRUE) { + colour(10, 0); + /* Delete ending at line */ + printf("%s# (1 - %d): ", (char *) Language(179), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(176)); + Enter(1); + return; + } + + end = atoi(temp); + + colour(10, 0); + if(end > (Line - 1)) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)\n\n", (char *) Language(179), (Line - 1) ); + else + break; + + } + + /* Get total by minusing the end line from the start line */ + /* and + 1 will give you total lines between start and end */ + total = (end - start) + 1; + + /* Define loop by minusing total lines from end which will */ + /* do a loop for only the amount of lines left after the */ + /* end line */ + Loop = Line - end++; + + /* Minus the total amount of deleted lines from the current */ + /* amount of lines to keep track of how many lines you are */ + /* working with */ + Line -= total; + + /* Do loop to copy the current message over the deleted lines */ + + for (i = 0; i < Loop; i++) + strcpy(*(Message + start++), *(Message + end++)); +} + + + +void Line_Edit_Edit() +{ + int j, edit; + char temp[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to edit */ + printf("\n%s(1 - %d): ", (char *) Language(181), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1) ); + else + break; + } + + colour(10, 0); + printf("\n%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + fflush(stdout); + j = strlen(Message[edit]); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + alarm_on(); + GetstrP(Message[edit], 81, j); + } +} + + + +void Line_Edit_Insert() +{ + int i, j, start, end = 0, total; + char temp[81]; + + if((Line - 1) == TEXTBUFSIZE) { + Enter(1); + /* Maximum message length exceeded */ + pout(3, 0, (char *) Language(166)); + Enter(1); + return; + } + + while (TRUE) { + colour(10, 0); + /* Enter line # to insert text before */ + printf("\n\n%s(1 - %d): ", (char *) Language(183), (Line - 1)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + /* Aborted. */ + pout(15, 0, (char *) Language(177)); + return; + } + + start = atoi(temp); + + colour(10, 0); + if(start > (Line - 1)) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d)", (char *) Language(178), (Line - 1)); + else + break; + } + + j = start; + colour(10, 0); + printf("\n%-2d : ", start); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + return; + + total = Line - start; + end = Line; + Line++; + start = Line; + + for (i = 0; i < total + 1; i++) { + strcpy(Message[start], Message[end]); + start--; + end--; + } + + strcpy(Message[j], temp); +} + + + +void Line_Edit_Replace() +{ + int edit; + char temp[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to replace */ + printf("\n\n%s(1 - %d): ", (char *) Language(185), (Line - 1) ); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1)); + else + break; + } + + Enter(1); + /* Line reads: */ + pout(15, 0, (char *) Language(186)); + Enter(1); + + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n\n", Message[edit]); + + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) { + Enter(1); + /* Unchanged. */ + pout(15, 0, (char *) Language(187)); + Enter(1); + } else + strcpy(Message[edit], temp); + + Enter(1); + /* Line now reads: */ + pout(15, 0, (char *) Language(188)); + Enter(1); + + colour(10, 0); + printf("%d : ", edit); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + } +} + + + +void Line_Edit_Text() +{ + int edit; + char temp[81]; + char temp1[81]; + + while (TRUE) { + while (TRUE) { + colour(10, 0); + /* Enter line # to edit */ + printf("\n\n%s(1 - %d): ", (char *) Language(194), (Line - 1)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + edit = atoi(temp); + + colour(10, 0); + if(edit > Line) + /* Please enter a number in the range of */ + printf("\n%s(1 - %d) ", (char *) Language(178), (Line - 1) ); + else + break; + } + + Enter(1); + /* Line reads: */ + pout(15, 0, (char *) Language(186)); + Enter(1); + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n\n", Message[edit]); + + /* Text to replace: */ + pout(10, 0, (char *) Language(195)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + /* Replacement text: */ + pout(10, 0, (char *) Language(196)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp1, 80); + + strreplace(Message[edit], temp, temp1); + + Enter(1); + /* Line now reads: */ + pout(15, 0, (char *) Language(197)); + Enter(1); + colour(10, 0); + printf("%d : ", edit); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Message[edit]); + } +} + + + +void Line_Edit_Center() +{ + int i, j, z, center; + int maxlen = 78; + char *CEnter; + char temp[81]; + + colour(15, 0); + /* Enter line # to center */ + printf("\n\n%s(1 - %d): ", (char *) Language(203), (Line - 1)); + fflush(stdout); + GetstrC(temp, 80); + if((strcmp(temp, "")) == 0) + return; + + CEnter = calloc(81, sizeof(char)); + center = atoi(temp); + j = strlen(Message[center]); + if (j >= maxlen) + /* Line is maximum length and cannot be centered */ + printf("\n%s\n", (char *) Language(204)); + else { + z = 35 - (j / 2); + + for(i = 0; i < z; i++) + strcat(CEnter," "); + strcat(CEnter, Message[center]); + strcpy(Message[center], CEnter); + } + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("\n%s\n", Message[center]); + free(CEnter); +} + + + +int Line_Edit() +{ + int i, j; + + clear(); + colour(12, 0); + /* Begin your message now, Blank line to end */ + Center((char *) Language(164)); + /* Maximum of TEXTBUFSIZE lines, 73 chars per line */ + Center((char *) Language(165)); + colour(14, 0); + printf(" ("); + for (i = 0; i < 74; i++) + printf("-"); + printf(")\n"); + + Line_Edit_Append(); + + while (TRUE) { + colour(14, 0); + /* Functions available: (Current Message: */ + printf("\n%s%d ", (char *) Language(167), (Line - 1)); + /* Lines) */ + printf("%s\n\n", (char *) Language(168)); + colour(11, 0); + /* L - List message S - Save message C - Continue message */ + printf("%s\n", (char *) Language(169)); + + /* Q - Quit message D - Delete line I - Insert line */ + printf("%s\n", (char *) Language(170)); + + /* T - Text edit E - Edit line R - Replace line */ + printf("%s\n", (char *) Language(171)); + + /* Z - Center line */ + printf("%s\n", (char *) Language(172)); + + colour(15, 0); + printf("\n%s [", (char *) Language(173)); + for (i = 0; i < 10; i++) + putchar(Keystroke(172, i)); + printf("]: "); + fflush(stdout); + + alarm_on(); + j = toupper(Getone()); + + if (j == Keystroke(172, 2)) { + /* Continue */ + pout(15, 0, (char *) Language(174)); + Enter(1); + Line_Edit_Append(); + } else + + if (j == Keystroke(172, 4)) { + /* Delete */ + pout(15, 0, (char *) Language(175)); + Enter(1); + Line_Edit_Delete(); + } else + + if (j == Keystroke(172, 7)) { + /* Edit */ + pout(15, 0, (char *) Language(180)); + Enter(1); + Line_Edit_Edit(); + } else + + if (j == Keystroke(172, 5)) { + /* Insert */ + pout(15, 0, (char *) Language(182)); + Enter(1); + Line_Edit_Insert(); + } else + + if (j == Keystroke(172, 0)) { + pout(15, 0, (char *) Language(184)); + Enter(2); + + for(i = 1; i < Line; i++) { + colour(10, 0); + printf("%d: ", i); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s\n", Message[i]); + } + } else + + if (j == Keystroke(172, 8)) { + /* Replace */ + pout(15, 0, (char *) Language(362)); + Enter(1); + Line_Edit_Replace(); + } else + + if (j == Keystroke(172, 3)) { + /* Quit */ + pout(15, 0, (char *) Language(189)); + Enter(2); + + /* Are you sure [y/N] */ + printf("%s", (char *) Language(190)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(190, 0)) { + /* Yes */ + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(356)); + Enter(1); + /* Message aborted. */ + pout(15, 0, (char *) Language(191)); + Enter(2); + + fflush(stdout); + sleep(1); + return FALSE; + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* No */ + printf("%s\n", (char *) Language(192)); + } else + + if (j == Keystroke(172, 6)) { + /* Text Edit */ + pout(15, 0, (char *) Language(193)); + Line_Edit_Text(); + } else + + if (j == Keystroke(172, 1)) { + /* Save */ + pout(15, 0, (char *) Language(198)); + Enter(1); + fflush(stdout); + + if (Line > 1) + return TRUE; + + return FALSE; + } else + + if (j == Keystroke(172, 9)) { + /* Center */ + pout(15, 0, (char *) Language(376)); + Enter(1); + Line_Edit_Center(); + } + } +} + + diff --git a/mbsebbs/lineedit.h b/mbsebbs/lineedit.h new file mode 100644 index 00000000..71894eca --- /dev/null +++ b/mbsebbs/lineedit.h @@ -0,0 +1,7 @@ +#ifndef _LINEEDIT_H +#define _LINEEDIT_H + +int Line_Edit(void); /* The message line editor */ + +#endif + diff --git a/mbsebbs/mail.c b/mbsebbs/mail.c new file mode 100644 index 00000000..93238a8c --- /dev/null +++ b/mbsebbs/mail.c @@ -0,0 +1,2163 @@ +/***************************************************************************** + * + * File ..................: bbs/mail.c + * Purpose ...............: Message reading and writing. + * Last modification date : 28-Jun-2001 + * Todo ..................: Implement message groups. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************** + * + * JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, + * Mats Birch, Mats Wallin. + * ALL RIGHTS RESERVED. + * + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/msgtext.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "mail.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "oneline.h" +#include "exitinfo.h" +#include "lineedit.h" +#include "fsedit.h" +#include "filesub.h" +#include "msgutil.h" +#include "pop3.h" +#include "email.h" + + + +/* + * Global variables + */ +unsigned long LastNum; /* Last read message number */ +int Kludges = FALSE; /* Show kludges or not */ +int Line = 1; /* Line counter in editor */ +char *Message[TEXTBUFSIZE +1];/* Message compose text buffer */ +FILE *qf; /* Quote file */ +extern int do_mailout; + + +/* + * Internal prototypes + */ + +void ShowMsgHdr(void); /* Show message header */ +int Read_a_Msg(unsigned long Num, int);/* Read a message */ +int Export_a_Msg(unsigned long Num);/* Export message to homedir */ +int ReadPanel(void); /* Read panel bar */ +int Save_Msg(int, faddr *); /* Save a message */ +void Reply_Msg(int); /* Reply to message */ +void Delete_MsgNum(unsigned long); /* Delete specified message */ +int CheckUser(char *); /* Check if user exists */ +int IsMe(char *); /* Test if this is my userrecord */ + + +/****************************************************************************/ + + +/* + * More prompt, returns 1 if user decides not to look any further. + */ +int LC(int Lines) +{ + int z; + + iLineCount += Lines; + + if (iLineCount >= exitinfo.iScreenLen && iLineCount < 1000) { + iLineCount = 1; + + pout(CFG.MoreF, CFG.MoreB, (char *) Language(61)); + fflush(stdout); + alarm_on(); + z = toupper(Getone()); + + if (z == Keystroke(61, 1)) { + printf("\n"); + return(1); + } + + if (z == Keystroke(61, 2)) + iLineCount = 50000; + + Blanker(strlen(Language(61))); + } + + return(0); +} + + + +/* + * Check if posting is allowed + */ +int Post_Allowed(void); +int Post_Allowed(void) +{ + if (msgs.MsgKinds == RONLY) { + /* Message area is Readonly */ + pout(12, 0, (char *) Language(437)); + fflush(stdout); + sleep(3); + return FALSE; + } + return TRUE; +} + + + +/* + * Check if netmail may be send crash or immediate. + */ +int Crash_Option(faddr *); +int Crash_Option(faddr *Dest) +{ + node *Nlent; + int rc = 0; + unsigned short point; + + if (exitinfo.Security.level < CFG.iCrashLevel) + return 0; + + point = Dest->point; + Dest->point = 0; + + if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) { + if (Nlent->oflags & OL_CM) { + /* Crash [y/N]: */ + pout(3, 0, (char *)Language(461)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(461, 0)) { + rc = 1; + printf("%c", Keystroke(461, 0)); + } else + printf("%c", Keystroke(461, 1)); + } else { + /* Warning: node is not CM, send Immediate [y/N]: */ + pout(3, 0, (char *)Language(462)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(462, 0)) { + rc = 2; + printf("%c", Keystroke(462, 0)); + } else + printf("%c", Keystroke(462, 1)); + } + fflush(stdout); + } + + Dest->point = point; + return rc; +} + + + +/* + * Ask if message must be private, only allowed in areas which allow + * both public and private. Private areas are forced to private. + */ +int IsPrivate(void); +int IsPrivate(void) +{ + int rc = FALSE; + + if (msgs.MsgKinds == BOTH) { + Enter(1); + /* Private [y/N]: */ + pout(3, 0, (char *) Language(163)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(163, 0)) { + rc = TRUE; + printf("%c", Keystroke(163, 0)); + } else { + printf("%c", Keystroke(163, 1)); + } + fflush(stdout); + } + + /* + * Allways set the private flag in Private areas. + */ + if (msgs.MsgKinds == PRIVATE) + rc = TRUE; + + return rc; +} + + + +void Check_Attach(void); +void Check_Attach(void) +{ + char *Attach, *dospath; + struct stat sb; + + /* + * This is a dangerous option! Every file on the system to which the + * bbs has read access and is in the range of paths translatable by + * Unix to DOS can be attached to the netmail. + */ + if ((msgs.Type == NETMAIL) && (exitinfo.Security.level >= CFG.iAttachLevel)) { + + Attach = calloc(PATH_MAX, sizeof(char)); + while (TRUE) { + Enter(1); + /* Attach file [y/N]: */ + pout(3, 0, (char *)Language(463)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(463, 0)) { + + printf("%c", Keystroke(463, 0)); + Enter(1); + /* Please enter filename: */ + pout(14, 0, (char *)Language(245)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + sprintf(Attach, "%s/", CFG.uxpath); + printf("%s", Attach); + fflush(stdout); + GetstrP(Attach, 71, strlen(Attach)); + if (strcmp(Attach, "") == 0) + break; + + if ((stat(Attach, &sb) == 0) && (S_ISREG(sb.st_mode))) { + dospath = xstrcpy(Unix2Dos(Attach)); + if (strncasecmp(Attach, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + Syslog('+', "FileAttach \"%s\"", Attach); + if (strlen(CFG.dospath)) + strcpy(Msg.Subject, dospath); + else + sprintf(Msg.Subject, "%s", Attach); + Msg.FileAttach = TRUE; + Enter(1); + colour(11, 0); + /* File */ /* will be attached */ + printf("%s %s %s", (char *)Language(464), Msg.Subject, Language(465)); + Enter(1); + fflush(stdout); + sleep(2); + break; + } else { + Enter(1); + colour(10, 0); + /* File not within */ + printf("%s \"%s\"", Language(466), CFG.uxpath); + Enter(1); + Pause(); + } + } else { + Enter(1); + /* File does not exist, please try again ... */ + pout(10, 0, (char *)Language(296)); + Enter(1); + Pause(); + } + } else { + break; + } /* if attach */ + } /* while true */ + free(Attach); + } +} + + + +/* + * Comment to sysop + */ +void SysopComment(char *Cmt) +{ + unsigned long tmp; + char *temp; + FILE *fp; + + tmp = iMsgAreaNumber; + + /* + * Make sure that the .quote file is empty. + */ + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((fp = fopen(temp, "w")) != NULL) + fclose(fp); + free(temp); + + SetMsgArea(CFG.iSysopArea -1); + sprintf(Msg.From, "%s", CFG.sysop_name); + sprintf(Msg.Subject, "%s", Cmt); + Reply_Msg(FALSE); + + SetMsgArea(tmp); +} + + + +/* + * Edit a message. Call the users preffered editor. + */ +int Edit_Msg() +{ + if (exitinfo.FsMsged) + return Fs_Edit(); + else + return Line_Edit(); +} + + + +/* + * Post a message, called from the menu or ReadPanel(). + */ +void Post_Msg() +{ + int i, x; + char *FidoNode; + faddr *Dest = NULL; + node *Nlent; + unsigned short point; + + Line = 1; + WhosDoingWhat(READ_POST); + SetMsgArea(iMsgAreaNumber); + + clear(); + if (!Post_Allowed()) + return; + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Line = 1; + + Msg_New(); + + colour(9, 0); + /* Posting message in area: */ + printf("\n%s\"%s\"\n", (char *) Language(156), sMsgAreaDesc); + pout(14, 0, (char *) Language(157)); + + if (msgs.Type == NEWS) { + if (CFG.EmailMode != E_PRMISP) { + /* + * If not permanent connected to the internet, use Fido style addressing. + */ + Dest = fido2faddr(CFG.EmailFidoAka); + strcpy(Msg.From, exitinfo.sUserName); + tlcap(Msg.From); + } else { + sprintf(Msg.From, "%s@%s (%s)", exitinfo.sUserName, CFG.sysdomain, exitinfo.sUserName); + for (i = 0; i < strlen(Msg.From); i++) { + if (Msg.From[i] == ' ') + Msg.From[i] = '_'; + if (Msg.From[i] == '@') + break; + } + } + } else { + strcpy(Msg.From, exitinfo.sUserName); + tlcap(Msg.From); + } + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s", Msg.From); + Syslog('b', "Setting From: %s", Msg.From); + + if (msgs.Type != NEWS) { + while (TRUE) { + Enter(1); + /* To : */ + pout(14, 0, (char *) Language(158)); + + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + Getname(Msg.To, 35); + + if ((strcmp(Msg.To, "")) == 0) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + return; + } + + if ((strcasecmp(Msg.To, "sysop")) == 0) + strcpy(Msg.To, CFG.sysop_name); + + /* + * Localmail and Echomail may be addressed to All + */ + if ((msgs.Type == LOCALMAIL) || (msgs.Type == ECHOMAIL)) { + if (strcasecmp(Msg.To, "all") == 0) + x = TRUE; + else { + /* + * Local users must exist in the userbase. + */ + if (msgs.Type == LOCALMAIL) { + /* Verifying user ... */ + pout(3, 0, (char *) Language(159)); + x = CheckUser(Msg.To); + } else + x = TRUE; + } + } else if (msgs.Type == NETMAIL) { + x = FALSE; + pout(14, 0, (char *)"Address : "); + FidoNode = calloc(61, sizeof(char)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrC(FidoNode, 60); + + if ((Dest = parsefnode(FidoNode)) != NULL) { + point = Dest->point; + Dest->point = 0; + if (((Nlent = getnlent(Dest)) != NULL) && (Nlent->addr.zone)) { + colour(14, 0); + if (point) + printf("Boss : "); + else + printf("Node : "); + Dest->point = point; + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + printf("%s in %s", Nlent->name, Nlent->location); + colour(14, 0); + printf(" Is this correct Y/N: "); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == 'Y') { + Enter(1); + sprintf(Msg.ToAddress, "%s", ascfnode(Dest, 0x1f)); + x = TRUE; + switch (Crash_Option(Dest)) { + case 1: Msg.Crash = TRUE; + break; + case 2: Msg.Immediate = TRUE; + break; + } + } + } else { + Dest->point = point; + printf("\r"); + pout(3, 0, (char *) Language(241)); + fflush(stdout); + alarm_on(); + if (toupper(Getone()) == Keystroke(241, 0)) { + x = TRUE; + Syslog('+', "Node %s not found, forced continue", FidoNode); + } + } + } else { + Syslog('m', "Can't parse address %s", FidoNode); + } + free(FidoNode); + } else { + x = FALSE; + } + + if(!x) { + printf("\r"); + /* User not found. Try again, or (Enter) to quit */ + pout(3, 0, (char *) Language(160)); + } else + break; + } + } else { + /* + * Newsmode, automatic addressing to All. + */ + strcpy(Msg.To, "All"); + } + + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(161)); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + fflush(stdout); + alarm_on(); + GetstrP(Msg.Subject, 65, 0); + tlf(Msg.Subject); + + if((strcmp(Msg.Subject, "")) == 0) { + Enter(1); + /* Abort Message [y/N] ?: */ + pout(3, 0, (char *) Language(162)); + fflush(stdout); + alarm_on(); + + if (toupper(Getone()) == Keystroke(162, 0)) { + for(i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); + return; + } + } + + /* + * If not addressed to "all" and the area is Private/Public we + * ask the user for the private flag. + */ + if ((strcasecmp(Msg.To, "all")) != 0) + Msg.Private = IsPrivate(); + + Check_Attach(); + + if (Edit_Msg()) + Save_Msg(FALSE, Dest); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +/* + * Save the message to disk. + */ +int Save_Msg(int IsReply, faddr *Dest) +{ + int i; + char *temp; + FILE *fp; + + if (Line < 2) + return TRUE; + + if (!Open_Msgbase(msgs.Base, 'w')) + return FALSE; + + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Written = Msg.Arrived; + Msg.Local = TRUE; + temp = calloc(PATH_MAX, sizeof(char)); + + if (strlen(Msg.ReplyTo) && (msgs.Type == NETMAIL)) { + /* + * Send message to internet gateway. + */ + Syslog('m', "UUCP message to %s", Msg.ReplyAddr); + sprintf(Msg.To, "UUCP"); + Add_Headkludges(Dest, IsReply); + sprintf(temp, "To: %s", Msg.ReplyAddr); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + } else { + Add_Headkludges(Dest, IsReply); + } + + /* + * Add message text + */ + for (i = 1; i < Line; i++) { + MsgText_Add2(Message[i]); + } + + Add_Footkludges(TRUE); + + /* + * Save if to disk + */ + Msg_AddMsg(); + Msg_UnLock(); + + ReadExitinfo(); + exitinfo.iPosted++; + WriteExitinfo(); + + do_mailout = TRUE; + + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %ld", Msg.Id, Msg.To, Msg.Subject, iMsgAreaNumber + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + /* Saving message to disk */ + printf("\n%s(%ld)\n\n", (char *) Language(202), Msg.Id); + fflush(stdout); + sleep(2); + + msgs.LastPosted = time(NULL); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r+")) != NULL) { + fseek(fp, msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)), SEEK_SET); + fwrite(&msgs, msgshdr.recsize, 1, fp); + fclose(fp); + } + + /* + * Add quick mailscan info + */ + if (msgs.Type != LOCALMAIL) { + sprintf(temp, "%s/tmp/%smail.jam", getenv("MBSE_ROOT"), (msgs.Type == ECHOMAIL)? "echo" : "net"); + if ((fp = fopen(temp, "a")) != NULL) { + fprintf(fp, "%s %lu\n", msgs.Base, Msg.Id); + fclose(fp); + } + } + free(temp); + Msg_Close(); + + SetMsgArea(iMsgAreaNumber); + return TRUE; +} + + + +/* + * Show message header screen top for reading messages. + */ +void ShowMsgHdr() +{ + static char Buf1[35], Buf2[35], Buf3[81]; + struct tm *tm; + time_t now; + + Buf1[0] = '\0'; + Buf2[0] = '\0'; + Buf3[0] = '\0'; + + clear(); + colour(1,7); + printf(" %-70s", sMsgAreaDesc); + + colour(4,7); + printf("#%-5lu\n", Msg.Id); + + /* Date : */ + pout(14, 0, (char *) Language(206)); + colour(10, 0); + /* Use intermediate variable to prevent SIGBUS on Sparc's */ + now = Msg.Written; + tm = gmtime(&now); + printf("%02d-%02d-%d %02d:%02d:%02d", tm->tm_mday, tm->tm_mon+1, + tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec); + colour(12, 0); + if (Msg.Local) printf(" Local"); + if (Msg.Intransit) printf(" Transit"); + if (Msg.Private) printf(" Priv."); + if (Msg.Received) printf(" Rcvd"); + if (Msg.Sent) printf(" Sent"); + if (Msg.KillSent) printf(" KillSent"); + if (Msg.ArchiveSent) printf(" ArchiveSent"); + if (Msg.Hold) printf(" Hold"); + if (Msg.Crash) printf(" Crash"); + if (Msg.Immediate) printf(" Imm."); + if (Msg.Direct) printf(" Dir"); + if (Msg.Gate) printf(" Gate"); + if (Msg.FileRequest) printf(" Freq"); + if (Msg.FileAttach) printf(" File"); + if (Msg.TruncFile) printf(" TruncFile"); + if (Msg.KillFile) printf(" KillFile"); + if (Msg.ReceiptRequest) printf(" RRQ"); + if (Msg.ConfirmRequest) printf(" CRQ"); + if (Msg.Orphan) printf(" Orphan"); + if (Msg.Encrypt) printf(" Crypt"); + if (Msg.Compressed) printf(" Comp"); + if (Msg.Escaped) printf(" 7bit"); + if (Msg.ForcePU) printf(" FPU"); + if (Msg.Localmail) printf(" Localmail"); + if (Msg.Netmail) printf(" Netmail"); + if (Msg.Echomail) printf(" Echomail"); + if (Msg.News) printf(" News"); + if (Msg.Email) printf(" E-mail"); + if (Msg.Nodisplay) printf(" Nodisp"); + if (Msg.Locked) printf(" LCK"); + if (Msg.Deleted) printf(" Del"); + printf("\n"); + + /* From : */ + pout(14,0, (char *) Language(209)); + colour(10, 0); + printf("%s ", Msg.From); + if (iMsgAreaType != LOCALMAIL) { + colour(11, 0); + printf("(%s)", Msg.FromAddress); + } + printf("\n"); + + /* To : */ + pout(14,0, (char *) Language(208)); + colour(10, 0); + printf("%s ", Msg.To); + if (iMsgAreaType == NETMAIL) { + colour(11, 0); + printf("(%s)", Msg.ToAddress); + } + printf("\n"); + + /* Subject : */ + pout(14,0, (char *) Language(210)); + colour(10, 0); + printf("%s\n", Msg.Subject); + + colour(CFG.HiliteF, CFG.HiliteB); + colour(14, 1); + if (Msg.Reply) + sprintf(Buf1, "\"+\" %s %lu", (char *)Language(211), Msg.Reply); + if (Msg.Original) + sprintf(Buf2, " \"-\" %s %lu", (char *)Language(212), Msg.Original); + sprintf(Buf3, "%s%s ", Buf1, Buf2); + colour(14, 1); + printf("%78s \n", Buf3); +} + + + +/* + * Export a message to file in the users home directory. + */ +int Export_a_Msg(unsigned long Num) +{ + char *p; + int ShowMsg = TRUE; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + Syslog('+', "Export msg %d in area #%d (%s)", Num, iMsgAreaNumber + 1, sMsgAreaDesc); + + /* + * The area data is already set, so we can do the next things + */ + if (MsgBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMsgAreaBase)) { + WriteError("Error open JAM base %s", sMsgAreaBase); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + + if (Msg.Private) { + ShowMsg = FALSE; + if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0)) + ShowMsg = TRUE; + if (exitinfo.Security.level >= msgs.SYSec.level) + ShowMsg = TRUE; + } + + if (!ShowMsg) { + printf("\n%s\n\n", (char *) Language(82)); + Msg_Close(); + sleep(3); + return FALSE; + } + + /* + * Export the message text to the file in the users home/wrk directory. + * Create the filename as _.msg The message is + * written in M$DOS format. + */ + p = calloc(128, sizeof(char)); + sprintf(p, "%s/%s/wrk/%d_%lu.msg", CFG.bbs_usersdir, exitinfo.Name, iMsgAreaNumber + 1, Num); + if ((qf = fopen(p, "w")) != NULL) { + free(p); + p = NULL; + if (Msg_Read(Num, 80)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + if (p[0] == '\001') { + p[0] = 'a'; + fprintf(qf, "^%s\r\n", p); + } else + fprintf(qf, "%s\r\n", p); + } + } else + fprintf(qf, "%s\r\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + Msg_Close(); + + /* + * Report the result. + */ + colour(CFG.TextColourF, CFG.TextColourB); + printf("\n\n%s", (char *) Language(46)); + colour(CFG.HiliteF, CFG.HiliteB); + printf("%d_%lu.msg\n\n", iMsgAreaNumber + 1, Num); + Pause(); + return TRUE; +} + + + +/* + * Read a message on screen. Update the lastread pointers, + * except while scanning and reading new mail at logon. + */ +int Read_a_Msg(unsigned long Num, int UpdateLR) +{ + char *p = NULL, *fn; + int ShowMsg = TRUE; + lastread LR; + + LastNum = Num; + iLineCount = 7; + WhosDoingWhat(READ_POST); + + /* + * The area data is already set, so we can do the next things + */ + if (MsgBase.Total == 0) { + colour(15, 0); + /* There are no messages in this area */ + printf("\n%s\n\n", (char *) Language(205)); + sleep(3); + return FALSE; + } + + if (!Msg_Open(sMsgAreaBase)) { + WriteError("Error open JAM base %s", sMsgAreaBase); + return FALSE; + } + + if (!Msg_ReadHeader(Num)) { + perror(""); + colour(15, 0); + printf("\n%s\n\n", (char *)Language(77)); + Msg_Close(); + sleep(3); + return FALSE; + } + if (Msg.Private) { + ShowMsg = FALSE; + if ((strcasecmp(exitinfo.sUserName, Msg.From) == 0) || (strcasecmp(exitinfo.sUserName, Msg.To) == 0)) + ShowMsg = TRUE; + if (exitinfo.Security.level >= msgs.SYSec.level) + ShowMsg = TRUE; + } + if (!ShowMsg) { + printf("\n%s\n\n", (char *) Language(82)); + Msg_Close(); + sleep(3); + return FALSE; + } + ShowMsgHdr(); + + /* + * Fill Quote file in case the user wants to reply. Note that line + * wrapping is set lower then normal message read, to create room + * for the Quote> strings at the start of each line. + */ + fn = calloc(128, sizeof(char)); + sprintf(fn, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(fn, "w")) != NULL) { + if (Msg_Read(Num, 75)) { + if ((p = (char *)MsgText_First()) != NULL) + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + if (p[0] == '\001') { + p[0] = 'a'; + fprintf(qf, "^%s\n", p); + } else + fprintf(qf, "%s\n", p); + } + } else + fprintf(qf, "%s\n", p); + } while ((p = (char *)MsgText_Next()) != NULL); + } + fclose(qf); + } else { + WriteError("$Can't open %s", p); + } + free(fn); + + /* + * Show message text + */ + colour(CFG.TextColourF, CFG.TextColourB); + if (Msg_Read(Num, 78)) { + if ((p = (char *)MsgText_First()) != NULL) { + do { + if ((p[0] == '\001') || (!strncmp(p, "SEEN-BY:", 8)) || (!strncmp(p, "AREA:", 5))) { + if (Kludges) { + colour(7, 0); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE)) + break; + } + } else { + colour(CFG.TextColourF, CFG.TextColourB); + if (strchr(p, '>') != NULL) + if ((strlen(p) - strlen(strchr(p, '>'))) < 10) + colour(CFG.HiliteF, CFG.HiliteB); + printf("%s\n", p); + if (CheckLine(CFG.TextColourF, CFG.TextColourB, FALSE)) + break; + } + } while ((p = (char *)MsgText_Next()) != NULL); + } + } + + /* + * Set the Received status on this message if it's for the user. + */ + if ((!Msg.Received) && (strlen(Msg.To) > 0) && + ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || (strcasecmp(exitinfo.sHandle, Msg.To) == 0))) { + Syslog('m', "Marking message received"); + Msg.Received = TRUE; + Msg.Read = time(NULL) - (gmt_offset((time_t)0) * 60); + if (Msg_Lock(30L)) { + Msg_WriteHeader(Num); + Msg_UnLock(); + } + } + + /* + * Update lastread pointer if needed. Netmail boards are always updated. + */ + if (Msg_Lock(30L) && (UpdateLR || msgs.Type == NETMAIL)) { + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = Num; + if (Num > LR.HighReadMsg) + LR.HighReadMsg = Num; + if (LR.HighReadMsg > MsgBase.Highest) + LR.HighReadMsg = MsgBase.Highest; + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = Num; + LR.HighReadMsg = Num; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append lastread"); + } + free(p); + Msg_UnLock(); + } + + Msg_Close(); + return TRUE; +} + + + +/* + * Read Messages, called from menu + */ +void Read_Msgs() +{ + char *temp; + unsigned long Start; + lastread LR; + + colour(CFG.TextColourF, CFG.TextColourB); + /* Message area \"%s\" contains %lu messages. */ + printf("\n%s\"%s\" %s%lu %s", (char *) Language(221), sMsgAreaDesc, (char *) Language(222), MsgBase.Total, (char *) Language(223)); + + /* + * Check for lastread pointer, suggest lastread number for start. + */ + Start = MsgBase.Lowest; + if (Msg_Open(sMsgAreaBase)) { + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = 1; + Msg_Close(); + /* + * If we already have read the last message, the pointer is + * higher then HighMsgNum, we set it at HighMsgNum to prevent + * errors and read that message again. + */ + if (Start > MsgBase.Highest) + Start = MsgBase.Highest; + } + + colour(15, 0); + /* Please enter a message between */ + printf("\n%s(%lu - %lu)", (char *) Language(224), MsgBase.Lowest, MsgBase.Highest); + /* Message number [ */ + printf("\n%s%lu]: ", (char *) Language(225), Start); + + temp = calloc(81, sizeof(char)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + if ((strcmp(temp, "")) != 0) + Start = atoi(temp); + free(temp); + + if (!Read_a_Msg(Start, TRUE)) + return; + + if (MsgBase.Total == 0) + return; + + while(ReadPanel()) {} +} + + + +/* + * The panel bar under the messages while reading + */ +int ReadPanel() +{ + int input; + + WhosDoingWhat(READ_POST); + + colour(15, 4); + if (msgs.UsrDelete || exitinfo.Security.level >= CFG.sysop_access) { + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (D)elete, (Q)uit, e(X)port */ + printf("%s", (char *) Language(214)); + } else { + /* (A)gain, (N)ext, (L)ast, (R)eply, (E)nter, (Q)uit, e(X)port */ + printf("%s", (char *) Language(215)); + } + if (exitinfo.Security.level >= CFG.sysop_access) + printf(", (!)"); + + printf(": "); + + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + + if (input == '!') { + if (exitinfo.Security.level >= CFG.sysop_access) { + if (Kludges) + Kludges = FALSE; + else + Kludges = TRUE; + } + Read_a_Msg(LastNum, TRUE); + } else if (input == Keystroke(214, 0)) { /* (A)gain */ + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 4)) { /* (P)ost */ + Post_Msg(); + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 2)) { /* (L)ast */ + if (LastNum > MsgBase.Lowest) + LastNum--; + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 3)) { /* (R)eply */ + Reply_Msg(TRUE); + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 5)) { /* (Q)uit */ + /* Quit */ + printf("%s\n", (char *) Language(189)); + return FALSE; + + } else if (input == Keystroke(214, 7)) { /* e(X)port */ + Export_a_Msg(LastNum); + Read_a_Msg(LastNum, TRUE); + + } else if (input == '+') { + if (Msg.Reply) + LastNum = Msg.Reply; + Read_a_Msg(LastNum, TRUE); + + } else if (input == '-') { + if (Msg.Original) + LastNum = Msg.Original; + Read_a_Msg(LastNum, TRUE); + + } else if (input == Keystroke(214, 6)) { /* (D)elete */ + Delete_MsgNum(LastNum); + if (LastNum < MsgBase.Highest) { + LastNum++; + Read_a_Msg(LastNum, TRUE); + } else { + return FALSE; + } + } else { + /* Next */ + pout(15, 0, (char *) Language(216)); + if (LastNum < MsgBase.Highest) + LastNum++; + else + return FALSE; + Read_a_Msg(LastNum, TRUE); + } + return TRUE; +} + + + +/* + * Reply message, in Msg.From and Msg.Subject must be the + * name to reply to and the subject. IsReply is true if the + * message is a real reply, and false for forced messages such + * as "message to sysop" + */ +void Reply_Msg(int IsReply) +{ + int i, j, x; + char to[65]; + char from[65]; + char subj[72]; + char msgid[81]; + char replyto[81]; + char replyaddr[81]; + char *tmp, *buf; + char qin[6]; + faddr *Dest = NULL; + + if (!Post_Allowed()) + return; + + sprintf(from, "%s", Msg.To); + sprintf(to, "%s", Msg.From); + sprintf(replyto, "%s", Msg.ReplyTo); + sprintf(replyaddr, "%s", Msg.ReplyAddr); + Dest = parsefnode(Msg.FromAddress); + Syslog('m', "Parsed from address %s", ascfnode(Dest, 0x1f)); + + if (strncasecmp(Msg.Subject, "Re:", 3) && strncasecmp(Msg.Subject, "Re^2:", 5) && IsReply) { + sprintf(subj, "Re: %s", Msg.Subject); + } else { + sprintf(subj, "%s", Msg.Subject); + } + Syslog('m', "Reply msg to %s, subject %s", to, subj); + Syslog('m', "Msgid was %s", Msg.Msgid); + sprintf(msgid, "%s", Msg.Msgid); + + x = 0; + WhosDoingWhat(READ_POST); + clear(); + colour(1,7); + printf(" %-71s", sMsgAreaDesc); + colour(4,7); + printf("#%-5lu", MsgBase.Highest + 1); + + colour(CFG.HiliteF, CFG.HiliteB); + sLine(); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + Message[i] = (char *) calloc(81, sizeof(char)); + Msg_New(); + + sprintf(Msg.Replyid, "%s", msgid); + sprintf(Msg.ReplyTo, "%s", replyto); + sprintf(Msg.ReplyAddr, "%s", replyaddr); + + /* From : */ + sprintf(Msg.From, "%s", exitinfo.sUserName); + pout(14, 0, (char *) Language(209)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.From); + Enter(1); + + /* To : */ + sprintf(Msg.To, "%s", to); + pout(14, 0, (char *) Language(208)); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.To); + Enter(1); + + /* Enter to keep Subject. */ + pout(12, 0, (char *) Language(219)); + Enter(1); + /* Subject : */ + pout(14, 0, (char *) Language(210)); + sprintf(Msg.Subject, "%s", subj); + pout(CFG.MsgInputColourF, CFG.MsgInputColourB, Msg.Subject); + + x = strlen(subj); + fflush(stdout); + colour(CFG.MsgInputColourF, CFG.MsgInputColourB); + GetstrP(subj, 50, x); + fflush(stdout); + + if (strlen(subj)) + strcpy(Msg.Subject, subj); + tlf(Msg.Subject); + + Msg.Private = IsPrivate(); + Enter(1); + + /* + * If netmail reply and enough security level, allow crashmail. + */ + if (msgs.Type == NETMAIL) { + switch (Crash_Option(Dest)) { + case 1: Msg.Crash = TRUE; + break; + case 2: Msg.Immediate = TRUE; + break; + } + } + + Check_Attach(); + + /* + * Quote original message now, format the original users + * initials into qin. No quoting if this is a message to Sysop. + */ + Line = 1; + if (IsReply) { + sprintf(Message[1], "%s wrote to %s:", to, from); + memset(&qin, 0, sizeof(qin)); + x = TRUE; + j = 0; + for (i = 0; i < strlen(to); i++) { + if (x) { + qin[j] = to[i]; + j++; + x = FALSE; + } + if (to[i] == ' ' || to[i] == '.') + x = TRUE; + if (j == 6) + break; + } + Line = 2; + + tmp = calloc(128, sizeof(char)); + buf = calloc(128, sizeof(char)); + + sprintf(tmp, "%s/%s/.quote", CFG.bbs_usersdir, exitinfo.Name); + if ((qf = fopen(tmp, "r")) != NULL) { + while ((fgets(buf, 128, qf)) != NULL) { + Striplf(buf); + sprintf(Message[Line], "%s> %s", (char *)qin, buf); + Line++; + if (Line == TEXTBUFSIZE) + break; + } + fclose(qf); + } else + WriteError("$Can't read %s", tmp); + + free(buf); + free(tmp); + } + + if (Edit_Msg()) + Save_Msg(IsReply, Dest); + + for (i = 0; i < (TEXTBUFSIZE + 1); i++) + free(Message[i]); +} + + + +int IsMe(char *Name) +{ + char *p, *q; + int i, rc = FALSE; + + if (strlen(Name) == 0) + return FALSE; + + if (strcasecmp(Name, exitinfo.sUserName) == 0) + rc = TRUE; + + if (strcasecmp(Name, exitinfo.sHandle) == 0) + rc = TRUE; + + q = xstrcpy(Name); + if (strstr(q, (char *)"@")) { + p = strtok(q, "@"); + for (i = 0; i < strlen(p); i++) + if (p[i] == '_') + p[i] = ' '; + if (strcasecmp(p, exitinfo.sUserName) == 0) + rc = TRUE; + if (strcasecmp(p, exitinfo.sHandle) == 0) + rc = TRUE; + if (strcasecmp(p, exitinfo.Name) == 0) + rc = TRUE; + } + free(q); + return rc ; +} + + + +void QuickScan_Msgs() +{ + int FoundMsg = FALSE; + long i; + + iLineCount = 2; + WhosDoingWhat(READ_POST); + + if (MsgBase.Total == 0) { + Enter(1); + /* There are no messages in this area. */ + pout(15, 0, (char *) Language(205)); + Enter(3); + sleep(3); + return; + } + + clear(); + /* # From To Subject */ + poutCR(14, 1, (char *) Language(220)); + + if (Msg_Open(sMsgAreaBase)) { + for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + + colour(15, 0); + printf("%-6lu", Msg.Id); + if (IsMe(Msg.From)) + colour(11, 0); + else + colour(3, 0); + printf("%s ", padleft(Msg.From, 20, ' ')); + + if (IsMe(Msg.To)) + colour(10, 0); + else + colour(2, 0); + printf("%s ", padleft(Msg.To, 20, ' ')); + colour(5, 0); + printf("%s", padleft(Msg.Subject, 31, ' ')); + printf("\n"); + FoundMsg = TRUE; + if (LC(1)) + break; + } + } + Msg_Close(); + } + + if(!FoundMsg) { + Enter(1); + /* There are no messages in this area. */ + pout(10, 0, (char *) Language(205)); + Enter(2); + sleep(3); + } + + iLineCount = 2; + Pause(); +} + + + +/* + * Called from the menu + */ +void Delete_Msg() +{ + return; +} + + + +/* + * Check linecounter for reading messages. + */ +int CheckLine(int FG, int BG, int Email) +{ + int i, x, z; + + x = strlen(Language(61)); + iLineCount++; + + if ((iLineCount >= (exitinfo.iScreenLen -1)) && (iLineCount < 1000)) { + iLineCount = 7; + + DoNop(); + pout(CFG.MoreF, CFG.MoreB, (char *) Language(61)); + + fflush(stdout); + alarm_on(); + z = tolower(Getone()); + + for (i = 0; i < x; i++) + putchar('\b'); + for (i = 0; i < x; i++) + putchar(' '); + for (i = 0; i < x; i++) + putchar('\b'); + fflush(stdout); + + switch(z) { + + case 'n': + printf("\n"); + return TRUE; + break; + case '=': + iLineCount = 1000; + } + if (Email) + ShowEmailHdr(); + else + ShowMsgHdr(); + colour(FG, BG); + } + return FALSE; +} + + + +/* + * Select message area from the list. + */ +void MsgArea_List(char *Option) +{ + FILE *pAreas; + int iAreaCount = 6, Recno = 0; + int iOldArea = 0, iAreaNum = 0; + int iGotArea = FALSE; /* Flag to check if user typed in area */ + long offset; + char *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(temp,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + + /* + * Save old area, incase he picks a invalid area + */ + iOldArea = iMsgAreaNumber; + + if(( pAreas = fopen(temp, "rb")) == NULL) { + WriteError("Can't open msg areas file: %s", temp); + free(temp); + fclose(pAreas); + return; + } + + /* + * Count how many records there are + */ + fread(&msgshdr, sizeof(msgshdr), 1, pAreas); + fseek(pAreas, 0, SEEK_END); + iAreaNum = (ftell(pAreas) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + + /* + * If there are menu options, select area direct. + */ + if (strlen(Option) != 0) { + + if (strcmp(Option, "M+") == 0) + while(TRUE) { + iMsgAreaNumber++; + if (iMsgAreaNumber >= iAreaNum) + iMsgAreaNumber = 0; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + + fread(&msgs, msgshdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0)) + break; + } + + if (strcmp(Option, "M-") == 0) + while(TRUE) { + iMsgAreaNumber--; + if (iMsgAreaNumber < 0) + iMsgAreaNumber = iAreaNum -1; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + + fread(&msgs, msgshdr.recsize, 1, pAreas); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active) && (strlen(msgs.Password) == 0)) + break; + } + SetMsgArea(iMsgAreaNumber); + Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc); + free(temp); + fclose(pAreas); + return; + } + + clear(); + Enter(1); + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(231)); + Enter(2); + + fseek(pAreas, msgshdr.hdrsize, 0); + + while (fread(&msgs, msgshdr.recsize, 1, pAreas) == 1) { + /* + * Skip the echomail systems + */ + fseek(pAreas, msgshdr.syssize, SEEK_CUR); + if ((Access(exitinfo.Security, msgs.RDSec)) && (msgs.Active)) { + msgs.Name[31] = '\0'; + + colour(15,0); + printf("%5d", Recno + 1); + + colour(9,0); + printf(" %c ", 46); + + colour(3,0); + printf("%-31s", msgs.Name); + + iAreaCount++; + + if ((iAreaCount % 2) == 0) + printf("\n"); + else + printf(" "); + } + + Recno++; + + if((iAreaCount / 2) == exitinfo.iScreenLen) { + /* More (Y/n/=/Area #): */ + pout(CFG.MoreF, CFG.MoreB, (char *) Language(207)); + /* + * Ask user for Area or enter to continue + */ + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 7); + + if (toupper(temp[0]) == Keystroke(207, 1)) + break; + + if ((strcmp(temp, "")) != 0) { + iGotArea = TRUE; + break; + } + + iAreaCount = 2; + } + } + + /* + * If user type in area above during area listing + * don't ask for it again + */ + if (!iGotArea) { + Enter(1); + pout(CFG.HiliteF, CFG.HiliteB, (char *) Language(232)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 80); + } + + /* + * Check if user pressed ENTER + */ + if ((strcmp(temp, "")) == 0) { + fclose(pAreas); + return; + } + iMsgAreaNumber = atoi(temp); + iMsgAreaNumber--; + + /* + * Do a check in case user presses Zero + */ + if (iMsgAreaNumber == -1) + iMsgAreaNumber = 0; + + offset = msgshdr.hdrsize + (iMsgAreaNumber * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pAreas, offset, 0) != 0) { + printf("Can't move pointer there."); + } + fread(&msgs, msgshdr.recsize, 1, pAreas); + + /* + * Do a check if area is greater or less number than allowed, + * security acces (level, flags and age) is oke, and the area + * is active. + */ + if (iMsgAreaNumber > iAreaNum || iMsgAreaNumber < 0 || (Access(exitinfo.Security, msgs.RDSec) == FALSE) || (!msgs.Active)) { + Enter(1); + /* + * Invalid area specified - Please try again ... + */ + pout(12, 0, (char *) Language(233)); + Enter(2); + Pause(); + fclose(pAreas); + iMsgAreaNumber = iOldArea; + SetMsgArea(iMsgAreaNumber); + free(temp); + return; + } + + SetMsgArea(iMsgAreaNumber); + Syslog('+', "Msg area %lu %s", iMsgAreaNumber, sMsgAreaDesc); + + /* + * Check if msg area has a password, if it does ask user for it + */ + if((strlen(msgs.Password)) > 2) { + Enter(2); + /* Please enter Area Password: */ + pout(15, 0, (char *) Language(233)); + fflush(stdout); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(temp, 20); + + if((strcmp(temp, msgs.Password)) != 0) { + Enter(1); + pout(15, 0, (char *) Language(234)); + Syslog('!', "Incorrect Message Area # %d password given: %s", iMsgAreaNumber, temp); + SetMsgArea(iOldArea); + } else { + Enter(1); + pout(15, 0, (char *) Language(235)); + Enter(2); + } + Pause(); + } + + free(temp); + fclose(pAreas); +} + + + +/* + * Function deletes a specified message. + */ +void Delete_MsgNum(unsigned long MsgNum) +{ + int Result = FALSE; + + pout(12, 0, (char *) Language(230)); + + if (Msg_Open(sMsgAreaBase)) { + if (Msg_Lock(15L)) { + Result = Msg_Delete(MsgNum); + Msg_UnLock(); + } + Msg_Close(); + } + + if (Result) + Syslog('+', "Deleted msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc); + else + WriteError("ERROR delete msg #%lu in Area #%d (%s)", MsgNum, iMsgAreaNumber, sMsgAreaDesc); +} + + + +/* + * This Function checks to see if the user exists in the user database + * and returns a int TRUE or FALSE + */ +int CheckUser(char *To) +{ + FILE *pUsrConfig; + int Found = FALSE; + char *temp; + long offset; + unsigned long Crc; + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"rb")) == NULL) { + perror(""); + WriteError("Can't open file %s for reading", temp); + Pause(); + free(temp); + return FALSE; + } + free(temp); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + Crc = StringCRC32(tl(To)); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) { + if (StringCRC32(tl(usrconfig.sUserName)) == Crc) { + Found = TRUE; + break; + } + } + + if (!Found) + Syslog('!', "User attempted to mail unknown user: %s", tlcap(To)); + + /* + * Restore users record + */ + offset = usrconfighdr.hdrsize + (grecno * usrconfighdr.recsize); + if (fseek(pUsrConfig, offset, 0) != 0) + printf("Can't move pointer there."); + else + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + fclose(pUsrConfig); + + return Found; +} + + + +/* + * Check for new mail + */ +void CheckMail() +{ + FILE *pMsgArea, *Tmp; + int x, Found = 0; + int Color, Count = 0, Reading; + int OldMsgArea; + char *temp; + char *sFileName; + unsigned long i, Start; + typedef struct _Mailrec { + long Area; + unsigned long Msg; + } _Mail; + _Mail Mail; + lastread LR; + + OldMsgArea = iMsgAreaNumber; + iMsgAreaNumber = 0; + Syslog('+', "Start checking for new mail"); + + clear(); + /* Checking your mail box ... */ + language(10, 0, 150); + Enter(2); + Color = 9; + fflush(stdout); + + /* + * Open temporary file + */ + if ((Tmp = tmpfile()) == NULL) { + WriteError("$unable to open temporary file"); + return; + } + + /* + * First check the e-mail mailbox + */ + temp = calloc(PATH_MAX, sizeof(char)); + if (exitinfo.Email && strlen(exitinfo.Password)) { + check_popmail(exitinfo.Name, exitinfo.Password); + colour(Color, 0); + printf("\re-mail Private e-mail mailbox"); + fflush(stdout); + Color++; + Count = 0; + sprintf(temp, "%s/%s/mailbox", CFG.bbs_usersdir, exitinfo.Name); + SetEmailArea((char *)"mailbox"); + if (Msg_Open(temp)) { + /* + * Check lastread pointer, if none found start + * at the begin of the messagebase. + */ + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = EmailBase.Lowest; + + for (i = Start; i <= EmailBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + /* + * Only check the received status of the email. The mail + * may not be direct addressed to this user (aliases database) + * but if it is in his mailbox it is always for the user. + */ + if (!Msg.Received) { + /* + * Store area and message number in temporary file. + */ + Mail.Area = -1; /* Means e-mail mailbox */ + Mail.Msg = Msg.Id + EmailBase.Lowest -1; + fwrite(&Mail, sizeof(Mail), 1, Tmp); + Count++; + Found++; + } + } + } + Msg_Close(); + } + if (Count) { + colour(CFG.TextColourF, CFG.TextColourB); + /* messages in */ + printf("\n\n%d %s private e-mail mailbox\n\n", Count, (char *)Language(213)); + Syslog('m', " %d messages in private e-mail mailbox", Count); + } + } + + /* + * Open the message base configuration + */ + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + if((pMsgArea = fopen(sFileName, "r+")) == NULL) { + WriteError("$Can't open: %s", sFileName); + free(temp); + free(sFileName); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + + /* + * Check all normal areas one by one + */ + while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) { + fseek(pMsgArea, msgshdr.syssize, SEEK_CUR); + if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) { + SetMsgArea(iMsgAreaNumber); + sprintf(temp, "%d", iMsgAreaNumber + 1); + colour(Color, 0); + if (Color < 15) + Color++; + else + Color = 9; + printf("\r%6s %-40s", temp, sMsgAreaDesc); + fflush(stdout); + Count = 0; + Nopper(); + + if (Msg_Open(sMsgAreaBase)) { + /* + * Check lastread pointer, if none found start + * at the begin of the messagebase. + */ + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg + 1; + else + Start = MsgBase.Lowest; + + for (i = Start; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + if ((!Msg.Received) && (IsMe(Msg.To))) { + /* + * Store area and message number + * in temporary file. + */ + Mail.Area = iMsgAreaNumber; + Mail.Msg = Msg.Id + MsgBase.Lowest -1; + fwrite(&Mail, sizeof(Mail), 1, Tmp); + Count++; + Found++; + } + } + } + Msg_Close(); + } + if (Count) { + colour(CFG.TextColourF, CFG.TextColourB); + /* messages in */ + printf("\n\n%d %s %s\n\n", Count, (char *)Language(213), sMsgAreaDesc); + Syslog('m', " %d messages in %s", Count, sMsgAreaDesc); + } + } + iMsgAreaNumber++; + } + + fclose(pMsgArea); + putchar('\r'); + for (i = 0; i < 48; i++) + putchar(' '); + putchar('\r'); + + if (Found) { + colour(14, 0); + /* You have messages, read your mail now? [Y/n]: */ + printf("\n%s%d %s", (char *) Language(142), Found, (char *) Language(143)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + fflush(stdin); + alarm_on(); + + if (toupper(Getone()) != Keystroke(143,1)) { + rewind(Tmp); + Reading = TRUE; + + while ((Reading) && (fread(&Mail, sizeof(Mail), 1, Tmp) == 1)) { + if (Mail.Area == -1) { + /* + * Private e-mail + */ + Read_a_Email(Mail.Msg); + } else { + SetMsgArea(Mail.Area); + Read_a_Msg(Mail.Msg, FALSE); + } + /* (R)eply, (N)ext, (Q)uit */ + pout(CFG.CRColourF, CFG.CRColourB, (char *)Language(218)); + fflush(stdout); + fflush(stdin); + alarm_on(); + x = toupper(Getone()); + + if (x == Keystroke(218, 0)) { + Syslog('m', " Reply!"); + if (Mail.Area == -1) { + } else { + Reply_Msg(TRUE); + } + } + if (x == Keystroke(218, 2)) { + Syslog('m', " Quit check for new mail"); + iMsgAreaNumber = OldMsgArea; + fclose(Tmp); + SetMsgArea(OldMsgArea); + printf("\n\n"); + free(temp); + free(sFileName); + return; + } + } + } + } else { + language(12, 0, 144); + Enter(1); + sleep(3); + } /* if (Found) */ + + iMsgAreaNumber = OldMsgArea; + fclose(Tmp); + SetMsgArea(OldMsgArea); + printf("\n\n"); + free(temp); + free(sFileName); +} + + + +/* + * Status of all mail areas. + */ +void MailStatus() +{ + FILE *pMsgArea; + int Count = 0; + int OldMsgArea; + char temp[81]; + char *sFileName; + unsigned long i; + + sFileName = calloc(PATH_MAX, sizeof(char)); + OldMsgArea = iMsgAreaNumber; + iMsgAreaNumber = 0; + clear(); + colour(14, 1); + /* Area Type Description Messages Personal */ + printf("%-79s", (char *)Language(226)); + Enter(1); + iLineCount = 2; + fflush(stdout); + + if (exitinfo.Email) { + sprintf(temp, "%s", sMailbox); + for (i = 0; i < 3; i++) { + switch (i) { + case 0: SetEmailArea((char *)"mailbox"); + break; + case 1: SetEmailArea((char *)"archive"); + break; + case 2: SetEmailArea((char *)"trash"); + break; + } + colour(12, 0); + printf(" Email"); + colour(11, 0); + printf(" %-40s", Language(467 + i)); + colour(14, 0); + if (EmailBase.Highest) + printf(" %8lu", EmailBase.Highest - EmailBase.Lowest + 1); + else + printf(" 0"); + colour(9, 0); + if (EmailBase.Highest) + printf(" %8lu\n", EmailBase.Highest - EmailBase.Lowest + 1); + else + printf(" 0\n"); + } + iLineCount = 5; + SetEmailArea(temp); + } + + /* + * Open the message base configuration + */ + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + if((pMsgArea = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + free(sFileName); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + + /* + * Check all areas one by one + */ + while (fread(&msgs, msgshdr.recsize, 1, pMsgArea) == 1) { + fseek(pMsgArea, msgshdr.syssize, SEEK_CUR); + if ((msgs.Active) && (exitinfo.Security.level >= msgs.RDSec.level)) { + SetMsgArea(iMsgAreaNumber); + sprintf(temp, "%d", iMsgAreaNumber + 1); + colour(15, 0); + printf("%5s", temp); + colour(12, 0); + switch(msgs.Type) { + case LOCALMAIL: + printf(" Local"); + break; + + case NETMAIL: + printf(" Net "); + break; + + case ECHOMAIL: + printf(" Echo "); + break; + + case NEWS: + printf(" News "); + break; + } + colour(11, 0); + printf(" %-40s", sMsgAreaDesc); + Count = 0; + + if (Msg_Open(sMsgAreaBase)) { + for (i = MsgBase.Lowest; i <= MsgBase.Highest; i++) { + if (Msg_ReadHeader(i)) { + if (IsMe(Msg.To) || IsMe(Msg.From)) + Count++; + } + } + Msg_Close(); + } else + WriteError("Error open JAM %s", sMsgAreaBase); + colour(14, 0); + if (MsgBase.Highest) + printf(" %8lu", MsgBase.Highest - MsgBase.Lowest + 1); + else + printf(" 0"); + colour(9, 0); + printf(" %8d\n", Count); + if (LC(1)) + break; + } + iMsgAreaNumber++; + } + + fclose(pMsgArea); + SetMsgArea(OldMsgArea); + free(sFileName); + Pause(); +} + + + +/* + * Set message area number, set global area description and JAM path + */ +void SetMsgArea(unsigned long AreaNum) +{ + FILE *pMsgArea; + long offset; + char *sFileName; + + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/mareas.data", getenv("MBSE_ROOT")); + memset(&msgs, 0, sizeof(msgs)); + + if((pMsgArea = fopen(sFileName, "r")) == NULL) { + WriteError("$Can't open file: %s", sFileName); + free(sFileName); + return; + } + + fread(&msgshdr, sizeof(msgshdr), 1, pMsgArea); + offset = msgshdr.hdrsize + (AreaNum * (msgshdr.recsize + msgshdr.syssize)); + if(fseek(pMsgArea, offset, 0) != 0) { + WriteError("$Can't move pointer in %s",sFileName); + free(sFileName); + return; + } + + fread(&msgs, msgshdr.recsize, 1, pMsgArea); + strcpy(sMsgAreaDesc, msgs.Name); + strcpy(sMsgAreaBase, msgs.Base); + iMsgAreaNumber = AreaNum; + iMsgAreaType = msgs.Type; + + fclose(pMsgArea); + + /* + * Get information from the message base + */ + + if (Msg_Open(sMsgAreaBase)) { + + MsgBase.Lowest = Msg_Lowest(); + MsgBase.Highest = Msg_Highest(); + MsgBase.Total = Msg_Number(); + Msg_Close(); + } else + WriteError("Error open JAM %s", sMsgAreaBase); + free(sFileName); +} + + + diff --git a/mbsebbs/mail.h b/mbsebbs/mail.h new file mode 100644 index 00000000..cdd79b58 --- /dev/null +++ b/mbsebbs/mail.h @@ -0,0 +1,21 @@ +#ifndef _MAIL_H +#define _MAIL_H + +#define TEXTBUFSIZE 500 + +int LC(int); /* More prompt for reading messages */ +int Edit_Msg(void); /* Edit a message */ +int CheckLine(int, int, int); /* Check linecounter for read */ +void SysopComment(char *); /* Comment to Sysop */ +void Post_Msg(void); /* Post a message */ +void Read_Msgs(void); /* Read Messages */ +void QuickScan_Msgs(void); /* List Message Headers */ +void Delete_Msg(void); /* Delete a specified message */ +void MsgArea_List(char *); /* Select message area */ +void CheckMail(void); /* Check for new mail */ +void MailStatus(void); /* Mail status in areas */ +void SetMsgArea(unsigned long); /* Set message area and variables */ + + +#endif + diff --git a/mbsebbs/mball.c b/mbsebbs/mball.c new file mode 100644 index 00000000..a9af5290 --- /dev/null +++ b/mbsebbs/mball.c @@ -0,0 +1,963 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mball.c + * Purpose ...............: Creates allfiles listings + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/mbse.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/dbcfg.h" +#include "../lib/clcomm.h" +#include "mball.h" + + +extern int do_quiet; /* Supress screen output */ +int do_zip = FALSE; /* Create ZIP archives */ +int do_list = FALSE; /* Create filelist */ +int do_index = FALSE; /* Create 00index files */ +extern int e_pid; /* Pid of child */ +extern int show_log; /* Show logging */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +struct tm *l_date; /* Structure for Date */ +int lastfile; /* Last file number */ + + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed",(char *)"Thu",(char *)"Fri",(char *)"Sat"}; +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar",(char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep",(char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +void ProgName() +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBALL: MBSE BBS %s Allfiles Listing Creator\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); +} + + + +void die(int onsig) +{ + /* + * First check if a child is running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeded", e_pid); + else + WriteError("$Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode... + */ + system("stty sane"); + } + + signal(onsig, SIG_IGN); + + if (onsig) { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + + time(&t_end); + Syslog(' ', "MBALL finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + ExitClient(onsig); +} + + + +void Help() +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mball [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" i index Create \"00index\" files and WWW pages in areas\n"); + printf(" l list Create allfiles and newfiles lists\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet mode\n"); + printf(" -z -zip Create .zip archives\n"); + colour(7, 0); + printf("\n"); + die(0); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + time(&t_start); + umask(000); + + /* + * Catch all signals we can, and ignore the rest. + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGKILL) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + if(argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line: mball"); + + for (i = 1; i < argc; i++) { + + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + + if (!strncasecmp(argv[i], "l", 1)) + do_list = TRUE; + if (!strncasecmp(argv[i], "i", 1)) + do_index = TRUE; + if (!strncasecmp(argv[i], "-q", 2)) + do_quiet = TRUE; + if (!strncasecmp(argv[i], "-z", 2)) + do_zip = TRUE; + } + + if (!(do_list || do_index)) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mball", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBALL v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_list) { + Masterlist(); + if (do_zip) + MakeArc(); + } + + if (do_index) + MakeIndex(); + + if (do_list) + CreateSema((char *)"mailin"); + + if (!do_quiet) + printf("Done!\n"); + + die(0); + return 0; +} + + + +/* + * Translate ISO 8859-1 characters to named character entities + */ +void html_massage(char *, char *); +void html_massage(char *inbuf, char *outbuf) +{ + char *inptr = inbuf; + char *outptr = outbuf; + + memset(outbuf, 0, sizeof(outbuf)); + + while (*inptr) { + + switch ((unsigned char)*inptr) { + case '"': sprintf(outptr, """); break; + case '&': sprintf(outptr, "&"); break; + case '<': sprintf(outptr, "<"); break; + case '>': sprintf(outptr, ">"); break; + case 160: sprintf(outptr, " "); break; + case 161: sprintf(outptr, "¡"); break; + case 162: sprintf(outptr, "¢"); break; + case 163: sprintf(outptr, "£"); break; + case 164: sprintf(outptr, "¤"); break; + case 165: sprintf(outptr, "¥"); break; + case 166: sprintf(outptr, "¦"); break; + case 167: sprintf(outptr, "§"); break; + case 168: sprintf(outptr, "¨"); break; + case 169: sprintf(outptr, "©"); break; + case 170: sprintf(outptr, "ª"); break; + case 171: sprintf(outptr, "«"); break; + case 172: sprintf(outptr, "¬"); break; + case 173: sprintf(outptr, "­"); break; + case 174: sprintf(outptr, "®"); break; + case 175: sprintf(outptr, "¯"); break; + case 176: sprintf(outptr, "°"); break; + case 177: sprintf(outptr, "&plumn;"); break; + case 178: sprintf(outptr, "²"); break; + case 179: sprintf(outptr, "³"); break; + case 180: sprintf(outptr, "´"); break; + case 181: sprintf(outptr, "µ"); break; + case 182: sprintf(outptr, "¶"); break; + case 183: sprintf(outptr, "·"); break; + case 184: sprintf(outptr, "¸"); break; + case 185: sprintf(outptr, "&supl;"); break; + case 186: sprintf(outptr, "º"); break; + case 187: sprintf(outptr, "»"); break; + case 188: sprintf(outptr, "¼"); break; + case 189: sprintf(outptr, "½"); break; + case 190: sprintf(outptr, "¾"); break; + case 191: sprintf(outptr, "¿"); break; + case 192: sprintf(outptr, "À"); break; + case 193: sprintf(outptr, "Á"); break; + case 194: sprintf(outptr, "Â"); break; + case 195: sprintf(outptr, "Ã"); break; + case 196: sprintf(outptr, "Ä"); break; + case 197: sprintf(outptr, "Å"); break; + case 198: sprintf(outptr, "Æ"); break; + case 199: sprintf(outptr, "Ç"); break; + case 200: sprintf(outptr, "È"); break; + case 201: sprintf(outptr, "É"); break; + case 202: sprintf(outptr, "Ê"); break; + case 203: sprintf(outptr, "Ë"); break; + case 204: sprintf(outptr, "Ì"); break; + case 205: sprintf(outptr, "Í"); break; + case 206: sprintf(outptr, "Î"); break; + case 207: sprintf(outptr, "Ï"); break; + case 208: sprintf(outptr, "Ð"); break; + case 209: sprintf(outptr, "Ñ"); break; + case 210: sprintf(outptr, "Ò"); break; + case 211: sprintf(outptr, "Ó"); break; + case 212: sprintf(outptr, "Ô"); break; + case 213: sprintf(outptr, "Õ"); break; + case 214: sprintf(outptr, "Ö"); break; + case 215: sprintf(outptr, "×"); break; + case 216: sprintf(outptr, "Ø"); break; + case 217: sprintf(outptr, "Ù"); break; + case 218: sprintf(outptr, "Ú"); break; + case 219: sprintf(outptr, "Û"); break; + case 220: sprintf(outptr, "Ü"); break; + case 221: sprintf(outptr, "Ý"); break; + case 222: sprintf(outptr, "Þ"); break; + case 223: sprintf(outptr, "ß"); break; + case 224: sprintf(outptr, "à"); break; + case 225: sprintf(outptr, "á"); break; + case 226: sprintf(outptr, "â"); break; + case 227: sprintf(outptr, "ã"); break; + case 228: sprintf(outptr, "ä"); break; + case 229: sprintf(outptr, "å"); break; + case 230: sprintf(outptr, "æ"); break; + case 231: sprintf(outptr, "ç"); break; + case 232: sprintf(outptr, "è"); break; + case 233: sprintf(outptr, "é"); break; + case 234: sprintf(outptr, "ê"); break; + case 235: sprintf(outptr, "ë"); break; + case 236: sprintf(outptr, "ì"); break; + case 237: sprintf(outptr, "í"); break; + case 238: sprintf(outptr, "î"); break; + case 239: sprintf(outptr, "ï"); break; + case 240: sprintf(outptr, "ð"); break; + case 241: sprintf(outptr, "ñ"); break; + case 242: sprintf(outptr, "ò"); break; + case 243: sprintf(outptr, "ó"); break; + case 244: sprintf(outptr, "ô"); break; + case 245: sprintf(outptr, "õ"); break; + case 246: sprintf(outptr, "ö"); break; + case 247: sprintf(outptr, "÷"); break; + case 248: sprintf(outptr, "ø"); break; + case 249: sprintf(outptr, "ù"); break; + case 250: sprintf(outptr, "ú"); break; + case 251: sprintf(outptr, "û"); break; + case 252: sprintf(outptr, "ü"); break; + case 253: sprintf(outptr, "ý"); break; + case 254: sprintf(outptr, "þ"); break; + case 255: sprintf(outptr, "ÿ"); break; + default: *outptr++ = *inptr; *outptr = '\0'; break; + } + while (*outptr) + outptr++; + + inptr++; + } + *outptr = '\0'; +} + + + +char *rfcdate(time_t); +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm; + + ptm = *gmtime(&now); + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d GMT", + wdays[ptm.tm_wday], ptm.tm_mday, months[ptm.tm_mon], + ptm.tm_year + 1900, ptm.tm_hour, ptm.tm_min, ptm.tm_sec); + return(buf); +} + + + +void pagelink(FILE *, char *, int, int); +void pagelink(FILE *fa, char *Path, int inArea, int Current) +{ + char nr[20]; + + fprintf(fa, "
\n"); + + if ((Current >= CFG.www_files_page) && (inArea >= CFG.www_files_page)) { + if (((Current / CFG.www_files_page) - 1) > 0) + sprintf(nr, "%d", (Current / CFG.www_files_page) -1); + else + nr[0] = '\0'; + fprintf(fa, "\"%s\"%s \n", + CFG.www_url, CFG.www_link2ftp, Path+strlen(CFG.ftp_base), nr, + CFG.www_icon_prev, CFG.www_name_prev, CFG.www_name_prev); + } + + fprintf(fa, "\"%s\"%s \n", + CFG.www_url, CFG.www_icon_home, CFG.www_name_home, CFG.www_name_home); + fprintf(fa, "\"%s\"%s\n", + CFG.www_url, CFG.www_link2ftp, CFG.www_icon_back, CFG.www_name_back, CFG.www_name_back); + + if ((Current < (inArea - CFG.www_files_page)) && (inArea >= CFG.www_files_page)) { + fprintf(fa, " \"%s\"%s\n", + CFG.www_url, CFG.www_link2ftp, Path+strlen(CFG.ftp_base), (Current / CFG.www_files_page) + 1, + CFG.www_icon_next, CFG.www_name_next, CFG.www_name_next); + } + + fprintf(fa, "

\n"); +} + + + +FILE *newpage(char *, char *, time_t, int, int); +FILE *newpage(char *Path, char *Name, time_t later, int inArea, int Current) +{ + char linebuf[1024], outbuf[1024]; + static FILE* fa; + + lastfile = Current; + if (Current) + sprintf(linebuf, "%s/index%d.temp", Path, Current / CFG.www_files_page); + else + sprintf(linebuf, "%s/index.temp", Path); + if ((fa = fopen(linebuf, "w")) == NULL) { + WriteError("$Can't create %s", linebuf); + } else { + sprintf(linebuf, "%s", Name); + html_massage(linebuf, outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n", rfcdate(later)); + fprintf(fa, "\n"); + fprintf(fa, "\n", CFG.www_charset); + fprintf(fa, "\n", CFG.www_author, outbuf); + fprintf(fa, "%s\n", outbuf); + fprintf(fa, "\n", CFG.www_url); + fprintf(fa, "\n\n\n"); + pagelink(fa, Path, inArea, Current); + fprintf(fa, "

File index of %s

\n", outbuf); + fprintf(fa, "\n"); + fprintf(fa, "\n"); + return fa; + } + return NULL; +} + + + +void closepage(FILE *, char *, int, int); +void closepage(FILE *fa, char *Path, int inArea, int Current) +{ + char *temp1, *temp2; + + if (fa == NULL) + return; + + temp1 = calloc(PATH_MAX, sizeof(char)); + temp2 = calloc(PATH_MAX, sizeof(char)); + fprintf(fa, "
Nr.FilenameDateSizeDownloadsDescription

\n"); + pagelink(fa, Path, inArea, lastfile); + fprintf(fa, "\n"); + fclose(fa); + if (lastfile) { + sprintf(temp1, "%s/index%d.html", Path, lastfile / CFG.www_files_page); + sprintf(temp2, "%s/index%d.temp", Path, lastfile / CFG.www_files_page); + } else { + sprintf(temp1, "%s/index.html", Path); + sprintf(temp2, "%s/index.temp", Path); + } + rename(temp2, temp1); + free(temp1); + free(temp2); + fa = NULL; +} + + + +void MakeIndex() +{ + FILE *fp, *fm, *fa, *pAreas, *pFile; + int AreaNr = 0, j, z, x = 0, Areas = 0; + int iTotal = 0, aTotal = 0, inArea = 0; + long iSize = 0L, aSize = 0; + char *sAreas, *fAreas; + char temp[81], fn[PATH_MAX], linebuf[1024], outbuf[1024]; + time_t last = 0L, later; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + later = time(NULL) + 86400; + + IsDoing("Create Indexes"); + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if ((pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("$Can't open File Areas File: %s", sAreas); + colour(7,0); + die(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + if (!do_quiet) + printf("Processing index lists\n"); + + sprintf(fn, "%s/index.temp", CFG.ftp_base); + if ((fm = fopen(fn, "w")) == NULL) { + WriteError("$Can't create %s", fn); + die(0); + } + + /* + * Because these web pages are dynamic, ie. they change everytime you + * receive new files and recreates these pages, extra HTTP headers are + * send to the client about these pages. It forbids proxy servers to + * cache these pages. The pages will expire within 24 hours. The pages + * also have an author name, this is the bbs name, and a content + * description for search engines. Automatic advertising. + */ + sprintf(linebuf, "File areas at %s", CFG.bbs_name); + html_massage(linebuf, outbuf); + fprintf(fm, "\n"); + fprintf(fm, "\n", rfcdate(later)); + fprintf(fm, "\n"); + fprintf(fm, "\n", CFG.www_charset); + fprintf(fm, "\n", CFG.www_author, outbuf); + fprintf(fm, "%s\n", outbuf); + fprintf(fm, "\n", CFG.www_url); + fprintf(fm, "\n\n\n"); + fprintf(fm, "

%s

\n", outbuf); + fprintf(fm, "\n"); + fprintf(fm, "\n"); + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + + AreaNr++; + + if (area.Available && !area.CDrom && + (strncmp(CFG.ftp_base, area.Path, strlen(CFG.ftp_base)) == 0)) { + + sprintf(temp, "%s/00index", area.Path); + + if ((fp = fopen(temp, "w")) == NULL) { + WriteError("$Can't create %s", temp); + } else { + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), AreaNr); + + if ((pFile = fopen (fAreas, "r")) == NULL) { + WriteError("$Can't open Area %d (%s)! Skipping ...", AreaNr, area.Name); + } else { + Areas++; + inArea = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) + inArea++; + } + fseek(pFile, 0, SEEK_SET); + + aSize = 0L; + aTotal = 0; + last = 0L; + fa = newpage(area.Path, area.Name, later, inArea, aTotal); + + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) { + /* + * The next is to reduce system + * loading. + */ + x++; + iTotal++; + aTotal++; + if (CFG.slow_util && do_quiet && ((x % 3) == 0)) + usleep(1); + + for (z = 0; z <= 25; z++) { + if (strlen(file.Desc[z])) { + if (z == 0) + fprintf(fp, "%-12s %7luK %s ", file.Name, + file.Size / 1024, + StrDateDMY(file.UploadDate)); + else + fprintf(fp, " "); + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) + fprintf(fp, "%s\n", file.Desc[z]+4); + else + fprintf(fp, "%s\n", file.Desc[z]); + } + } + + fprintf(fa, "", aTotal); + /* + * Check if this is a .gif or .jpg file, if so then + * check if a thumbnail file exists. If not try to + * create a thumbnail file to add to the html listing. + */ + if (strstr(file.Name, ".gif") || strstr(file.Name, ".jpg")) { + sprintf(linebuf, "%s/%s", area.Path, file.Name); + sprintf(outbuf, "%s/.%s", area.Path, file.Name); + if (file_exist(outbuf, R_OK)) { + if ((j = execute(CFG.www_convert, linebuf, outbuf, + (char *)"/dev/null", (char *)"/dev/null", + (char *)"/dev/null"))) { + Syslog('+', "Failed to create thumbnail for %s, rc=%d", file.Name, j); + } + } + fprintf(fa, ""); + } else { + fprintf(fa, "", + CFG.www_url, CFG.www_link2ftp, + area.Path+strlen(CFG.ftp_base), file.Name, file.Name); + } + fprintf(fa, "", StrDateDMY(file.FileDate)); + fprintf(fa, "", file.Size / 1024); + fprintf(fa, "", + file.TimesDL + file.TimesFTP + file.TimesReq); + fprintf(fa, "\n"); + aSize += file.Size; + iSize += file.Size; + if (file.FileDate > last) + last = file.FileDate; + if ((aTotal % CFG.www_files_page) == 0) { + closepage(fa, area.Path, inArea, aTotal); + fa = newpage(area.Path, area.Name, later, inArea, aTotal); + } + + } /* if (!file.deletd) */ + } + fclose(pFile); + closepage(fa, area.Path, inArea, aTotal); + } + fclose(fp); + fprintf(fm, "", + AreaNr, CFG.www_url, CFG.www_link2ftp, area.Path+strlen(CFG.ftp_base), area.Name); + fprintf(fm, "", aTotal); + if (aSize > 1048576) + fprintf(fm, "", aSize / 1048576); + else + fprintf(fm, "", aSize / 1024); + if (last == 0L) + fprintf(fm, "\n"); + else + fprintf(fm, "\n", StrDateDMY(last)); + } + } + } /* End of While Loop Checking for Areas Done */ + + fprintf(fm, "\n", + iTotal, iSize / 1048576); + fprintf(fm, "
AreaDescriptionFilesTotal sizeLast added
%d
",
+									CFG.www_url, CFG.www_link2ftp, 
+									area.Path+strlen(CFG.ftp_base), file.Name);
+								fprintf(fa, "\"%s\"", 
+									CFG.www_url, CFG.www_link2ftp,
+									area.Path+strlen(CFG.ftp_base), file.Name, file.Name);
+								fprintf(fa, "
%s
%s
%lu Kb.
%8ld
");
+							for (j = 0; j < 25; j++)
+								if (strlen(file.Desc[j])) {
+									if (j)
+										fprintf(fa, "\n");
+									sprintf(linebuf, "%s", strkconv(file.Desc[j], CHRS_DEFAULT_FTN, CHRS_DEFAULT_RFC));
+									html_massage(linebuf, outbuf);
+									fprintf(fa, "%s", outbuf);
+								}
+							fprintf(fa, "
%d%s%d%ld Mb.%ld Kb. 
%s
 Total%d%ld Mb. 

\n"); + fprintf(fm, "\"%s\"%s\n", + CFG.www_icon_home, CFG.www_name_home, CFG.www_name_home); + fprintf(fm, "\n"); + fclose(fm); + sprintf(linebuf, "%s/index.html", CFG.ftp_base); + rename(fn, linebuf); + + fclose(pAreas); + free(sAreas); + free(fAreas); + Syslog('+', "Created %d indexes with %d files", Areas, iTotal); +} + + + +void MidLine(char *txt, FILE *fp, int doit) +{ + char temp[81]; + int x, y, z; + + if (!doit) + return; + + z = strlen(txt); + x = 77 - z; + x /= 2; + strcpy(temp, ""); + + for (y = 0; y < x; y++) + strcat(temp, " "); + + strcat(temp, txt); + z = strlen(temp); + x = 77 - z; + + for (y = 0; y < x; y++) + strcat(temp, " "); + + fprintf(fp, "%c", 179); + fprintf(fp, "%s", temp); + fprintf(fp, "%c\r\n", 179); +} + + + +void TopBox(FILE *fp, int doit) +{ + int y; + + if (!doit) + return; + + fprintf(fp, "\r\n%c", 213); + for(y = 0; y < 77; y++) + fprintf(fp, "%c", 205); + fprintf(fp, "%c\r\n", 184); +} + + + +void BotBox(FILE *fp, int doit) +{ + int y; + + if (!doit) + return; + + fprintf(fp, "%c", 212); + for (y = 0; y < 77; y++) + fprintf(fp, "%c", 205); + fprintf(fp, "%c\r\n\r\n", 190); +} + + + +void Masterlist() +{ + FILE *fp, *np, *pAreas, *pFile, *pHeader; + int AreaNr = 0, z, x = 0, New; + long AllFiles = 0, AllBytes = 0, NewFiles = 0, NewBytes = 0; + int AllAreaFiles, AllAreaBytes, popdown, down; + int NewAreaFiles, NewAreaBytes; + char *sAreas, *fAreas; + char temp[81], pop[81]; + + sAreas = calloc(PATH_MAX, sizeof(char)); + fAreas = calloc(PATH_MAX, sizeof(char)); + + IsDoing("Create Allfiles list"); + + sprintf(sAreas, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + + if(( pAreas = fopen (sAreas, "r")) == NULL) { + WriteError("Can't open File Areas File: %s", sAreas); + colour(7,0); + die(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + + if (!do_quiet) + printf("Processing file areas\n"); + + if ((fp = fopen("allfiles.tmp", "a+")) == NULL) { + WriteError("$Can't open allfiles.tmp"); + die(1); + } + if ((np = fopen("newfiles.tmp", "a+")) == NULL) { + WriteError("$Can't open newfiles.tmp"); + fclose(fp); + die(1); + } + + TopBox(fp, TRUE); + TopBox(np, TRUE); + sprintf(temp, "All available files at %s", CFG.bbs_name); + MidLine(temp, fp, TRUE); + sprintf(temp, "New available files since %d days at %s", CFG.newdays, CFG.bbs_name); + MidLine(temp, np, TRUE); + BotBox(fp, TRUE); + BotBox(np, TRUE); + + sprintf(temp, "%s/etc/header.txt", getenv("MBSE_ROOT")); + if(( pHeader = fopen(temp, "r")) != NULL) { + Syslog('+', "Inserting %s", temp); + + while( fgets(temp, 80 ,pHeader) != NULL) { + Striplf(temp); + fprintf(fp, "%s\r\n", temp); + fprintf(np, "%s\r\n", temp); + } + } + + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + AreaNr++; + AllAreaFiles = 0; + AllAreaBytes = 0; + NewAreaFiles = 0; + NewAreaBytes = 0; + + if (area.Available && (area.LTSec.level <= CFG.security.level)) { + + sprintf(fAreas, "%s/fdb/fdb%d.data", getenv("MBSE_ROOT"), AreaNr); + + if ((pFile = fopen (fAreas, "r")) == NULL) { + WriteError("$Can't open Area %d (%s)! Skipping ...", AreaNr, area.Name); + } else { + popdown = 0; + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if ((!file.Deleted) && (!file.Missing)) { + /* + * The next is to reduce system + * loading. + */ + x++; + if (CFG.slow_util && do_quiet && ((x % 3) == 0)) + usleep(1); + AllFiles++; + AllBytes += file.Size; + AllAreaFiles++; + AllAreaBytes += file.Size; + down = file.TimesDL + file.TimesFTP + file.TimesReq; + if (down > popdown) { + popdown = down; + sprintf(pop, "%s", file.Name); + } + if (((t_start - file.UploadDate) / 84400) <= CFG.newdays) { + NewFiles++; + NewBytes += file.Size; + NewAreaFiles++; + NewAreaBytes += file.Size; + } + } + } + + /* + * If there are files to report do it. + */ + if (AllAreaFiles) { + TopBox(fp, TRUE); + TopBox(np, NewAreaFiles); + + sprintf(temp, "Area %d - %s", AreaNr, area.Name); + MidLine(temp, fp, TRUE); + MidLine(temp, np, NewAreaFiles); + + sprintf(temp, "File Requests allowed"); + MidLine(temp, fp, area.FileReq); + MidLine(temp, np, area.FileReq && NewAreaFiles); + + sprintf(temp, "%d KBytes in %d files", AllAreaBytes / 1024, AllAreaFiles); + MidLine(temp, fp, TRUE); + sprintf(temp, "%d KBytes in %d files", NewAreaBytes / 1024, NewAreaFiles); + MidLine(temp, np, NewAreaFiles); + if (popdown) { + sprintf(temp, "Most popular file is %s", pop); + MidLine(temp, fp, TRUE); + } + + BotBox(fp, TRUE); + BotBox(np, NewAreaFiles); + + fseek(pFile, 0, SEEK_SET); + while (fread(&file, sizeof(file), 1, pFile) == 1) { + if((!file.Deleted) && (!file.Missing)) { + New = (((t_start - file.UploadDate) / 84400) <= CFG.newdays); + sprintf(temp, "%-12s%10lu K %s [%04ld] Uploader: %s", + file.Name, file.Size / 1024, StrDateDMY(file.UploadDate), + file.TimesDL + file.TimesFTP + file.TimesReq, + strlen(file.Uploader)?file.Uploader:""); + fprintf(fp, "%s\r\n", temp); + if (New) + fprintf(np, "%s\r\n", temp); + + for (z = 0; z <= 25; z++) { + if (strlen(file.Desc[z])) { + if ((file.Desc[z][0] == '@') && (file.Desc[z][1] == 'X')) { + fprintf(fp, " %s\r\n",file.Desc[z]+4); + if (New) + fprintf(np, " %s\r\n",file.Desc[z]+4); + } else { + fprintf(fp, " %s\r\n",file.Desc[z]); + if (New) + fprintf(np, " %s\r\n",file.Desc[z]); + } + } + } + } + } + } + fclose(pFile); + } + } + } /* End of While Loop Checking for Areas Done */ + + fclose(pAreas); + + TopBox(fp, TRUE); + TopBox(np, TRUE); + sprintf(temp, "Total %ld files, %ld KBytes", AllFiles, AllBytes / 1024); + MidLine(temp, fp, TRUE); + sprintf(temp, "Total %ld files, %ld KBytes", NewFiles, NewBytes / 1024); + MidLine(temp, np, TRUE); + + MidLine((char *)"", fp, TRUE); + MidLine((char *)"", np, TRUE); + + sprintf(temp, "Created by MBSE BBS v%s (Linux) at %s", VERSION, StrDateDMY(t_start)); + MidLine(temp, fp, TRUE); + MidLine(temp, np, TRUE); + + BotBox(fp, TRUE); + BotBox(np, TRUE); + + sprintf(temp, "%s/etc/footer.txt", getenv("MBSE_ROOT")); + if(( pHeader = fopen(temp, "r")) != NULL) { + Syslog('+', "Inserting %s", temp); + + while( fgets(temp, 80 ,pHeader) != NULL) { + Striplf(temp); + fprintf(fp, "%s\r\n", temp); + fprintf(np, "%s\r\n", temp); + } + } + + fclose(fp); + fclose(np); + + if ((rename("allfiles.tmp", "allfiles.txt")) == 0) + unlink("allfiles.tmp"); + if ((rename("newfiles.tmp", "newfiles.txt")) == 0) + unlink("newfiles.tmp"); + + Syslog('+', "Allfiles: %ld, %ld MBytes", AllFiles, AllBytes / 1048576); + Syslog('+', "Newfiles: %ld, %ld MBytes", NewFiles, NewBytes / 1048576); + free(sAreas); + free(fAreas); +} + + + +void MakeArc() +{ + char *cmd; + + if (!getarchiver((char *)"ZIP")) { + WriteError("ZIP Archiver not available"); + return; + } + + cmd = xstrcpy(archiver.farc); + + if (cmd == NULL) { + WriteError("ZIP archive command not available"); + return; + } + + if (!do_quiet) + printf("Creating allfiles.zip\n"); + if (!execute(cmd, (char *)"allfiles.zip allfiles.txt", (char *)NULL, (char *)"/dev/null", + (char *)"/dev/null", (char *)"/dev/null") == 0) + WriteError("Create allfiles.zip failed"); + + if (!do_quiet) + printf("Creating newfiles.zip\n"); + if (!execute(cmd, (char *)"newfiles.zip newfiles.txt", (char *)NULL, (char *)"/dev/null", + (char *)"/dev/null", (char *)"/dev/null") == 0) + WriteError("Create newfiles.zip failed"); + free(cmd); +} + + diff --git a/mbsebbs/mball.h b/mbsebbs/mball.h new file mode 100644 index 00000000..e8f05de4 --- /dev/null +++ b/mbsebbs/mball.h @@ -0,0 +1,17 @@ +#ifndef _MBALL_H +#define _MBALL_H + + +void ProgName(void); +void die(int); +void Help(void); +void MakeIndex(void); +void MidLine(char *, FILE *, int); +void TopBox(FILE *, int); +void BotBox(FILE *, int); +void Masterlist(void); +void MakeArc(void); + + +#endif + diff --git a/mbsebbs/mbchat.c b/mbsebbs/mbchat.c new file mode 100644 index 00000000..07891ede --- /dev/null +++ b/mbsebbs/mbchat.c @@ -0,0 +1,257 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mbchat.c + * Purpose ...............: Sysop chat utility. + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:2801/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" + + +char *ttime2(void); /* Returns current time HH:MM */ + +struct sysconfig CFG; + + +int main(int argc, char **argv) +{ + FILE *fp1, *pChatDev, *pPid, *pLog; + FILE *pDataFile; + int ch; + int iLetter = 0; + short ipid; + char *tty; + char *sStr1= (char *)""; + char pid[81]; + char pid1[20]; + char sTTY[10]; + char *sLog= (char *)""; + char *Config, *FileName, *LogName; + char *BBSpath; + +#ifdef MEMWATCH + mwInit(); +#endif + + FileName = calloc(PATH_MAX, sizeof(char)); + Config = calloc(PATH_MAX, sizeof(char)); + LogName = calloc(PATH_MAX, sizeof(char)); + + if ((BBSpath = getenv("MBSE_ROOT")) == NULL) { + printf("Could not get MBSE_ROOT environment variable\n"); + printf("Please set the environment variable ie:\n\n"); + printf("\"MBSE_ROOT=/usr/local/mbse;export MBSE_ROOT\"\n\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(FileName, "%s/etc/config.data", BBSpath); + + if ((pDataFile = fopen(FileName, "rb")) == NULL) { + perror("\n\nFATAL ERROR: Can't open config.data for reading!!!"); + printf("Please run mbsetup to create configuration file.\n"); + printf("Or check that your MBSE_ROOT variable is set to the BBS Path!\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + fread(&CFG, sizeof(CFG), 1, pDataFile); + fclose(pDataFile); + free(Config); + free(FileName); + + if(CFG.iAutoLog) + sLog = calloc(56, sizeof(char)); + + if(argc != 2) { + printf("\nSCHAT: MBSE BBS %s Sysop chat facilty\n", VERSION); + printf(" %s\n", Copyright); + + printf("\nCommand-line parameters:\n\n"); + + printf(" %s ", *(argv)); + + printf("\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); + } + + printf("\f"); + + if (strncmp( (tty = *(argv+1)), "/dev/", 5 ) == 0 ) { + tty+=5; + sprintf(pid,"%s/tmp/.bbs-exitinfo.%s",BBSpath,tty); + strcpy(sTTY,""); + } else { + sprintf(pid,"%s/tmp/.bbs-exitinfo.%s",BBSpath,*(argv+1)); + strcpy(sTTY,"/dev/"); + } + + strcat(sTTY, *(argv + 1)); + + if(( fp1 = fopen(sTTY,"w")) == NULL) + perror("Error"); + + if(( pPid = fopen(pid,"r")) == NULL) { + printf("\nThere is no user on %s\n", pid); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } else { + fgets(pid1,19,pPid); + fclose(pPid); + } + + ipid = atoi(pid1); + + if(( pChatDev = fopen("/tmp/chatdev","w")) == NULL) + perror("Can't open file"); + else { + sStr1=ttyname(1); + fprintf(pChatDev,"%s", sStr1); + fclose(pChatDev); + } + + if(!CFG.iExternalChat || (strlen(CFG.sExternalChat) < 1) || \ + (access(CFG.sExternalChat, X_OK) != 0)) { + printf("Users chatting device: %s\n", sTTY); + printf("Wait until the user is ready"); + printf("Press ESC to exit chat\n\n"); + + umask(00000); + chmod("/tmp/chatdev", 00777); + chmod(sStr1, 00777); + + sleep(2); + + Setraw(); + + sleep(2); + + while (1) { + ch = getc(stdin); + ch &= '\377'; + if (ch == '\033') + break; + putchar(ch); + putc(ch, fp1); + + if(CFG.iAutoLog) { + if(ch != '\b') + iLetter++; /* Count the letters user presses for logging */ + sprintf(sLog, "%s%c", sLog, ch); + } + + if (ch == '\n') { + ch = '\r'; + putchar(ch); + putc(ch, fp1); + } + + if (ch == '\r') { + ch = '\n'; + putchar(ch); + putc(ch, fp1); + } + + if (ch == '\b') { + ch = ' '; + putchar(ch); + putc(ch, fp1); + ch = '\b'; + putchar(ch); + putc(ch, fp1); + + if(CFG.iAutoLog) + sLog[--iLetter] = '\0'; + } + + /* Check if log chat is on and if so log chat to disk */ + if(CFG.iAutoLog) { + if(iLetter >= 55 || ch == '\n') { + iLetter = 0; + sprintf(LogName, "%s/log/chat.log", BBSpath); + if(( pLog = fopen(LogName, "a+")) != NULL) { + fflush(pLog); + fprintf(pLog, "%s [%s]: %s\n", CFG.sysop_name, ttime2(), sLog); + fclose(pLog); + strcpy(sLog, ""); + } else + perror("\nCan't open chat.log"); + } + } + } /* while chatting */ +// fprintf(fp1, "The sysop ended the chat, press a key.\n"); + } else { + system(CFG.sExternalChat); + printf("\n\n"); + } + + fclose(fp1); + sleep(2); + Unsetraw(); + sleep(2); + unlink("/tmp/chatdev"); + unlink("/tmp/.BusyChatting"); + fclose(fp1); + printf("Done chatting.\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); +} + + + +/* + * This function returns the date for today, to test against other functions + * HH:MM (HOUR-MINUTE) + */ +char *ttime2() +{ + struct tm *l_date; /* Structure for Date */ + time_t Time_Now; + static char Ttime2[9]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + + sprintf(Ttime2, "%02d:%02d", l_date->tm_hour,l_date->tm_min); + + return(Ttime2); +} + + diff --git a/mbsebbs/mbfbgen.c b/mbsebbs/mbfbgen.c new file mode 100644 index 00000000..7ec5c63f --- /dev/null +++ b/mbsebbs/mbfbgen.c @@ -0,0 +1,332 @@ +/***************************************************************************** + * + * File ..................: mbfbgen.c + * Purpose ...............: mbfbgen generates file databases from the old + * style files.bbs. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" + + +struct stat statfile; +struct FILERecord file; + + +int main(void) +{ + FILE *pAreas, *pFilesBBS, *pDataBase; + int i, j = 0, k = 0, x; + int Append = FALSE, Doit, Files = 0, TotalFiles = 0; + long offset; + long TotalAreas = 0, StartArea, EndArea, recno = 0; + char sFileName[PATH_MAX]; + char temp[81]; + char sDataBase[PATH_MAX]; + char sString1[256]; + char sUploader[36]; + char *token = NULL; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + InitConfig(); + TermInit(1); + umask(002); + system("clear"); + colour(15, 0); + printf("\nMBFBGEN: MBSE BBS %s FileBase Generator Utility\n", VERSION); + colour(14, 0); + printf(" %s\n\n", Copyright); + colour(7, 0); + + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"fbgen", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + + Syslog(' ', " "); + Syslog(' ', "MBFBGEN v%s", VERSION); + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp,"r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("Can't open %s\n", temp); + ExitClient(1); + } + + fread(&areahdr, sizeof(areahdr), 1, pAreas); + while (fread(&area, areahdr.recsize, 1, pAreas) == 1) { + TotalAreas++; + } + fclose(pAreas); + + recno = 0; + + colour(3, 0); + printf("Total File Areas : %ld\n", TotalAreas); + printf("File Record Size : %d\n", (int)sizeof(file)); + + printf("\nStart at area [1]: "); + colour(10, 0); + fgets(temp, 10, stdin); + if ((strcmp(temp, "")) == 0) + StartArea = 1L; + else + StartArea = atoi(temp); + + colour(3, 0); + printf("\nStop at area [%ld]: ", TotalAreas); + colour(10, 0); + fgets(temp, 10, stdin); + if ((strcmp(temp, "")) == 0) + EndArea = TotalAreas; + else + EndArea = atoi(temp); + + if ((StartArea < 1L) || (StartArea > TotalAreas)) { + colour(12, 0); + printf("\007\nIllegal \"Start\" area %ld\n", StartArea); + colour(7, 0); + ExitClient(0); + } + if ((EndArea < StartArea) || (EndArea > TotalAreas)) { + colour(12, 0); + printf("\007\nIllegal \"End\" area %ld\n", EndArea); + colour(7, 0); + ExitClient(0); + } + + colour(3, 0); + printf("\nDefault is [Sysop]\n"); + printf("Name of Uploader for files: "); + colour(10, 0); + fgets(sUploader, 35, stdin); + for (i = 0; i < strlen(sUploader); i++) + if (sUploader[i] == '\n') + sUploader[i] = '\0'; + if ((strcmp(sUploader, "")) == 0) + sprintf(sUploader, "Sysop"); + + colour(7, 0); + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((pAreas = fopen(temp,"r")) == NULL) { + WriteError("$Can't open %s", temp); + printf("Can't open %s\n", temp); + ExitClient(1); + } + fread(&areahdr, sizeof(areahdr), 1, pAreas); + recno = StartArea; + + Syslog('+', "From %ld to %ld, Uploader: \"%s\"", StartArea, EndArea, sUploader); + colour(14, 0); + printf("\n\n"); + + while (TRUE) { + + offset = areahdr.hdrsize + ((recno -1) * areahdr.recsize); + if (fseek(pAreas, offset, 0) != 0) { + WriteError("$Can't seek in fareas.data"); + printf("Can't seek in fareas.data\n"); + ExitClient(1); + } + fread(&area, areahdr.recsize, 1, pAreas); + + sprintf(sDataBase,"%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), recno); + + /* + * Try to find files.bbs at 2 places, in the subdirectory + * with the files, and at the path given in the setup. + */ + sprintf(sFileName,"%s/files.bbs", area.Path); + if ((pFilesBBS = fopen(sFileName,"r")) == NULL) { + sprintf(sFileName, "%s", area.FilesBbs); + if ((pFilesBBS = fopen(sFileName, "r")) == NULL) + WriteError("$Can't process area: %ld %s", recno, area.Name); + } + + if (pFilesBBS != NULL) { + Files = 0; + + while (fgets(sString1,255,pFilesBBS) != NULL) { + + if ((sString1[0] != ' ') && (sString1[0] != '\t')) { + /* + * New file entry, check if there hase been a file + * that is not saved yet. + */ + if (Append) { + if ((pDataBase = fopen(sDataBase,"a+")) == NULL) { + WriteError("$Can't open %s", sDataBase); + ExitClient(1); + } else { + fwrite(&file, sizeof(file), 1, pDataBase); + fclose(pDataBase); + } + Append = FALSE; + } + + Files++; + TotalFiles++; + printf("\rArea: %-6ld Fileno: %-6d Total: %-6d", recno, Files, TotalFiles); + fflush(stdout); + + memset(&file, 0, sizeof(file)); + + token = tl(strtok(sString1, " ,\t")); + strcpy(file.Name, token); + strcpy(file.LName, token); + token = strtok(NULL,"\0"); + i = strlen(token); + j = k = 0; + for (x = 0; x < i; x++) { + if ((token[x] == '\n') || (token[x] == '\r')) + token[x] = '\0'; + } + Doit = FALSE; + for (x = 0; x < i; x++) { + if (!Doit) { + if (isalnum(token[x])) + Doit = TRUE; + } + if (Doit) { + if (k > 42) { + if (token[x] == ' ') { + file.Desc[j][k] = '\0'; + j++; + k = 0; + } else { + if (k == 49) { + file.Desc[j][k] = '\0'; + k = 0; + j++; + } + file.Desc[j][k] = token[x]; + k++; + } + } else { + file.Desc[j][k] = token[x]; + k++; + } + } + } + + sprintf(temp,"%s/%s", area.Path, file.Name); + if (stat(temp,&statfile) != 0) { + WriteError("Cannot locate file on disk! Skipping... -> %s\n",temp); + Append = FALSE; + } + + Append = TRUE; + file.Size = statfile.st_size; + file.FileDate = statfile.st_mtime; + file.Crc32 = file_crc(temp, FALSE); + + strcpy(file.Uploader,sUploader); + time(&file.UploadDate); + } else { + /* + * Add multiple description lines + */ + token = strtok(sString1, "\0"); + i = strlen(token); + j++; + k = 0; + Doit = FALSE; + for (x = 0; x < i; x++) { + if ((token[x] == '\n') || (token[x] == '\r')) + token[x] = '\0'; + } + for (x = 0; x < i; x++) { + if (Doit) { + if (k > 42) { + if (token[x] == ' ') { + file.Desc[j][k] = '\0'; + j++; + k = 0; + } else { + if (k == 49) { + file.Desc[j][k] = '\0'; + k = 0; + j++; + } + file.Desc[j][k] = token[x]; + k++; + } + } else { + file.Desc[j][k] = token[x]; + k++; + } + } else { + /* + * Skip until + or | is found + */ + if ((token[x] == '+') || (token[x] == '|')) + Doit = TRUE; + } + } + } + } /* End of files.bbs */ + + /* + * Flush the last file to the database + */ + if (Append) { + if ((pDataBase = fopen(sDataBase, "a+")) == NULL) { + WriteError("$Can't open %s", sDataBase); + ExitClient(1); + } else { + fwrite(&file, sizeof(file), 1, pDataBase); + fclose(pDataBase); + } + Append = FALSE; + } + fclose(pFilesBBS); + } + Syslog('+', "Area %ld added %ld files", recno, Files); + recno++; + if (recno > EndArea) + break; + } + fclose(pAreas); + + colour(3, 0); + printf("\r \rAdded total %d files\n", TotalFiles); + colour(7, 0); + + Syslog('+', "Added total %ld files", TotalFiles); + Syslog(' ', "MBFBGEN Finished"); + ExitClient(0); + return 0; +} + + diff --git a/mbsebbs/mblang.c b/mbsebbs/mblang.c new file mode 100644 index 00000000..b4514f19 --- /dev/null +++ b/mbsebbs/mblang.c @@ -0,0 +1,136 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/mblang.c + * Purpose ...............: Language Compiler + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" + + +int main(int argc, char **argv) +{ + FILE *fp, *fp1; + int i, j, lines; + char *temp, *temp1; + +#ifdef MEMWATCH + mwInit(); +#endif + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + printf("\nMBLANG: MBSE BBS %s Quick Language Data File Creator\n", VERSION); + printf(" %s\n", Copyright); + + if (argc < 3) { + printf("\nUsage: %s [language data file] [language text file]\n\n", *(argv)); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(temp1, "%s", *(argv + 1)); + unlink(temp1); + + sprintf(temp, "%s", *(argv + 2)); + if ((fp1 = fopen(temp, "r")) == NULL) { + printf("\nUnable to open %s\n", temp); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + sprintf(temp1, "%s", *(argv + 1)); + if ((fp = fopen(temp1, "a+")) == NULL) { + printf("\nUnable to open %s\n", temp1); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + lines = 0; + while (fgets(temp, 115, fp1) != NULL) { + + memset(&ldata, 0, sizeof(ldata)); + + /* + * Take the response keys part + */ + for(i = 0; i < strlen(temp); i++) { + if(temp[i] == '|') + break; + ldata.sKey[i] = temp[i]; + } + if (i > 29) { + printf("\nKey part in line %d too long (%d chars)", lines, i); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Take the prompt string part + */ + j = 0; + for (i = i+1; i < strlen(temp); i++) { + if (temp[i] == '\n') + break; + ldata.sString[j] = temp[i]; + j++; + } + if (j > 84) { + printf("\nLanguage string in line %d too long (%d chars)", lines, j); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + fwrite(&ldata, sizeof(ldata), 1, fp); + lines++; + } + + fclose(fp); + fclose(fp1); + free(temp); + free(temp1); + + printf("\nCompiled %d language lines\n", lines); + +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + diff --git a/mbsebbs/mbpasswd.c b/mbsebbs/mbpasswd.c new file mode 100644 index 00000000..f2e995ff --- /dev/null +++ b/mbsebbs/mbpasswd.c @@ -0,0 +1,663 @@ +/***************************************************************************** + * + * File ..................: mbpasswd.c + * Purpose ...............: setuid root version of passwd + * Last modification date : 27-Jun-2001 + * Shadow Suite (c) ......: Julianne Frances Haugh + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(SHADOW_PASSWORD) +#include +#endif + +#include "encrypt.h" +#include "rad64.h" +#include "myname.h" +#include "xmalloc.h" +#include "pwio.h" +#include "shadowio.h" +#include "mbpasswd.h" + + +#ifndef AGING +#if defined(SHADOW_PASSWORD) +#define AGING 1 +#endif +#else +#if !defined(SHADOW_PASSWORD) +#undef AGING +#endif +#endif + +static int do_update_age = 0; +#ifndef PAM +static char crypt_passwd[128]; /* The "old-style" password, if present */ +static int do_update_pwd = 0; +#endif + + +#ifdef SHADOW_PASSWORD +static void check_password(const struct passwd *, const struct spwd *); +#else /* !SHADOW_PASSWORD */ +static void check_password(const struct passwd *); +#endif /* !SHADOW_PASSWORD */ + +#ifndef DAY +#define DAY (24L*3600L) +#endif + +#define WEEK (7*DAY) +#define SCALE DAY + + +/* + * string to use for the pw_passwd field in /etc/passwd when using + * shadow passwords - most systems use "x" but there are a few + * exceptions, so it can be changed here if necessary. --marekm + */ +#ifndef SHADOW_PASSWD_STRING +#define SHADOW_PASSWD_STRING "x" +#endif + + +/* + * Global variables + */ + +static char *name; /* The name of user whose password is being changed */ +static char *myname; /* The current user's name */ +static int force; /* Force update of locked passwords */ + + + +static void fail_exit(int status) +{ + pw_unlock(); +#ifdef SHADOWPWD + spw_unlock(); +#endif + exit(status); +} + + + +static void oom(void) +{ + fprintf(stderr, "mbpasswd: out of memory\n"); + fail_exit(3); +} + + + +/* + * insert_crypt_passwd - add an "old-style" password to authentication string + * result now malloced to avoid overflow, just in case. --marekm + */ +static char * +insert_crypt_passwd(const char *string, char *passwd) +{ +#ifdef AUTH_METHODS + if (string && *string) { + char *cp, *result; + + result = xmalloc(strlen(string) + strlen(passwd) + 1); + cp = result; + while (*string) { + if (string[0] == ';') { + *cp++ = *string++; + } else if (string[0] == '@') { + while (*string && *string != ';') + *cp++ = *string++; + } else { + while (*passwd) + *cp++ = *passwd++; + while (*string && *string != ';') + string++; + } + } + *cp = '\0'; + return result; + } +#endif + return xstrdup(passwd); +} + + + +static char *update_crypt_pw(char *cp) +{ + if (do_update_pwd) + cp = insert_crypt_passwd(cp, crypt_passwd); + + return cp; +} + + + +/* + * pwd_init - ignore signals, and set resource limits to safe + * values. Call this before modifying password files, so that + * it is less likely to fail in the middle of operation. + */ +void pwd_init(void) +{ + struct rlimit rlim; + +#ifdef RLIMIT_CORE + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; +#ifdef RLIMIT_AS + setrlimit(RLIMIT_AS, &rlim); +#endif +#ifdef RLIMIT_CPU + setrlimit(RLIMIT_CPU, &rlim); +#endif +#ifdef RLIMIT_DATA + setrlimit(RLIMIT_DATA, &rlim); +#endif +#ifdef RLIMIT_FSIZE + setrlimit(RLIMIT_FSIZE, &rlim); +#endif +#ifdef RLIMIT_NOFILE + setrlimit(RLIMIT_NOFILE, &rlim); +#endif +#ifdef RLIMIT_RSS + setrlimit(RLIMIT_RSS, &rlim); +#endif +#ifdef RLIMIT_STACK + setrlimit(RLIMIT_STACK, &rlim); +#endif + signal(SIGALRM, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif + + umask(077); +} + + + +/* + * isexpired - determine if account is expired yet + * + * isexpired calculates the expiration date based on the + * password expiration criteria. + */ +#ifdef SHADOW_PASSWORD +int isexpired(const struct passwd *pw, const struct spwd *sp) +{ +#else +int isexpired(const struct passwd *pw) +{ +#endif + long now; + + now = time ((time_t *) 0) / SCALE; + +#ifdef SHADOW_PASSWORD + + if (!sp) + sp = pwd_to_spwd(pw); + + /* + * Quick and easy - there is an expired account field + * along with an inactive account field. Do the expired + * one first since it is worse. + */ + if (sp->sp_expire > 0 && now >= sp->sp_expire) + return 3; + + /* + * Last changed date 1970-01-01 (not very likely) means that + * the password must be changed on next login (passwd -e). + * + * The check for "x" is a workaround for RedHat NYS libc bug - + * if /etc/shadow doesn't exist, getspnam() still succeeds and + * returns sp_lstchg==0 (must change password) instead of -1! + */ + if (sp->sp_lstchg == 0 && !strcmp(pw->pw_passwd, SHADOW_PASSWD_STRING)) + return 1; + if (sp->sp_lstchg > 0 && sp->sp_max >= 0 && sp->sp_inact >= 0 && + now >= sp->sp_lstchg + sp->sp_max + sp->sp_inact) + return 2; + + /* + * The last and max fields must be present for an account + * to have an expired password. A maximum of >10000 days + * is considered to be infinite. + */ + if (sp->sp_lstchg == -1 || + sp->sp_max == -1 || sp->sp_max >= (10000L*DAY/SCALE)) + return 0; + + /* + * Calculate today's day and the day on which the password + * is going to expire. If that date has already passed, + * the password has expired. + */ + if (now >= sp->sp_lstchg + sp->sp_max) + return 1; +#endif + return 0; +} + + + +/* + * check_password - test a password to see if it can be changed + * + * check_password() sees if the invoker has permission to change the + * password for the given user. + */ +#ifdef SHADOW_PASSWORD +static void check_password(const struct passwd *pw, const struct spwd *sp) +{ +#else +static void check_password(const struct passwd *pw) +{ +#endif + time_t now, last, ok; + int exp_status; + +#ifdef SHADOW_PASSWORD + exp_status = isexpired(pw, sp); +#else + exp_status = isexpired(pw); +#endif + + time(&now); + +#ifdef SHADOW_PASSWORD + /* + * If the force flag is set (for new users) this check is skipped. + */ + if (force == 1) + return; + + /* + * Expired accounts cannot be changed ever. Passwords + * which are locked may not be changed. Passwords where + * min > max may not be changed. Passwords which have + * been inactive too long cannot be changed. + */ + if (sp->sp_pwdp[0] == '!' || exp_status > 1 || + (sp->sp_max >= 0 && sp->sp_min > sp->sp_max)) { + fprintf (stderr, "The password for %s cannot be changed.\n", sp->sp_namp); + syslog(LOG_WARNING, "password locked for %s", sp->sp_namp); + closelog(); + exit (1); + } + + /* + * Passwords may only be changed after sp_min time is up. + */ + + last = sp->sp_lstchg * SCALE; + ok = last + (sp->sp_min > 0 ? sp->sp_min * SCALE : 0); +#else /* !SHADOW_PASSWORD */ + if (pw->pw_passwd[0] == '!' || exp_status > 1) { + fprintf (stderr, "The password for %s cannot be changed.\n", pw->pw_name); + syslog(LOG_WARNING, "password locked for %s", pw->pw_name); + closelog(); + exit (1); + } + last = 0; + ok = 0; +#endif /* !SHADOW_PASSWORD */ + if (now < ok) { + fprintf(stderr, "Sorry, the password for %s cannot be changed yet.\n", pw->pw_name); + syslog(LOG_WARNING, "now < minimum age for `%s'", pw->pw_name); + closelog(); + exit (1); + } +} + + + +/* + * pwd_to_spwd - create entries for new spwd structure + * + * pwd_to_spwd() creates a new (struct spwd) containing the + * information in the pointed-to (struct passwd). + * + * This function is borrowed from the Shadow Password Suite. + */ +#ifdef SHADOW_PASSWORD +struct spwd *pwd_to_spwd(const struct passwd *pw) +{ + static struct spwd sp; + + /* + * Nice, easy parts first. The name and passwd map directly + * from the old password structure to the new one. + */ + sp.sp_namp = pw->pw_name; + sp.sp_pwdp = pw->pw_passwd; + + /* + * Defaults used if there is no pw_age information. + */ + sp.sp_min = 0; + sp.sp_max = (10000L * DAY) / SCALE; + sp.sp_lstchg = time((time_t *) 0) / SCALE; + + /* + * These fields have no corresponding information in the password + * file. They are set to uninitialized values. + */ + sp.sp_warn = -1; + sp.sp_expire = -1; + sp.sp_inact = -1; + sp.sp_flag = -1; + + return &sp; +} +#endif + + + +/* + * new_password - validate old password and replace with new + * (both old and new in global "char crypt_passwd[128]") + */ +static int new_password(const struct passwd *pw, char *newpasswd) +{ + char *cp; /* Pointer to getpass() response */ + char pass[200]; /* New password */ +#ifdef HAVE_LIBCRACK_HIST + int HistUpdate P_((const char *, const char *)); +#endif + + sprintf(pass, "%s", newpasswd); + + /* + * Encrypt the password, then wipe the cleartext password. + */ + cp = pw_encrypt(pass, crypt_make_salt()); + bzero(pass, sizeof pass); + +#ifdef HAVE_LIBCRACK_HIST + HistUpdate(pw->pw_name, crypt_passwd); +#endif + STRFCPY(crypt_passwd, cp); + return 0; +} + + + +static void update_noshadow(int shadow_locked) +{ + const struct passwd *pw; + struct passwd *npw; + + /* + * call this with shadow_locked != 0 to avoid calling lckpwdf() + * twice (which will fail). XXX - pw_lock(), pw_unlock(), + * spw_lock(), spw_unlock() really should track the lock count + * and call lckpwdf() only before the first lock, and ulckpwdf() + * after the last unlock. + */ + if (!(shadow_locked ? pw_lock() : pw_lock_first())) { + fprintf(stderr, "Cannot lock the password file; try again later.\n"); + syslog(LOG_WARNING, "can't lock password file"); + exit(5); + } + if (!pw_open(O_RDWR)) { + fprintf(stderr, "Cannot open the password file.\n"); + syslog(LOG_ERR, "can't open password file"); + fail_exit(3); + } + pw = pw_locate(name); + if (!pw) { + fprintf(stderr, "mbpasswd: user %s not found in /etc/passwd\n", name); + fail_exit(1); + } + npw = __pw_dup(pw); + if (!npw) + oom(); + npw->pw_passwd = update_crypt_pw(npw->pw_passwd); + if (!pw_update(npw)) { + fprintf(stderr, "Error updating the password entry.\n"); + syslog(LOG_ERR, "error updating password entry"); + fail_exit(3); + } + if (!pw_close()) { + fprintf(stderr, "Cannot commit password file changes.\n"); + syslog(LOG_ERR, "can't rewrite password file"); + fail_exit(3); + } + pw_unlock(); +} + + + +#ifdef SHADOW_PASSWORD +static void update_shadow(void) +{ + const struct spwd *sp; + struct spwd *nsp; + + if (!spw_lock_first()) { + fprintf(stderr, "Cannot lock the password file; try again later.\n"); + syslog(LOG_WARNING, "can't lock password file"); + exit(5); + } + if (!spw_open(O_RDWR)) { + fprintf(stderr, "Cannot open the password file.\n"); + syslog(LOG_ERR, "can't open password file"); + fail_exit(3); + } + sp = spw_locate(name); + if (!sp) { +#if 0 + fprintf(stderr, "%s: user %s not found in /etc/shadow\n", + Prog, name); + fail_exit(1); +#else + /* Try to update the password in /etc/passwd instead. */ + spw_unlock(); + update_noshadow(1); + return; +#endif + } + nsp = __spw_dup(sp); + if (!nsp) + oom(); + nsp->sp_pwdp = update_crypt_pw(nsp->sp_pwdp); + if (do_update_age) + nsp->sp_lstchg = time((time_t *) 0) / SCALE; + + if (!spw_update(nsp)) { + fprintf(stderr, "Error updating the password entry.\n"); + syslog(LOG_ERR, "error updating password entry"); + fail_exit(3); + } + if (!spw_close()) { + fprintf(stderr, "Cannot commit password file changes.\n"); + syslog(LOG_ERR, "can't rewrite password file"); + fail_exit(3); + } + spw_unlock(); +} +#endif /* SHADOWPWD */ + + + +/* + * Function will set a new password in the users password file. + * Note that this function must run setuid root! + */ +int main(int argc, char *argv[]) +{ + const struct passwd *pw; + const struct group *gr; +#ifdef SHADOW_PASSWORD + const struct spwd *sp; +#endif + char *cp; + + /* + * Get my username + */ + pw = get_my_pwent(); + if (!pw) { + fprintf(stderr, "mbpasswd: Cannot determine your user name.\n"); + exit(1); + } + myname = xstrdup(pw->pw_name); + + /* + * Get my groupname, this must be "bbs", other users may not + * use this program, not even root. + */ + gr = getgrgid(pw->pw_gid); + if (!gr) { + fprintf(stderr, "mbpasswd: Cannot determine group name.\n"); + exit(1); + } + if (strcmp(gr->gr_name, (char *)"bbs")) { + fprintf(stderr, "mbpasswd: You are not a member of group \"bbs\".\n"); + exit(1); + } + +// NOOT dit programma moet kontroleren of het is aangeroepen door mbsebbs. +// ook kontroleren of de originele uid en gid correct zijn. +// Gewone stervelingen mogen dit niet kunnen starten. +// Dit programma is een groot security gat. + + if (argc != 4) { + printf("\nmbpasswd commandline:\n\n"); + printf("mbpasswd [-opt] [username] [newpassword]\n"); + printf("options are: -n normal password change\n"); + printf(" -f forced password change\n"); + exit(1); + } + + if (strncmp(argv[1], "-f", 2) == 0) + force = 1; + else + force = 0; + + /* + * Check stringlengths + */ + if (strlen(argv[2]) > 16) { + fprintf(stderr, "mbpasswd: Username too long\n"); + exit(1); + } + if (strlen(argv[3]) > 16) { + fprintf(stderr, "mbpasswd: Password too long\n"); + exit(1); + } + + name = strdup(argv[2]); + if ((pw = getpwnam(name)) == NULL) { + fprintf(stderr, "mbpasswd: Unknown user %s\n", name); + exit(1); + } + + openlog("mbpasswd", LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH); + +#ifdef SHADOW_PASSWORD + sp = getspnam(name); + if (!sp) + sp = pwd_to_spwd(pw); + + cp = sp->sp_pwdp; +#else + cp = pw->pw_passwd; +#endif + + /* + * See if the user is permitted to change the password. + * Otherwise, go ahead and set a new password. + */ +#ifdef SHADOW_PASSWORD + check_password(pw, sp); +#else + check_password(pw); +#endif + + if (new_password(pw, argv[3])) { + fprintf(stderr, "The password for %s is unchanged.\n", name); + closelog(); + exit(1); + } + do_update_pwd = 1; + do_update_age = 1; + + /* + * Before going any further, raise the ulimit to prevent + * colliding into a lowered ulimit, and set the real UID + * to root to protect against unexpected signals. Any + * keyboard signals are set to be ignored. + */ + pwd_init(); + + if (setuid(0)) { + fprintf(stderr, "Cannot change ID to root.\n"); + syslog(LOG_ERR, "can't setuid(0)"); + closelog(); + exit(1); + } + +#ifdef SHADOW_PASSWORD + if (spw_file_present()) + update_shadow(); + else +#endif + update_noshadow(0); + + syslog(LOG_INFO, "password for `%s' changed by user `%s'", name, myname); + closelog(); + exit(0); +} + + diff --git a/mbsebbs/mbpasswd.h b/mbsebbs/mbpasswd.h new file mode 100644 index 00000000..e76aebeb --- /dev/null +++ b/mbsebbs/mbpasswd.h @@ -0,0 +1,30 @@ +#ifndef _MBUSERADD_H +#define _MBUSERADD_H + + + /* danger - side effects */ +#define STRFCPY(A,B) \ + (strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0') + + +/* + * Function prototypes + */ +struct passwd *get_my_pwent(void); +static int new_password (const struct passwd *, char *); +static void fail_exit(int); +static void oom(void); +void pwd_init(void); +char *crypt_make_salt(void); +char *pw_encrypt(const char *, const char *); +int i64c(int); +char *l64a(long); +static void update_noshadow(int); + +#ifdef SHADOW_PASSWORD +struct spwd *pwd_to_spwd(const struct passwd *); +static void update_shadow(void); +#endif + +#endif + diff --git a/mbsebbs/mbsebbs.c b/mbsebbs/mbsebbs.c new file mode 100644 index 00000000..b56a2c39 --- /dev/null +++ b/mbsebbs/mbsebbs.c @@ -0,0 +1,241 @@ +/***************************************************************************** + * + * File ..................: bbs/mbsebbs.c + * Purpose ...............: Main startup + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "mbsebbs.h" +#include "user.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "menu.h" +#include "misc.h" +#include "bye.h" +#include "timeout.h" + +extern int do_quiet; /* Logging quiet flag */ +extern char *Passwd; +time_t t_start; + + + +int main(int argc, char **argv) +{ + FILE *pTty; + char *p, *tty; + int i; + char temp[PATH_MAX]; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + printf("Loading MBSE BBS ...\n"); + pTTY = calloc(15, sizeof(char)); + tty = ttyname(1); + + /* + * Set the users device to writable by other bbs users, so they + * can send one-line messages + */ + chmod(tty, 00666); + + /* + * Get MBSE_ROOT Path and load Config into Memory + */ + FindMBSE(); + if (!strlen(CFG.startname)) { + printf("FATAL: No bbs startname, edit mbsetup 1.1.10\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Set uid and gid to the "mbse" user. + */ + if ((pw = getpwnam((char *)"mbse")) == NULL) { + perror("Can't find user \"mbse\" in /etc/passwd"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + if ((setuid(pw->pw_uid) == -1) || (setgid(pw->pw_gid) == -1)) { + perror("Can't setuid() or setgid() to \"mbse\" user"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * Set local time and statistic indexes. + */ + time(&Time_Now); + time(&t_start); + l_date = localtime(&Time_Now); + Diw = l_date->tm_wday; + Miy = l_date->tm_mon; + time(<ime); + + /* + * Initialize this client with the server. We don't know + * who is at the other end of the line, so that's what we tell. + */ + do_quiet = TRUE; + InitClient((char *)"Unknown", (char *)"mbsebbs", (char *)"Unknown", CFG.logfile, CFG.bbs_loglevel, CFG.error_log); + IsDoing("Loging in"); + + Syslog(' ', " "); + Syslog(' ', "MBSEBBS v%s", VERSION); + + if ((p = getenv("CONNECT")) != NULL) + Syslog('+', "CONNECT %s", p); + if ((p = getenv("CALLER_ID")) != NULL) + if (!strncmp(p, "none", 4)) + Syslog('+', "CALLER %s", p); + + sUnixName[0] = '\0'; + + if (argc == 3) { + iUnixMode = TRUE; + strcpy(sUnixName, argv[2]); + } else if ((getenv("LOGNAME") != NULL) && (strcmp(getenv("LOGNAME"), CFG.startname))) { + iUnixMode = TRUE; + strcpy(sUnixName, getenv("LOGNAME")); + } + + /* + * Initialize + */ + InitLanguage(); + InitMenu(); + memset(&MsgBase, 0, sizeof(MsgBase)); + + i = getpid(); + + tty = ttyname(0); + if (strncmp("/dev/", tty, 5) == 0) + sprintf(pTTY, "%s", tty+5); + else if (*tty == '/') { + tty = strrchr(ttyname(0), '/'); + ++tty; + sprintf(pTTY, "%s", tty); + } + + umask(007); + + /* + * Trap signals + */ + for(i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGBUS) || (i == SIGILL) || + (i == SIGSEGV) || (i == SIGTERM) || (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + /* + * Default set the terminal to ANSI mode. If your logo + * is in color, the user will see color no mather what. + */ + TermInit(1); + + sprintf(temp, "chat.%s", pTTY); + if(access(temp, F_OK) == 0) + unlink(temp); + + /* + * Now it's time to check if the bbs is open. If not, we + * log the user off. + */ + if (CheckStatus() == FALSE) { + Syslog('+', "Kicking user out, the BBS is closed"); + Quick_Bye(0); + } + + clear(); + DisplayLogo(); + + colour(14, 0); + printf("MBSE BBS v%s (Release: %s)\n", VERSION, ReleaseDate); + colour(15, 0); + printf("%s\n\n", Copyright); + + /* + * Check if this port is available. + */ + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + + if ((pTty = fopen(temp, "r")) == NULL) { + WriteError("Can't read %s", temp); + } else { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, pTty); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, pTty) == 1) { + if (strcmp(ttyinfo.tty, pTTY) == 0) + break; + } + fclose(pTty); + + if ((strcmp(ttyinfo.tty, pTTY) != 0) || (!ttyinfo.available)) { + Syslog('+', "No BBS allowed on port \"%s\"", pTTY); + printf("No BBS on this port allowed!\n\n"); + Quick_Bye(0); + } + + /* + * Ask whether to display Connect String + */ + if(CFG.iConnectString) { + /* Connected on port */ + colour(3, 0); + printf("%s\"%s\" ", (char *) Language(348), ttyinfo.comment); + /* on */ + printf("%s %s\n", (char *) Language(135), ctime(<ime)); + } + } + + sprintf(sMailbox, "mailbox"); + colour(7, 0); + Passwd = calloc(16, sizeof(char)); + user(); + return 0; +} + diff --git a/mbsebbs/mbsebbs.h b/mbsebbs/mbsebbs.h new file mode 100644 index 00000000..db7bcade --- /dev/null +++ b/mbsebbs/mbsebbs.h @@ -0,0 +1,10 @@ +/* mbsebbs.h */ + +#ifndef _MBSEBBS_H +#define _MBSEBBS_H + +#define ReleaseDate __DATE__ + + +#endif + diff --git a/mbsebbs/mbstat.c b/mbsebbs/mbstat.c new file mode 100644 index 00000000..acb9bbd1 --- /dev/null +++ b/mbsebbs/mbstat.c @@ -0,0 +1,284 @@ +/***************************************************************************** + * + * File ..................: mbstat/mbstat.c + * Purpose ...............: Change BBS status + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbstat.h" + + +extern int do_quiet; +time_t t_start, t_end; + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbstat [command] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" c close Close the BBS for users\n"); + printf(" o open Open the BBS for users\n"); + printf(" s set semafore Set named semafore\n"); + printf(" w wait Wait until the BBS is free\n\n"); + colour(9,0); + printf(" Options are:\n\n"); + colour(3, 0); + printf(" -q -quiet Quiet, no screen output\n"); + colour(7, 0); + die(0); +} + + + +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBSTAT: MBSE BBS %s Status Changer\n", VERSION); + colour(14, 0); + printf(" %s\n", Copyright); + colour(3, 0); +} + + + +void die(int onsig) +{ + signal(onsig, SIG_IGN); + + if (onsig) + WriteError("$Terminated on signal %d", onsig); + + if (!do_quiet) { + colour(7, 0); + printf("\n"); + } + + time(&t_end); + Syslog(' ', "MBSTAT finished in %s", t_elapsed(t_start, t_end)); + + ExitClient(onsig); +} + + + +int main(int argc, char **argv) +{ + int i; + char *cmd, *semafore = NULL; + int do_open = FALSE; + int do_close = FALSE; + int do_wait = FALSE; + int do_sema = FALSE; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + time(&t_start); + + /* + * Catch or ignore signals + */ + for (i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || + (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM) || + (i == SIGKILL)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + cmd = xstrcpy((char *)"Command line: mbstat"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (!strncmp(tl(argv[i]), "w", 1)) + do_wait = TRUE; + if (!strncmp(tl(argv[i]), "o", 1)) + do_open = TRUE; + if (!strncmp(tl(argv[i]), "c", 1)) + do_close = TRUE; + if (!strncmp(tl(argv[i]), "s", 1)) { + do_sema = TRUE; + i++; + semafore = xstrcpy(tl(argv[i])); + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + } + if (!strncmp(tl(argv[i]), "-q", 2)) + do_quiet = TRUE; + } + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbstat", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + usleep(1); + + Syslog(' ', " "); + Syslog(' ', "MBSTAT v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!do_quiet) { + colour(3, 0); + printf("\n"); + } + + if (do_close) + do_open = FALSE; + + if (do_open) { + Open(); + do_close = FALSE; + do_wait = FALSE; + } + + if (do_close) + Close(); + + if (do_wait) + Wait(); + + if (do_sema) + Semafore(semafore); + + if (!(do_open || do_close || do_wait || do_sema)) + Help(); + + usleep(1); + die(0); + return 0; +} + + + +int Semafore(char *semafore) +{ + char buf[81]; + + strcpy(buf, SockR("SECR:1,%s;", semafore)); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "Semafore \"%s\" is set", semafore); + if (!do_quiet) + printf("Semafore \"%s\" is set\n", semafore); + return TRUE; + } else { + Syslog('+', "Failed to set \"%s\" semafore", semafore); + printf("Failed to set \"%s\" semafore\n", semafore); + return FALSE; + } +} + + + +int Close(void) +{ + char buf[81]; + + strcpy(buf, SockR("SCLO:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is closed"); + if (!do_quiet) + printf("The BBS is closed\n"); + return TRUE; + } else { + printf("Failed to close the BBS\n"); + return FALSE; + } +} + + + +int Open(void) +{ + char buf[81]; + + strcpy(buf, SockR("SOPE:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is open"); + if (!do_quiet) + printf("The BBS is open\n"); + return TRUE; + } else { + printf("Failed to open the BBS\n"); + return FALSE; + } +} + + + +int Wait(void) +{ + int Waiting = 3600; + char buf[PATH_MAX]; + + sprintf(buf, "%s/sema/upsdown", getenv("MBSE_ROOT")); + if (file_exist(buf, R_OK)) + Waiting = 30; + + Syslog('+', "Waiting for the BBS to become free, timout %d seconds", Waiting); + while (Waiting) { + strcpy(buf, SockR("SFRE:0;")); + if (strncmp(buf, "100:0;", 6) == 0) { + Syslog('+', "The BBS is free"); + if (!do_quiet) + printf("The BBS is free. \n"); + return TRUE; + } + if (!do_quiet) { + buf[strlen(buf) -1] = '\0'; + printf("\r%s\r", buf+6); + fflush(stdout); + } + sleep(1); + Waiting--; + } + + WriteError("Wait for BBS free timeout, aborting"); + return FALSE; +} + + diff --git a/mbsebbs/mbstat.h b/mbsebbs/mbstat.h new file mode 100644 index 00000000..195c189c --- /dev/null +++ b/mbsebbs/mbstat.h @@ -0,0 +1,14 @@ +#ifndef _MBSTAT_H +#define _MBSTAT_H + + +void Help(void); +void ProgName(void); +void die(int); +int Semafore(char *); +int Open(void); +int Close(void); +int Wait(void); + +#endif + diff --git a/mbsebbs/mbtoberep.c b/mbsebbs/mbtoberep.c new file mode 100644 index 00000000..c7f6a279 --- /dev/null +++ b/mbsebbs/mbtoberep.c @@ -0,0 +1,102 @@ +/***************************************************************************** + * + * File ..................: mbtoberep/mbtoberep.c + * Purpose ...............: Show contents of toberep.data + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" + + +int main(int argc, char **argv) +{ + char *BBSpath; + char *temp; + FILE *fp; + struct _filerecord rep; + int i; + +#ifdef MEMWATCH + mwInit(); +#endif + if ((BBSpath = getenv("MBSE_ROOT")) == NULL) { + printf("MBSE_ROOT variable not set\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(temp, "%s/etc/toberep.data", BBSpath); + + if ((fp = fopen(temp, "r")) == NULL) { + printf("File %s not found\n", temp); + free(temp); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + while (fread(&rep, sizeof(rep), 1, fp) == 1) { + printf("File echo %s\n", rep.Echo); + printf("Comment %s\n", rep.Comment); + printf("Group %s\n", rep.Group); + printf("File name %s\n", rep.Name); + printf("FIle size %lu\n", rep.Size); + printf("File size Kb %lu\n", rep.SizeKb); + printf("File date %s", ctime(&rep.Fdate)); + printf("File CRC %s\n", rep.Crc); + printf("Origin system %s\n", rep.Origin); + printf("From system %s\n", rep.From); + printf("Replace %s\n", rep.Replace); + printf("Magic %s\n", rep.Magic); + printf("Cost %ld\n", rep.Cost); + printf("Announce "); + if (rep.Announce) + printf("yes\n"); + else + printf("no\n"); + printf("Description %s\n", rep.Desc); + for (i = 0; i < rep.TotLdesc; i++) { + printf(" %2d %s\n", (int)strlen(rep.LDesc[i]), rep.LDesc[i]); + } + printf("\n\n"); + } + + fclose(fp); + free(temp); +#ifdef MEMWATCH + mwTerm(); +#endif + return 0; +} + + + diff --git a/mbsebbs/mbuser.c b/mbsebbs/mbuser.c new file mode 100644 index 00000000..46db78b1 --- /dev/null +++ b/mbsebbs/mbuser.c @@ -0,0 +1,361 @@ +/***************************************************************************** + * + * File ..................: mbuser/mbuser.c + * Purpose ...............: User Pack Util + * Last modification date : 01-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/dbcfg.h" +#include "mbuser.h" + + +extern int e_pid; /* External pid */ +extern int do_quiet; /* Quiet flag */ +time_t t_start; /* Start time */ +time_t t_end; /* End time */ +int Days, Level; /* Kill days and up to level */ +struct userhdr usrhdr; /* Database header */ +struct userrec usr; /* Database record */ +mode_t oldmask; /* Old umask value */ + + +int main(int argc, char **argv) +{ + int i, pack = FALSE; + char *cmd; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + InitConfig(); + TermInit(1); + Days = 0; + Level = 0; + + time(&t_start); + + if (argc < 2) + Help(); + + cmd = xstrcpy((char *)"Command line:"); + + for (i = 1; i < argc; i++) { + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, tl(argv[i])); + + if (strncasecmp(tl(argv[i]), "-q", 2) == 0) + do_quiet = TRUE; + if (strncasecmp(tl(argv[i]), "p", 1) == 0) + pack = TRUE; + if (strncasecmp(tl(argv[i]), "k", 1) == 0) { + if (argc <= (i + 2)) + Help(); + i++; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + Days = atoi(argv[i]); + i++; + cmd = xstrcat(cmd, (char *)" "); + cmd = xstrcat(cmd, argv[i]); + Level = atoi(argv[i]); + + if ((Days == 0) || (Level == 0)) + Help(); + } + } + + if ((Days + Level + pack) == 0) + Help(); + + ProgName(); + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbuser", CFG.location, CFG.logfile, CFG.util_loglevel, CFG.error_log); + Syslog(' ', " "); + Syslog(' ', "MBUSER v%s", VERSION); + Syslog(' ', cmd); + free(cmd); + + if (!diskfree(CFG.freespace)) + ExitClient(101); + + oldmask = umask(027); + if (!do_quiet) + colour(3, 0); + UserPack(Days, Level, pack); + umask(oldmask); + + time(&t_end); + Syslog(' ', "MBUSER finished in %s", t_elapsed(t_start, t_end)); + + if (!do_quiet) + colour(7, 0); + ExitClient(0); + return 0; +} + + + +/* + * Program header + */ +void ProgName(void) +{ + if (do_quiet) + return; + + colour(15, 0); + printf("\nMBUSER: MBSE BBS %s - User maintenance utility\n", VERSION); + colour(14, 0); + printf(" %s\n\n", Copyright); + colour(7, 0); +} + + + +void Help(void) +{ + do_quiet = FALSE; + ProgName(); + + colour(11, 0); + printf("\nUsage: mbuser [commands] \n\n"); + colour(9, 0); + printf(" Commands are:\n\n"); + colour(3, 0); + printf(" kill [n] [l] Kill users not called in \"n\" days below level \"l\"\n"); + printf(" pack Pack the userbase\n"); + colour(9, 0); + printf("\n Options are:\n\n"); + colour(3, 0); + printf(" -quiet Quiet mode, (no screen output)\n\n"); + + colour(7, 0); + printf("\n"); + ExitClient(1); +} + + + +/* + * Userpack routine + */ +void UserPack(int days, int level, int pack) +{ + FILE *fin, *fout; + char *fnin, *fnout; + long oldsize, curpos; + int updated, delete = 0, rc, highest = 0, record = 0, sysop = FALSE; + + fnin = calloc(PATH_MAX, sizeof(char)); + fnout = calloc(PATH_MAX, sizeof(char)); + sprintf(fnin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/users.temp", getenv("MBSE_ROOT")); + + /* + * First copy the users database, all packing will be done + * on a the copy. + */ + if ((fin = fopen(fnin, "r")) == NULL) { + WriteError("Can't open %s", fnin); + free(fnin); + free(fnout); + return; + } + if ((fout = fopen(fnout, "w+")) == NULL) { + WriteError("Can't create %s", fnout); + fclose(fin); + free(fnin); + free(fnout); + return; + } + fread(&usrhdr, sizeof(usrhdr), 1, fin); + oldsize = usrhdr.recsize; + updated = FALSE; + + /* + * First count records and blanks at the end. Check if the sysop name + * in the main configuration exists in the userdatabase. + */ + while (fread(&usr, oldsize, 1,fin) == 1) { + delete++; + if (!usr.Deleted && strlen(usr.sUserName)) { + highest = (ftell(fin) / oldsize); + if (!strcmp(usr.sUserName, CFG.sysop_name) && !strcmp(usr.Name, CFG.sysop)) + sysop = TRUE; + } + } + if (highest != delete) { + Syslog('+', "Blank records at the end, truncating userbase"); + updated = TRUE; + } + if (!sysop) + WriteError("No valid Sysop Fidoname and/or Unixname found in userbase, check setup!"); + + fseek(fin, usrhdr.hdrsize, SEEK_SET); + + if (oldsize != sizeof(usr)) { + updated = TRUE; + Syslog('+', "Userbase recordsize is changed, making update"); + } + + usrhdr.hdrsize = sizeof(usrhdr); + usrhdr.recsize = sizeof(usr); + fwrite(&usrhdr, sizeof(usrhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each read + * so that if the record format changed, the new fields will + * be empty by default. The blank records at the end of the + * database are dropped. + */ + memset(&usr, 0, sizeof(usr)); + while (fread(&usr, oldsize, 1,fin) == 1) { + record++; + fwrite(&usr, sizeof(usr), 1, fout); + memset(&usr, 0, sizeof(usr)); + if (CFG.slow_util && do_quiet) + usleep(1); + } + fclose(fin); + delete = 0; + + /* + * Handle packing for days below level + */ + if ((days) && (level)) { + fseek(fout, sizeof(usrhdr), SEEK_SET); + curpos = sizeof(usrhdr); + + while (fread(&usr, sizeof(usr), 1, fout) == 1) { + /* + * Wow, killing on the second exact!. Don't kill + * the guest accounts. + */ + if ((((t_start - usr.tLastLoginDate) / 86400) > days) && + (usr.Security.level < level) && (!usr.Guest) && + (usr.sUserName[0] != '\0') && (!usr.NeverDelete)) { + Syslog('+', "Mark user %s", usr.sUserName); + if (!do_quiet) { + printf("Mark user %s\n", usr.sUserName); + fflush(stdout); + } + delete++; + updated = TRUE; + fseek(fout, - sizeof(usr), SEEK_CUR); + /* + * Just mark for deletion + */ + usr.Deleted = TRUE; + fwrite(&usr, sizeof(usr), 1, fout); + } + if (CFG.slow_util && do_quiet) + usleep(1); + } + Syslog('+', "Marked %d users to delete", delete); + } + + /* + * Pack the userbase if told so + */ + if (pack) { + Syslog('+', "Packing userbase"); + delete = 0; + fseek(fout, sizeof(usrhdr), SEEK_SET); + while (fread(&usr, sizeof(usr), 1, fout) == 1) { + if (CFG.slow_util && do_quiet) + usleep(1); + + if (usr.Deleted) { + if (!do_quiet) { + printf("Delete user %s\n", usr.Name); + fflush(stdout); + } + if (usr.Name[0] != '\0') { + if ((setuid(0) == -1) || (setgid(0) == -1)) { + WriteError("Cannot setuid(root) or setgid(root)"); + WriteError("Cannot delete unix account %s", usr.Name); + } else { + rc = execute((char *)"/usr/sbin/userdel ", usr.Name, NULL, + (char *)"/dev/null",(char *)"/dev/null",(char *)"/dev/null"); + if (chdir(CFG.bbs_usersdir) == 0) + rc = execute((char *)"/bin/rm -Rf ", usr.Name, NULL, + (char *)"/dev/null",(char *)"/dev/null",(char *)"/dev/null"); + } + } + + fseek(fout, - sizeof(usr), SEEK_CUR); + /* + * Blank the deleted records for reuse. + */ + memset(&usr, 0, sizeof(usr)); + fwrite(&usr, sizeof(usr), 1, fout); + delete++; + updated = TRUE; + } + } + Syslog('+', "Deleted %d records", delete); + } + + if (updated) { + /* + * Copy file back to the original file, truncate any + * deleted records at the end. + */ + fseek(fout, 0, SEEK_SET); + if ((fin = fopen(fnin, "w")) == NULL) { + WriteError("Can't open %s", fnin); + free(fnin); + free(fnout); + return; + } + fread(&usrhdr, sizeof(usrhdr), 1, fout); + fwrite(&usrhdr, sizeof(usrhdr), 1, fin); + record = 0; + + while (fread(&usr, sizeof(usr), 1,fout) == 1) { + record++; + fwrite(&usr, sizeof(usr), 1, fin); + if (record >= highest) + break; + } + fclose(fin); + fclose(fout); + Syslog('+', "Userbase is updated, written %d records", record); + } + unlink(fnout); + free(fnin); + free(fnout); +} + + + diff --git a/mbsebbs/mbuser.h b/mbsebbs/mbuser.h new file mode 100644 index 00000000..6f69e12e --- /dev/null +++ b/mbsebbs/mbuser.h @@ -0,0 +1,9 @@ +#ifndef _MBUSER_H +#define _MBUSER_H + +void ProgName(void); +void Help(void); +void UserPack(int, int, int); + +#endif + diff --git a/mbsebbs/mbuseradd.c b/mbsebbs/mbuseradd.c new file mode 100644 index 00000000..74d36c83 --- /dev/null +++ b/mbsebbs/mbuseradd.c @@ -0,0 +1,265 @@ +/***************************************************************************** + * + * File ..................: mbuseradd.c + * Purpose ...............: setuid root version of useradd + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mbuseradd.h" + + + + +int execute(char *cmd, char *file, char *in, char *out, char *err) +{ + char buf[PATH_MAX]; + char *vector[16]; + int i; + int pid, status, rc, sverr; + + sprintf(buf, "%s %s", cmd, file); + + i=0; + vector[i++] = strtok(buf, " \t\n"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i < 16)); + vector[15] = NULL; + fflush(stdout); + fflush(stderr); + + if ((pid = fork()) == 0) { + if (in) { + close(0); + if (open(in, O_RDONLY) != 0) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stdin to %s failed\n", in); + exit(-1); + } + } + if (out) { + close(1); + if (open(out, O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stdout to %s failed\n", out); + exit(-1); + } + } + if (err) { + close(2); + if (open(err, O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + perror(""); + fprintf(stderr, "mbuseradd: Reopen of stderr to %s failed\n", err); + exit(-1); + } + } + rc = execv(vector[0],vector); + fprintf(stderr, "mbuseradd: Exec \"%s\" returned %d\n", vector[0], rc); + exit(-1); + } + + do { + rc = wait(&status); + sverr = errno; + } while (((rc > 0) && (rc != pid)) || ((rc == -1) && (sverr == EINTR))); + + if (rc == -1) { + fprintf(stderr, "mbuseradd: Wait returned %d, status %d,%d\n", rc, status >> 8, status & 0xff); + return -1; + } + + return status; +} + + + +void makedir(char *path, mode_t mode, uid_t owner, gid_t group) +{ + if (mkdir(path, mode) != 0) { + perror(""); + fprintf(stderr, "mbuseradd: Can't create %s\n", path); + exit(2); + } + if ((chown(path, owner, group)) == -1) { + perror(""); + fprintf(stderr, "mbuseradd: Unable to change ownership of %s\n", path); + exit(2); + } +} + + + +/* + * Function will create the users name in the passwd file + * Note that this function must run setuid root! + */ +int main(int argc, char *argv[]) +{ + char *PassEnt, *temp, *shell; + int i; + struct passwd *pwent, *pwuser; + FILE *fp; + + if (setuid(0) == -1 || setgid(1) == -1) { + perror(""); + fprintf(stderr, "mbuseradd: Unable to setuid(root) or setgid(root)\n"); + fprintf(stderr, "Make sure that this program is set to -rwsr-sr-x\n"); + fprintf(stderr, "Owner must be root and group root\n"); + exit(1); + } + + if (argc != 5) + Help(); + + for (i = 1; i < 5; i++) { + if (strlen(argv[i]) > 80) { + fprintf(stderr, "mbuseradd: Argument %d is too long\n", i); + exit(1); + } + } + + PassEnt = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + shell = calloc(PATH_MAX, sizeof(char)); + + /* + * Build command to add user entry to the /etc/passwd and /etc/shadow + * files. We use the systems own useradd program. + */ + if ((access("/usr/bin/useradd", R_OK)) == 0) + strcpy(temp, "/usr/bin/useradd"); + else if ((access("/bin/useradd", R_OK)) == 0) + strcpy(temp, "/bin/useradd"); + else if ((access("/usr/sbin/useradd", R_OK)) == 0) + strcpy(temp, "/usr/sbin/useradd"); + else if ((access("/sbin/useradd", R_OK)) == 0) + strcpy(temp, "/sbin/useradd"); + else { + fprintf(stderr, "mbuseradd: Can't find useradd\n"); + exit(1); + } + + sprintf(shell, "%s/bin/mbsebbs", getenv("MBSE_ROOT")); + + sprintf(PassEnt, "%s -c \"%s\" -d %s/%s -g %s -s %s %s", + temp, argv[3], argv[4], argv[2], argv[1], shell, argv[2]); + fflush(stdout); + fflush(stdin); + + if (system(PassEnt) != 0) { + perror("mbuseradd: Failed to create unix account\n"); + exit(1); + } + + /* + * Now create directories and files for this user. + */ + if ((pwent = getpwnam((char *)"mbse")) == NULL) { + perror("mbuseradd: Can't get password entry for \"mbse\"\n"); + exit(2); + } + + /* + * Check bbs users base home directory + */ + if ((access(argv[4], R_OK)) != 0) + makedir(argv[4], 0770, pwent->pw_uid, pwent->pw_gid); + + /* + * Now create users home directory. Check for an existing directory, + * some systems have already created a home directory. If one is found + * it is removed to create a fresh one. + */ + sprintf(temp, "%s/%s", argv[4], argv[2]); + if ((access(temp, R_OK)) == 0) { + if ((access("/bin/rm", X_OK)) == 0) + strcpy(shell, "/bin/rm"); + else if ((access("/usr/bin/rm", X_OK)) == 0) + strcpy(shell, "/usr/bin/rm"); + else { + fprintf(stderr, "mbuseradd: Can't find rm\n"); + exit(2); + } + sprintf(PassEnt, " -Rf %s", temp); + fflush(stdout); + fflush(stdin); + i = execute(shell, PassEnt, (char *)"/dev/tty", (char *)"/dev/tty", (char *)"/dev/tty"); + + if (i != 0) { + fprintf(stderr, "mbuseradd: Unable remove old home directory\n"); + exit(2); + } + } + + /* + * Create users home directory. + */ + pwuser = getpwnam(argv[2]); + makedir(temp, 0770, pwuser->pw_uid, pwent->pw_gid); + + /* + * Create Maildir and subdirs for Qmail. + */ + sprintf(temp, "%s/%s/Maildir", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/cur", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/new", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + sprintf(temp, "%s/%s/Maildir/tmp", argv[4], argv[2]); + makedir(temp, 0700, pwuser->pw_uid, pwent->pw_gid); + + free(shell); + free(PassEnt); + free(temp); + + exit(0); +} + + + +void Help() +{ + fprintf(stderr, "\nmbuseradd commandline:\n\n"); + fprintf(stderr, "mbuseradd [gid] [name] [comment] [usersdir]\n"); + exit(1); +} + + diff --git a/mbsebbs/mbuseradd.h b/mbsebbs/mbuseradd.h new file mode 100644 index 00000000..963f8fa6 --- /dev/null +++ b/mbsebbs/mbuseradd.h @@ -0,0 +1,10 @@ +#ifndef _MBUSERADD_H +#define _MBUSERADD_H + + +int execute(char *, char *, char *, char *, char *); +void makedir(char *, mode_t, uid_t, gid_t); +void Help(void); + +#endif + diff --git a/mbsebbs/menu.c b/mbsebbs/menu.c new file mode 100644 index 00000000..afa4f7f2 --- /dev/null +++ b/mbsebbs/menu.c @@ -0,0 +1,672 @@ +/***************************************************************************** + * + * File ..................: bbs/menu.c + * Purpose ...............: Display and handle the menus. + * Last modification date : 10-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "oneline.h" +#include "mail.h" +#include "bbslist.h" +#include "change.h" +#include "bank.h" +#include "chat.h" +#include "file.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "nextuser.h" +#include "safe.h" +#include "timeout.h" +#include "menu.h" +#include "page.h" +#include "pinfo.h" +#include "bye.h" +#include "timecheck.h" +#include "exitinfo.h" +#include "language.h" +#include "offline.h" +#include "email.h" + + +/* + * Menu stack, 50 levels deep. + */ +char Menus[50][15]; +int MenuLevel; +int MenuError; + + +void InitMenu() +{ + int i; + + for (i = 0; i < 50; i++) + memset(Menus[i], 0, 51); + MenuLevel = 0; + MenuError = 0; + sprintf(Menus[0], "%s", CFG.default_menu); +} + + + +void menu() +{ + FILE *pMenuFile; + int iFoundKey = FALSE, Key; + char *Input, *Semfile; + char *sMenuPathFileName; + + Input = calloc(81, sizeof(char)); + sMenuPathFileName = calloc(PATH_MAX, sizeof(char)); + + /* + * Loop forever, this is what a BBS should do until a user logs out. + */ + while (TRUE) { + + WhosDoingWhat(BROWSING); + + /* + * Open menufile, first users language menu, if it fails + * try to open the default menu. + */ + sprintf(sMenuPathFileName,"%s/%s", lang.MenuPath, Menus[MenuLevel]); + if ((pMenuFile = fopen(sMenuPathFileName, "r")) == NULL) { + sprintf(sMenuPathFileName,"%s/%s", CFG.bbs_menus, Menus[MenuLevel]); + pMenuFile = fopen(sMenuPathFileName,"r"); + if (pMenuFile != NULL) + Syslog('+', "Menu %s (Default)", Menus[MenuLevel]); + } else { + Syslog('+', "Menu %s (%s)", Menus[MenuLevel], lang.Name); + } + + if (pMenuFile == NULL) { + clear(); + WriteError("Can't open menu file: %s", sMenuPathFileName); + MenuError++; + + /* + * Is this the last attempt to open the default menu? + */ + if (MenuError == 10) { + WriteError("FATAL ERROR: Too many menu errors"); + printf("Too many menu errors, notifying Sysop\n\n"); + sleep(3); + die(SIGILL); + } + + /* + * Switch back to the default menu + */ + MenuLevel = 0; + strcpy(Menus[0], CFG.default_menu); + } else { + /* + * Do all autoexec menus first + */ + while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { + if (menus.AutoExec && Access(exitinfo.Security, menus.MenuSecurity) && (UserAge >= menus.Age)) + DoMenu(menus.MenuType); + } + + /* + * Check if the BBS closed down for Zone Mail Hour or + * system shutdown. If so, we run the Goodbye show. + */ + if (CheckStatus() == FALSE) { + fclose(pMenuFile); + Syslog('+', "Kicking user out, the BBS is closed."); + sleep(3); + Good_Bye(0); + } + + /* + * Check the upsdown semafore + */ + Semfile = calloc(PATH_MAX, sizeof(char)); + sprintf(Semfile, "%s/sema/upsdown", getenv("MBSE_ROOT")); + if (file_exist(Semfile, R_OK) == 0) { + fclose(pMenuFile); + Syslog('+', "Kicking user out, upsdown semafore detected"); + printf("System power failure, closing the bbs\n\n"); + free(Semfile); + sleep(3); + Good_Bye(0); + } + free(Semfile); + + /* + * Check if SysOp wants to chat to user everytime user + * gets prompt. Make sure /tmp/chatdev exists before + * before calling chat(). Make sure if a second user + * logs in, that .BusyChatting does exist. + */ + if(CFG.iChatPromptChk && (access("/tmp/chatdev", R_OK) == 0) && (access("/tmp/.BusyChatting", F_OK) != 0)) + Chat(); + + /* + * Check users timeleft + */ + TimeCheck(); + + alarm_on(); + + if (exitinfo.HotKeys) { + fflush(stdout); + Key = Getone(); + sprintf(Input, "%c", Key); + printf("\n"); + } else { + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(Input, 80); + } + + if((strcmp(Input, "")) != 0) { + + fseek(pMenuFile, 0, SEEK_SET); + + while (fread(&menus, sizeof(menus), 1, pMenuFile) == 1) { + + if ((strcmp(tu(Input), menus.MenuKey)) == 0) { + if ((Access(exitinfo.Security, menus.MenuSecurity)) && (UserAge >= menus.Age)) { + Syslog('b', "Menu[%d] %d=(%s), Opt: '%s'", MenuLevel, menus.MenuType, menus.TypeDesc, menus.OptionalData); + if (menus.MenuType == 13) { + /* + * Terminate call, cleanup here + */ + free(Input); + free(sMenuPathFileName); + fclose(pMenuFile); + } + DoMenu(menus.MenuType); + iFoundKey = TRUE; + break; + } + } + } + } + fclose(pMenuFile); + + } /* If menu open */ + } /* while true */ +} + + + +void DoMenu(int Type) +{ + int Strlen, i, x; + char *DisplayF; + char *sPrompt; + char *sPromptBak; + char *temp; + + DisplayF = calloc(81, sizeof(char)); + sPrompt = calloc(81, sizeof(char)); + sPromptBak = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + TimeCheck(); + + switch(Type) { + case 1: + /* Goto another menu */ + strncpy(Menus[MenuLevel], menus.OptionalData, 14); + break; + + case 2: + /* Gosub another menu */ + if (MenuLevel < 49) { + MenuLevel++; + strncpy(Menus[MenuLevel], menus.OptionalData, 14); + } else + Syslog('?', "More than 50 menu levels"); + break; + + case 3: + /* Return from gosub */ + if (MenuLevel > 0) + MenuLevel--; + break; + + case 4: + /* Return to top menu */ + MenuLevel = 0; + break; + + case 5: + /* Display .a?? file with controlcodes */ + DisplayFile(menus.OptionalData); + break; + + case 6: + /* Show menu prompt */ + Strlen = strlen(menus.OptionalData); + for(x = 0; x < Strlen; x++) { + if( menus.OptionalData[x] == '~') { + strcat(sPrompt, sUserTimeleft); + } else { + sprintf(temp, "%c", menus.OptionalData[x]); + strcat(sPrompt, temp); + } + } + strcpy(sPromptBak, sPrompt); + strcpy(sPrompt, ""); + Strlen = strlen(sPromptBak); + for(x = 0; x < Strlen; x++) { + if( *(sPromptBak + x) == '@') + strcat(sPrompt, sAreaDesc); + else + if ( *(sPromptBak + x) == '^') + strcat(sPrompt, sMsgAreaDesc); + else + if ( *(sPromptBak + x) == '#') + sprintf(sPrompt, "%s%s", sPrompt, (char *) GetLocalHM()); + + else { + sprintf(temp, "%c", *(sPromptBak + x)); + strcat(sPrompt, temp); + } + } + pout(15, 0, sPrompt); + break; + + case 7: + /* Run external program */ + ExtDoor(menus.OptionalData, menus.NoDoorsys, menus.Y2Kdoorsys, menus.Comport); + break; + + case 8: + /* Show product information */ + cr(); + break; + + case 9: + /* display todays callers */ + LastCallers(menus.OptionalData); + break; + + case 10: + /* display userlist */ + UserList(menus.OptionalData); + break; + + case 11: + /* display time statistics */ + TimeStats(); + break; + + case 12: + /* page sysop for chat */ + Page_Sysop(menus.OptionalData); + break; + + case 13: + /* terminate call */ + free(DisplayF); + free(sPrompt); + free(sPromptBak); + free(temp); + Good_Bye(0); + break; + + case 14: + /* make a log entry */ + LogEntry(menus.OptionalData); + break; + + case 15: + /* print text to screen */ + if (exitinfo.Security.level >= menus.MenuSecurity.level) { + for(i = 0; i < strlen(menus.OptionalData); i++) + if(*(menus.OptionalData + i) == '@') + *(menus.OptionalData + i) = '\n'; + printf("%s\n", menus.OptionalData); + } + break; + + case 16: + /* who's currently online */ + WhosOn(menus.OptionalData); + Pause(); + break; + + case 17: + /* comment to sysop */ + SysopComment((char *)"Comment to Sysop"); + break; + + case 18: + /* send on-line message */ + SendOnlineMsg(menus.OptionalData); + break; + + case 19: + /* display Textfile with more */ + MoreFile(menus.OptionalData); + break; + + case 20: + /* display a?? file with controlcode and wait for enter */ + DisplayFileEnter(menus.OptionalData); + break; + + case 22: + /* nextuser door */ + nextuser(); + break; + + case 23: + /* timebank door */ + Bank(); + break; + + case 24: + /* voting door Not anymore */ + break; + + case 25: + /* safe cracker door */ + Safe(); + break; + + case 101: + FileArea_List(menus.OptionalData); + break; + + case 102: + File_List(); + break; + + case 103: + ViewFile(); + break; + + case 104: + Download(); + break; + + case 105: + File_RawDir(menus.OptionalData); + break; + + case 106: + KeywordScan(); + break; + + case 107: + FilenameScan(); + break; + + case 108: + NewfileScan(TRUE); + break; + + case 109: + Upload(); + break; + + case 110: + EditTaglist(); + break; + + case 111: /* View file in homedir */ + break; + + case 112: + DownloadDirect(menus.OptionalData, TRUE); + break; + + case 113: + Copy_Home(); + break; + + case 114: + List_Home(); + break; + + case 115: + Delete_Home(); + break; + + /* 116 Unpack file in homedir */ + + /* 117 Pack files in homedir */ + + case 118: + Download_Home(); + break; + + case 119: + Upload_Home(); + break; + + case 201: + MsgArea_List(menus.OptionalData); + break; + + case 202: + Post_Msg(); + break; + + case 203: + Read_Msgs(); + break; + + case 204: + CheckMail(); + break; + + case 205: + QuickScan_Msgs(); + break; + + case 206: + Delete_Msg(); + break; + + case 207: + MailStatus(); + break; + + case 208: + OLR_TagArea(); + break; + + case 209: + OLR_UntagArea(); + break; + + case 210: + OLR_ViewTags(); + break; + + case 211: + OLR_RestrictDate(); + break; + + case 212: + OLR_Upload(); + break; + + case 213: + OLR_DownBW(); + break; + + case 214: + OLR_DownQWK(); + break; + + case 215: + OLR_DownASCII(); + break; + + case 216: + Read_Email(); + break; + + case 217: + Write_Email(); + break; + + case 218: + Trash_Email(); + break; + + case 219: + Choose_Mailbox(menus.OptionalData); + break; + + case 220: + QuickScan_Email(); + break; + + case 301: + Chg_Protocol(); + break; + + case 302: + Chg_Password(); + break; + + case 303: + Chg_Location(); + break; + + case 304: + Chg_Graphics(); + break; + + case 305: + Chg_VoicePhone(); + break; + + case 306: + Chg_DataPhone(); + break; + + case 307: + Chg_News(); + break; + + case 308: + Chg_ScreenLen(); + break; + + case 309: + Chg_DOB(); + break; + + case 310: + Chg_Language(FALSE); + break; + + case 311: + Chg_Hotkeys(); + break; + + case 312: + Chg_Handle(); + break; + + case 313: + Chg_MailCheck(); + break; + + case 314: + Chg_Disturb(); + break; + + case 315: + Chg_FileCheck(); + break; + + case 316: + Chg_FsMsged(); + break; + + case 401: + Oneliner_Add(); + break; + + case 402: + Oneliner_List(); + break; + + case 403: + Oneliner_Show(); + break; + + case 404: + Oneliner_Delete(); + break; + + case 405: + Oneliner_Print(); + break; + + case 501: + BBS_Add(); + break; + + case 502: + BBS_List(); + break; + + case 503: + BBS_Show(); + break; + + case 504: + BBS_Delete(); + break; + + case 506: + BBS_Search(); + break; + + default: + Enter(1); + pout(15, 0, (char *) Language(339)); + Enter(2); + Syslog('?', "Option: %s -> Unknown Menu Type: %d on %s", menus.MenuKey, Type, Menus[MenuLevel]); + Pause(); + } + + free(DisplayF); + free(sPrompt); + free(sPromptBak); + free(temp); +} + diff --git a/mbsebbs/menu.h b/mbsebbs/menu.h new file mode 100644 index 00000000..a925d779 --- /dev/null +++ b/mbsebbs/menu.h @@ -0,0 +1,9 @@ +#ifndef _MENU_H +#define _MENU_H + +void InitMenu(void); +void menu(void); +void DoMenu(int); + +#endif + diff --git a/mbsebbs/misc.c b/mbsebbs/misc.c new file mode 100644 index 00000000..08756485 --- /dev/null +++ b/mbsebbs/misc.c @@ -0,0 +1,446 @@ +/***************************************************************************** + * + * File ..................: bbs/misc.c + * Purpose ...............: Misc functions + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "misc.h" +#include "timeout.h" +#include "exitinfo.h" + + +extern pid_t mypid; /* Pid of this program */ + + +int MoreFile(char *filename) +{ + char Buf[80]; + static FILE *fptr; + int lines; + int input; + int ignore = FALSE; + int maxlines; + + maxlines = lines = exitinfo.iScreenLen - 2; + + if ((fptr = fopen(filename,"r")) == NULL) { + printf("%s%s\n", (char *) Language(72), filename); + return(0); + } + + printf("\n"); + + while (fgets(Buf,80,fptr) != NULL) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%s",Buf); + } + + if (strlen(Buf) == 0) { + fclose(fptr); + return(0); + } + if (lines == 0) { + fflush(stdin); + /* More (Y/n/=) */ + printf(" %sY\x08", (char *) Language(61)); + fflush(stdout); + alarm_on(); + input = toupper(getchar()); + + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + fclose(fptr); + return(0); + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + } + printf("\n\n"); + Pause(); + } + fclose(fptr); + return 1; +} + + + +int GetLastUser() +{ + FILE *pCallerLog; + char *sDataFile; + + sDataFile = calloc(PATH_MAX, sizeof(char)); + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + if((pCallerLog = fopen(sDataFile, "r+")) == NULL) + WriteError("GetLastUser: Can't open file: %s", sDataFile); + else { + fread(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + + /* Get lastcaller in memory */ + strcpy(LastCaller, SYSINFO.LastCaller); + + /* Set next lastcaller (this user) */ + if(!usrconfig.Hidden) + strcpy(SYSINFO.LastCaller,exitinfo.sUserName); + + SYSINFO.SystemCalls++; + switch(ttyinfo.type) { + case POTS: + SYSINFO.Pots++; + break; + + case ISDN: + SYSINFO.ISDN++; + break; + + case NETWORK: + SYSINFO.Network++; + break; + + case LOCAL: + SYSINFO.Local++; + break; + } + + rewind(pCallerLog); + fwrite(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + + fclose(pCallerLog); + } + free(sDataFile); + return 1; +} + + + +int ChkFiles() +{ + FILE *pCallerLog, *pUsersFile; + char *sDataFile; + time_t Now; + char *temp; + + sDataFile = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + sprintf(sDataFile, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + /* + * Check if users.data exists, if not create a new one. + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if((pUsersFile = fopen(temp,"rb")) == NULL) { + if((pUsersFile = fopen(temp,"wb")) == NULL) { + WriteError("$Can't create %s", temp); + ExitClient(1); + } else { + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, pUsersFile); + fclose(pUsersFile); + } + } + + /* + * Check if sysinfo.data exists, if not, create a new one. + */ + if((pCallerLog = fopen(sDataFile, "rb")) == NULL) { + if((pCallerLog = fopen(sDataFile, "wb")) == NULL) + WriteError("$ChkFiles: Can't create %s", sDataFile); + else { + memset((char *)&SYSINFO, 0, sizeof(SYSINFO)); + time(&Now); + SYSINFO.StartDate = Now; + + rewind(pCallerLog); + fwrite(&SYSINFO, sizeof(SYSINFO), 1, pCallerLog); + fclose(pCallerLog); + } + } + free(temp); + free(sDataFile); + return 1; +} + + + +void DisplayLogo() +{ + FILE *pLogo; + char *sString, *temp; + + temp = calloc(PATH_MAX, sizeof(char)); + sString = calloc(81, sizeof(char)); + + sprintf(temp, "%s/%s", CFG.bbs_txtfiles, CFG.welcome_logo); + if((pLogo = fopen(temp,"rb")) == NULL) + WriteError("$DisplayLogo: Can't open %s", temp); + else { + while( fgets(sString,80,pLogo) != NULL) + printf("%s", sString); + fclose(pLogo); + } + free(sString); + free(temp); +} + + + +/* + * Update a variable in the exitinfo file. + */ +void Setup(char *Option, char *variable) +{ + ReadExitinfo(); + strcpy(Option, variable); + WriteExitinfo(); +} + + + +void GetLastCallers() +{ + FILE *pGLC; + char *sFileName; + char sFileDate[9]; + char sDate[9]; + struct stat statfile; + + /* + * First check if we passed midnight, in that case we + * create a fresh file. + */ + sFileName = calloc(PATH_MAX, sizeof(char)); + sprintf(sFileName,"%s/etc/lastcall.data", getenv("MBSE_ROOT")); + stat(sFileName, &statfile); + + sprintf(sFileDate,"%s", StrDateDMY(statfile.st_mtime)); + sprintf(sDate,"%s", (char *) GetDateDMY()); + + if ((strcmp(sDate,sFileDate)) != 0) { + unlink(sFileName); + Syslog('+', "Erased old lastcall.data"); + } + + /* + * Check if file exists, if not create the file and + * write the fileheader. + */ + if ((pGLC = fopen(sFileName, "r")) == NULL) { + if ((pGLC = fopen(sFileName, "w")) != NULL) { + LCALLhdr.hdrsize = sizeof(LCALLhdr); + LCALLhdr.recsize = sizeof(LCALL); + fwrite(&LCALLhdr, sizeof(LCALLhdr), 1, pGLC); + Syslog('+', "Created new lastcall.data"); + } + fclose(pGLC); + } + + if(( pGLC = fopen(sFileName,"a+")) == NULL) { + WriteError("$Can't open %s", sFileName); + return; + } else { + ReadExitinfo(); + memset(&LCALL, 0, sizeof(LCALL)); + sprintf(LCALL.UserName,"%s", exitinfo.sUserName); + sprintf(LCALL.Handle,"%s", exitinfo.sHandle); + sprintf(LCALL.TimeOn,"%s", (char *) GetLocalHM()); + sprintf(LCALL.Device,"%s", pTTY); + LCALL.SecLevel = exitinfo.Security.level; + LCALL.Calls = exitinfo.iTotalCalls; + sprintf(LCALL.Speed, "%s", ttyinfo.speed); + + /* If true then set hidden so it doesn't display in lastcallers function */ + LCALL.Hidden = exitinfo.Hidden; + + sprintf(LCALL.Location,"%s", exitinfo.sLocation); + + rewind(pGLC); /* ???????????? */ + fwrite(&LCALL, sizeof(LCALL), 1, pGLC); + fclose(pGLC); + } + free(sFileName); +} + + + +/* Gets Date for GetLastCallers(), returns DD:Mmm */ +char *GLCdate() +{ + static char GLcdate[15]; + + time(&Time_Now); + l_date = localtime(&Time_Now); + sprintf(GLcdate,"%02d-", l_date->tm_mday); + + strcat(GLcdate,GetMonth(l_date->tm_mon+1)); + return(GLcdate); +} + + + +/* + * Display last callers screen. + */ +void LastCallers(char *OpData) +{ + FILE *pLC; + int LineCount = 5; + int count = 0; + char *sFileName; + char *Heading; + char *Underline; + int i, x; + struct lastcallers lcall; + struct lastcallershdr lcallhdr; + + sFileName = calloc(PATH_MAX, sizeof(char)); + Heading = calloc(81, sizeof(char)); + Underline = calloc(81, sizeof(char)); + + clear(); + + sprintf(sFileName,"%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if((pLC = fopen(sFileName,"r")) == NULL) + WriteError("$LastCallers: Can't open %s", sFileName); + else { + fread(&lcallhdr, sizeof(lcallhdr), 1, pLC); + colour(15, 0); + /* Todays callers to */ + sprintf(Heading, "%s%s", (char *) Language(84), CFG.bbs_name); + Center(Heading); + + x = strlen(Heading); + + for(i = 0; i < x; i++) + sprintf(Underline, "%s%c", Underline, exitinfo.GraphMode ? 196 : 45); + + colour(12, 0); + Center(Underline); + + printf("\n"); + + /* # User Name Device timeOn Calls Location */ + pout(10, 0, (char *) Language(85)); + Enter(1); + + colour(2, 0); + fLine(79); + + while (fread(&lcall, lcallhdr.recsize, 1, pLC) == 1) { + if(!lcall.Hidden) { + count++; + + colour(15,0); + printf("%-5d", count); + + colour(11, 0); + if((strcmp(OpData, "/H")) == 0) { + if((strcmp(lcall.Handle, "") != 0 && *(lcall.Handle) != ' ')) + printf("%-20s", lcall.Handle); + else + printf("%-20s", lcall.UserName); + } else + printf("%-20s", lcall.UserName); + + colour(9, 0); + printf("%-8s", lcall.Device); + + colour(13, 0); + printf("%-8s", lcall.TimeOn); + + colour(14, 0); + printf("%-7d", lcall.Calls); + + colour(12, 0); + printf("%-32s\n", lcall.Location); + + LineCount++; + if (LineCount == exitinfo.iScreenLen) { + Pause(); + LineCount = 0; + } + } /* End of check if user is sysop */ + } + + colour(2, 0); + fLine(79); + + fclose(pLC); + printf("\n"); + Pause(); + } + free(sFileName); + free(Heading); + free(Underline); +} + + + +/* + * Check for a personal message, this will go via mbsed. If there + * is a message, it will be displayed, else nothing happens. + */ +void Check_PM(void) +{ + static char buf[128]; + char resp[128]; + + sprintf(buf, "CIPM:1,%d;", mypid); + if (socket_send(buf) == 0) { + strcpy(buf, socket_receive()); + if (strncmp(buf, "100:0;", 6) == 0) + return; + + strcpy(resp, strtok(buf, ":")); + strcpy(resp, strtok(NULL, ",")); + colour(CYAN, BLACK); + /* ** Message ** from */ + printf("\n\n\007%s %s:\n", (char *)Language(434), strtok(NULL, ",")); + printf("%s\n", strtok(NULL, ";")); + Pause(); + } +} + + + diff --git a/mbsebbs/misc.h b/mbsebbs/misc.h new file mode 100644 index 00000000..1f5adb4a --- /dev/null +++ b/mbsebbs/misc.h @@ -0,0 +1,15 @@ +#ifndef _MISC_H +#define _MISC_H + +void Setup(char *, char *); /* This function replaces a string in the users file */ +int GetLastUser(void); +void LastCallers(char *); +void GetLastCallers(void); +char *GLCdate(void); /* Returns current date DD-Mmm */ +void DisplayLogo(void); +int ChkFiles(void); +int MoreFile(char *); +void Check_PM(void); /* Check for personal message */ + +#endif + diff --git a/mbsebbs/msgutil.c b/mbsebbs/msgutil.c new file mode 100644 index 00000000..7d513384 --- /dev/null +++ b/mbsebbs/msgutil.c @@ -0,0 +1,279 @@ +/***************************************************************************** + * + * File ..................: bbs/msgutil.c + * Purpose ...............: Utilities for message handling. + * Last modification date : 18-Feb-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "oneline.h" +#include "msgutil.h" + + + +int BaseWrite = FALSE; + +static char *wdays[]={(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; + +static char *months[]={(char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec"}; + + + +char *rfcdate(time_t now) +{ + static char buf[40]; + struct tm ptm, gtm; + char sign; + int hr, min; + long offset; + + if (!now) + time(&now); + ptm = *localtime(&now); + + /* + * To get the timezone, compare localtime with GMT. + */ + gtm = *gmtime(&now); + + /* + * Assume we are never more than 24 hours away. + */ + offset = gtm.tm_yday - ptm.tm_yday; + if (offset > 1) + offset = -24; + else if (offset < -1) + offset = 24; + else + offset *= 24; + + /* + * Scale in the hours and minutes; ignore seconds. + */ + offset += gtm.tm_hour - ptm.tm_hour; + offset *= 60; + offset += gtm.tm_min - ptm.tm_min; + + if (offset <= 0) + { + sign='+'; + offset=-offset; + } + else sign='-'; + hr=offset/60L; + min=offset%60L; + + sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d", + wdays[gtm.tm_wday],gtm.tm_mday,months[gtm.tm_mon], + gtm.tm_year+1900,gtm.tm_hour,gtm.tm_min,gtm.tm_sec, + sign,hr,min); + return(buf); +} + + + +/* + * Open specified message base for read or write. + */ +int Open_Msgbase(char *Base, int Mode) +{ + BaseWrite = FALSE; + + if (!Msg_Open(Base)) + return FALSE; + + if (Mode != 'w') + return TRUE; + + if (!Msg_Lock(30L)) { + Msg_Close(); + return FALSE; + } + + BaseWrite = TRUE; + return TRUE; +} + + + +/* + * Close current messagebase. + */ +void Close_Msgbase() +{ + if (BaseWrite) { + Msg_UnLock(); + BaseWrite = FALSE; + } + Msg_Close(); +} + + + +void Add_Headkludges(faddr *dest, int IsReply) +{ + char *temp, *temp2; + unsigned long crc = -1; + time_t tt; + int i; + faddr *Node; + + temp = calloc(128, sizeof(char)); + + switch (msgs.Type) { + case LOCALMAIL: Msg.Localmail = TRUE; + break; + + case NETMAIL: Msg.Netmail = TRUE; + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + sprintf(Msg.ToAddress, "%s", ascfnode(dest, 0x1f)); + + if (msgs.Aka.point) { + sprintf(temp, "\001FMPT %d", msgs.Aka.point); + MsgText_Add2(temp); + } + + if (dest->point) { + sprintf(temp, "\001TOPT %d", dest->point); + MsgText_Add2(temp); + } + + sprintf(temp, "\001INTL %d:%d/%d %d:%d/%d", dest->zone, dest->net, dest->node, msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + MsgText_Add2(temp); + + break; + + case ECHOMAIL: Msg.Echomail = TRUE; + sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka)); + break; + + case NEWS: /* + * Header style is the same as GoldED does. + */ + Msg.News = TRUE; + sprintf(temp, "\001Date: %s", rfcdate(Msg.Written)); + MsgText_Add2(temp); + Node = fido2faddr(msgs.Aka); + temp2 = xstrcpy(Msg.From); + for (i = 0; i < strlen(temp2); i++) + if (temp2[i] == ' ') + temp2[i] = '_'; + sprintf(temp, "\001From: %s@%s (%s)", temp2, ascinode(Node, 0x2f), Msg.From); + MsgText_Add2(temp); + sprintf(temp, "\001Subject: %s", Msg.Subject); + MsgText_Add2(temp); + sprintf(temp, "\001Sender: %s@%s (%s)", temp2, ascinode(Node, 0x2f), Msg.From); + MsgText_Add2(temp); + free(temp2); + tidy_faddr(Node); + MsgText_Add2((char *)"\001To: All"); + MsgText_Add2((char *)"\001MIME-Version: 1.0"); + MsgText_Add2((char *)"\001Content-Type: text/plain"); + MsgText_Add2((char *)"\001Content-Transfer-Encoding: 8bit"); + sprintf(temp, "\001X-Mailreader: MBSE BBS %s", VERSION); + MsgText_Add2(temp); + break; + } + + sprintf(temp, "\001CHRS: %s", getchrs(msgs.Ftncode)); + MsgText_Add2(temp); + sprintf(temp, "\001MSGID: %s %08lx", aka2str(msgs.Aka), sequencer()); + MsgText_Add2(temp); + Msg.MsgIdCRC = upd_crc32(temp, crc, strlen(temp)); + + if (IsReply) { + sprintf(temp, "\001REPLY: %s", Msg.Replyid); + MsgText_Add2(temp); + crc = -1; + Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp)); + } else + Msg.ReplyCRC = 0xffffffff; + + sprintf(temp, "\001PID: MBSE-BBS %s", VERSION); + MsgText_Add2(temp); + (void)time(&tt); + sprintf(temp, "\001TZUTC: %s", gmtoffset(tt)); + MsgText_Add2(temp); + free(temp); +} + + + +/* + * Add bottom message kludges. The flag Quote is false if this is called + * from Offline Reader, the user then may or may have not added a quote. + */ +void Add_Footkludges(int Quote) +{ + char *temp; + char *aka; + + temp = calloc(128, sizeof(char)); + aka = calloc(32, sizeof(char)); + + if (msgs.Quotes && Quote) { + Syslog('m', " Add quote"); + MsgText_Add2((char *)""); + sprintf(temp, "... %s", Oneliner_Get()); + MsgText_Add2(temp); + MsgText_Add2((char *)""); + } + + sprintf(temp, "--- MBSE BBS v%s (Linux)", VERSION); + MsgText_Add2(temp); + + if (msgs.Type == ECHOMAIL) { + /* RANDOM ORIGIN LINES IMPLEMENTEREN */ + if (msgs.Aka.point) + sprintf(aka, "(%d:%d/%d.%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node, msgs.Aka.point); + else + sprintf(aka, "(%d:%d/%d)", msgs.Aka.zone, msgs.Aka.net, msgs.Aka.node); + + if (strlen(msgs.Origin)) + sprintf(temp, " * Origin: %s %s", msgs.Origin, aka); + else + sprintf(temp, " * Origin: %s %s", CFG.origin, aka); + MsgText_Add2(temp); + } + + free(aka); + free(temp); +} + + + diff --git a/mbsebbs/msgutil.h b/mbsebbs/msgutil.h new file mode 100644 index 00000000..7d4143d4 --- /dev/null +++ b/mbsebbs/msgutil.h @@ -0,0 +1,14 @@ +#ifndef _MSGUTIL_H +#define _MSGUTIL_H + + +char *rfcdate(time_t); /* Create RFC style date */ +int Open_Msgbase(char *, int); /* Open msgbase for read/write */ +void Close_Msgbase(void); /* Close msgbase */ +void Add_Headkludges(faddr *, int); /* Header part of kludges */ +void Add_Footkludges(int); /* Footer part of kludges */ +void Sema_Mailout(void); /* Set mailout semafore */ + + +#endif + diff --git a/mbsebbs/myname.c b/mbsebbs/myname.c new file mode 100644 index 00000000..8c9e4120 --- /dev/null +++ b/mbsebbs/myname.c @@ -0,0 +1,72 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/myname.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Jul-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * myname.c - determine the current username and get the passwd entry + * + * Copyright (C) 1996 Marek Michalkiewicz + * + * This code may be freely used, modified and distributed for any purpose. + * There is no warranty, if it breaks you have to keep both pieces, etc. + * If you improve it, please send me your changes. Thanks! + */ + +#include "../config.h" +#include +#include +#include + + +struct passwd *get_my_pwent(void) +{ + struct passwd *pw; + const char *cp = getlogin(); + uid_t ruid = getuid(); + + /* + * Try getlogin() first - if it fails or returns a non-existent + * username, or a username which doesn't match the real UID, fall + * back to getpwuid(getuid()). This should work reasonably with + * usernames longer than the utmp limit (8 characters), as well as + * shared UIDs - but not both at the same time... + * + * XXX - when running from su, will return the current user (not + * the original user, like getlogin() does). Does this matter? + */ + if (cp && *cp && (pw = getpwnam(cp)) && pw->pw_uid == ruid) + return pw; + + return getpwuid(ruid); +} + + diff --git a/mbsebbs/myname.h b/mbsebbs/myname.h new file mode 100644 index 00000000..8e4ca5aa --- /dev/null +++ b/mbsebbs/myname.h @@ -0,0 +1,7 @@ +#ifndef _MYNAME_H +#define _MYNAME_H + +struct passwd *get_my_pwent(void); + +#endif + diff --git a/mbsebbs/newuser.c b/mbsebbs/newuser.c new file mode 100644 index 00000000..c4b8cd39 --- /dev/null +++ b/mbsebbs/newuser.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/newuser.c + * Purpose ...............: New User login under Unix, creates both + * BBS and unix accounts. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "funcs4.h" +#include "pwcheck.h" +#include "newuser.h" +#include "language.h" +#include "timeout.h" +#include "change.h" +#include "bye.h" + + +extern int do_quiet; /* No logging to the screen */ +extern pid_t mypid; /* Pid of this program */ +char UnixName[9]; /* Unix Name */ +extern int ieLogin; /* IEMSI Login Successfull */ +extern int ieRows; /* Rows on screen */ +extern int ieHOT; /* Use Hotkeys */ +extern char *ieHandle; /* Users Handle */ +extern char *ieLocation; /* Users Location */ +extern char *Passwd; /* Plain password */ + + +int newuser(char *FullName) +{ + FILE *pUsrConfig; + int i, x, Found, iLang, recno = 0; + unsigned long crc; + char temp[PATH_MAX]; + char *temp1, *temp2; + char *Phone1, *Phone2; + long offset; + struct userrec us; + + IsDoing("New user login"); + Syslog('+', "Newuser registration"); + clear(); + iLang = Chg_Language(TRUE); + + Enter(1); + /* MBSE BBS - NEW USER REGISTRATION */ + language(3, 0, 37); + Enter(2); + + Syslog('+', "Name entered: %s", FullName); + + memset(&usrconfig, 0, sizeof(usrconfig)); + memset(&exitinfo, 0, sizeof(exitinfo)); + + temp1 = calloc(81, sizeof(char)); + temp2 = calloc(81, sizeof(char)); + Phone1 = calloc(81, sizeof(char)); + Phone2 = calloc(81, sizeof(char)); + + usrconfig.iLanguage = iLang; + usrconfig.FsMsged = TRUE; + + while (TRUE) { + do { + alarm_on(); + Enter(1); + /* Use this name: */ + language(14, 0, 38); + printf("%s [Y/n]? ", FullName); + fflush(stdout); + fflush(stdin); + GetstrC(temp, 80); + + if ((strcasecmp(temp, "y") == 0) || (strcmp(temp, "") == 0)) + sprintf(temp, "%s", FullName); + else { + do { + Syslog('+', "User chose to use a different name"); + Enter(1); + /* Please enter your First and Last name: */ + language(3, 0, 0); + fflush(stdout); + alarm_on(); + Getname(temp, 35); + if (CheckName(temp)) + printf("\n%s\n", (char *) Language(149)); + /* + * Do a check to see if name exists + */ + } while ((CheckName(temp) || strchr(temp, ' ') == NULL)); + } + } while (BadNames(temp) || *(temp) == '\n'); + + /* + * Used to get users full name for other functions + */ + strcpy(FullName, tlcap(temp)); + UserCity(mypid, FullName, (char *)"Unknown"); + + while (1) { + Enter(1); + /* Please enter your BBS password, this can be the same as the unix password */ + printf("%s\n\n", (char *) Language(388)); + /* Please enter new password : */ + language(11, 0, 39); + fflush(stdout); + alarm_on(); + Getpass(temp1); + if((x = strlen(temp1)) >= CFG.password_length) { + Enter(1); + /* Please enter password again : */ + language(11, 0, 40); + fflush(stdout); + alarm_on(); + Getpass(temp2); + if((i = strcmp(temp1,temp2)) != 0) { + Enter(2); + /* Your passwords do not match! Try again. */ + language(12, 0, 41); + Enter(1); + } else { + crc = StringCRC32(tu(temp1)); + break; + } + } else { + Enter(2); + /* Your password must contain at least */ + language(12, 0, 42); + printf("%d ", CFG.password_length); + /* characters! Try again. */ + language(15, 0, 43); + Enter(1); + } + } + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", temp2); + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", temp2); + usrconfig.iPassword = crc; + alarm_on(); + sprintf(UnixName, "%s", (char *) NameCreate(NameGen(FullName), FullName, temp2)); + break; + } + + strcpy(usrconfig.sUserName, FullName); + strcpy(usrconfig.Name, UnixName); + Time_Now = time(NULL); + l_date = localtime(&Time_Now); + ltime = time(NULL); + + if(CFG.iAnsi) { + Enter(2); + /* Do you want ANSI and graphics mode [Y/n]: */ + language(7, 0, 44); + + alarm_on(); + i = toupper(getchar()); + + if (i == Keystroke(44, 0) || i == '\n') + usrconfig.GraphMode = TRUE; + else + usrconfig.GraphMode = FALSE; + } else { + usrconfig.GraphMode = TRUE; /* Default set it to ANSI */ + Enter(1); + } + exitinfo.GraphMode = usrconfig.GraphMode; + TermInit(exitinfo.GraphMode); + + if (CFG.iVoicePhone) { + while (1) { + Enter(1); + /* Please enter you Voice Number */ + language(10, 0, 45); + Enter(1); + + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + GetPhone(temp, 16); + + if (strlen(temp) < 6) { + Enter(1); + language(12, 0, 47); + Enter(1); + } else { + strcpy(usrconfig.sVoicePhone, temp); + strcpy(Phone1, temp); + break; + } + } + } /* End of first if statement */ + + if (CFG.iDataPhone) { + while (TRUE) { + Enter(1); + /* Please enter you Data Number */ + language(10, 0, 48); + Enter(1); + + pout(10, 0, (char *)": "); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetPhone(temp, 16); + + /* + * If no dataphone, copy voicephone. + */ + if (strcmp(temp, "") == 0) { + strcpy(usrconfig.sDataPhone, usrconfig.sVoicePhone); + break; + } + + if( strlen(temp) < 6) { + Enter(1); + /* Please enter a proper phone number */ + language(12, 0, 47); + Enter(1); + } else { + strcpy(usrconfig.sDataPhone, temp); + strcpy(Phone2, temp); + break; + } + } + } /* End of if Statement */ + + if(!CFG.iDataPhone) + printf("\n"); + + if (ieLogin && (strlen(ieLocation) >= CFG.CityLen) && (strlen(ieLocation) < 24)) { + strcpy(usrconfig.sLocation, ieLocation); + } else { + while (TRUE) { + Enter(1); + /* Enter your location */ + pout(14, 0, (char *) Language(49)); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + if (CFG.iCapLocation) { /* Cap Location is turn on, Capitalise first letter */ + fflush(stdout); + GetnameNE(temp, 24); + } else + GetstrC(temp, 80); + + if( strlen(temp) < CFG.CityLen) { + Enter(1); + /* Please enter a longer location */ + language(12, 0, 50); + Enter(1); + printf("%s%d)", (char *) Language(74), CFG.CityLen); + Enter(1); + } else { + strcpy(usrconfig.sLocation, temp); + UserCity(mypid, FullName, temp); + break; + } + } + } + + if(CFG.iHandle) { + Enter(1); + /* Enter a handle (Enter to Quit): */ + pout(12, 0, (char *) Language(412)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + Getname(temp, 34); + + if(strcmp(temp, "") == 0) + strcpy(usrconfig.sHandle, ""); + else + strcpy(usrconfig.sHandle, temp); + } + + /* + * Note, the users database always contains the english sex + */ + if(CFG.iSex) { + while (TRUE) { + Enter(1); + /* What is your sex? (M)ale or (F)emale: */ + language(9, 0, 51); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(51, 0)) { + /* Male */ + sprintf(usrconfig.sSex, "Male"); + pout(CFG.InputColourF, CFG.InputColourB, (char *) Language(52)); + Enter(1); + break; + } else + if (i == Keystroke(51, 1)) { + /* Female */ + sprintf(usrconfig.sSex, "Female"); + pout(CFG.InputColourF, CFG.InputColourB, (char *) Language(53)); + Enter(1); + break; + } else { + Enter(2); + /* Please answer M or F */ + language(12, 0, 54); + Enter(1); + } + } + } else /* End of if Statement */ + sprintf(usrconfig.sSex, "Unknown"); /* If set off, set to Unknown */ + + while (TRUE) { + Enter(1); + /* Please enter your Date of Birth DD-MM-YYYY: */ + pout(3, 0, (char *) Language(56)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + GetDate(temp, 10); + + sprintf(temp1, "%c%c%c%c", temp[6], temp[7], temp[8], temp[9]); + sprintf(temp2, "%02d", l_date->tm_year); + iLang = atoi(temp2) + 1900; + sprintf(temp2, "%04d", iLang); + + Syslog('-', "DOB: test %s %s", temp1, temp2); + + if ((strcmp(temp1,temp2)) == 0) { + Enter(1); + /* Sorry you entered this year by mistake. */ + pout(12, 0, (char *) Language(57)); + Enter(1); + } else + if((strlen(temp)) != 10) { + Enter(1); + /* Please enter the correct date format */ + pout(12, 0, (char *) Language(58)); + Enter(1); + } else { + strcpy(usrconfig.sDateOfBirth,temp); + break; + } + } + + usrconfig.tFirstLoginDate = ltime; /* Set first login date to current date */ + usrconfig.tLastLoginDate = (time_t)0; /* To force setting new limits */ + strcpy(usrconfig.sExpiryDate,"00-00-0000"); + usrconfig.ExpirySec = CFG.newuser_access; + usrconfig.Security = CFG.newuser_access; + usrconfig.Email = CFG.GiveEmail; + + if (ieLogin) + usrconfig.HotKeys = ieHOT; + else { + if (CFG.iHotkeys) { + while (TRUE) { + Enter(1); + /* Would you like hot-keyed menus [Y/n]: */ + pout(12, 0, (char *) Language(62)); + colour(CFG.InputColourF, CFG.InputColourB); + alarm_on(); + GetstrC(temp, 8); + + if ((toupper(temp[0]) == Keystroke(62, 0)) || (strcmp(temp,"") == 0)) { + usrconfig.HotKeys = TRUE; + break; + } + if (toupper(temp[0]) == Keystroke(62, 1)) { + usrconfig.HotKeys = FALSE; + break; + } else { + /* Please answer Y or N */ + pout(15, 0, (char *) Language(63)); + } + } + } /* End of if Statement */ + else + usrconfig.HotKeys = TRUE; /* Default set it to Hotkeys */ + } + + usrconfig.iTimeLeft = 20; /* Set Timeleft in users file to 20 */ + + Enter(1); + if (ieLogin) + usrconfig.iScreenLen = ieRows; + else { + /* Please enter your Screen Length [24]: */ + pout(13, 0, (char *) Language(64)); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + alarm_on(); + Getnum(temp, 3); + + if(strlen(temp) == 0) + usrconfig.iScreenLen = 24; + else + usrconfig.iScreenLen = atoi(temp); + } + + alarm_on(); + + usrconfig.tLastPwdChange = ltime; /* Days Since Last Password Change */ + usrconfig.iLastFileArea = 1; + + sprintf(usrconfig.sProtocol, "%s", (char *) Language(65)); + usrconfig.DoNotDisturb = FALSE; + usrconfig.MailScan = TRUE; + usrconfig.ieFILE = TRUE; + usrconfig.ieNEWS = TRUE; + usrconfig.Cls = TRUE; + usrconfig.More = TRUE; + usrconfig.ieASCII8 = TRUE; + + /* + * Search a free slot in the users datafile + */ + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp, "r+")) == NULL) { + WriteError("Can't open file: %s", temp); + ExitClient(1); + } + + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + offset = ftell(pUsrConfig); + Found = FALSE; + + while ((fread(&us, usrconfighdr.recsize, 1, pUsrConfig) == 1) && (!Found)) { + if (us.sUserName[0] == '\0') { + Found = TRUE; + } else { + offset = ftell(pUsrConfig); + recno++; + } + } + + if (Found) + fseek(pUsrConfig, offset, SEEK_SET); + else + fseek(pUsrConfig, 0, SEEK_END); + + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + + Enter(2); + /* Your user account has been created: */ + pout(14, 0, (char *) Language(67)); + Enter(2); + + /* Login Name : */ + pout(9, 0, (char *) Language(68)); + colour(11, 0); + printf("%s (%s)\n", FullName, UnixName); + /* Password : */ + pout(9, 0, (char *) Language(69)); + pout(3, 0, (char *)"<"); + /* not displayed */ + pout(15, 0, (char *) Language(70)); + pout(3, 0, (char *)">\n\n"); + fflush(stdout); + fflush(stdin); + + if(CFG.iVoicePhone) { + if(TelephoneScan(Phone1, FullName)) + Syslog('!', "Duplicate phone numbers found"); + } + + if(CFG.iDataPhone) { + if(TelephoneScan(Phone2, FullName)) + Syslog('!', "Duplicate phone numbers found"); + } + + free(temp1); + free(temp2); + free(Phone1); + free(Phone2); + + Syslog('+', "Completed new-user procedure"); + /* New user registration completed. */ + pout(10, 0, (char *) Language(71)); + Enter(2); + alarm_on(); + Pause(); + alarm_off(); + printf("\n"); + return recno; +} + + diff --git a/mbsebbs/newuser.h b/mbsebbs/newuser.h new file mode 100644 index 00000000..36b2cbe8 --- /dev/null +++ b/mbsebbs/newuser.h @@ -0,0 +1,9 @@ +#ifndef _NEWUSER_H +#define _NEWUSER_H + + +int newuser(char *); /* Newuser function */ + + +#endif + diff --git a/mbsebbs/nextuser.c b/mbsebbs/nextuser.c new file mode 100644 index 00000000..2b189dab --- /dev/null +++ b/mbsebbs/nextuser.c @@ -0,0 +1,360 @@ +/***************************************************************************** + * + * File ..................: bbs/nextuser.c + * Purpose ...............: Message to next User door + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/ansi.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "nextuser.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "timeout.h" + + +int iLoop, iLine = 1; + +char sFrom[81]; +char To[81]; +char Subject[81]; + +int finish(void); +void addlines(void); + +char *sLiNE[11]; + + + +void nextuser(void) +{ + int i; + + for (i = 0; i < 11; i++) + *(sLiNE + i) = (char *) calloc(81, sizeof(char)); + + addlines(); + while (TRUE) { + if (finish() == TRUE) + break; + } + + for (i = 0; i < 11; i++) + free(*(sLiNE + i)); +} + + + +void addlines(void) +{ + iLine = 1; + clear(); + + /* Message to Nextuser Door */ + pout(15, 0, (char *) Language(107)); + Enter(2); + + Syslog('+', "%s ran Nextuser Door", exitinfo.sUserName); + + /* The FROM, TO and SUBJECT fields are optional. */ + pout(14, 0, (char *) Language(108)); + Enter(1); + + Enter(1); + /* From: */ + pout(12, 0, (char *) Language(109)); + colour(9, 0); + fflush(stdout); + Getname(sFrom, 50); + + /* To: */ + pout(12, 0, (char *) Language(110)); + colour(9, 0); + fflush(stdout); + Getname(To, 50); + + /* Subject: */ + pout(12, 0, (char *) Language(111)); + colour(9, 0); + fflush(stdout); + GetstrC(Subject, 80); + + Enter(2); + /* Type up to 10 lines 74 Characters per line */ + pout(10 , 0, (char *) Language(112)); + Enter(1); + + colour(14, 0); + printf(" Õ"); + for(iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¸"); + + while (1) { + colour(12, 0); + printf("%d: ", iLine); + colour(9, 0); + fflush(stdout); + GetstrC(*(sLiNE + iLine), 75); + + if ((strcmp(*(sLiNE + iLine), "")) == 0) + return; + + iLine++; + if(iLine >= 11) + break; + } + + pout(14, 0, (char *)" Ô"); + for(iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¾"); +} + + + +/* Save Abort File */ +int finish(void) +{ + FILE *pTextFileANS, *pTextFileASC; + int iStrLen, i, x, NLChk = FALSE; + char *temp, *temp1; + + temp = calloc(PATH_MAX, sizeof(char)); + temp1 = calloc(PATH_MAX, sizeof(char)); + + while (TRUE) { + Enter(1); + poutCR(15, 0, (char *) Language(113)); + Enter(1); + /* (L)ist, (R)eplace text, (E)dit line, (A)bort, (S)ave */ + pout(15, 1, (char *) Language(114)); + Enter(2); + + /* Select: */ + pout(15, 0, (char *) Language(115)); + + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(114, 3)) { + /* Aborting... */ + pout(15, 0, (char *) Language(116)); + Enter(1); + Enter(1); + pout(15, 0, (char *) Language(117)); + poutCR(15, 0, CFG.bbs_name); + sleep(2); + Syslog('+', "User aborted message and exited door"); + free(temp); + free(temp1); + return TRUE; + } else + + if (i == Keystroke(114, 2)) { + /* Edit which line: */ + printf("\n %s", (char *) Language(118)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + i = atoi(temp); + if( i > iLine - 1) { + /* Line does not exist. */ + printf("%s\n", (char *) Language(119)); + break; + } + x = strlen(sLiNE[i]); + printf("%d : %s", i, *(sLiNE + i)); + fflush(stdout); + GetstrP(sLiNE[i],74, x); + } else + + if (i == Keystroke(114, 0)) { + colour(14, 0); + printf("\n\n Õ"); + for (iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¸"); + + for(i = 1; i < iLine; i++) { + colour(12, 0); + printf("%d: ", i); + colour(9, 0); + printf("%s\n", *(sLiNE + i)); + } + + colour(14, 0); + printf(" Ô"); + for (iLoop = 0; iLoop <= 75; iLoop++) + printf("Í"); + printf("¾\n"); + } else + + if (i == Keystroke(114, 4)) { + /* Open TextFile for Writing NextUser Info */ + sprintf(temp, "%s/%s.ans", CFG.bbs_txtfiles, CFG.sNuScreen); + sprintf(temp1, "%s/%s.ans.bak", CFG.bbs_txtfiles, CFG.sNuScreen); + rename(temp, temp1); + + if((pTextFileANS = fopen(temp, "w")) == NULL) { + perror(""); + WriteError("NextUser: Can't open file: %s", temp); + return TRUE; + } + + sprintf(temp, "%s/%s.asc", CFG.bbs_txtfiles, CFG.sNuScreen); + if(( pTextFileASC = fopen(temp, "w")) == NULL) { + perror(""); + WriteError("NextUser: Can't open file: %s", temp); + return TRUE; + } + + fprintf(pTextFileANS,"%s%s%s%s",ANSI_CLEAR,ANSI_NORMAL,ANSI_WHITE,ANSI_BOLD); + + if((iStrLen = strlen(sFrom)) > 1) { + fprintf(pTextFileANS,"%s\x1B[1;4HFrom:%s %s\n",ANSI_RED,ANSI_BLUE,sFrom); + fprintf(pTextFileASC,"\n From: %s\n", sFrom); + Syslog('+', " From: %s", sFrom); + NLChk = TRUE; + } + + if((iStrLen = strlen(To)) > 1) { + fprintf(pTextFileANS,"%s\x1B[2;6HTo:%s %s\n",ANSI_RED,ANSI_BLUE,To); + fprintf(pTextFileASC," To: %s\n", To); + Syslog('+', " To: %s", To); + NLChk = TRUE; + } + + if((iStrLen = strlen(Subject)) > 1) { + fprintf(pTextFileANS,"%sSubject:%s %s\n\n",ANSI_RED,ANSI_BLUE,Subject); + fprintf(pTextFileASC,"Subject: %s\n\n", Subject); + Syslog('+', "Subject: %s", Subject); + NLChk = TRUE; + } + + if(!NLChk) { + fprintf(pTextFileANS, "\n"); + fprintf(pTextFileASC, "\n"); + } + + fprintf(pTextFileANS,"%sÕ",ANSI_YELLOW); + for(iLoop = 0; iLoop <= 75; iLoop++) { + fprintf(pTextFileANS,"Í"); + fprintf(pTextFileASC,"="); + } + fprintf(pTextFileANS,"¸\n"); + fprintf(pTextFileASC,"\n"); + + for(i = 0; i < iLine; i++) { + if((iStrLen = strlen( *(sLiNE + i) )) > 0) { + fprintf(pTextFileANS," %s%s\n",ANSI_BLUE, *(sLiNE + i)); + fprintf(pTextFileASC," %s\n", *(sLiNE + i)); + } + } + + Enter(2); + pout(12, 0, (char *) Language(340)); + fprintf(pTextFileANS,"%sÔ",ANSI_YELLOW); + for(iLoop = 0; iLoop <= 75; iLoop++) { + fprintf(pTextFileANS,"Í"); + fprintf(pTextFileASC,"="); + } + fprintf(pTextFileANS,"¾\n"); + fprintf(pTextFileASC,"\n"); + + fprintf(pTextFileANS,"%s%s",ANSI_RED,CFG.sNuQuote); + fprintf(pTextFileASC,"%s", CFG.sNuQuote); + + fclose(pTextFileANS); + fclose(pTextFileASC); + colour(9, 0); + /* Returning to */ + printf("\n%s%s\n", (char *) Language(117), CFG.bbs_name); + + Syslog('+', "User Saved Nextuser message and exited door"); + free(temp); + free(temp1); + return TRUE; + } else + + if (i == Keystroke(114, 1)) { + /* Edit which line: */ + colour(15, 0); + printf("\n%s", (char *) Language(118)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + i = atoi(temp); + + if( i > iLine - 1) { + /* Line does not exist. */ + printf("\n%s", (char *) Language(119)); + break; + } + + Enter(1); + /* Line reads: */ + colour(15, 0); + poutCR(15, 0, (char *) Language(186)); + printf("%2d: %s\n", i, *(sLiNE + i)); + + Enter(1); + /* Text to replace: */ + pout(15, 0, (char *) Language(195)); + GetstrC(temp, 80); + + if((strcmp(temp, "")) == 0) + break; + + /* Replacement text: */ + pout(15, 0, (char *) Language(196)); + GetstrC(temp1, 80); + + if((strcmp(temp1, "")) == 0) + break; + + strreplace(*(sLiNE + i), temp, temp1); + } else + printf("\n"); + } + free(temp); + free(temp1); + return FALSE; +} + diff --git a/mbsebbs/nextuser.h b/mbsebbs/nextuser.h new file mode 100644 index 00000000..24903597 --- /dev/null +++ b/mbsebbs/nextuser.h @@ -0,0 +1,7 @@ +#ifndef _NEXTUSER_H +#define _NEXTUSER_H + +void nextuser(void); + +#endif + diff --git a/mbsebbs/offline.c b/mbsebbs/offline.c new file mode 100644 index 00000000..6d1581e1 --- /dev/null +++ b/mbsebbs/offline.c @@ -0,0 +1,2910 @@ +/***************************************************************************** + * + * File ..................: bbs/offline.c + * Purpose ...............: Offline Reader + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/mbse.h" +#include "../lib/records.h" +#ifndef BIG_ENDIAN +#define BIG_ENDIAN +#endif +#include "../lib/bluewave.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "mail.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" +#include "file.h" +#include "filesub.h" +#include "exitinfo.h" +#include "timeout.h" +#include "msgutil.h" +#include "pop3.h" +#include "offline.h" + + + +long Total, TotalPersonal, Current, Personal; +unsigned long TotalPack; +unsigned short BarWidth; +lastread LR; +static char TempStr[128]; +extern int do_mailout; + + +typedef struct _msg_high { + struct _msg_high *next; + unsigned long Area; + unsigned long LastMsg; + unsigned long Personal; +} msg_high; + + + +/* + * Internal prototypes. + */ +void AddArc(char *, char *); +void tidy_high(msg_high **); +void fill_high(msg_high **, unsigned long, unsigned long, unsigned long); +void UpdateLR(msg_high *, FILE *); +void Add_Kludges(fidoaddr, int, char *); +int OLR_Prescan(void); +void DrawBar(char *); +unsigned long BlueWave_PackArea(unsigned long, long); +void BlueWave_Fetch(void); +unsigned long QWK_PackArea(unsigned long, long); +void QWK_Fetch(void); +float IEEToMSBIN(float); +float MSBINToIEE(float); +char *StripSpaces(char *, int); +unsigned long ASCII_PackArea(unsigned long, long); + + + +/**************************************************************************** + * + * Global Functions + */ + + +void AddArc(char *Temp, char *Pktname) +{ + execute((char *)archiver.marc, Pktname, Temp, (char *)"/dev/null", (char *)"/dev/null", (char *)"/dev/null"); + unlink(Temp); + printf("."); + fflush(stdout); +} + + + +void tidy_high(msg_high **hdp) +{ + msg_high *tmp, *old; + + for (tmp = *hdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *hdp = NULL; +} + + + +/* + * Add an area to the array + */ +void fill_high(msg_high **hdp, unsigned long Area, unsigned long Last, unsigned long Pers) +{ + msg_high *tmp; + + Syslog('M', "fill_high Area %lu Msg %lu, Pers %lu", Area, Last, Pers); + + tmp = (msg_high *)malloc(sizeof(msg_high)); + tmp->next = *hdp; + tmp->Area = Area; + tmp->LastMsg = Last; + tmp->Personal = Pers; + *hdp = tmp; +} + + + +void UpdateLR(msg_high *mhl, FILE *mf) +{ + char *p; + msg_high *tmp; + + colour(14, 0); + /* Updating lastread pointer */ + printf("%s\n", (char *)Language(449)); + colour(13, 0); + + for (tmp = mhl; tmp; tmp = tmp->next) { + printf("."); + fflush(stdout); + fseek(mf, ((tmp->Area -1) * (msgshdr.recsize + msgshdr.syssize)) + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + if (Msg_Open(msgs.Base)) { + if (Msg_Lock(30L)) { + if (tmp->Personal) + Syslog('?', "Personal messages to update"); + + LR.UserID = grecno; + p = xstrcpy(exitinfo.sUserName); + if (Msg_GetLastRead(&LR) == TRUE) { + LR.LastReadMsg = tmp->LastMsg; + if (tmp->LastMsg > LR.HighReadMsg) + LR.HighReadMsg = tmp->LastMsg; + if (LR.HighReadMsg > Msg_Highest()) { + Syslog('?', "Highread was too high"); + LR.HighReadMsg = Msg_Highest(); + } + LR.UserCRC = StringCRC32(tl(p)); + if (!Msg_SetLastRead(LR)) + WriteError("Error update lastread"); + } else { + /* + * Append new lastread pointer + */ + LR.UserCRC = StringCRC32(tl(p)); + LR.UserID = grecno; + LR.LastReadMsg = tmp->LastMsg; + LR.HighReadMsg = tmp->LastMsg; + if (!Msg_NewLastRead(LR)) + WriteError("Can't append new lastread"); + } + free(p); + Msg_UnLock(); + } + Msg_Close(); + } + } +} + + + +/* + * Add message kludges at the start, append the message text and add + * trailing kludges, tearline and originline. + */ +void Add_Kludges(fidoaddr dest, int IsReply, char *fn) +{ + char *temp, *aka; + FILE *tp; + + temp = calloc(2048, sizeof(char)); + aka = calloc(81, sizeof(char)); + + Add_Headkludges(fido2faddr(dest), IsReply); + Syslog('m', "Kludges done, start textfile %s", fn); + + if ((tp = fopen(fn, "r")) != NULL) { + Msg_Write(tp); + fclose(tp); + } + + Syslog('m', "Add footer"); + Add_Footkludges(FALSE); + + Syslog('m', "Add message now"); + Msg_AddMsg(); + Syslog('m', "Msg added"); + + free(aka); + free(temp); +} + + + +/**************************************************************************** + * + * Offline Configuration + */ + + +/* + * Tag areas, called from menu. + */ +void OLR_TagArea() +{ + char *Msgname, *Tagname; + FILE *ma, *tf; + char *buf; + long total, Offset, Area; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Msgname = calloc(PATH_MAX, sizeof(char)); + Tagname = calloc(PATH_MAX, sizeof(char)); + buf = calloc(81, sizeof(char)); + + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + + clear(); + colour(14, 0); + /* Tag Offline Reader message areas */ + printf("%s\n", (char *)Language(66)); + + do { + colour(15, 0); + /* Enter the name of the conference, or ? for a list: */ + printf("\n%s", (char *)Language(228)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(buf, 20); + + if (buf[0] == '?') { + maxlines = lines = exitinfo.iScreenLen - 1; + colour(11, 0); + /* Conference Area Msgs Description */ + printf("%s\n", (char *)Language(229)); + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + if ((tf = fopen(Tagname, "r")) != NULL) { + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + colour(3, 0); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + (!olrtagrec.Tagged) && strlen(msgs.QWKname)) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + } + } + fclose(tf); + } + fclose(ma); + } + } else + if (buf[0] != '\0') { + if (atoi(buf) != 0) { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Offset = msgshdr.hdrsize + ((atoi(buf)-1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(ma, Offset, SEEK_SET); + if (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (atoi(buf)-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (!olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Tagged %d %s", + atoi(buf), msgs.QWKname); + } + fclose(tf); + } + } + } + fclose(ma); + } + } else { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + Area++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if (strcasecmp(msgs.QWKname, buf) == 0) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (Area-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (!olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Tagged %d %s", + Area, msgs.QWKname); + } + fclose(tf); + } + } + } + } + fclose(ma); + } + } + } + + } while (buf[0] != '\0'); + + free(buf); + free(Tagname); + free(Msgname); +} + + + +/* + * Untag areas, called from menu. + */ +void OLR_UntagArea() +{ + char *Msgname, *Tagname, *buf; + FILE *ma, *tf; + long total, Offset, Area; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Msgname = calloc(PATH_MAX, sizeof(char)); + Tagname = calloc(PATH_MAX, sizeof(char)); + buf = calloc(81, sizeof(char)); + + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + + clear(); + colour(14, 0); + /* Untag Offline Reader message areas */ + printf("%s\n", (char *)Language(256)); + + do { + colour(15, 0); + /* Enter the name of the conference, or ? for a list: */ + printf("\n%s", (char *)Language(228)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(buf, 20); + + if (buf[0] == '?') { + maxlines = lines = exitinfo.iScreenLen - 1; + colour(11, 0); + /* Conference Area Msgs Description */ + printf("%s\n", (char *)Language(229)); + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + if ((tf = fopen(Tagname, "r")) != NULL) { + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + colour(3, 0); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + olrtagrec.Tagged && strlen(msgs.QWKname)) { + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + } + } + fclose(tf); + } + fclose(ma); + } + } else + if (buf[0] != '\0') { + if (atoi(buf) != 0) { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Offset = msgshdr.hdrsize + ((atoi(buf)-1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(ma, Offset, SEEK_SET); + if (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (atoi(buf)-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (olrtagrec.Tagged) { + if (msgs.OLR_Forced) { + printf("Area cannot be switched off\n"); + } else { + olrtagrec.Tagged = FALSE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Untagged %d %s", + atoi(buf), msgs.QWKname); + } + } + fclose(tf); + } + } + } + fclose(ma); + } + } else { + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + Area++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname)) { + if (strcasecmp(msgs.QWKname, buf) == 0) { + if ((tf = fopen(Tagname, "r+")) != NULL) { + fseek(tf, (Area-1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + if (olrtagrec.Tagged) { + if (msgs.OLR_Forced) { + printf("Area cannot be switched off\n"); + } else { + olrtagrec.Tagged = FALSE; + fseek(tf, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, tf); + Syslog('+', "OLR Untagged %d %s", + Area, msgs.QWKname); + } + } + fclose(tf); + } + } + } + } + fclose(ma); + } + } + } + + } while (buf[0] != '\0'); + + free(buf); + free(Tagname); + free(Msgname); +} + + + +void New_Hdr(void); +void New_Hdr() +{ + char *temp; + + temp = calloc(81, sizeof(char)); + clear(); + colour(14, 0); + /* New or deleted mail areas at */ + sprintf(temp, "%s%s", (char *) Language(364), CFG.bbs_name); + Center(temp); + free(temp); + printf("\n"); + colour(15, 1); + /* Area State Type Description */ + printf("%-79s\n", (char *) Language(365)); +} + + + +void New_Area(long); +void New_Area(long Area) +{ + colour(11, 0); + /* New */ + printf("%4ld %s", Area, (char *)Language(391)); + switch (msgs.Type) { + case LOCALMAIL: printf(Language(392)); /* Local */ + break; + case NETMAIL: printf(Language(393)); /* Netmail */ + break; + case ECHOMAIL: printf(Language(394)); /* Echomail */ + break; + case NEWS: printf(Language(395)); /* News */ + break; + } + printf("%s\n", msgs.Name); +} + + + +void Old_Area(long); +void Old_Area(long Area) +{ + colour(12, 0); + /* Del */ + printf("%4ld %s\n", Area, (char *)Language(397)); +} + + + +/* + * Sync tagged areas file. If CFG.NewAreas is on then we show the + * changed areas to the user. This one is called by user.c during login. + */ +void OLR_SyncTags() +{ + char *Tagname, *Msgname; + FILE *fp, *ma; + long Area; + int Changed = FALSE; + + Tagname = calloc(PATH_MAX, sizeof(char)); + Msgname = calloc(PATH_MAX, sizeof(char)); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(Tagname, "r+")) == NULL) { + + /* + * If the user has no .olrtagsfile yet, we silently create + * a new one. The user will not be notified of new areas + * of coarse. + */ + Syslog('m', "Creating %s", Tagname); + if ((fp = fopen(Tagname, "w")) != NULL) { + + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + memset(&olrtagrec, 0, sizeof(olrtagrec)); + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec)) { + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + } + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + fseek(ma, msgshdr.syssize, SEEK_CUR); + } + + fclose(ma); + } + } + } else { + /* + * The user has been here before... + */ + if ((ma = fopen(Msgname, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, ma); + Area = 0; + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + Area++; + + if (fread(&olrtagrec, sizeof(olrtagrec), 1, fp) == 1) { + + /* + * Check if this is a new area for the user. + */ + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec) && (!olrtagrec.Available)) { + Syslog('m', "New msg area %ld %s", Area, msgs.Name); + fseek(fp, - sizeof(olrtagrec), SEEK_CUR); + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + New_Area(Area); + } + } else { + /* + * Check if this area is no longer + * available for the user. + */ + if (((!msgs.Active) || (!Access(exitinfo.Security, msgs.RDSec))) && + olrtagrec.Available) { + Syslog('m', "Deleted msg area %ld", Area); + fseek(fp, - sizeof(olrtagrec), SEEK_CUR); + olrtagrec.Available = FALSE; + olrtagrec.ScanNew = FALSE; + olrtagrec.Tagged = FALSE; + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + Old_Area(Area); + } + } + } + + } else { + /* + * If the number if msg areas was increased, + * append a new tagrecord. + */ + memset(&olrtagrec, 0, sizeof(olrtagrec)); + if ((msgs.Active) && Access(exitinfo.Security, msgs.RDSec)) { + Syslog('m', "Append new area %ld %s", Area, msgs.Name); + olrtagrec.Available = TRUE; + olrtagrec.ScanNew = TRUE; + if (msgs.OLR_Forced || msgs.OLR_Default) + olrtagrec.Tagged = TRUE; + if (CFG.NewAreas) { + if (!Changed) { + New_Hdr(); + Changed = TRUE; + } + New_Area(Area); + } + } + fwrite(&olrtagrec, sizeof(olrtagrec), 1, fp); + } + fseek(ma, msgshdr.syssize, SEEK_CUR); + } + + fclose(ma); + } + } + + fclose(fp); + + if (Changed) { + colour(10, 0); + fLine(79); + Pause(); + } + + SetMsgArea(exitinfo.iLastMsgArea); + free(Tagname); + free(Msgname); +} + + + +/* + * View tagged areas, called from menu. + */ +void OLR_ViewTags() +{ + char *Tagname, *Msgname; + FILE *tf, *ma; + long total, Area = 0; + int lines, input, ignore = FALSE, maxlines; + + WhosDoingWhat(OLR); + + Tagname = calloc(PATH_MAX, sizeof(char)); + Msgname = calloc(PATH_MAX, sizeof(char)); + sprintf(Tagname, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + sprintf(Msgname, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + + if ((tf = fopen(Tagname, "r")) == NULL) { + WriteError("$Can't open %s", Tagname); + return; + } + + if ((ma = fopen(Msgname, "r")) == NULL) { + WriteError("$Can't open %s", Msgname); + fclose(tf); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, ma); + + clear(); + colour(14, 0); + /* You have selected the following Conference(s): */ + printf ("%s\n", (char *)Language(260)); + colour(11, 0); + /* Conference Area Msgs Description */ + printf ("\n%s\n", (char *)Language(229)); + colour(3, 0); + fflush(stdout); + maxlines = lines = exitinfo.iScreenLen - 1; + + while (fread(&msgs, msgshdr.recsize, 1, ma) == 1) { + fseek(ma, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + total = Msg_Number(); + Msg_Close(); + } else + total = 0; + if ( (lines != 0) || (ignore) ) { + lines--; + printf("%-20.20s %-5ld %-5ld %s\n", msgs.QWKname, Area, total, msgs.Name); + } + if (lines == 0) { + fflush(stdin); + colour(15, 0); + /* More (Y/n/=) */ + printf("%s%c\x08", (char *) Language(61),Keystroke(61,0)); + fflush(stdout); + alarm_on(); + input = toupper(Getone()); + printf("%c\r",input); + if ((input == Keystroke(61, 0)) || (input == '\r')) + lines = maxlines; + + if (input == Keystroke(61, 1)) { + break; + } + if (input == Keystroke(61, 2)) + ignore = TRUE; + else + lines = maxlines; + colour(3, 0); + } + fflush(stdout); + } + } + + fclose(tf); + fclose(ma); + Pause(); + free(Tagname); + free(Msgname); +} + + + +/* + * Prescan all selected areas. Show the user the areas and messages in it. + */ +int OLR_Prescan() +{ + unsigned short RetVal = FALSE, Areas; + unsigned long Number; + char *Temp; + FILE *mf, *tf; + int x; + + WhosDoingWhat(OLR); + clear(); + colour(13, 0); + /* Offline Reader Download */ + printf("%s\n\n", (char *)Language(277)); + fflush(stdout); + + if (exitinfo.Email) + check_popmail(exitinfo.Name, exitinfo.Password); + + Temp = calloc(PATH_MAX, sizeof(char)); + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + mf = fopen(Temp, "r"); + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + tf = fopen(Temp, "r"); + Total = TotalPersonal = Areas = 0; + + colour(15, 1); + /* Forum Description Msgs. Pers. */ + printf("\n%s\n", (char *)Language(297)); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname) && olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Areas++; + Current = Personal = 0; + colour(11, 0); + printf("%-20.20s %-41.41s ", msgs.QWKname, msgs.Name); + fflush(stdout); + + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Number = LR.HighReadMsg; + else + Number = Msg_Lowest() -1; + if (Number > Msg_Highest()) + Number = Msg_Highest(); + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Current++; + Total++; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Current--; + Total--; + } + } while (Msg_Next(&Number)); + } + + colour(10, 0); + printf("%5lu %5lu\n", Current, Personal); + fflush(stdout); + Msg_Close(); + } + } + } + + Syslog('+', "OLR Prescan: %u Areas, %lu Messages", Areas, Total); + + colour(9, 0); + /* Total messages found: */ + printf("\n%s %lu\n\n", (char *)Language(338), Total); + if (Total == 0L) { + colour(14, 0); + /* No messages found to download! */ + printf("%s\n\007", (char *)Language(374)); + Pause(); + } else { + if (CFG.OLR_MaxMsgs != 0 && Total > CFG.OLR_MaxMsgs) { + /* Too much messages. Only the first will be packed! */ + printf("%s %d %s\n\n\007", (char *)Language(377), CFG.OLR_MaxMsgs, (char *)Language(411)); + Total = CFG.OLR_MaxMsgs; + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Do you want to download these messages [Y/n]? */ + printf("%s", (char *)Language(425)); + fflush(stdout); + alarm_on(); + x = toupper(Getone()); + + if (x != Keystroke(425, 1)) { + RetVal = TRUE; + TotalPack = Total; + BarWidth = 0; + } + } + + if (mf != NULL) + fclose(mf); + if (tf != NULL) + fclose(tf); + + free(Temp); + return(RetVal); +} + + + +/* + * Draw progess bar + */ +void DrawBar(char *Pktname) +{ + colour(14, 0); + /* Preparing packet */ + printf("\n%s %s...\n\n", (char *)Language(445), Pktname); + colour(10, 0); + printf("0%% 10%% 20%% 30%% 40%% 50%% 60%% 70%% 80%% 90%% 100%%\n"); + printf("|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\r"); + fflush(stdout); +} + + + +void OLR_RestrictDate() +{ + WhosDoingWhat(OLR); + + printf("Not Yet Implemented\n"); + Pause(); +} + + +/* +VOID TOffline::RestrictDate (VOID) +{ + int dd, mm, yy; + CHAR Temp[32]; + ULONG Restrict; + struct tm ltm; + class TMsgTag *MsgTag = User->MsgTag; + + memcpy (<m, localtime ((time_t *)&User->LastCall), sizeof (struct tm)); + Embedded->Printf ("\n\026\001\017Enter date of oldest message to pack, or press for %d-%02d-%d: ", ltm.tm_mday, ltm.tm_mon + 1, ltm.tm_year % 100); + Embedded->Input (Temp, 10); + + if (Embedded->AbortSession () == FALSE) { + Restrict = User->LastCall; + if (Temp[0] != '\0') { + sscanf (Temp, "%d-%d-%d", &dd, &mm, &yy); + if (yy < 90) + yy += 100; + memset (<m, 0, sizeof (struct tm)); + ltm.tm_mday = dd; + ltm.tm_mon = mm - 1; + ltm.tm_year = yy; + Restrict = mktime (<m); + } + + if (MsgTag->First () == TRUE) + do { + if (MsgTag->Tagged == TRUE) { + MsgTag->LastRead = 0L; + MsgTag->OlderMsg = Restrict; + MsgTag->Update (); + } + } while (MsgTag->Next () == TRUE); + } +} +*/ + +/* +USHORT TOffline::TooOld (ULONG Restrict, class TMsgBase *Msg) +{ + USHORT RetVal = FALSE; + struct tm ltm; + + memset (<m, 0, sizeof (struct tm)); + ltm.tm_mday = Msg->Written.Day; + ltm.tm_mon = Msg->Written.Month - 1; + ltm.tm_year = Msg->Written.Year - 1900; + if (mktime (<m) < Restrict) + RetVal = TRUE; + + return (RetVal); +} +*/ + + + +/* + * Upload offline mail. Filenames: BBSID.NEW or BBSID.REP. + * Should also do hhhhhhhh.SU0 for point uploads. + * NOTE: THE FIRST PART OF THE CODE IS FROM UPLOAD_HOME + */ +void OLR_Upload(void) +{ + char *File, *temp, *Arc; + time_t ElapstimeStart, ElapstimeFin, iTime; + int err, Strlen, RetVal = FALSE; + struct stat statbuf; + FILE *fp; + + WhosDoingWhat(OLR); + clear(); + colour(13, 0); + /* Offline Reader Upload */ + printf("%s\n", (char *)Language(439)); + + if (!ForceProtocol()) + return; + + File = calloc(PATH_MAX, sizeof(char)); + temp = calloc(PATH_MAX, sizeof(char)); + + if (!uProtBatch) { + Enter(1); + /* Please enter file to upload: */ + pout(14, 0, (char *) Language(276)); + + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(File, 80); + + Syslog('+', "Filename entered \"%s\"", File); + + if ((strcmp(File, "")) == 0) + return; + + if (File[0] == '.' || File[0] == '*' || File[0] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + + Strlen = strlen(File); + Strlen--; + + if (File[Strlen] == '.' || File[Strlen] == '/' || File[Strlen] == ' ') { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal Filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + + if (strncasecmp(File, CFG.bbsid, strlen(CFG.bbsid))) { + colour(CFG.HiliteF, CFG.HiliteB); + /* Illegal filename! */ + printf("\n%s\n\n", (char *) Language(247)); + Pause(); + return; + } + Syslog('+', "Filename accepted"); + } + + colour(CFG.HiliteF, CFG.HiliteB); + /* Please start your upload now */ + printf("\n%s, %s\n\n", sProtAdvice, (char *) Language(283)); + if (uProtBatch) + Syslog('+', "Upload using %s", sProtName); + else + Syslog('+', "Upload \"%s\" using %s", File, sProtName); + + sprintf(temp, "%s/%s/upl", CFG.bbs_usersdir, exitinfo.Name); + + if (chdir(temp)) { + WriteError("$Can't chdir to %s", temp); + return; + } + + sprintf(temp, "%s", sProtUp); + Syslog('+', "Upload command %s", temp); + fflush(stdout); + fflush(stdin); + sleep(2); + time(&ElapstimeStart); + + /* + * Get the file + */ + Altime(7200); + alarm_set(7190); + if ((err = system(temp)) != 0) { + colour(CFG.HiliteF, CFG.HiliteB); + WriteError("$Upload error %d, prot: %s", err, sProtUp); + } + Altime(0); + alarm_off(); + alarm_on(); + printf("\n"); + fflush(stdout); + fflush(stdin); + time(&ElapstimeFin); + + /* + * Get the upload time. + */ + iTime = ElapstimeFin - ElapstimeStart; + if (!iTime) + iTime = 1; + + Syslog('m', "Transfer time %ld", iTime); + Home(); + + if (!RetVal) { + sprintf(File, "%s/%s/upl/%s.NEW", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + File = tl(File); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + sprintf(File, "%s/%s/upl/%s.REP", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (!RetVal) { + File = tl(File); + Syslog('m', "Check %s", File); + if (stat(File, &statbuf) == 0) + RetVal = TRUE; + } + + if (RetVal == FALSE) { + WriteError("Invalid OLR packed received"); + /* Invalid packet received */ + printf("%s\n\n", (char *)Language(440)); + sleep(2); + return; + } + Syslog('+', "Received OLR packet %s", File); + + if ((Arc = GetFileType(File)) == NULL) { + /* Unknown compression type */ + printf("%s\n", (char *)Language(441)); + Syslog('+', "Unknown compression type"); + Pause(); + return; + } + + Syslog('m', "File type is %s", Arc); + + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) + return; + + fread(&archiverhdr, sizeof(archiverhdr), 1, fp); + + while (fread(&archiver, archiverhdr.recsize, 1, fp) == 1) { + if ((strcmp(Arc, archiver.name) == 0) && archiver.available) + break; + } + fclose(fp); + + if (strcmp(Arc, archiver.name) || (!archiver.available)) { + Syslog('+', "Archiver %s not available", Arc); + /* Archiver not available */ + printf("%s\n", (char *)Language(442)); + Pause(); + return; + } + + Syslog('m', "Archiver %s", archiver.comment); + + colour(CFG.TextColourF, CFG.TextColourB); + /* Unpacking archive */ + printf("%s ", (char *) Language(201)); + fflush(stdout); + sprintf(temp, "%s %s", archiver.funarc, File); + Syslog('m', "Unarc %s", temp); + colour(CFG.HiliteF, CFG.HiliteB); + + if ((err = system(temp))) { + WriteError("$Failed %s", temp); + /* ERROR */ + printf("%s\n", (char *) Language(217)); + fflush(stdout); + Pause(); + return; + } + + /* Ok */ + printf("%s\n", (char *) Language(200)); + fflush(stdout); + unlink(File); + + /* + * Check for BlueWave files, upper and lowercase. + */ + RetVal = FALSE; + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.REQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + sprintf(temp, "%s/%s/%s.OLC", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + if (RetVal) { + Syslog('+', "OLR packet is BlueWave"); + free(File); + free(temp); + BlueWave_Fetch(); + return; + } + + sprintf(temp, "%s/%s/%s.MSG", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + temp = tl(temp); + if (!file_exist(temp, R_OK)) + RetVal = TRUE; + + if (RetVal) { + Syslog('+', "OLR packet is QWK"); + free(File); + free(temp); + QWK_Fetch(); + return; + } + + WriteError("OLR_Upload: Garbage in mailpacket, clean directory!"); + /* Unknown type mailpacket */ + printf("%s\n", (char *)Language(443)); + Pause(); + free(File); + free(temp); +} + + + +/*************************************************************************** + * + * BlueWave specific functions. + */ + + +char *Extensions[] = { + (char *)".SU0", (char *)".MO0", (char *)".TU0", (char *)".WE0", + (char *)".TH0", (char *)".FR0", (char *)".SA0" +}; + + + +/* + * Download a BlueWave mailpacket, called from menu. + */ +void OLR_DownBW() +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + char *Work, *Temp; + long Area = 0; + int RetVal = FALSE, rc; + FILE *fp, *tf, *mf, *af; + INF_HEADER Inf; + INF_AREA_INFO AreaInf; + unsigned long Start, High; + msg_high *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0; + clear(); + colour(9, 0); + /* BlueWave Offline download */ + printf("%s\n", (char *)Language(444)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing BlueWave packet"); + + sprintf(Pktname, "%s%s", CFG.bbsid , Extensions[tp->tm_wday]); + Syslog('m', "Packet name %s", Pktname); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + Syslog('m', "Work path %s", Work); + + sprintf(Temp, "%s/%s.INF", Work, CFG.bbsid); + if ((fp = fopen(Temp, "w+")) == NULL) { + WriteError("$Can't create %s", Temp); + return; + } + + /* + * Write the info header. + */ + memset(&Inf, 0, sizeof(Inf)); + Inf.ver = PACKET_LEVEL; + strcpy((char *)Inf.loginname, exitinfo.sUserName); + strcpy((char *)Inf.aliasname, exitinfo.sHandle); + Inf.zone = CFG.aka[0].zone; + Inf.net = CFG.aka[0].net; + Inf.node = CFG.aka[0].node; + Inf.point = CFG.aka[0].point; + strcpy((char *)Inf.sysop, CFG.sysop_name); + strcpy((char *)Inf.systemname, CFG.bbs_name); + Inf.maxfreqs = CFG.OLR_MaxReq; + if (exitinfo.HotKeys) + Inf.uflags |= INF_HOTKEYS; + if (exitinfo.GraphMode) + Inf.uflags |= INF_GRAPHICS; + if (exitinfo.OL_ExtInfo) + Inf.uflags |= INF_EXT_INFO; + Inf.credits = exitinfo.Credit; + Inf.inf_header_len = sizeof(INF_HEADER); + Inf.inf_areainfo_len = sizeof(INF_AREA_INFO); + Inf.mix_structlen = sizeof(MIX_REC); + Inf.fti_structlen = sizeof(FTI_REC); + Inf.uses_upl_file = TRUE; + Inf.can_forward = TRUE; + strcpy((char *)Inf.packet_id, CFG.bbsid); + fwrite(&Inf, sizeof(INF_HEADER), 1, fp); + + /* + * Check to see if this stuff is compiled packed. If not the + * download packet is useless. + */ + if ((sizeof(Inf) != ORIGINAL_INF_HEADER_LEN) || + (sizeof(AreaInf) != ORIGINAL_INF_AREA_LEN)) { + WriteError("PANIC: Probably not \"packed\" compiled!"); + fclose(fp); + return; + } + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + /* + * Write the areas information + */ + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec)) { + memset(&AreaInf, 0, sizeof(AreaInf)); + sprintf((char *)AreaInf.areanum, "%lu", Area); + strcpy((char *)AreaInf.echotag, msgs.QWKname); + strcpy((char *)AreaInf.title, msgs.Name); + if (olrtagrec.Tagged) { + AreaInf.area_flags |= INF_SCANNING; + RetVal = TRUE; + } + + switch(msgs.Type) { + case LOCALMAIL: + break; + + case NETMAIL: AreaInf.area_flags |= (INF_ECHO+INF_NETMAIL+INF_HASFILE); + break; + + case ECHOMAIL: AreaInf.area_flags |= INF_ECHO; + break; + +// case EMAIL: AreaInf.area_flags |= (INF_ECHO+INF_NETMAIL); +// AreaInf.network_type |= INF_NET_INTERNET; +// break; + + case NEWS: AreaInf.area_flags |= INF_ECHO; + AreaInf.network_type |= INF_NET_INTERNET; + break; + } + switch(msgs.MsgKinds) { + case BOTH: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + break; + + case PRIVATE: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + AreaInf.area_flags |= INF_NO_PUBLIC; + break; + + case PUBLIC: if (Access(exitinfo.Security, msgs.WRSec)) + AreaInf.area_flags |= INF_POST; + AreaInf.area_flags |= INF_NO_PRIVATE; + break; + + case RONLY: break; + } + + if (msgs.Aliases) + AreaInf.area_flags |= INF_ALIAS_NAME; + + fwrite(&AreaInf, sizeof(AreaInf), 1, fp); + } + } + fclose(fp); + + if (RetVal) { + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + Syslog('m', "First %lu, Last %lu, Start %lu", Msg_Lowest(), Msg_Highest(), Start); + High = BlueWave_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + Syslog('+', "Packed %ld messages (%ld personal)", Total, TotalPersonal); + } + fclose(tf); + + rc = FALSE; + alarm_on(); + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + sprintf(Temp, "%s/%s.DAT", Work, CFG.bbsid); + AddArc(Temp, Pktname); + alarm_on(); + sprintf(Temp, "%s/%s.FTI", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s.INF", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s.MIX", Work, CFG.bbsid); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + Syslog('m', "Download result %d", rc); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "BlueWave download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "BlueWave download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + + fclose(mf); + tidy_high(&mhl); + + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * BlueWave Fetch reply packet. + */ +void BlueWave_Fetch() +{ + char *temp; + FILE *up, *mf, *tp; + UPL_HEADER Uph; + UPL_REC Upr; + PDQ_HEADER Pdh; + PDQ_REC Pdr; + REQ_REC Req; + int i, Found; + fidoaddr dest; + + colour(9, 0); + /* Processing BlueWave reply packet */ + printf("%s\n", (char *)Language(450)); + temp = calloc(PATH_MAX, sizeof(char)); + + /* + * Process uploaded mail + */ + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + fread(&Uph, sizeof(UPL_HEADER), 1, up); + Syslog('+', "Processing BlueWave .UPL file"); + Syslog('+', "Client: %s %d.%d", Uph.reader_name, Uph.reader_major, Uph.reader_minor); + if (Uph.upl_header_len != sizeof(UPL_HEADER)) { + WriteError("Recordsize mismatch"); + fclose(up); + /* ERROR in packet */ + printf("%s\n", (char *)Language(451)); + Pause(); + return; + } + Syslog('+', "Login %s, Alias %s", Uph.loginname, Uph.aliasname); + /* MORE CHECKS HERE */ + + colour(CFG.TextColourF, CFG.TextColourB); + /* Import messages */ + printf("%s ", (char *)Language(452)); + colour(CFG.HiliteF, CFG.HiliteB); + fflush(stdout); + i = 0; + + memset(&Upr, 0, sizeof(UPL_REC)); + while (fread(&Upr, Uph.upl_rec_len, 1, up) == 1) { + printf("."); + fflush(stdout); + Syslog('m', " From : %s", Upr.from); + Syslog('m', " To : %s", Upr.to); + Syslog('m', " Subj : %s", Upr.subj); + Syslog('m', " Date : %ld", Upr.unix_date); + Syslog('m', " Dest : %d:%d/%d.%d", Upr.destzone, Upr.destnet, Upr.destnode, Upr.destpoint); + if (Upr.msg_attr & UPL_INACTIVE) + Syslog('m', " Message is Inactive"); + if (Upr.msg_attr & UPL_PRIVATE) + Syslog('m', " Message is Private"); + if (Upr.msg_attr & UPL_HAS_FILE) + Syslog('m', " File Attach"); + if (Upr.msg_attr & UPL_NETMAIL) + Syslog('m', " Is Netmail"); + if (Upr.msg_attr & UPL_IS_REPLY) + Syslog('m', " Is Reply"); + if (Upr.network_type) + Syslog('m', " Type : Internet"); + else + Syslog('m', " Type : Fidonet"); + Syslog('m', " File : %s", Upr.filename); + Syslog('m', " Tag : %s", Upr.echotag); + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(temp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + Found = FALSE; + + if (strlen(Upr.echotag)) { + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (msgs.Active && (strcasecmp(msgs.QWKname, Upr.echotag) == 0)) { + Found = TRUE; + break; + } + } + } else { + /* + * If there is no echotag, the filename is used + * this is "areanum.msgnum" so we pick the part + * before the dot and pray that it's ok. + */ + temp = strtok(strdup(Upr.filename), "."); + if (fseek(mf, ((atoi(temp) -1) * (msgshdr.recsize + msgshdr.syssize)) + msgshdr.hdrsize, SEEK_SET) == 0) + if (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + Found = TRUE; + fseek(mf, msgshdr.syssize, SEEK_CUR); + } + } + + /* SHOULD ALSO CHECK FROM FIELD */ + if (!Found) { + WriteError("No msg area, File \"%s\"", Upr.filename); + } else { + if ((Access(exitinfo.Security, msgs.WRSec)) && (msgs.MsgKinds != RONLY)) { + + if (Open_Msgbase(msgs.Base, 'w')) { + Msg_New(); + Syslog('m', "Msgbase open and locked"); + strcpy(Msg.From, Upr.from); + strcpy(Msg.To, Upr.to); + strcpy(Msg.Subject, Upr.subj); + if (Upr.msg_attr & UPL_PRIVATE) + Msg.Private = TRUE; + if (msgs.MsgKinds == PRIVATE) + Msg.Private = TRUE; + Msg.Written = Upr.unix_date; + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Local = TRUE; + dest.zone = Upr.destzone; + dest.net = Upr.destnet; + dest.node = Upr.destnode; + dest.point = Upr.destpoint; + Syslog('m', "Header fields are set, starting kludges"); + Add_Kludges(dest, FALSE, Upr.filename); + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %s", Msg.Id, Msg.To, Msg.Subject, msgs.QWKname); + sprintf(temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Upr.filename); + unlink(temp); + i++; + Close_Msgbase(); + Syslog('m', "Msgbase closed again"); + fseek(mf, - (msgshdr.recsize + msgshdr.syssize), SEEK_CUR); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + msgs.LastPosted = time(NULL); + fwrite(&msgs, msgshdr.recsize, 1, mf); + } + } else { + /* No Write access to area */ + printf("\n%s %s\n", (char *)Language(453), msgs.Name); + WriteError("No Write Access to area %s", msgs.Name); + } + } + fclose(mf); + } + memset(&Upr, 0, sizeof(UPL_REC)); + } + printf("\n"); + colour(CFG.TextColourF, CFG.TextColourB); + if (i) { + /* Messages imported */ + printf("%d %s\n", i, (char *)Language(454)); + ReadExitinfo(); + exitinfo.iPosted += i; + WriteExitinfo(); + do_mailout = TRUE; + } + fflush(stdout); + fclose(up); + + /* + * Remove processed files. + */ + sprintf(temp, "%s/%s/%s.UPL", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + temp = tl(temp); + unlink(temp); + } + + /* + * If a .UPL file was not found it is possible we received an version 2 + * reply packet. + */ + sprintf(temp, "%s/%s/%s.UPI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + Syslog('+', "Received Version 2 .UPI packet, not supported"); + fclose(up); + } + sprintf(temp, "%s/%s/%s.NET", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + if (up != NULL) { + Syslog('+', "Received Version 2 .NET packet, not supported"); + fclose(up); + } + + /* + * Process offline configuration + */ + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((tp = fopen(temp, "r")) == NULL) { + temp = tl(temp); + tp = fopen(temp, "r"); + } + if (tp != NULL) { + colour(9, 0); + /* Processing Offline Configuration */ + printf("%s\n", (char *)Language(455)); + Syslog('+', "Processing offline configuration"); + + fread(&Pdh, sizeof(PDQ_HEADER), 1, tp); + for (i = 0; i < 10; i++) + if (strlen(Pdh.keywords[i])) + Syslog('m', " Kwrd %2d : %s", i+1, Pdh.keywords[i]); + for (i = 0; i < 10; i++) + if (strlen(Pdh.filters[i])) + Syslog('m', " Filt %2d : %s", i+1, Pdh.filters[i]); + for (i = 0; i < 3; i++) + if (strlen(Pdh.macros[i])) + Syslog('m', " Macro %d : %s", i+1, Pdh.macros[i]); + Syslog('m', " Pwtype : %d", Pdh.passtype); + Syslog('m', " Flags : %08x", Pdh.flags); + + /* + * If the changes flag is set there are records with + * active areas. Reset all areas first and then set + * the active areas back on. + */ + if (Pdh.flags & PDQ_AREA_CHANGES) { + Syslog('m', " New Area Configuration present"); + i = 0; + + sprintf(temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((up = fopen(temp, "r+")) != NULL) { + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(temp, "r")) != NULL) { + + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + while (fread(&olrtagrec, sizeof(olrtagrec), 1, up) == 0) { + fread(&msgs, msgshdr.recsize, 1, mf); + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (!msgs.OLR_Forced) + olrtagrec.Tagged = FALSE; + fseek(up, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, up); + } + + while (fread(&Pdr, sizeof(PDQ_REC), 1, tp) == 1) { + if (strlen(Pdr.echotag)) { + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(up, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, up); + if ((strcmp(msgs.QWKname, Pdr.echotag) == 0) && + (msgs.Active) && + (Access(exitinfo.Security, msgs.RDSec))) { + Syslog('m', " Area %s", Pdr.echotag); + olrtagrec.Tagged = TRUE; + fseek(up, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, up); + i++; + break; + } + } + } + } + fclose(mf); + colour(3, 0); + /* Message areas selected */ + printf("%d %s\n", i, (char *)Language(456)); + } + fclose(up); + } + } + fclose(tp); + sprintf(temp, "%s/%s/%s.PDQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + unlink(temp); + } + + /* + * Check for .REQ file. + */ + sprintf(temp, "%s/%s/%s.REQ", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((tp = fopen(temp, "r")) == NULL) { + temp = tl(temp); + tp = fopen(temp, "r"); + } + if (tp != NULL) { + i = 0; + colour(9, 0); + /* Processing file requests */ + printf("%s\n", (char *)Language(457)); + Syslog('+', "Processing file requests"); + + while (fread(&Req, sizeof(REQ_REC), 1, tp) == 1) { + Syslog('m', " File %s", Req.filename); + colour(CFG.TextColourF, CFG.TextColourB); + printf("%-12s ", Req.filename); + colour(CFG.HiliteF, CFG.HiliteB); + fflush(stdout); + + printf("\n"); + } + + fclose(tp); + } + + free(temp); + Pause(); +} + + + +/* + * Add one area to the BlueWave download packet + */ +unsigned long BlueWave_PackArea(unsigned long ulLast, long Area) +{ + FILE *fdm, *fdfti, *fdmix; + char *Temp, *Text; + unsigned long Number; + MIX_REC Mix; + FTI_REC Fti; + struct tm *tp; + int Pack; + + Number = ulLast; + Temp = calloc(PATH_MAX, sizeof(char)); + + sprintf(Temp, "%s/%s/tmp/%s.FTI", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdfti = fopen(Temp, "a+"); + + sprintf(Temp, "%s/%s/tmp/%s.MIX", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdmix = fopen(Temp, "a+"); + + sprintf(Temp, "%s/%s/tmp/%s.DAT", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + fdm = fopen(Temp, "a+"); + + memset(&Mix, 0, sizeof(MIX_REC)); + sprintf((char *)Mix.areanum, "%lu", Area); + Mix.msghptr = ftell(fdfti); + + if ((fdfti != NULL) && (fdmix != NULL) && (fdm != NULL)) { + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if (msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if (Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + Current++; + Total++; + memset (&Fti, 0, sizeof (FTI_REC)); + + Msg.From[sizeof(Fti.from) - 1] = '\0'; + strcpy((char *)Fti.from, Msg.From); + Msg.To[sizeof(Fti.to) - 1] = '\0'; + strcpy((char *)Fti.to, Msg.To); + Msg.Subject[sizeof(Fti.subject) - 1] = '\0'; + strcpy((char *)Fti.subject, Msg.Subject); + tp = localtime(&Msg.Written); + sprintf((char *)Fti.date, "%2d %.3s %2d %2d:%02d:%02d", tp->tm_mday, + (char *) Language(398 + tp->tm_mon), tp->tm_year, + tp->tm_hour, tp->tm_min, tp->tm_sec); + Fti.msgnum = Number; + Fti.msgptr = ftell(fdm); + Fti.replyto = Msg.Original; + Fti.replyat = Msg.Reply; + if (msgs.Type == NETMAIL) { + Fti.orig_zone = msgs.Aka.zone; + Fti.orig_net = msgs.Aka.net; + Fti.orig_node = msgs.Aka.node; + } + + Fti.msglength += fwrite(" ", 1, 1, fdm); + + if ((Text = (char *)MsgText_First()) != NULL) + do { + if ((Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9))|| + (strncmp(Text, "\001MSGID", 6) == 0) /* || + (exitinfo.OL_ExtInfo) */ ) { + Fti.msglength += fwrite(Text, 1, strlen(Text), fdm); + Fti.msglength += fwrite("\r\n", 1, 2, fdm); + } + } while ((Text = (char *)MsgText_Next()) != NULL); + + fwrite(&Fti, sizeof (Fti), 1, fdfti); + } + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } while (Msg_Next(&Number)); + } + } + + Mix.totmsgs = (tWORD)Current; + Mix.numpers = (tWORD)Personal; + fwrite(&Mix, sizeof (Mix), 1, fdmix); + + if (fdfti != NULL) + fclose(fdfti); + if (fdmix != NULL) + fclose(fdmix); + if (fdm != NULL) + fclose(fdm); + + free(Temp); + return Number; +} + + + +/*********************************************************************************** + * + * QWK specific functions + * + */ + + + +void OLR_DownQWK(void) +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + long Area = 0; + char *Work, *Temp; + int i, rc = 0; + FILE *fp = NULL, *tf, *mf, *af; + unsigned long Start, High; + msg_high *tmp, *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0L; + clear(); + colour(9, 0); + /* QWK Offline Download */ + printf("%s\n", (char *)Language(458)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing QWK packet"); + + sprintf(Temp, "%s.QWK", CFG.bbsid); + sprintf(Pktname, "%s", tl(Temp)); + Syslog('m', "Packet name %s", Pktname); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + Syslog('m', "Work path %s", Work); + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + Syslog('m', "First %lu, Last %lu, Start %lu", Msg_Lowest(), Msg_Highest(), Start); + High = QWK_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + + sprintf(Temp, "%s/CONTROL.DAT", Work); + if ((fp = fopen(Temp, "w+")) != NULL) { + fprintf(fp, "%s\n", CFG.bbs_name); + fprintf(fp, "%s\n", CFG.location); + fprintf(fp, "%s\n", CFG.Phone); + fprintf(fp, "%s\n", CFG.sysop_name); + fprintf(fp, "00000,%s\n", CFG.bbsid); + + fprintf(fp, "%02d-%02d-%04d,%02d:%02d:%02d\n", tp->tm_mday, tp->tm_mon+1, tp->tm_year+1900, + tp->tm_hour, tp->tm_min, tp->tm_sec); + sprintf(Temp, "%s", exitinfo.sUserName); + fprintf(fp, "%s\n", tu(Temp)); + fprintf(fp, " \n"); + fprintf(fp, "0\n"); + fprintf(fp, "%lu\n", Total); + + /* + * Count available areas. + */ + i = 0; + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(tf, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname)) + i++; + } + fprintf(fp, "%d\n", i - 1); + + /* + * Write available areas + */ + i = 0; + fseek(mf, msgshdr.hdrsize, SEEK_SET); + fseek(tf, 0, SEEK_SET); + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + i++; + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && strlen(msgs.QWKname)) { + fprintf(fp, "%d\n%s\n", i, msgs.QWKname); + } + } + + fprintf(fp, "WELCOME\n"); + fprintf(fp, "NEWS\n"); + fprintf(fp, "GOODBYE\n"); + fclose(fp); + } + + sprintf(Temp, "%s/DOOR.ID", Work); + if ((fp = fopen(Temp, "w+")) != 0) { + fprintf(fp, "DOOR = MBSE BBS QWK\n"); + fprintf(fp, "VERSION = %s\n", VERSION); + fprintf(fp, "SYSTEM = %s\n", CFG.bbs_name); + fprintf(fp, "CONTROLNAME = MBSEQWK\n"); + fprintf(fp, "CONTROLTYPE = ADD\n"); + fprintf(fp, "CONTROLTYPE = DROP\n"); + fclose(fp); + } + + Syslog('+', "Packed %ld messages (%ld personal)", Total, TotalPersonal); + fclose(tf); + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + sprintf(Temp, "%s/CONTROL.DAT", Work); + AddArc(Temp, Pktname); + alarm_on(); + sprintf(Temp, "%s/MESSAGES.DAT", Work); + AddArc(Temp, Pktname); + + for (tmp = mhl; tmp; tmp = tmp->next) { + sprintf(Temp, "%s/%03ld.NDX", Work, tmp->Area); + AddArc(Temp, Pktname); + } + + sprintf(Temp, "%s/PERSONAL.NDX", Work); + if (TotalPersonal) { + AddArc(Temp, Pktname); + } else + unlink(Temp); + + sprintf(Temp, "%s/DOOR.ID", Work); + AddArc(Temp, Pktname); + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + Syslog('m', "Download result %d", rc); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "QWK download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "QWK download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + fclose(mf); + tidy_high(&mhl); + + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * QWK Fetch Reply packet + */ +void QWK_Fetch() +{ + char *temp, *otemp, Temp[128], szLine[132], *pLine = NULL, *pBuff; + FILE *up, *op, *mf; + unsigned short nRec, i, r, x, nCol = 0, nWidth, nReaded, nPosted = 0; + unsigned long Area; + struct tm *ltm = NULL; + fidoaddr dest; + + colour(9, 0); + /* Processing BlueWave reply packet */ + printf("%s\n", (char *)Language(459)); + temp = calloc(2048, sizeof(char)); + otemp = calloc(PATH_MAX, sizeof(char)); + nWidth = 78; + + sprintf(temp, "%s/%s/%s.MSG", CFG.bbs_usersdir, exitinfo.Name, CFG.bbsid); + if ((up = fopen(temp, "r")) == NULL) { + temp = tl(temp); + up = fopen(temp, "r"); + } + + if (up != NULL) { + Syslog('+', "Processing QWK file %s", temp); + + fread(&Temp, 128, 1, up); + Temp[8] = '\0'; + if (strcmp(CFG.bbsid, StripSpaces(Temp, 8))) { + Syslog('?', "Wrong QWK packet id: \"%s\"", StripSpaces(Temp, 8)); + fclose(up); + unlink(temp); + /* ERROR in packet */ + printf("%s\n", (char *)Language(451)); + free(temp); + free(otemp); + Pause(); + return; + } + + while (fread(&Qwk, sizeof(Qwk), 1, up) == 1) { + Area = atol(StripSpaces(Qwk.Msgnum, sizeof(Qwk.Msgnum))); + nRec = atoi(StripSpaces(Qwk.Msgrecs, sizeof(Qwk.Msgrecs))); + + /* + * Test for blank records. + */ + if (Area && nRec) { + Syslog('m', "Conference %u", Area); + Syslog('m', "Records %d", nRec); + Syslog('m', "To %s", tlcap(StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo)))); + Syslog('m', "From %s", tlcap(StripSpaces(Qwk.MsgFrom, sizeof(Qwk.MsgFrom)))); + Syslog('m', "Subject %s", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + sprintf(Temp, "%s", StripSpaces(Qwk.Msgdate, sizeof(Qwk.Msgdate))); + Syslog('m', "Date %s %s", Temp, StripSpaces(Qwk.Msgtime, sizeof(Qwk.Msgtime))); + + if (strcmp("MBSEQWK", StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo))) == 0) { + Syslog('m', "Command %s", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + sprintf(otemp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((op = fopen(otemp, "r+")) != NULL) { + + sprintf(otemp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(otemp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + fseek(op, (Area -1) * sizeof(olrtagrec), SEEK_SET); + fread(&olrtagrec, sizeof(olrtagrec), 1, op); + + if (strcmp("ADD", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))) == 0) { + if (msgs.Active && Access(exitinfo.Security, msgs.RDSec) && + strlen(msgs.QWKname) && !olrtagrec.Tagged) { + olrtagrec.Tagged = TRUE; + fseek(op, - sizeof(olrtagrec), SEEK_CUR); + Syslog('m', "%d", fwrite(&olrtagrec, sizeof(olrtagrec), 1, op)); + Syslog('+', "QWK added area %s", msgs.QWKname); + } + } + + if (strcmp("DROP", StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))) == 0) { + if (!msgs.OLR_Forced && olrtagrec.Tagged) { + olrtagrec.Tagged = FALSE; + fseek(op, - sizeof(olrtagrec), SEEK_CUR); + fwrite(&olrtagrec, sizeof(olrtagrec), 1, op); + Syslog('+', "QWK dropped area %s", msgs.QWKname); + } + } + + fclose(mf); + } + fclose(op); + } + } else { + /* + * Normal message + */ + Syslog('m', "Message"); + sprintf(otemp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(otemp, "r+")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, mf); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, mf); + + /* + * Check access to this area + */ + if (msgs.Active && strlen(msgs.QWKname) && Access(exitinfo.Security, msgs.WRSec) && + (msgs.MsgKinds != RONLY)) { + if (Open_Msgbase(msgs.Base, 'w')) { + Msg_New(); + pLine = szLine; + nCol = 0; + Syslog('m', "Msgbase open and locked"); + strcpy(Msg.From, tlcap(StripSpaces(Qwk.MsgFrom, sizeof(Qwk.MsgFrom)))); + strcpy(Msg.To, tlcap(StripSpaces(Qwk.MsgTo, sizeof(Qwk.MsgTo)))); + strcpy(Msg.Subject, StripSpaces(Qwk.MsgSubj, sizeof(Qwk.MsgSubj))); + if ((Qwk.Msgstat == '*') || (Qwk.Msgstat == '+')) + Msg.Private = TRUE; + strcpy(Temp, StripSpaces(Qwk.Msgdate, sizeof(Qwk.Msgdate))); + ltm = malloc(sizeof(struct tm)); + memset(ltm, 0, sizeof(struct tm)); + ltm->tm_mday = atoi(&Temp[3]); + ltm->tm_mon = atoi(&Temp[0]) -1; + ltm->tm_year = atoi(&Temp[6]); + if (ltm->tm_year < 96) + ltm->tm_year += 100; + strcpy(Temp, StripSpaces(Qwk.Msgtime, sizeof(Qwk.Msgtime))); + ltm->tm_hour = atoi(&Temp[0]); + ltm->tm_min = atoi(&Temp[3]); + ltm->tm_sec = 0; + Msg.Written = mktime(ltm); + free(ltm); + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Local = TRUE; + memset(&dest, 0, sizeof(dest)); +// dest.zone = Upr.destzone; +// dest.net = Upr.destnet; +// dest.node = Upr.destnode; +// dest.point = Upr.destpoint; + Add_Headkludges(fido2faddr(dest), FALSE); + + for (r = 1; r < nRec; r++) { + nReaded = fread(Temp, 1, 128, up); + Syslog('m', "nReaded=%d", nReaded); + if (r == (nRec - 1)) { + x = 127; + while (x > 0 && Temp[x] == ' ') { + nReaded--; + x--; + } + Syslog('m', "Final=%d", nReaded); + } + + for (i = 0, pBuff = Temp; i < nReaded; i++, pBuff++) { + if (*pBuff == '\r' || *pBuff == (char)0xE3) { + *pLine = '\0'; + Syslog('m', "1 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + pLine = szLine; + nCol = 0; + } else if (*pBuff != '\n') { + *pLine++ = *pBuff; + nCol++; + if (nCol >= nWidth) { + *pLine = '\0'; + while (nCol > 1 && *pLine != ' ') { + nCol--; + pLine--; + } + if (nCol > 0) { + while (*pLine == ' ') + pLine++; + strcpy (szWrp, pLine); + } + *pLine = '\0'; + Syslog('m', "2 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + strcpy(szLine, szWrp); + pLine = strchr(szLine, '\0'); + nCol = (short)strlen (szLine); + } + } + } + } + if (nCol > 0) { + *pLine = '\0'; + Syslog('m', "3 Len=%d \"%s\"", strlen(szLine), printable(szLine, 0)); + MsgText_Add2(szLine); + } + + Add_Footkludges(FALSE); + Msg_AddMsg(); + + Syslog('+', "Msg (%ld) to \"%s\", \"%s\", in %s", Msg.Id, + Msg.To, Msg.Subject, msgs.QWKname); + nPosted++; + Close_Msgbase(); + Syslog('m', "Msgbase closed again"); + fseek(mf, ((Area -1) * (msgshdr.recsize + msgshdr.syssize)) + + msgshdr.hdrsize, SEEK_SET); + msgs.Posted.total++; + msgs.Posted.tweek++; + msgs.Posted.tdow[Diw]++; + msgs.Posted.month[Miy]++; + msgs.LastPosted = time(NULL); + fwrite(&msgs, msgshdr.recsize, 1, mf); + } + } else { + Syslog('+', "Can't post messages in area %u", Area); + } + fclose(mf); + } + } + } else { + Syslog('m', "Skip blank record"); + } + } + + fclose(up); + } + + printf("\n"); + colour(CFG.TextColourF, CFG.TextColourB); + if (nPosted) { + /* Messages imported */ + printf("%d %s\n", nPosted, (char *)Language(454)); + ReadExitinfo(); + exitinfo.iPosted += nPosted; + WriteExitinfo(); + do_mailout = TRUE; + } + fflush(stdout); + unlink(temp); + free(temp); + free(otemp); + Pause(); +} + + + +union Converter { + unsigned char uc[10]; + unsigned short ui[5]; + unsigned long ul[2]; + float f[2]; + double d[1]; +}; + + + +float IEEToMSBIN(float f) +{ + int sign, exp; + union Converter t; + + t.f[0] = f; + sign = t.uc[3] / 0x80; + exp = ((t.ui[1] >> 7) - 0x7F + 0x81) & 0xFF; + t.ui[1] = (t.ui[1] & 0x7F) | (sign << 7) | (exp << 8); + + return t.f[0]; +} + + + +float MSBINToIEEE(float f) +{ + union Converter t; + int sign, exp; + + t.f[0] = f; + sign = t.uc[2] / 0x80; + exp = (t.uc[3] - 0x81 + 0x7f) & 0xff; + t.ui[1] = (t.ui[1] & 0x7f) | (exp << 7) | (sign << 15); + return t.f[0]; +} + + + +/* + * Pack messages in one mail area + */ +unsigned long QWK_PackArea(unsigned long ulLast, long Area) +{ + FILE *fdm, *fdi, *fdp; + float out, in; + char *Work, *Temp, *Text; + unsigned long Number, Pos, Size, Blocks; + int Pack = FALSE; + struct tm *tp; + + Number = ulLast; + Current = Personal = 0L; + + Temp = calloc(PATH_MAX, sizeof(char)); + Work = calloc(PATH_MAX, sizeof(char)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/%03ld.NDX", Work, Area); + fdi = fopen(Temp, "a+"); + + sprintf(Temp, "%s/PERSONAL.NDX", Work); + fdp = fopen(Temp, "a+"); + + /* + * Open MESSAGES.DAT, if it doesn't exist, create it and write + * the header. Then reopen the file in r/w mode. + */ + sprintf(Temp, "%s/MESSAGES.DAT", Work); + if ((fdm = fopen (Temp, "r+")) == NULL) { + Syslog('m', "Creating new %s", Temp); + fdm = fopen(Temp, "a+"); + // ---------------------------------------------------------------------- + // The first record of the MESSAGE.DAT file must be the Sparkware id + // block, otherwise some applications may complain. + // ---------------------------------------------------------------------- + fprintf(fdm, "Produced by Qmail..."); + fprintf(fdm, "Copywright (c) 1987 by Sparkware. "); + fprintf(fdm, "All Rights Reserved"); + memset(Temp, ' ', 54); + fwrite(Temp, 54, 1, fdm); + fclose(fdm); + sprintf(Temp, "%s/MESSAGES.DAT", Work); + fdm = fopen(Temp, "r+"); + } + + if ((fdm != NULL) && (fdp != NULL) && (fdi != NULL)) { + fseek(fdm, 0, SEEK_END); + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + fwrite(&out, sizeof(float), 1, fdp); + fwrite("", 1, 1, fdp); + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if (msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if (Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + /* + * Calculate the recordnumber from the current file + * position and store it in M$oft BIN format. + */ + Pos = ftell(fdm); + Blocks = (Pos / 128L) + 1L; + sprintf(Temp, "%lu", Blocks); + in = atof(Temp); + out = IEEToMSBIN(in); + fwrite(&out, sizeof(float), 1, fdi); + fwrite(" ", 1, 1, fdi); + Current++; + Total++; + + memset(&Qwk, ' ', sizeof(Qwk)); + sprintf(Temp, "%-*lu", sizeof(Qwk.Msgnum), (long)Number); + Syslog('M', "Message %s", Temp); + memcpy(Qwk.Msgnum, Temp, sizeof(Qwk.Msgnum)); + tp = localtime(&Msg.Written); + sprintf(Temp, "%02d-%02d-%02d", tp->tm_mon+1, tp->tm_mday, tp->tm_year % 100); + memcpy(Qwk.Msgdate, Temp, sizeof(Qwk.Msgdate)); + sprintf(Temp, "%02d:%02d", tp->tm_hour, tp->tm_min); + memcpy(Qwk.Msgtime, Temp, sizeof(Qwk.Msgtime)); + Msg.From[sizeof(Qwk.MsgFrom) - 1] = '\0'; + memcpy(Qwk.MsgFrom, Msg.From, strlen(Msg.From)); + Msg.To[sizeof(Qwk.MsgTo) - 1] = '\0'; + memcpy(Qwk.MsgTo, Msg.To, strlen(Msg.To)); + Msg.Subject[sizeof(Qwk.MsgSubj) - 1] = '\0'; + memcpy(Qwk.MsgSubj, Msg.Subject, strlen(Msg.Subject)); + Qwk.Msglive = 0xE1; + Qwk.Msgarealo = (unsigned char)(Area & 0xFF); + Qwk.Msgareahi = (unsigned char)((Area & 0xFF00) >> 8); + fwrite(&Qwk, sizeof(Qwk), 1, fdm); + Size = 128L; + if ((Text = (char *)MsgText_First()) != NULL) { + do { + if (Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9)) { + Size += fwrite(Text, 1, strlen(Text), fdm); + Size += fwrite("\xE3", 1, 1, fdm); + } + } while ((Text = (char *)MsgText_Next()) != NULL); + + if ((Size % 128L) != 0) { + memset(Temp, ' ', 128); + Size += fwrite(Temp, (int)(128L - (Size % 128L)), 1, fdm); + } + + sprintf(Qwk.Msgrecs, "%-*lu", sizeof(Qwk.Msgrecs), (long)((ftell(fdm) - Pos) / 128L)); + fseek(fdm, Pos, SEEK_SET); + fwrite(&Qwk, sizeof(Qwk), 1, fdm); + fseek(fdm, 0L, SEEK_END); + if ((Total % 16L) == 0L) + usleep(1); + } + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } + } while (Msg_Next(&Number)); + } + } else { + WriteError("Not all files open"); + } + + if (fdm != NULL) + fclose(fdm); + if (fdi != NULL) + fclose(fdi); + if (fdp != NULL) + fclose(fdp); + free(Work); + free(Temp); + + return Number; +} + + + +char *StripSpaces(char *String, int Size) +{ + int x; + + memcpy(TempStr, String, Size); + TempStr[Size] = '\0'; + if ((x = (Size - 1)) > 0) { + while (x > 0 && TempStr[x] == ' ') + TempStr[x--] = '\0'; + } + + return TempStr; +} + + +/***************************************************************************** + * + * ASCII Offline Functions + * + */ + + +void OLR_DownASCII(void) +{ + struct tm *tp; + time_t Now; + char Pktname[32]; + long Area = 0; + char *Work, *Temp; + int rc = 0; + FILE *fp = NULL, *tf, *mf, *af; + unsigned long Start, High; + msg_high *tmp, *mhl = NULL; + + if (!OLR_Prescan()) + return; + + Total = TotalPersonal = 0L; + clear(); + colour(9, 0); + /* ASCII Offline Download */ + printf("%s\n", (char *)Language(460)); + + Work = calloc(PATH_MAX, sizeof(char)); + Temp = calloc(PATH_MAX, sizeof(char)); + + Now = time(NULL); + tp = localtime(&Now); + Syslog('+', "Preparing ASCII packet"); + + sprintf(Temp, "%s.MSG", CFG.bbsid); + sprintf(Pktname, "%s", tl(Temp)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((mf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + return; + } + fread(&msgshdr, sizeof(msgshdr), 1, mf); + + sprintf(Temp, "%s/%s/.olrtags", CFG.bbs_usersdir, exitinfo.Name); + if ((tf = fopen(Temp, "r")) == NULL) { + WriteError("$Can't open %s", Temp); + fclose(fp); + fclose(mf); + return; + } + + Area = 0; + DrawBar(Pktname); + fseek(mf, sizeof(msgshdr), SEEK_SET); + fseek(tf, 0, SEEK_SET); + + while (fread(&msgs, msgshdr.recsize, 1, mf) == 1) { + fseek(mf, msgshdr.syssize, SEEK_CUR); + fread(&olrtagrec, sizeof(olrtagrec), 1, tf); + Area++; + if (olrtagrec.Tagged) { + if (Msg_Open(msgs.Base)) { + Current = Personal = 0; + if (Msg_Highest() != 0) { + memset(&LR, 0, sizeof(LR)); + LR.UserID = grecno; + if (Msg_GetLastRead(&LR)) + Start = LR.HighReadMsg; + else + Start = Msg_Lowest() -1; + if (Start > Msg_Highest()) + Start = Msg_Highest(); + if (Start < Msg_Highest()) { + High = ASCII_PackArea(Start, Area); + fill_high(&mhl, Area, High, Personal); + } + } + Syslog('+', "Area %-20s %5ld (%ld personal)", msgs.QWKname, Current, Personal); + Msg_Close(); + } + } + } + + if (Total) { + /* Packing with */ + printf("\n%s ", (char *)Language(446)); + sprintf(Temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((af = fopen(Temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, af); + while (fread(&archiver, archiverhdr.recsize, 1, af) == 1) { + if (archiver.available && (!strcmp(archiver.name, exitinfo.Archiver))) { + Syslog('+', "Archiver %s", archiver.comment); + printf("%s ", archiver.comment); + alarm_on(); + + for (tmp = mhl; tmp; tmp = tmp->next) { + sprintf(Temp, "%s/%03ld.TXT", Work, tmp->Area); + AddArc(Temp, Pktname); + } + sprintf(Temp, "%s/%s/%s", CFG.bbs_usersdir, exitinfo.Name, Pktname); + rc = DownloadDirect(Temp, FALSE); + unlink(Temp); + } + } + fclose(af); + } + } + + colour(CFG.HiliteF, CFG.HiliteB); + if (rc == FALSE) { + Syslog('+', "ASCII download failed"); + /* Download failed */ + printf("%s", (char *)Language(447)); + } else { + Syslog('+', "ASCII download successfull"); + /* Download successfull */ + printf("\r%s\n", (char *)Language(448)); + + if (mhl != NULL) + UpdateLR(mhl, mf); + } + fclose(mf); + tidy_high(&mhl); + free(Temp); + free(Work); + printf("\n\n"); + Pause(); +} + + + +/* + * Pack messages in one mail area + */ +unsigned long ASCII_PackArea(unsigned long ulLast, long Area) +{ + FILE *fp; + char *Work, *Temp, *Text; + unsigned long Number; + int Pack = FALSE; + struct tm *tp; + + Number = ulLast; + Current = Personal = 0L; + + Temp = calloc(128, sizeof(char)); + Work = calloc(128, sizeof(char)); + sprintf(Work, "%s/%s/tmp", CFG.bbs_usersdir, exitinfo.Name); + + sprintf(Temp, "%s/%03ld.TXT", Work, Area); + if ((fp = fopen(Temp, "a+")) != NULL) { + if (Msg_Next(&Number)) { + do { + Msg_ReadHeader(Number); + Msg_Read(Number, 78); + Pack = TRUE; + if ((strcasecmp(Msg.To, exitinfo.sUserName) == 0) || + (strcasecmp(Msg.To, exitinfo.sHandle) == 0)) { + Personal++; + TotalPersonal++; + } else if (msgs.Type == NETMAIL) { + Pack = FALSE; + } else if ( msgs.MsgKinds == PRIVATE ) { + Pack = FALSE; + } else if (msgs.MsgKinds == BOTH ) { + if ( Msg.Private == TRUE ) Pack = FALSE; + } + + if (Pack) { + fprintf (fp, "\n==============================================\n Msg. #%ld of %ld (%s)\n", Number, Msg_Number(), msgs.Name); + tp = localtime(&Msg.Written); + fprintf (fp, " Date: %d %s %d %2d:%02d\n", tp->tm_mday, + GetMonth(tp->tm_mon + 1), tp->tm_year, tp->tm_hour, tp->tm_min); + fprintf (fp, " From: %s\n", Msg.From); + if (Msg.To[0]) + fprintf (fp, " To: %s\n", Msg.To); + fprintf (fp, "Subject: %s\n----------------------------------------------\n", Msg.Subject); + Current++; + Total++; + + if ((Text = (char *)MsgText_First()) != NULL) { + do { + if (Text[0] != 0x01 && strncmp(Text, "SEEN-BY: ", 9)) + fprintf(fp, "%s\n", Text); + } while ((Text = (char *)MsgText_Next()) != NULL); + } + + if ((Total % 16L) == 0L) + usleep(1); + + if (BarWidth != (unsigned short)((Total * 61L) / TotalPack)) { + BarWidth = (unsigned short)((Total * 61L) / TotalPack); + colour(3, 0); + printf("\r%.*s", BarWidth, "ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ"); + fflush(stdout); + } + } + } while (Msg_Next(&Number)); + } + fclose(fp); + } else { + WriteError("Not all files open"); + } + + free(Work); + free(Temp); + return Number; +} + + diff --git a/mbsebbs/offline.h b/mbsebbs/offline.h new file mode 100644 index 00000000..2f46002f --- /dev/null +++ b/mbsebbs/offline.h @@ -0,0 +1,52 @@ +#ifndef _OFFLINE_H +#define _OFFLINE_H + + + +/* + * Each area has a tag if the area exists, so we can check + * at login if the sysop added new areas (or deleted). This + * file is synced at login. Location: usershomedir/.olrtags + */ +struct _olrtagrec { + unsigned short Available : 1; /* Is the area available */ + unsigned short Tagged : 1; /* Is this area tagged */ + unsigned short ScanNew : 1; /* Scan for new mail */ +}; + +struct _olrtagrec olrtagrec; + + +struct _qwkhdr { + unsigned char Msgstat; /* Message status */ + unsigned char Msgnum[7]; /* Message number */ + unsigned char Msgdate[8]; /* Message date MM-DD-YY */ + unsigned char Msgtime[5]; /* Message time HH:MM */ + unsigned char MsgTo[25]; /* Message To: */ + unsigned char MsgFrom[25]; /* Message From: */ + unsigned char MsgSubj[25]; /* Message Subject: */ + unsigned char Msgpass[12]; /* Message password */ + unsigned char Msgrply[8]; /* Message reply to */ + unsigned char Msgrecs[6]; /* Length in records */ + unsigned char Msglive; /* Message active status */ + unsigned char Msgarealo; /* Lo-byte message area */ + unsigned char Msgareahi; /* Hi-byte message area */ + unsigned char Msgfiller[3]; /* Filler bytes */ +}; + +struct _qwkhdr Qwk; + + +void OLR_TagArea(void); /* Tag area(s) */ +void OLR_UntagArea(void); /* Untag area(s) */ +void OLR_SyncTags(void); /* Sync tag/msg area(s) */ +void OLR_ViewTags(void); /* View tagged areas */ +void OLR_Upload(void); /* Upload mail packet */ +void OLR_RestrictDate(void); /* Restrict download date */ +void OLR_DownBW(void); /* Download BlueWave format */ +void OLR_DownQWK(void); /* Download QWK format */ +void OLR_DownASCII(void); /* Download ASCII format */ + + +#endif + diff --git a/mbsebbs/oneline.c b/mbsebbs/oneline.c new file mode 100644 index 00000000..149c41e1 --- /dev/null +++ b/mbsebbs/oneline.c @@ -0,0 +1,447 @@ +/***************************************************************************** + * + * File ..................: mbsebbs/oneline.c + * Purpose ...............: Oneliner functions. + * Last modification date : 28-jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "oneline.h" +#include "funcs.h" +#include "funcs4.h" +#include "language.h" + + +char sOneliner[81]; +int iColour; /* Current color */ + + +void Oneliner_Check() +{ + FILE *pOneline; + char *sFileName; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((pOneline = fopen(sFileName, "r")) == NULL) { + if ((pOneline = fopen(sFileName, "w")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, pOneline); + fclose(pOneline); + Syslog('-', "Created oneliner database"); + } + } + free(sFileName); +} + + + +void Oneliner_Add() +{ + FILE *pOneline; + char *sFileName; + int x; + char temp[81]; + + Oneliner_Check(); + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "a+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + free(sFileName); + + memset(&ol, 0, sizeof(ol)); + clear(); + /* MBSE BBS Oneliners will randomly appear on the main menu. */ + poutCR(15, 0, Language(341)); + Enter(1); + + /* Obscene or libellous oneliners will be deleted!! */ + poutCR(15, 1, Language(342)); + Enter(1); + + /* Please enter your oneliner below. You have 75 characters.*/ + pout(12, 0, Language(343)); + Enter(1); + pout(15, 0, (char *)"> "); + colour(CFG.InputColourF, CFG.InputColourB); + fflush(stdout); + GetstrC(temp, 75); + + if((strcmp(temp, "")) == 0) { + fclose(pOneline); + return; + } else { + x = strlen(temp); + if(x >= 78) + temp[78] = '\0'; + + strcpy(ol.Oneline, temp); + } + + Enter(1); + /* Oneliner added */ + pout(3, 0, Language(344)); + Enter(2); + Pause(); + + Syslog('!', "User added oneliner:"); + Syslog('!', ol.Oneline); + + sprintf(ol.UserName,"%s", exitinfo.sUserName); + sprintf(ol.DateOfEntry,"%02d-%02d-%04d",l_date->tm_mday,l_date->tm_mon+1,l_date->tm_year+1900); + ol.Available = TRUE; + + fwrite(&ol, sizeof(ol), 1, pOneline); + fclose(pOneline); +} + + + + +/* + * Print global string sOneliner centered on the screen + */ +void Oneliner_Print() +{ + int i, x, z; + int Strlen; + int Maxlen = 80; + char sNewOneliner[81] = ""; + + /* + * Select a new colour + */ + if (iColour < 8) + iColour = 8; + else + if (iColour == 15) + iColour = 8; + else + iColour++; + + /* + * Get a random oneliner + */ + strcpy(sOneliner, Oneliner_Get()); + + /* + * Now display it on screen + */ + Strlen = strlen(sOneliner); + + if(Strlen == Maxlen) + printf("%s\n", sOneliner); + else { + x = Maxlen - Strlen; + z = x / 2; + for(i = 0; i < z; i++) + strcat(sNewOneliner," "); + strcat(sNewOneliner, sOneliner); + colour(iColour, 0); + printf("%s\n", sNewOneliner); + } +} + + + +/* + * Get a random oneliner + */ +char *Oneliner_Get() +{ + FILE *pOneline; + int i, j, in, id; + int recno = 0; + long offset; + int nrecno; + char *sFileName; + static char temp[81]; + + /* + * Get a random oneliner + */ + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return '\0'; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + } + nrecno = recno; + fseek(pOneline, olhdr.hdrsize, 0); + + /* + * Generate random record number + */ + while (TRUE) { + in = nrecno; + id = getpid(); + + i = rand(); + j = i % id; + if ((j <= in)) + break; + } + + offset = olhdr.hdrsize + (j * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) { + WriteError("Can't move pointer in %s", sFileName); + return '\0'; + } + + fread(&ol, olhdr.recsize, 1, pOneline); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, ol.Oneline); + fclose(pOneline); + free(sFileName); + return temp; +} + + + +/* + * List Oneliners + */ +void Oneliner_List() +{ + FILE *pOneline; + int recno = 0; + int Colour = 1; + char *sFileName; + + clear(); + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + /* # A Date User Description */ + pout(10, 0, Language(345)); + Enter(1); + } else { + /* # Description */ + pout(10, 0, Language(346)); + Enter(1); + } + colour(2, 0); + sLine(); + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + if((SYSOP == TRUE) || (exitinfo.Security.level >= CFG.sysop_access)) { + colour(15, 0); + printf("%2d", recno); + + colour(9, 0); + printf("%2d ", ol.Available); + + colour(11, 0); + printf("%s ", ol.DateOfEntry); + + colour(3, 0); + printf("%-15s ", ol.UserName); + + colour(Colour, 0); + printf("%-.48s\n", ol.Oneline); + } else { + colour(15, 0); + printf("%2d ", recno); + colour(Colour, 0); + printf("%-.76s\n", ol.Oneline); + } + + recno++; + Colour++; + if(Colour >= 16) + Colour = 1; + } + fclose(pOneline); + printf("\n"); + Pause(); + free(sFileName); +} + + + +void Oneliner_Show() +{ + FILE *pOneline; + int recno = 0; + long offset; + char *sFileName; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + Enter(1); + /* Please enter number to list: */ + pout(15, 0, Language(347)); + colour(CFG.InputColourF, CFG.InputColourB); + scanf("%d", &recno); + + offset = olhdr.hdrsize + (recno * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) + WriteError("Can't move pointer in %s",sFileName); + + fread(&ol, olhdr.recsize, 1, pOneline); + + colour(15, 0); + printf("\n%d ", recno); + colour(12, 0); + printf("%s\n\n", ol.Oneline); + + Pause(); + fclose(pOneline); + free(sFileName); +} + + + +void Oneliner_Delete() +{ + FILE *pOneline; + int recno = 0; + long offset; + int nrecno = 0; + char srecno[7]; + char *sFileName; + char stemp[50]; + char sUser[35]; + + sFileName = calloc(128, sizeof(char)); + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if((pOneline = fopen(sFileName, "r+")) == NULL) { + WriteError("Can't open file: %s", sFileName); + return; + } + fread(&olhdr, sizeof(olhdr), 1, pOneline); + + Enter(1); + /* Please enter number to delete: */ + pout(15, 0, Language(331)); + colour(CFG.InputColourF, CFG.InputColourB); + GetstrC(srecno, 6); + + if((strcmp(srecno,"")) == 0) { + fclose(pOneline); + return; + } + + recno = atoi(srecno); + + nrecno = recno; + recno = 0; + + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + } + + if(nrecno >= recno) { + Enter(1); + /* Record does not exist */ + pout(12, 0, Language(319)); + Enter(2); + fclose(pOneline); + Pause(); + } else { + offset = olhdr.hdrsize + (nrecno * olhdr.recsize); + if (fseek(pOneline, offset, 0) != 0) { + WriteError("Can't move pointer in %s",sFileName); + } + + fread(&ol, olhdr.recsize, 1, pOneline); + + /* Convert Record Int to string, so we can print to logfiles */ + sprintf(stemp,"%d", nrecno); + + /* Print UserName to String, so we can compare for deletion */ + sprintf(sUser,"%s", exitinfo.sUserName); + + if((strcmp(sUser, ol.UserName)) != 0) { + if((!SYSOP) && (exitinfo.Security.level < CFG.sysop_access)) { + colour(12, 0); + /* Record *//* does not belong to you.*/ + printf("\n%s%s %s\n\n", (char *) Language(332), stemp, (char *) Language(333)); + Syslog('!', "User tried to delete somebody else's record: %s", stemp); + Pause(); + fclose(pOneline); + return; + } + } + + if ((ol.Available ) == FALSE) { + colour(12, 0); + /* Record: %d already marked for deletion */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('!', "User tried to mark an already marked record: %s", stemp); + Pause(); + } else { + ol.Available = FALSE; + colour(10, 0); + /* Record *//* marked for deletion */ + printf("\n%s%d %s\n\n", (char *) Language(332), nrecno, (char *) Language(334)); + Syslog('+', "User marked oneliner record for deletion: %s", stemp); + Pause(); + } + + if (fseek(pOneline, offset, 0) != 0) + WriteError("Can't move pointer in %s",sFileName); + fwrite(&ol, olhdr.recsize, 1, pOneline); + } + fclose(pOneline); + free(sFileName); +} + + diff --git a/mbsebbs/oneline.h b/mbsebbs/oneline.h new file mode 100644 index 00000000..8d926e68 --- /dev/null +++ b/mbsebbs/oneline.h @@ -0,0 +1,13 @@ +#ifndef _ONELINE_H +#define _ONELINE_H + +void Oneliner_Check(void); /* Check if database exists, creates new */ +void Oneliner_Add(void); /* Add oneliner */ +void Oneliner_Print(void); /* Print a oneliner centered at the screen */ +char *Oneliner_Get(void); /* Get a random oneliner */ +void Oneliner_List(void); /* List Oneliners */ +void Oneliner_Show(void); +void Oneliner_Delete(void); + +#endif + diff --git a/mbsebbs/page.c b/mbsebbs/page.c new file mode 100644 index 00000000..a4e53250 --- /dev/null +++ b/mbsebbs/page.c @@ -0,0 +1,296 @@ +/***************************************************************************** + * + * File ..................: bbs/page.c + * Purpose ...............: Sysop Paging + * Last modification date : 28-Jun-2001 + * Todo ..................: Implement new config settings. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs.h" +#include "funcs4.h" +#include "chat.h" +#include "page.h" +#include "timeout.h" +#include "mail.h" +#include "language.h" + + +/* + * Function to Page Sysop + */ +void Page_Sysop(char *String) +{ + int i; + FILE *pWritingDevice, *pBusy; + int iOpenDevice = FALSE; /* Flag to check if you can write to CFG.sChatDevice */ + char *Reason; + char temp[81]; + + Reason = calloc(81, sizeof(char)); + + clear(); + colour(12, 0); + /* MBSE BBS Chat */ + Center((char *) Language(151)); + + if (CFG.iAskReason) { + locate(6, 0); + colour(1, 0); + printf("%c", 213); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c ", 184); + + colour(7, 0); + for(i = 0; i < 78; i++) + printf("%c", 250); + printf("\n"); + + colour(1, 0); + printf("%c", 212); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c\n", 190); + + locate(7, 2); + + colour(7, 0); + fflush(stdout); + GetPageStr(temp, 76); + + colour(1, 0); + printf("%c", 212); + for(i = 0; i < 78; i++) + printf("%c", 205); + printf("%c\n", 190); + + if((strcmp(temp, "")) == 0) + return; + + Syslog('+', "Chat Reason: %s", temp); + strcpy(Reason, temp); + } + + if (access("/tmp/.BusyChatting", F_OK) == 0) { + if((pBusy = fopen("/tmp/.BusyChatting", "r")) == NULL) + WriteError("Unable to open BusyChatting file", pTTY); + else { + fscanf(pBusy, "%10s", temp); + fclose(pBusy); + } + colour(13, 0); + printf("%s%s\n", (char *) Language(152), temp); + pout(10, 0, (char *) Language(153)); + Enter(2); + Syslog('+', "SysOp was busy chatting to user on %s", temp); + Pause(); + free(Reason); + return; + } + + CFG.iMaxPageTimes--; + + if(CFG.iMaxPageTimes <= 0) { + if (!DisplayFile((char *)"maxpage")) { + /* If i is FALSE display hard coded message */ + Enter(1); + pout(15, 0, (char *) Language(154)); + Enter(2); + } + + Syslog('!', "Attempted to page Sysop, above maximum page limit."); + Pause(); + } else { + locate(14, ((80 - strlen(String) ) / 2 - 2)); + pout(15, 0, (char *)"["); + pout(7, 0, String); + pout(15, 0, (char *)"]"); + + locate(16, ((80 - CFG.iPageLength) / 2 - 2)); + pout(15, 0, (char *)"["); + colour(1, 0); + for(i = 0; i < CFG.iPageLength; i++) + printf("%c", 176); + pout(15, 0, (char *)"]"); + + locate(16, ((80 - CFG.iPageLength) / 2 - 2) + 1); + + if((pWritingDevice = fopen(CFG.sChatDevice, "w")) != NULL) { + fprintf(pWritingDevice, "\n\n\n%s is trying to page you on %s.\n", \ + usrconfig.sUserName, pTTY); + + fprintf(pWritingDevice, "Type: '%s/bin/schat %s' to talk to him, you have", \ + getenv("MBSE_ROOT"), pTTY); + fprintf(pWritingDevice, "\n%d seconds to respond!\n\n", CFG.iPageLength); + fprintf(pWritingDevice, "%s\n", temp); + iOpenDevice = TRUE; + } + + colour(9, 0); + for(i = 0; i < CFG.iPageLength; i++) { + printf("\x07"); + /* If there weren't any problems opening the writing device */ + if(iOpenDevice) + fprintf(pWritingDevice, "\x07"); + printf("%c", 219); + fflush(pWritingDevice); + fflush(stdout); + sleep(1); + if(access("/tmp/chatdev", R_OK) == 0) { + fclose(pWritingDevice); + Chat(); + free(Reason); + return; + } + } + + fclose(pWritingDevice); + PageReason(); + printf("\n\n\n"); + if (strlen(Reason)) + SysopComment(Reason); + else + SysopComment((char *)"Failed chat"); + } + + free(Reason); + Pause(); +} + + + +/* + * Function gets string from user for Pager Function + */ +void GetPageStr(char *sStr, int iMaxlen) +{ + unsigned char ch = 0; + int iPos = 0; + + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 6"); + return; + } + Setraw(); + + strcpy(sStr, ""); + + alarm_on(); + while (ch != 13) { + ch = Readkey(); + + if (((ch == 8) || (ch == KEY_DEL) || (ch == 127)) && (iPos > 0)) { + printf("\b%c\b", 250); + fflush(stdout); + sStr[--iPos]='\0'; + } + + if (ch > 31 && ch < 127) { + if (iPos <= iMaxlen) { + iPos++; + sprintf(sStr, "%s%c", sStr, ch); + printf("%c", ch); + fflush(stdout); + } else + ch=13; + } + } + + Unsetraw(); + close(ttyfd); + printf("\n"); +} + + + +/* + * Function gets page reason from a file in the txtfiles directory + * randomly generates a number and prints the string to the screen + */ +void PageReason() +{ + FILE *Page; + int iLoop = FALSE, id, i, j = 0; + int Lines = 0, Count = 0, iFoundString = FALSE; + char *String; + char *temp; + + temp = calloc(128, sizeof(char)); + String = calloc(81, sizeof(char)); + + sprintf(temp, "%s/page.asc", CFG.bbs_txtfiles); + if(( Page = fopen(temp, "r")) != NULL) { + + while (( fgets(String, 80 ,Page)) != NULL) + Lines++; + + rewind(Page); + + Count = Lines; + id = getpid(); + do { + i = rand(); + j = i % id; + if ((j <= Count) && (j != 0)) + iLoop = 1; + } while (!iLoop); + + Lines = 0; + + while (( fgets(String,80,Page)) != NULL) { + if(Lines == j) { + Striplf(String); + locate(18, ((78 - strlen(String) ) / 2)); + pout(15, 0, (char *)"["); + pout(9, 0, String); + pout(15, 0, (char *)"]"); + iFoundString = TRUE; + } + + Lines++; /* Increment Lines until correct line is found */ + } + } /* End of Else */ + + if(!iFoundString) { + /* Sysop currently is not available ... please leave a comment */ + sprintf(String, "%s", (char *) Language(155)); + locate(18, ((78 - strlen(String) ) / 2)); + pout(15, 0, (char *)"["); + pout(9, 0, String); + pout(15, 0, (char *)"]"); + } + + free(temp); + free(String); +} + diff --git a/mbsebbs/page.h b/mbsebbs/page.h new file mode 100644 index 00000000..52e4318a --- /dev/null +++ b/mbsebbs/page.h @@ -0,0 +1,13 @@ +/* page.h */ + +#ifndef _PAGE_H +#define _PAHE_H + + +void Page_Sysop(char *); /* Sysop Pager */ +void GetPageStr(char *, int); /* Get String for Pager from User */ +void PageReason(void); /* Get Page Reason and Print String */ + + +#endif + diff --git a/mbsebbs/pinfo.c b/mbsebbs/pinfo.c new file mode 100644 index 00000000..d69715e6 --- /dev/null +++ b/mbsebbs/pinfo.c @@ -0,0 +1,159 @@ +/***************************************************************************** + * + * File ..................: bbs/pinfo.c + * Purpose ...............: Product information + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "funcs4.h" + + + +void ls(int a) +{ + printf("%c ", a ? 179 : '|'); +} + + + +void rs(int a) +{ + colour(8, 0); + printf("%c\n", a ? 179 : '|'); +} + + + +void wl(int a) +{ + int i; + + ls(a); + for(i = 0; i < 76; i++) + printf(" "); + rs(a); +} + + + +/* + * Product information screen + */ +void cr(void) +{ + int a, i; + char *string, *temp; + + a = exitinfo.GraphMode; + + string = calloc(81, sizeof(char)); + temp = calloc(81, sizeof(char)); + + clear(); + colour(8, 0); + + /* Print top row */ + printf("%c", a ? 213 : '+'); + for(i = 0; i < 77; i++) + printf("%c", a ? 205 : '='); + printf("%c\n", a ? 184 : '+'); + + wl(a); + + ls(a); + sprintf(temp, "MBSE Bulletin Board System %s Linux Pro", VERSION); + pout(14, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + sprintf(temp, "%s", Copyright); + pout(11, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + sprintf(temp, "Compiled on %s at %s", __DATE__, __TIME__); + pout(14, 0, padleft(temp, 76, ' ')); + rs(a); + + wl(a); + + ls(a); + pout(11, 0, (char *)"MBSE has been written and designed by Michiel Broek. Many others have given "); + rs(a); + + ls(a); + pout(11, 0, (char *)"valuable time in the form of new ideas and suggestions on how to make MBSE "); + rs(a); + + ls(a); + pout(11, 0, (char *)"BBS a better BBS "); + rs(a); + + wl(a); + + ls(a); + pout(12, 0, (char *)"JAM(mbp) - Copyright 1993 Joaquim Homrighausen, Andrew Milner, "); + rs(a); + + ls(a); + pout(12, 0, (char *)" Mats Birch, Mats Wallin. "); + rs(a); + + ls(a); + pout(12, 0, (char *)" ALL RIGHTS RESERVED. "); + rs(a); + + wl(a); + + ls(a); + pout(9, 0, (char *)"Special thanks to Steven Wishart who wrote RapidBBS "); + rs(a); + + wl(a); + + printf("%c", a ? 212 : '+'); + for(i = 0; i < 77; i++) + printf("%c", a ? 205 : '='); + printf("%c", a ? 190 : '+'); + + free(string); + free(temp); + printf("\n"); + Pause(); +} + + diff --git a/mbsebbs/pinfo.h b/mbsebbs/pinfo.h new file mode 100644 index 00000000..79a49247 --- /dev/null +++ b/mbsebbs/pinfo.h @@ -0,0 +1,9 @@ +#ifndef _PINFO_H +#define _PINFO_H + +void ls(int); /* Left side of block */ +void rs(int); /* Right side of block */ +void cr(void); /* Show product info screen */ + +#endif + diff --git a/mbsebbs/pop3.c b/mbsebbs/pop3.c new file mode 100644 index 00000000..a98e8481 --- /dev/null +++ b/mbsebbs/pop3.c @@ -0,0 +1,212 @@ +/***************************************************************************** + * + * File ..................: bbs/pop3.c + * Purpose ...............: POP3 client + * Last modification date : 13-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/mbinet.h" +#include "../lib/msgtext.h" +#include "../lib/msg.h" +#include "msgutil.h" +#include "pop3.h" + + + +void error_popmail(char *); +void error_popmail(char *umsg) +{ + char *p; + + pop3_send((char *)"QUIT\r\n"); + p = pop3_receive(); + pop3_close(); + colour(12, 0); + printf("%s\r\n", umsg); + fflush(stdout); +} + + + +void retr_msg(int); +void retr_msg(int msgnum) +{ + char *p, *q, temp[128]; + int Header; + unsigned long crc = -1; + + sprintf(temp, "RETR %d\r\n", msgnum); + if (pop3_cmd(temp) == 0) { + Msg_New(); + Header = TRUE; + sprintf(temp, "%s/%s/mailbox", CFG.bbs_usersdir, exitinfo.Name); + Open_Msgbase(temp, 'w'); + Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60); + Msg.Private = TRUE; + while (TRUE) { + p = pop3_receive(); + if ((p[0] == '.') && (strlen(p) == 1)) { + break; + } else { + if (Header) { + /* + * Check the primary message header lines. + */ + if (strncmp(p, "To: ", 4) == 0) { + if (strlen(p) > 104) + p[104] = '\0'; + sprintf(Msg.To, "%s", p+4); + } + if (strncmp(p, "From: ", 6) == 0) { + if (strlen(p) > 106) + p[106] = '\0'; + sprintf(Msg.From, "%s", p+6); + } + if (strncmp(p, "Subject: ", 9) == 0) { + if (strlen(p) > 109) + p[109] = '\0'; + sprintf(Msg.Subject, "%s", p+9); + } + if (strncmp(p, "Date: ", 6) == 0) + Msg.Written = parsedate(p+6, NULL) - (gmt_offset((time_t)0) * 60); + if (strncmp(p, "Message-Id: ", 12) == 0) { + q = xstrcpy(p+12); + Msg.MsgIdCRC = upd_crc32(q, crc, strlen(q)); + free(q); + } + Msg.ReplyCRC = 0xffffffff; + if (strlen(p) == 0) { + Header = FALSE; + } else { + sprintf(temp, "\001%s", p); + MsgText_Add2(temp); + } + } else { + MsgText_Add2(p); + } + } + } + Msg_AddMsg(); + Msg_UnLock(); + Msg_Close(); + sprintf(temp, "DELE %d\r\n", msgnum); + pop3_cmd(temp); + } else { + WriteError("POP3: Can't retrieve message %d", msgnum); + } +} + + + +void check_popmail(char *user, char *pass) +{ + char *p, *q, temp[128]; + int tmsgs = 0, size, msgnum, color = 9; + FILE *tp; + + /* + * If nothing is retrieved from the POP3 mailbox, the user sees nothing. + */ + Syslog('+', "POP3: connect user %s", user); + if (pop3_connect() == -1) { + WriteError("Can't connect POP3 server"); + return; + } + + sprintf(temp, "USER %s\r\n", user); + if (pop3_cmd(temp)) { + error_popmail((char *)"You have no email box"); + return; + } + + sprintf(temp, "PASS %s\r\n", pass); + if (pop3_cmd(temp)) { + error_popmail((char *)"Wrong email password, reset your password"); + return; + } + + Syslog('+', "POP3: logged in"); + + pop3_send((char *)"STAT\r\n"); + p = pop3_receive(); + if (strncmp(p, "+OK", 3) == 0) { + q = strtok(p, " "); + q = strtok(NULL, " "); + tmsgs = atoi(q); + q = strtok(NULL, " \r\n\0"); + size = atoi(q); + Syslog('+', "POP3: %d messages, %d bytes", tmsgs, size); + if (tmsgs && ((tp = tmpfile()) != NULL)) { + if (pop3_cmd((char *)"LIST\r\n") == 0) { + while (TRUE) { + p = pop3_receive(); + if (p[0] == '.') { + break; + } else { + q = strtok(p, " "); + msgnum = atoi(q); + fwrite(&msgnum, sizeof(msgnum), 1, tp); + } + } + rewind(tp); + while (fread(&msgnum, sizeof(msgnum), 1, tp) == 1) { + /* + * Show progress + */ + colour(color, 0); + printf("\rFetching message %02d/%02d, total %d bytes", msgnum, tmsgs, size); + fflush(stdout); + if (color < 15) + color++; + else + color = 9; + retr_msg(msgnum); + } + fclose(tp); + } + } + fflush(stdout); + } + + pop3_cmd((char *)"QUIT\r\n"); + pop3_close(); + + if (tmsgs) { + colour(13, 0); + printf("\r \r"); + fflush(stdout); + } +} + + + diff --git a/mbsebbs/pop3.h b/mbsebbs/pop3.h new file mode 100644 index 00000000..ecf0dc01 --- /dev/null +++ b/mbsebbs/pop3.h @@ -0,0 +1,9 @@ +#ifndef _POP3_H +#define _POP3_H + + +void check_popmail(char *, char *); + + +#endif + diff --git a/mbsebbs/pwcheck.c b/mbsebbs/pwcheck.c new file mode 100644 index 00000000..9fce8492 --- /dev/null +++ b/mbsebbs/pwcheck.c @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * File ..................: bbs/pwcheck.c + * Purpose ...............: Password checking routines + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "pwcheck.h" +#include "funcs4.h" +#include "timeout.h" + + +/* + * Open up /dev/tty to get the password from the user + * because this is done in raw mode, it makes life a bit + * more difficult. + * This function gets a password from a user, upto CFG.max_passlen set above + */ +int Getpass(char *theword) +{ + unsigned char c = 0; + int counter = 0; + char password[Max_passlen+1]; + + /* + * Open the device that we want to read the password from, you can't use + * stdin as this might change in a pipe + */ + if ((ttyfd = open ("/dev/tty", O_RDWR)) < 0) { + perror("open 7"); + ExitClient(1); + } + + /* Set Raw mode so that the characters don't echo */ + Setraw(); + alarm_on(); + + /* + * Till the user presses ENTER or reaches the maximum length allowed + */ + while ((c != 13) && (counter < Max_passlen )) { + c = Readkey(); /* Reads a character from the raw device */ + + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (counter != 0 )) { /* If its a BACKSPACE */ + counter--; + password[counter] = '\0'; + printf("\x008 \x008"); + fflush(stdout); + continue; + } /* Backtrack to fix the BACKSPACE */ + + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (counter == 0) ) { + printf("\x007"); + fflush(stdout); + continue; + } /* Don't Backtrack as we are at the begining of the passwd field */ + + password[counter] = c; + counter++; + + if (c > 32 && c < 127) { /* If its a normal character, display a . */ + printf("%c", CFG.iPasswd_Char); + fflush(stdout); + } + } + Unsetraw(); /* Go normal */ + close(ttyfd); + + if (counter == Max_passlen) + password[counter] = '\0'; /* Make sure the string has a NULL at the end*/ + else + password[counter-1] ='\0'; + strcpy(theword,password); + + return(0); +} + + diff --git a/mbsebbs/pwcheck.h b/mbsebbs/pwcheck.h new file mode 100644 index 00000000..b0b7f050 --- /dev/null +++ b/mbsebbs/pwcheck.h @@ -0,0 +1,8 @@ +#ifndef _PWCHECK_H +#define _PWCHECK_H + + +int Getpass(char *); + +#endif + diff --git a/mbsebbs/pwio.c b/mbsebbs/pwio.c new file mode 100644 index 00000000..bd8cd640 --- /dev/null +++ b/mbsebbs/pwio.c @@ -0,0 +1,249 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/pwio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 18-Sep-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "sgetpwent.h" +#include "commonio.h" +#include "pwio.h" + + + + + +struct passwd *__pw_dup(const struct passwd *pwent) +{ + struct passwd *pw; + + if (!(pw = (struct passwd *) malloc(sizeof *pw))) + return NULL; + *pw = *pwent; + if (!(pw->pw_name = strdup(pwent->pw_name))) + return NULL; + if (!(pw->pw_passwd = strdup(pwent->pw_passwd))) + return NULL; +#ifdef ATT_AGE + if (!(pw->pw_age = strdup(pwent->pw_age))) + return NULL; +#endif +#ifdef ATT_COMMENT + if (!(pw->pw_comment = strdup(pwent->pw_comment))) + return NULL; +#endif + if (!(pw->pw_gecos = strdup(pwent->pw_gecos))) + return NULL; + if (!(pw->pw_dir = strdup(pwent->pw_dir))) + return NULL; + if (!(pw->pw_shell = strdup(pwent->pw_shell))) + return NULL; + return pw; +} + + + +static void *passwd_dup(const void *ent) +{ + const struct passwd *pw = ent; + return __pw_dup(pw); +} + + + +static void passwd_free(void *ent) +{ + struct passwd *pw = ent; + + free(pw->pw_name); + free(pw->pw_passwd); +#ifdef ATT_AGE + free(pw->pw_age); +#endif +#ifdef ATT_COMMENT + free(pw->pw_comment); +#endif + free(pw->pw_gecos); + free(pw->pw_dir); + free(pw->pw_shell); + free(pw); +} + + + +static const char *passwd_getname(const void *ent) +{ + const struct passwd *pw = ent; + return pw->pw_name; +} + + + +static void *passwd_parse(const char *line) +{ + return (void *) sgetpwent(line); +} + + + +static int passwd_put(const void *ent, FILE *file) +{ + const struct passwd *pw = ent; + return (putpwent(pw, file) == -1) ? -1 : 0; +} + + + +static struct commonio_ops passwd_ops = { + passwd_dup, + passwd_free, + passwd_getname, + passwd_parse, + passwd_put, + fgets, + fputs +}; + + + +static struct commonio_db passwd_db = { + "/etc/passwd", + &passwd_ops, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0 +}; + + + +int pw_name(const char *filename) +{ + return commonio_setname(&passwd_db, filename); +} + + + +int pw_lock(void) +{ + return commonio_lock(&passwd_db); +} + + + +int pw_lock_first(void) +{ + return commonio_lock_first(&passwd_db); +} + + + +int pw_open(int mode) +{ + return commonio_open(&passwd_db, mode); +} + + + +const struct passwd *pw_locate(const char *name) +{ + return commonio_locate(&passwd_db, name); +} + + + +int pw_update(const struct passwd *pw) +{ + return commonio_update(&passwd_db, (const void *) pw); +} + + + +int pw_remove(const char *name) +{ + return commonio_remove(&passwd_db, name); +} + + + +int pw_rewind(void) +{ + return commonio_rewind(&passwd_db); +} + + + +const struct passwd *pw_next(void) +{ + return commonio_next(&passwd_db); +} + + + +int pw_close(void) +{ + return commonio_close(&passwd_db); +} + + + +int pw_unlock(void) +{ + return commonio_unlock(&passwd_db); +} + + + +struct commonio_entry *__pw_get_head(void) +{ + return passwd_db.head; +} + + + +void __pw_del_entry(const struct commonio_entry *ent) +{ + commonio_del_entry(&passwd_db, ent); +} + + diff --git a/mbsebbs/pwio.h b/mbsebbs/pwio.h new file mode 100644 index 00000000..f21b263b --- /dev/null +++ b/mbsebbs/pwio.h @@ -0,0 +1,19 @@ +#ifndef _PWIO_H +#define _PWIO_H + +struct passwd *__pw_dup (const struct passwd *); +void __pw_set_changed (void); +int pw_close (void); +const struct passwd *pw_locate (const char *); +int pw_lock (void); +int pw_lock_first (void); +int pw_name (const char *); +const struct passwd *pw_next (void); +int pw_open (int); +int pw_remove (const char *); +int pw_rewind (void); +int pw_unlock (void); +int pw_update (const struct passwd *); + +#endif + diff --git a/mbsebbs/rad64.c b/mbsebbs/rad64.c new file mode 100644 index 00000000..991f37a0 --- /dev/null +++ b/mbsebbs/rad64.c @@ -0,0 +1,157 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/rad64c.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Sep-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1989 - 1992, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include "rad64.h" + + +#ifndef HAVE_C64I +/* + * c64i - convert a radix 64 character to an integer + */ +int c64i(char c) +{ + if (c == '.') + return (0); + + if (c == '/') + return (1); + + if (c >= '0' && c <= '9') + return (c - '0' + 2); + + if (c >= 'A' && c <= 'Z') + return (c - 'A' + 12); + + if (c >= 'a' && c <= 'z') + return (c - 'a' + 38); + else + return (-1); +} + + + +/* + * i64c - convert an integer to a radix 64 character + */ +int i64c(int i) +{ + if (i <= 0) + return ('.'); + + if (i == 1) + return ('/'); + + if (i >= 2 && i < 12) + return ('0' - 2 + i); + + if (i >= 12 && i < 38) + return ('A' - 12 + i); + + if (i >= 38 && i < 63) + return ('a' - 38 + i); + + return ('z'); +} +#endif + + +#ifndef HAVE_A64L +/* + * l64a - convert a long to a string of radix 64 characters + */ +char *l64a(long l) +{ + static char buf[8]; + int i = 0; + + if (l < 0L) + return ((char *) 0); + + do { + buf[i++] = i64c ((int) (l % 64)); + buf[i] = '\0'; + } while (l /= 64L, l > 0 && i < 6); + + return (buf); +} + + + +/* + * a64l - convert a radix 64 string to a long integer + */ +long a64l(const char *s) +{ + int i; + long value; + long shift = 0; + + for (i = 0, value = 0L;i < 6 && *s;s++) { + value += (c64i (*s) << shift); + shift += 6; + } + return (value); +} + +#endif /* !HAVE_A64L */ + diff --git a/mbsebbs/rad64.h b/mbsebbs/rad64.h new file mode 100644 index 00000000..3391cafb --- /dev/null +++ b/mbsebbs/rad64.h @@ -0,0 +1,15 @@ +#ifndef _RAD64_H +#define _RAD64_H + + +#ifndef HAVE_C64I +int c64i(char); +int i64c(int); +#endif +#ifndef HAVE_A64L +char *l64a(long); +long a64l(const char *); +#endif + +#endif + diff --git a/mbsebbs/safe.c b/mbsebbs/safe.c new file mode 100644 index 00000000..86d38e67 --- /dev/null +++ b/mbsebbs/safe.c @@ -0,0 +1,457 @@ +/***************************************************************************** + * + * File ..................: bbs/safe.c + * Purpose ...............: Safe Door + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "exitinfo.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "safe.h" +#include "timeout.h" +#include "language.h" + + + +FILE *pSafe; + +int iLoop, iFirst, iSecond, iThird; +char sFirst[4], sSecond[4], sThird[4]; + + +int getdigits(void); +int SafeCheckUser(void); + + + +void Safe(void) +{ + long isize; + int i; + + isize = sizeof(int); + srand(Time_Now); + + WhosDoingWhat(SAFE); + + Syslog('+', "User starts Safe Cracker Door"); + + Enter(1); + /* Safe Cracker Door */ + pout(15, 0, (char *) Language(86)); + Enter(1); + + clear(); + + DisplayFile(CFG.sSafeWelcome); + + if (SafeCheckUser() == TRUE) + return; + + /* In the safe lies */ + pout(15, 0, (char *) Language(87)); + + fflush(stdout); + alarm_on(); + Getone(); + + clear(); + + Enter(2); + pout(10, 0, (char *) Language(88)); + Enter(2); + + colour(13, 0); + printf("%s", CFG.sSafePrize); + + Enter(2); + /* Do you want to open the safe ? [Y/n]: */ + pout(15, 0, (char *) Language(102)); + + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + + if (i == Keystroke(102, 1)) { + Syslog('+', "User exited Safe Cracker Door"); + return; + } + + /* + * Loop until the safe is opened, maximum trys + * exceeded or the user is tired of this door. + */ + while (TRUE) { + /* Get digits, TRUE if safe cracked. */ + if (getdigits() == TRUE) + break; + + Enter(1); + /* Do you want to try again ? [Y/n]: */ + pout(12, 0, (char *) Language(101)); + fflush(stdout); + + alarm_on(); + i = toupper(Getone()); + if (i == Keystroke(101, 1)) + break; + + if (SafeCheckUser() == TRUE) + break; + } + Syslog('+', "User exited Safe Cracker Door"); +} + + + +/* + * Ask use for digits, returns TRUE if the safe is cracked. + */ +int getdigits(void) +{ + long result; + int i; + char temp[81]; + + colour(15, 0); + /* Please enter three numbers consisting from 1 to */ + printf("\n\n%s%d\n", (char *) Language(89), CFG.iSafeMaxNumber); + /* Please enter three combinations. */ + printf("%s", (char *) Language(90)); + + while (TRUE) { + Enter(2); + /* 1st Digit */ + pout(12, 0, (char *) Language(91)); + colour(9, 0); + fflush(stdout); + Getnum(sFirst, 2); + sprintf(temp, "1st: %s", sFirst); + if((strcmp(sFirst, "")) != 0) { + Syslog('-', temp); + iFirst=atoi(sFirst); + } + + if((iFirst > CFG.iSafeMaxNumber) || (iFirst <= 0) || (strcmp(sFirst, "") == 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + while (TRUE) { + Enter(1); + /* 2nd digit: */ + pout(12, 0, (char *) Language(93)); + colour(9, 0); + fflush(stdout); + Getnum(sSecond, 2); + sprintf(temp, "2nd: %s", sSecond); + if((strcmp(sSecond, "")) != 0) { + Syslog('-', temp); + iSecond=atoi(sSecond); + } + + if((iSecond > CFG.iSafeMaxNumber) || (iSecond <= 0) || (strcmp(sSecond, "") == 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.\n", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + while (TRUE) { + Enter(1); + pout(12, 0, (char *) Language(94)); + colour(9, 0); + fflush(stdout); + Getnum(sThird, 2); + if((strcmp(sThird, "")) != 0) { + if((strcmp(sThird, "737") != 0) && (strcmp(sThird, "747") != 0)) { + sprintf(temp, "3rd: %s", sThird); + Syslog('!', temp); + } else { + sprintf(temp, "3rd: %d", CFG.iSafeMaxNumber - 1); + Syslog('-', temp); + } + } + iThird=atoi(sThird); + + if((iThird == 737) || (iThird == 747)) + break; + + if((iThird > CFG.iSafeMaxNumber) || (iThird <= 0)) { + colour(15,1); + /* Please try again! You must input a number greater than Zero and less than */ + printf("\n%s%d.\n", (char *) Language(92), CFG.iSafeMaxNumber); + Syslog('-', "Value out of range!"); + } else + break; + } + + /* Left: */ + Enter(1); + pout(12, 0, (char *) Language(95)); + poutCR(9, 0, sFirst); + + /* Right: */ + pout(12, 0, (char *) Language(96)); + poutCR(9, 0, sSecond); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + poutCR(9, 0, sThird); + + Enter(1); + /* Attempt to open safe with this combination [Y/n]: */ + pout(12, 0, (char *) Language(97)); + fflush(stdout); + alarm_on(); + i = toupper(Getone()); + sprintf(temp, "%c", i); + + if ((i == Keystroke(97, 0)) || (i == 13)) { + printf("\n\n"); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + for (iLoop = 0; iLoop < iFirst; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sFirst); + + /* Right: */ + pout(12, 0, (char *) Language(96)); + for (iLoop = 0; iLoop < iSecond; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sSecond); + + /* Left: */ + pout(12, 0, (char *) Language(95)); + for (iLoop = 0; iLoop < iThird; iLoop++) + pout(14, 0, (char *)"."); + poutCR(9, 0, sThird); + + if(CFG.iSafeNumGen) { + CFG.iSafeFirstDigit = (rand() % CFG.iSafeMaxNumber) + 1; + CFG.iSafeSecondDigit = (rand() % CFG.iSafeMaxNumber) + 1; + CFG.iSafeThirdDigit = (rand() % CFG.iSafeMaxNumber) + 1; + } + + if(CFG.iSafeFirstDigit == iFirst) + if(CFG.iSafeSecondDigit == iSecond) + if(CFG.iSafeThirdDigit == iThird) { + + DisplayFile(CFG.sSafeOpened); + + Enter(1); + /* You have won the following... */ + pout(12, 0, (char *) Language(98)); + Enter(2); + poutCR(13, 0, CFG.sSafePrize); + Enter(1); + + sprintf(temp, "%s/etc/safe.data", getenv("MBSE_ROOT")); + if(( pSafe = fopen(temp, "r+")) == NULL) + WriteError("Can't open %s for updating", temp); + else { + fseek(pSafe, 0L, SEEK_END); + result = ftell(pSafe); + result /= sizeof(safe); + + fread(&safe, sizeof(safe), 1, pSafe); + + safe.Opened = TRUE; + + fseek(pSafe, 0L, SEEK_END); + result = ftell(pSafe); + result /= sizeof(safe); + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + + Syslog('!', "User opened Safe Cracker Door"); + + Pause(); + return TRUE; + } + + Enter(1); + pout(10, 0, (char *) Language(99)); + Enter(1); + + if(CFG.iSafeNumGen) { + Enter(1); + /* The safe code was: */ + pout(12, 0, (char *) Language(100)); + Enter(2); + colour(12, 0); + + /* Left: */ + printf("%s%d\n", (char *) Language(95), CFG.iSafeFirstDigit); + + /* Right */ + printf("%s%d\n", (char *) Language(96), CFG.iSafeSecondDigit); + + /* Left */ + printf("%s%d\n", (char *) Language(95), CFG.iSafeThirdDigit); + } + + if(iThird == 737) + CFG.iSafeNumGen = FALSE; + + if(iThird == 747) { + colour(9, 0); + printf("Code: %d %d %d\n", CFG.iSafeFirstDigit, CFG.iSafeSecondDigit, CFG.iSafeThirdDigit); + } + + Enter(1); + /* Please press key to continue */ + pout(10, 0, (char *) Language(87)); + alarm_on(); + getchar(); + } + return FALSE; +} + + + +/* + * Returns true when safe already cracked or maximum trys exceeded + */ +int SafeCheckUser(void) +{ + int Counter = 0; + char *File, *Name, *Date; + + File = calloc(PATH_MAX, sizeof(char)); + Name = calloc(50, sizeof(char)); + Date = calloc(50, sizeof(char)); + + sprintf(Name, "%s", exitinfo.sUserName); + sprintf(Date, "%s", (char *) GetDateDMY()); + sprintf(File, "%s/etc/safe.data", getenv("MBSE_ROOT")); + + if(( pSafe = fopen(File, "r")) == NULL) { + if((pSafe = fopen(File, "w")) != NULL) { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } else { + while ( fread(&safe, sizeof(safe), 1, pSafe) == 1) { + if(safe.Opened) { + fclose(pSafe); + Syslog('+', "Safe is currently LOCKED - exiting door."); + + /* THE SAFE IS CURRENTLY LOCKED */ + poutCR(15, 4, (char *) Language(103)); + Enter(1); + colour(12, 0); + + /* has cracked the safe. */ + printf("%s, %s\n", safe.Name, (char *) Language(104)); + + /* The safe will remain locked until the sysop rewards the user. */ + pout(10, 0, (char *) Language(105)); + Enter(2); + Pause(); + fclose(pSafe); + free(File); + free(Name); + free(Date); + return TRUE; + } + } + rewind(pSafe); + + fread(&safe, sizeof(safe), 1, pSafe); + if((strcmp(Date, safe.Date)) != 0) { + fclose(pSafe); + if((pSafe = fopen(File, "w")) != NULL) { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } else { + while ( fread(&safe, sizeof(safe), 1, pSafe) == 1) { + if((strcmp(Name, safe.Name)) == 0) + Counter++; + } + + rewind(pSafe); + + if(Counter >= CFG.iSafeMaxTrys - 1) { + Enter(2); + /* Maximum trys per day exceeded */ + pout(15, 0, (char *) Language(106)); + Enter(1); + sleep(3); + fclose(pSafe); + free(File); + free(Name); + free(Date); + return TRUE; + } + + fclose(pSafe); + + if(( pSafe = fopen(File, "a+")) == NULL) + WriteError("Unable to append to safe.data", File); + else { + sprintf(safe.Date, "%s", (char *) GetDateDMY()); + sprintf(safe.Name, "%s", Name); + safe.Trys = 0; + safe.Opened = 0; + fwrite(&safe, sizeof(safe), 1, pSafe); + fclose(pSafe); + } + } + } + free(File); + free(Name); + free(Date); + return FALSE; +} + + diff --git a/mbsebbs/safe.h b/mbsebbs/safe.h new file mode 100644 index 00000000..f9c10461 --- /dev/null +++ b/mbsebbs/safe.h @@ -0,0 +1,11 @@ +/* safe.h */ + +#ifndef _SAFE_H +#define _SAFE_H + + +void Safe(void); + + +#endif + diff --git a/mbsebbs/salt.c b/mbsebbs/salt.c new file mode 100644 index 00000000..2cff3d81 --- /dev/null +++ b/mbsebbs/salt.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/salt.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-May-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * salt.c - generate a random salt string for crypt() + * + * Written by Marek Michalkiewicz , + * public domain. + */ +#include "../config.h" +#include +#include +#include +#include +#include "rad64.h" + + +#if 1 +#include "getdef.h" + + +/* + * Generate 8 base64 ASCII characters of random salt. If MD5_CRYPT_ENAB + * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$" + * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible + * version of crypt() instead of the standard one. + */ +char *crypt_make_salt(void) +{ + struct timeval tv; + static char result[40]; + + result[0] = '\0'; + if (getdef_bool("MD5_CRYPT_ENAB")) { + strcpy(result, "$1$"); /* magic for the new MD5 crypt() */ + } + + /* + * Generate 8 chars of salt, the old crypt() will use only first 2. + */ + gettimeofday(&tv, (struct timezone *) 0); + strcat(result, l64a(tv.tv_usec)); + strcat(result, l64a(tv.tv_sec + getpid() + clock())); + + if (strlen(result) > 3 + 8) /* magic+salt */ + result[11] = '\0'; + + return result; +} +#else + +/* + * This is the old style random salt generator... + */ +char *crypt_make_salt(void) +{ + time_t now; + static unsigned long x; + static char result[3]; + + time(&now); + x += now + getpid() + clock(); + result[0] = i64c(((x >> 18) ^ (x >> 6)) & 077); + result[1] = i64c(((x >> 12) ^ x) & 077); + result[2] = '\0'; + return result; +} +#endif diff --git a/mbsebbs/salt.h b/mbsebbs/salt.h new file mode 100644 index 00000000..ff7cbfd5 --- /dev/null +++ b/mbsebbs/salt.h @@ -0,0 +1,9 @@ +#ifndef _SALT_H +#define _SALT_H + + +char *crypt_make_salt(void); + + +#endif + diff --git a/mbsebbs/sgetpwent.c b/mbsebbs/sgetpwent.c new file mode 100644 index 00000000..a9d6d6e9 --- /dev/null +++ b/mbsebbs/sgetpwent.c @@ -0,0 +1,167 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/sgetpwent.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 07-Feb-2001 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +/* + * Copyright 1989 - 1994, Julianne Frances Haugh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "../config.h" +#include +#include +#include +#include "sgetpwent.h" + + +#define NFIELDS 7 + +/* + * sgetpwent - convert a string to a (struct passwd) + * + * sgetpwent() parses a string into the parts required for a password + * structure. Strict checking is made for the UID and GID fields and + * presence of the correct number of colons. Any failing tests result + * in a NULL pointer being returned. + * + * NOTE: This function uses hard-coded string scanning functions for + * performance reasons. I am going to come up with some conditional + * compilation glarp to improve on this in the future. + */ + +struct passwd * sgetpwent(const char *buf) +{ + static struct passwd pwent; + static char pwdbuf[1024]; + register int i; + register char *cp; + char *ep; + char *fields[NFIELDS]; + + /* + * Copy the string to a static buffer so the pointers into + * the password structure remain valid. + */ + + if (strlen(buf) >= sizeof pwdbuf) + return 0; + strcpy(pwdbuf, buf); + + /* + * Save a pointer to the start of each colon separated + * field. The fields are converted into NUL terminated strings. + */ + + for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) { + fields[i] = cp; + while (*cp && *cp != ':') + ++cp; + + if (*cp) + *cp++ = '\0'; + else + cp = 0; + } + + /* + * There must be exactly NFIELDS colon separated fields or + * the entry is invalid. Also, the UID and GID must be non-blank. + */ + + if (i != NFIELDS || *fields[2] == '\0' || *fields[3] == '\0') + return 0; + + /* + * Each of the fields is converted the appropriate data type + * and the result assigned to the password structure. If the + * UID or GID does not convert to an integer value, a NULL + * pointer is returned. + */ + + pwent.pw_name = fields[0]; + pwent.pw_passwd = fields[1]; + if (fields[2][0] == '\0' || + ((pwent.pw_uid = strtol (fields[2], &ep, 10)) == 0 && *ep)) { + return 0; + } + if (fields[3][0] == '\0' || + ((pwent.pw_gid = strtol (fields[3], &ep, 10)) == 0 && *ep)) { + return 0; + } +#ifdef ATT_AGE + cp = pwent.pw_passwd; + while (*cp && *cp != ',') + ++cp; + + if (*cp) { + *cp++ = '\0'; + pwent.pw_age = cp; + } else { + cp = 0; + pwent.pw_age = ""; + } +#endif + pwent.pw_gecos = fields[4]; +#ifdef ATT_COMMENT + pwent.pw_comment = ""; +#endif + pwent.pw_dir = fields[5]; + pwent.pw_shell = fields[6]; + + return &pwent; +} + + diff --git a/mbsebbs/sgetpwent.h b/mbsebbs/sgetpwent.h new file mode 100644 index 00000000..90777b1d --- /dev/null +++ b/mbsebbs/sgetpwent.h @@ -0,0 +1,7 @@ +#ifndef _SGETPWENT_H +#define _SGETPWENT_H + +struct passwd * sgetpwent(const char *); + +#endif + diff --git a/mbsebbs/shadowio.c b/mbsebbs/shadowio.c new file mode 100644 index 00000000..84ecd3d7 --- /dev/null +++ b/mbsebbs/shadowio.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/shadowio.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 13-Aug-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +#include "../config.h" + +#ifdef SHADOW_PASSWORD +#include +#include +#include +#include + + +#include "commonio.h" +#include "shadowio.h" + + + +struct spwd *__spw_dup(const struct spwd *spent) +{ + struct spwd *sp; + + if (!(sp = (struct spwd *) malloc(sizeof *sp))) + return NULL; + *sp = *spent; + if (!(sp->sp_namp = strdup(spent->sp_namp))) + return NULL; + if (!(sp->sp_pwdp = strdup(spent->sp_pwdp))) + return NULL; + return sp; +} + + + +static void * shadow_dup(const void *ent) +{ + const struct spwd *sp = ent; + return __spw_dup(sp); +} + + + +static void shadow_free(void *ent) +{ + struct spwd *sp = ent; + + free(sp->sp_namp); + free(sp->sp_pwdp); + free(sp); +} + + + +static const char * shadow_getname(const void *ent) +{ + const struct spwd *sp = ent; + return sp->sp_namp; +} + + + +static void * shadow_parse(const char *line) +{ + return (void *) sgetspent(line); +} + + + +static int shadow_put(const void *ent, FILE *file) +{ + const struct spwd *sp = ent; + return (putspent(sp, file) == -1) ? -1 : 0; +} + + + +static struct commonio_ops shadow_ops = { + shadow_dup, + shadow_free, + shadow_getname, + shadow_parse, + shadow_put, + fgets, + fputs +}; + + + +static struct commonio_db shadow_db = { + SHADOW_FILE, + &shadow_ops, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0, + 0 +}; + + + +int spw_name(const char *filename) +{ + return commonio_setname(&shadow_db, filename); +} + + + +int spw_file_present(void) +{ + return commonio_present(&shadow_db); +} + + + +int spw_lock(void) +{ + return commonio_lock(&shadow_db); +} + + + +int spw_lock_first(void) +{ + return commonio_lock_first(&shadow_db); +} + + + +int spw_open(int mode) +{ + return commonio_open(&shadow_db, mode); +} + + + +const struct spwd * spw_locate(const char *name) +{ + return commonio_locate(&shadow_db, name); +} + + + +int spw_update(const struct spwd *sp) +{ + return commonio_update(&shadow_db, (const void *) sp); +} + + + +int spw_remove(const char *name) +{ + return commonio_remove(&shadow_db, name); +} + + + +int spw_rewind(void) +{ + return commonio_rewind(&shadow_db); +} + + + +const struct spwd * spw_next(void) +{ + return commonio_next(&shadow_db); +} + + + +int spw_close(void) +{ + return commonio_close(&shadow_db); +} + + + +int spw_unlock(void) +{ + return commonio_unlock(&shadow_db); +} + + + +struct commonio_entry * __spw_get_head(void) +{ + return shadow_db.head; +} + + + +void __spw_del_entry(const struct commonio_entry *ent) +{ + commonio_del_entry(&shadow_db, ent); +} + + +#endif + diff --git a/mbsebbs/shadowio.h b/mbsebbs/shadowio.h new file mode 100644 index 00000000..2bb725f7 --- /dev/null +++ b/mbsebbs/shadowio.h @@ -0,0 +1,27 @@ +#ifndef _SHADOWIO_H +#define _SHADOWIO_H + +#ifdef SHADOW_PASSWORD +#ifndef SHADOW_FILE +#define SHADOW_FILE "/etc/shadow" +#endif +#endif + + +struct spwd *__spw_dup (const struct spwd *); +void __spw_set_changed (void); +int spw_close (void); +int spw_file_present (void); +const struct spwd *spw_locate (const char *); +int spw_lock (void); +int spw_lock_first (void); +int spw_name (const char *); +const struct spwd *spw_next (void); +int spw_open (int); +int spw_remove (const char *); +int spw_rewind (void); +int spw_unlock (void); +int spw_update (const struct spwd *); + +#endif + diff --git a/mbsebbs/statetbl.h b/mbsebbs/statetbl.h new file mode 100644 index 00000000..5ed4475f --- /dev/null +++ b/mbsebbs/statetbl.h @@ -0,0 +1,48 @@ +#ifndef STATETBL_H +#define STATETBL_H + +#define SM_DECL(proc,name) \ +int proc(void)\ +{\ + int sm_success=0;\ + char *sm_name=name; + +#define SM_STATES \ + enum { + +#define SM_NAMES \ + } sm_state;\ + char * sm_sname[] = { + +#define SM_EDECL \ + }; + +#define SM_START(x) \ + sm_state=x;\ + Syslog('S', "Statemachine %s start %s (%d)", sm_name, sm_sname[sm_state], sm_state);\ + while (!sm_success) switch (sm_state)\ + {\ + default: WriteError("Statemachine %s error: state=%d",sm_name,sm_state);\ + sm_success=-1; + +#define SM_STATE(x) \ + break;\ + case x: + +#define SM_END \ + }\ + +#define SM_RETURN \ + return (sm_success != 1);\ +} + +#define SM_PROCEED(x) \ + sm_state=x; break; + +#define SM_SUCCESS \ + sm_success=1; break; + +#define SM_ERROR \ + sm_success=-1; break; + +#endif diff --git a/mbsebbs/timecheck.c b/mbsebbs/timecheck.c new file mode 100644 index 00000000..3f16dc50 --- /dev/null +++ b/mbsebbs/timecheck.c @@ -0,0 +1,96 @@ +/***************************************************************************** + * + * File ..................: bbs/timecheck.c + * Purpose ...............: Timecheck functions + * Last modification date : 28-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbroek@users.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "timecheck.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "bye.h" +#include "exitinfo.h" +#include "language.h" + + +/* + * This is the users onlinetime check. Must be REWRITTEN!! + */ +void TimeCheck(void) +{ + char temp[81]; + time_t Now; + int Elapsed; + + time(&Now); + + /* + * Update the global string for the menu prompt + */ + sprintf(sUserTimeleft, "%d", iUserTimeLeft); + ReadExitinfo(); + + if (iUserTimeLeft != ((Time2Go - Now) / 60)) { + + Elapsed = iUserTimeLeft - ((Time2Go - Now) / 60); + iUserTimeLeft -= Elapsed; + sprintf(sUserTimeleft, "%d", iUserTimeLeft); + + sprintf(temp, "/tmp/.chat.%s", pTTY); + /* + * Update users counter if not chatting + */ + if(!CFG.iStopChatTime || (access(temp, F_OK) != 0)) { + exitinfo.iTimeLeft -= Elapsed; + exitinfo.iConnectTime += Elapsed; + exitinfo.iTimeUsed += Elapsed; + WriteExitinfo(); + } + } + + if(exitinfo.iTimeLeft <= 0) { + printf("\n%s\n", (char *) Language(130)); + sleep(3); + Syslog('!', "Users time limit exceeded ... user disconnected!"); + iExpired = TRUE; + Good_Bye(1); + } + + /* + * Check for a personal message + */ + Check_PM(); +} + + diff --git a/mbsebbs/timecheck.h b/mbsebbs/timecheck.h new file mode 100644 index 00000000..f104fa70 --- /dev/null +++ b/mbsebbs/timecheck.h @@ -0,0 +1,8 @@ +#ifndef _TIMECHECK_H +#define _TIMECHECK_H + +void TimeCheck(void); /* Check Users Time Limit */ + + +#endif + diff --git a/mbsebbs/timeout.c b/mbsebbs/timeout.c new file mode 100644 index 00000000..77ce64e1 --- /dev/null +++ b/mbsebbs/timeout.c @@ -0,0 +1,144 @@ +/***************************************************************************** + * + * File ..................: bbs/timeout.c + * Purpose ...............: Inactivity timeout functions + * Last modification date : 24-Dec-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "timeout.h" +#include "funcs.h" +#include "funcs4.h" +#include "bye.h" +#include "filesub.h" +#include "language.h" + + +extern int e_pid; /* Pid of external program */ + + + +void die(int onsig) +{ + /* + * First check if there is a child running, if so, kill it. + */ + if (e_pid) { + if ((kill(e_pid, SIGTERM)) == 0) + Syslog('+', "SIGTERM to pid %d succeeded", e_pid); + else { + if ((kill(e_pid, SIGKILL)) == 0) + Syslog('+', "SIGKILL to pid %d succeeded", e_pid); + else + WriteError("Failed to kill pid %d", e_pid); + } + + /* + * In case the child had the tty in raw mode, reset the tty + */ + system("stty sane"); + } + + if (MsgBase.Locked) + Msg_UnLock(); + if (MsgBase.Open) + Msg_Close(); + + Home(); + signal(onsig, SIG_IGN); + if (onsig) + if (onsig == SIGHUP) { + Syslog('+', "Lost Carrier"); + } else if (onsig == SIGALRM) { + Syslog('+', "User inactivity timeout"); + } else { + if (onsig <= NSIG) + WriteError("$Terminated on signal %d (%s)", onsig, SigName[onsig]); + else + WriteError("Terminated with error %d", onsig); + } + else + Syslog(' ', "Terminated by user"); + + if (onsig == SIGSEGV) { + Syslog('+', "Last msg area %s", msgs.Name); + } + + if (LoginPrompt) { + Unsetraw(); + Quick_Bye(onsig); + } else + Good_Bye(onsig); +} + + + +void alarm_sig() +{ + colour(12, 0); + /* Autologout: idletime reached.*/ + printf("\r\n%s\r\n", (char *) Language(410)); + + if (LoginPrompt) + Syslog('!', "Autologout: idletime reached at login prompt"); + else + Syslog('!', "Autologout: idletime reached"); + + die(SIGALRM); +} + + + +void alarm_set(int val) +{ + signal(SIGALRM, (void (*))alarm_sig); + alarm(val); + Syslog('S', "Alarm set for %d seconds", val); +} + + + +void alarm_on() +{ + alarm_set(60 * CFG.idleout); +} + + + +void alarm_off() +{ + alarm(0); + signal(SIGALRM, SIG_IGN); + Syslog('S', "Alarm is off"); +} + diff --git a/mbsebbs/timeout.h b/mbsebbs/timeout.h new file mode 100644 index 00000000..e7835b52 --- /dev/null +++ b/mbsebbs/timeout.h @@ -0,0 +1,12 @@ +#ifndef _TIMEOUT_H +#define _TIMEOUT_H + +void die(int); +void alarm_sig(void); +void alarm_set(int); +void alarm_on(void); +void alarm_off(void); + + +#endif + diff --git a/mbsebbs/user.c b/mbsebbs/user.c new file mode 100644 index 00000000..d8964131 --- /dev/null +++ b/mbsebbs/user.c @@ -0,0 +1,1157 @@ +/***************************************************************************** + * + * File ..................: bbs/user.c + * Purpose ...............: Main user login procedure. Checks for limits, + * new ratio's cats all the welcome screens, and + * does a lot of checking in general. + * Last modification date : 28-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/mbse.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "timeout.h" +#include "user.h" +#include "pwcheck.h" +#include "funcs.h" +#include "funcs4.h" +#include "misc.h" +#include "bye.h" +#include "file.h" +#include "mail.h" +#include "change.h" +#include "menu.h" +#include "exitinfo.h" +#include "language.h" +#include "offline.h" +#include "statetbl.h" +#include "email.h" +#include "newuser.h" + + +extern int sock; +extern pid_t mypid; + + +/* Non global function prototypes */ + +char *AskLogin(void); +static int rxemsi(void); + + +char *Passwd = NULL; +int iMaxLogin = 1; +char *ieUserName = NULL; +char *ieHandle = NULL; +char *ieLocation = NULL; +char *ieVoicePhone = NULL; +char *ieDataPhone = NULL; +long iePassword = 0; +char *ieBirthDate = NULL; +char *ieTerminal = NULL; +int ieRows = 0; +int ieCols = 0; +int ieNulls = 0; +int ieDZA = FALSE; +int ieZAP = FALSE; +int ieZMO = FALSE; +int ieSLK = FALSE; +int ieKER = FALSE; +int ieCHT = FALSE; +int ieMNU = FALSE; +int ieTAB = FALSE; +int ieASCII8 = FALSE; +int ieNEWS = FALSE; +int ieMAIL = FALSE; +int ieFILE = FALSE; +int ieHOT = FALSE; +int ieCLR = FALSE; +int ieHUSH = FALSE; +int ieMORE = FALSE; +int ieFSED = FALSE; +int ieXPRS = FALSE; +char *ieSoftware = NULL; +int ieLogin = FALSE; + + + +/* + * Ask for BBS Login name (Firstname Lastname) and try to + * establish an IEMSI session if the client supports it. + */ +char *AskLogin(void); +char *AskLogin(void) +{ + char temp[36]; + int Count = 0, rc = 0; + static char GetName[36]; + + do { + /* + * if after the first time IEMSI failed rc will not be + * zero anymore so we don't check for IEMSI logon anymore. + */ + if (rc == 0) { + rc = rxemsi(); + if (rc) + Syslog('+', "rxemsi rc=%d", rc); + } + if (rc) { + /* + * IEMSI Aborted or other errors, so prompt user. + * Note that if the user didn't had an IEMSI client, + * rc is still 0, the name is entered in the rxemsi + * function. + */ + /* Please enter your First and Last name: */ + language(7, 0, 0); + fflush(stdout); + alarm_on(); + Getname(GetName, 35); + } else { + sprintf(GetName, "%s", ieUserName); + } + + if ((strcmp(GetName,"")) == 0) { + Count++; + + if (Count >= CFG.iCRLoginCount) { + Enter(1); + /* Disconnecting user ... */ + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + Syslog('!', "Exceeded maximum login attempts"); + free(Passwd); + Quick_Bye(0); + } + } + } while (strcmp(GetName, "") == 0); + + strcpy(temp, GetName); + + /* + * Secret escape name + */ + if ((strcasecmp(temp, "off")) == 0) { + Syslog('+', "Quick \"off\" logout"); + free(Passwd); + Quick_Bye(0); + } + + /* + * Check for singlename + */ + if ((strchr(GetName,' ') == NULL && !CFG.iOneName)) { + Syslog('+', "Did not enter a full name"); + + Count = -1; + while (TRUE) { + do { + Count++; + if (Count >= CFG.iCRLoginCount) { + Enter(1); + /* Disconnecting user ... */ + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + Syslog('!', "Exceeded maximum login attempts"); + free(Passwd); + Quick_Bye(0); + } + + /* Please enter your Last name: */ + language(7, 0, 1); + fflush(stdout); + alarm_on(); + Getname(temp, 34 - strlen(GetName)); + } while ((strcmp(temp, "")) == 0); + + if((strcmp(temp,"")) != 0) { + strcat(GetName," "); + strcat(GetName,temp); + break; + } + } + } + + alarm_off(); + return GetName; +} + + + +/* + * The next function is "borrowed" from Eugene M. Crossers ifcico. + */ +char *sel_brace(char *); +char *sel_brace(char *s) +{ + static char *save; + char *p, *q; + int i; + + if (s == NULL) + s = save; + for (; *s && (*s != '{'); s++); + if (*s == '\0') { + save = s; + return NULL; + } else + s++; + + for (p = s, q = s; *p; p++) + switch(*p) { + case '}': if (*(p+1) == '}') + *q++ = *p++; + else { + *q = '\0'; + save = p+1; + goto exit; + } + break; + + case '\\': if (*(p+1) == '\\') + *q++ = *p++; + else { + sscanf(p+1, "%02x", &i); + *q++ = i; + p+=2; + } + break; + + default: *q++ = *p; + break; + } +exit: + return s; +} + + + +int scanemsiici(char *); +int scanemsiici(char *buf) +{ + char *p, *q; + + ieUserName = xstrcpy(sel_brace(buf)); + Syslog('i', "Username : %s", MBSE_SS(ieUserName)); + ieHandle = xstrcpy(sel_brace(NULL)); + Syslog('i', "Handle : %s", MBSE_SS(ieHandle)); + ieLocation = xstrcpy(sel_brace(NULL)); + Syslog('i', "Location : %s", MBSE_SS(ieLocation)); + ieVoicePhone = xstrcpy(sel_brace(NULL)); + Syslog('i', "Voice Phone : %s", MBSE_SS(ieVoicePhone)); + ieDataPhone = xstrcpy(sel_brace(NULL)); + Syslog('i', "Data Phone : %s", MBSE_SS(ieDataPhone)); + p = sel_brace(NULL); + memset(Passwd, 0, 16); + if (strlen(p) < 16) + sprintf(Passwd, "%s", p); + iePassword = StringCRC32(tu(p)); + Syslog('i', "Password : %s (%ld)", p, iePassword); + ieBirthDate = xstrcpy(sel_brace(NULL)); + Syslog('i', "Birthdate : %s", MBSE_SS(ieBirthDate)); + p = sel_brace(NULL); + ieTerminal = strtok(p, ","); + ieRows = atoi(strtok(NULL, ",")); + ieCols = atoi(strtok(NULL, ",")); + ieNulls = atoi(strtok(NULL, ",")); + Syslog('i', "Terminal : %s (%d x %d) [%d]", ieTerminal, ieRows, ieCols, ieNulls); + + p = sel_brace(NULL); + Syslog('i', "Protocols : %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "DZA") == 0) + ieDZA = TRUE; + else if (strcasecmp(q, "ZAP") == 0) + ieZAP = TRUE; + else if (strcasecmp(q, "ZMO") == 0) + ieZMO = TRUE; + else if (strcasecmp(q, "SLK") == 0) + ieSLK = TRUE; + else if (strcasecmp(q, "KER") == 0) + ieKER = TRUE; + else + Syslog('+', "Unrecognized IEMSI Protocol \"%s\"", q); + } + + p = sel_brace(NULL); + Syslog('i', "Capabilities: %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "CHT") == 0) + ieCHT = TRUE; + else if (strcasecmp(q, "TAB") == 0) + ieTAB = TRUE; + else if (strcasecmp(q, "MNU") == 0) + ieMNU = TRUE; + else if (strcasecmp(q, "ASCII8") == 0) + ieASCII8 = TRUE; + else + Syslog('+', "Unrecognized IEMSI Capability \"%s\"", q); + } + + p = sel_brace(NULL); + Syslog('i', "Requests : %s", MBSE_SS(p)); + for (q = strtok(p, ","); q; q = strtok(NULL, ",")) { + if (strcasecmp(q, "NEWS") == 0) + ieNEWS = TRUE; + else if (strcasecmp(q, "MAIL") == 0) + ieMAIL = TRUE; + else if (strcasecmp(q, "FILE") == 0) + ieFILE = TRUE; + else if (strcasecmp(q, "HOT") == 0) + ieHOT = TRUE; + else if (strcasecmp(q, "CLR") == 0) + ieCLR = TRUE; + else if (strcasecmp(q, "HUSH") == 0) + ieHUSH = TRUE; + else if (strcasecmp(q, "MORE") == 0) + ieMORE = TRUE; + else if (strcasecmp(q, "FSED") == 0) + ieFSED = TRUE; + else if (strcasecmp(q, "XPRS") == 0) + ieXPRS = TRUE; + else + Syslog('+', "Unrecognized IEMSI Request \"%s\"", q); + } + + ieSoftware = xstrcpy(sel_brace(NULL)); + Syslog('i', "Software : %s", MBSE_SS(ieSoftware)); + + return 0; +} + + + +char *mkiemsiisi(void); +char *mkiemsiisi(void) +{ + char *p, cbuf[16]; + time_t tt; + + p = xstrcpy((char *)"EMSI_ISI0000{MBSE BBS,"); + p = xstrcat(p, (char *)VERSION); + p = xstrcat(p, (char *)",Linux}{"); + p = xstrcat(p, CFG.bbs_name); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.location); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.sysop_name); + p = xstrcat(p, (char *)"}{"); + (void)time(&tt); + sprintf(cbuf, "%08lX", mktime(localtime(&tt))); + p = xstrcat(p, cbuf); + p = xstrcat(p, (char *)"}{"); + p = xstrcat(p, CFG.comment); + p = xstrcat(p, (char *)"}{0}{}"); + sprintf(cbuf, "%04X", (unsigned int)strlen(p+12)); + memcpy(p+8, cbuf, 4); + + Syslog('i', "Prepared \"%s\"", p); + return p; +} + + + +SM_DECL(rxemsi, (char *)"rxemsi") +SM_STATES + prompt, + getpkt, + chkpkt, + chkici, + sendnak, + sendisi, + human +SM_NAMES + (char *)"prompt", + (char *)"getpkt", + (char *)"chkpkt", + (char *)"chkici", + (char *)"sendnak", + (char *)"sendisi", + (char *)"human" +SM_EDECL + int len, iemsi, newpos, tries = 0; + char *p, *buf = NULL; + unsigned char c = 0; + unsigned short lcrc, rcrc; + unsigned long llcrc, lrcrc; + + buf = calloc(2048, sizeof(char)); + +SM_START(prompt) + +SM_STATE(prompt) + Syslog('I', "SM: prompt"); + + /* + * Issue EMSI_IRQ and overwrite it with the prompt. + */ + printf("**EMSI_IRQ8E08\r \r"); + /* Please enter your First and Last name: */ + language(7, 0, 0); + fflush(stdout); + tries = 0; + SM_PROCEED(getpkt); + +SM_STATE(getpkt) + Syslog('I', "SM: getpkt"); + + fflush(stdin); + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + WriteError("$Can't open /dev/tty"); + SM_ERROR; + } + Setraw(); + len = 0; + iemsi = FALSE; + newpos = 0; + buf[0] = '\0'; + alarm_on(); + + while(TRUE) { + c = Readkey(); + + Syslog('I', "c=%s len=%d iemsi=%d", printablec(c), len, iemsi); + + if ((len == 0) && (c == '*')) { + iemsi = TRUE; + } else { + if (((c == 8) || (c == KEY_DEL) || (c == 127)) && (len > 0)) { + printf("\b \b"); + fflush(stdout); + buf[--len] = '\0'; + } + + if (c > 31 && c < 127) { + if ((len == 0) && (CFG.iCapUserName)) + c = toupper(c); + + if (c == 32) { + newpos = len; + newpos++; + } + + if (!iemsi) { + if (newpos == len && CFG.iCapUserName) + c = toupper(c); + else { + if (CFG.iCapUserName) + c = tolower(c); + } + printf("%c", c); + fflush(stdout); + } + buf[len] = c; + len++; + } + } + + if ((c == '\r') || (!iemsi && (len == 35)) || (iemsi && (len == 2047))) { + buf[len] = '\0'; + break; + } + } + + Unsetraw(); + close(ttyfd); + Syslog('I', "Buf \"%s\"", printable(buf,0)); + + if (strncasecmp(buf, "EMSI_", 5)) { + SM_PROCEED(human); + } else { + SM_PROCEED(chkpkt); + } + +SM_STATE(chkpkt) + Syslog('I', "SM: chkpkt"); + if (strncasecmp(buf, "EMSI_ICI", 8) == 0) { + SM_PROCEED(chkici) + } + lcrc = crc16xmodem(buf, 8); + sscanf(buf+8, "%04hx", &rcrc); + if (lcrc != rcrc) { + Syslog('+', "Got IEMSI packet \"%s\" with bad crc: %04x/%04x", printable(buf, 0), lcrc, rcrc); + SM_PROCEED(sendnak); + } + if (strncasecmp(buf, "EMSI_HBT", 8) == 0) { + tries = 0; + SM_PROCEED(getpkt); + } else if (strncasecmp(buf, "EMSI_IIR61E2", 12) == 0) { + Syslog('+', "IEMSI Interrupt Request received"); + SM_ERROR; + } else if (strncasecmp(buf, "EMSI_ACKA490", 12) == 0) { + Syslog('+', "Established IEMSI session"); + ieLogin = TRUE; + /* + * Clearup the part of the users screen where some IEMSI + * codes may be hanging around + */ + fflush(stdin); + printf("\r \r"); + fflush(stdout); + SM_SUCCESS; + } else if (strncasecmp(buf, "EMSI_NAKEEC3", 12) == 0) { + Syslog('+', "IEMSI NAK received"); + SM_PROCEED(getpkt); + } else { + Syslog('I', "rxemsi ignores packet \"%s\"", buf); + SM_PROCEED(getpkt); + } + +SM_STATE(chkici) + Syslog('I', "SM: chkici"); + sscanf(buf+8, "%04x", &len); + if (len != (strlen(buf) - 20)) { + Syslog('+', "Bad EMSI_ICI length: %d/%d", len, strlen(buf)-20); + SM_PROCEED(sendnak); + } + sscanf(buf+strlen(buf)-8, "%08lx", &lrcrc); + *(buf+strlen(buf)-8) = '\0'; + llcrc = crc32ccitt(buf, strlen(buf)); + if (llcrc != lrcrc) { + Syslog('+', "Got EMSI_ICI packet \"%s\" with bad crc: %08x/%08x", printable(buf, 0), llcrc, lrcrc); + SM_PROCEED(sendnak); + } + if (scanemsiici(buf+12) == 0) { + SM_PROCEED(sendisi); + } else { + WriteError("Could not parse EMSI_ICI packet \"%s\"", buf); + SM_ERROR; + } + +SM_STATE(sendnak) + Syslog('I', "SM: sendnak"); + if (++tries > 9) { + Syslog('+', "too many tries getting EMSI_ICI"); + SM_ERROR; + } + printf((char *)"**EMSI_IRQ8E08\r"); + if (tries > 1) + printf((char *)"**EMSI_NAKEEC3\r"); + fflush(stdout); + SM_PROCEED(getpkt); + +SM_STATE(sendisi) + Syslog('I', "SM: sendisi"); + p = mkiemsiisi(); + printf("**%s%08lX\r", p, crc32ccitt(p, strlen(p))); + fflush(stdout); + free(p); + SM_PROCEED(getpkt); + +SM_STATE(human) + printf("\n"); + fflush(stdout); + ieUserName = xstrcpy(buf); + Syslog('+', "Human caller (%s)", MBSE_SS(ieUserName)); + SM_SUCCESS; + +SM_END + free(buf); + +SM_RETURN + + + +void user() +{ + FILE *pUsrConfig, *pLimits; + int i, x, z; + int FoundName = FALSE, iFoundLimit = FALSE; + register int recno; + int lrecno = 0; + long l1, l2; + unsigned crc = 0; + char *token; + char temp[PATH_MAX]; + char temp1[84]; + char sGetName[84]; + char *FileName; + char *handle; + struct passwd *pw; + char *sGetPassword; + long offset; + time_t LastLogin; + struct stat st; + char UserName[36]; + int IsNew = FALSE; + + + recno=0; + LoginPrompt = TRUE; + + /* + * If not in unix mode ask for login + */ + if (!iUnixMode) { + strcpy(sGetName, AskLogin()); + } else { + Syslog('+', "Unixmode login: %s", sUnixName); + if ((pw = getpwnam(sUnixName))) + #ifdef linux + strcpy(sGetName, pw->pw_gecos); + #else + strcpy(sGetName, pw->pw_comment); + #endif + + /* + * If there are more fields in the passwd gecos field + * then only get the first field. + */ + if (strchr(sGetName, ',') != NULL) + strcpy(sGetName, strtok(sGetName, ",")); + + if (!(CheckName(sGetName))) { + printf("Unknown username: %s\n", sGetName); + /* FATAL ERROR: You are not in the BBS users file.*/ + printf("%s\n", (char *) Language(389)); + /* Please run 'newuser' to create an account */ + printf("%s\n", (char *) Language(390)); + Syslog('?', "FATAL: Could not find user in BBS users file."); + Syslog('?', " and system is using unix accounts\n"); + free(Passwd); + ExitClient(0); + } + } + + if (CFG.iCapUserName || SYSOP) + strcpy(sGetName, tlcap(sGetName)); + + /* + * Copy username, split first and lastname. + */ + strcpy(UserName, tlcap(sGetName)); + + if ((strchr(sGetName,' ') == NULL && !CFG.iOneName)) { + token = strtok(sGetName, " "); + strcpy(FirstName, token); + token = strtok(NULL, "\0"); + i = strlen(token); + for(x = 2; x < i; x++) { + if(token[x] == ' ') + token[x] = '\0'; + } + strcpy(LastName, token); + } else + strcpy(FirstName, sGetName); + + Syslog('+', "%s On-Line at %s", UserName, ttyinfo.comment); + + if ((strlen(sGetName)) < 2) + user(); + + /* + * Check some essential files, create them if they don't exist. + */ + ChkFiles(); + + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((pUsrConfig = fopen(temp,"r+b")) == NULL) { + /* + * This should only happen once, when you build the BBS + */ + WriteError("Can't open users file: %s", temp); + printf("Can't open userfile, run \"newuser\" first"); + free(Passwd); + ExitClient(0); + } + + handle = calloc(40, sizeof(char)); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, pUsrConfig); + strcpy(temp1, UserName); + while (fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig) == 1) { + strcpy(temp, usrconfig.sUserName); + strcpy(handle, usrconfig.sHandle); + + if ((strcasecmp(temp, temp1) == 0 || strcasecmp(handle, temp1) == 0)) { + FoundName = TRUE; + break; + } else + recno++; + } + free(handle); + + if (!FoundName) { + Syslog('+', "Name not in user file"); + Enter(1); + /* Scanning User File */ + language(7, 0, 3); + Enter(1); + + usrconfig.GraphMode = FALSE; + DisplayFile((char *)"notfound"); + + Enter(1); + /* Name entered: */ + language(7, 0, 5); + printf("%s\n\n", UserName); + /* Did you spell your name correctly [Y/n] */ + language(7, 0, 4); + fflush(stdout); + fflush(stdin); + i = toupper(Getone()); + if (i == Keystroke(4, 0) || i == '\r') { + if (!CFG.elite_mode) { + /* + * Here we run newuser. + */ + Syslog('+', "Creating user ..."); + recno = newuser(UserName); + IsNew = TRUE; + } else { + if (!DisplayFile((char *)"private")) { + /* If FALSE display hard coded message */ + Enter(1); + /* This is a PRIVATE System, Type "off" to leave */ + language(7, 0, 6); + Enter(2); + } + + Syslog('!', "NewUser tried to login to \"Private System\""); + free(Passwd); + Quick_Bye(0); + } + + } else { + Enter(1); + Syslog('+', "User spelt his/her name incorrectly"); + user(); + } + } + + /* + * Setup users favourite language. + */ + Set_Language(usrconfig.iLanguage); + Free_Language(); + InitLanguage(); + + /* + * User logged in, tell it to the server. + */ + UserCity(mypid, usrconfig.sUserName, usrconfig.sLocation); + + /* + * See if this user is the Sysop. + */ + strcpy(temp, UserName); + strcpy(temp1, CFG.sysop_name); + if ((strcasecmp(temp1, temp)) == 0) + SYSOP = TRUE; /* If login name is sysop, set SYSOP true */ + + grecno = recno; + + offset = usrconfighdr.hdrsize + (recno * usrconfighdr.recsize); + if (fseek(pUsrConfig, offset, 0) != 0) { + printf("Can't move pointer there."); + getchar(); + free(Passwd); + ExitClient(1); + } + + fread(&usrconfig, usrconfighdr.recsize, 1, pUsrConfig); + TermInit(usrconfig.GraphMode); + sGetPassword = malloc(Max_passlen+1); + + /* + * If UnixMode is False, else let crc = iPassword to bypass the + * passwd + */ + if (!iUnixMode && !IsNew) { + /* + * Check for a blank or expired password, they do exist + * after upgrading from RA 2.xx due to a bug in RA (or feature) + */ + if (usrconfig.iPassword == 0) { + Syslog('!', "User has blank password, asking new"); + z = 0; + while (TRUE) { + Enter(1); + /* Your password is expired, enter password: */ + language(7, 0, 435); + fflush(stdout); + alarm_on(); + Getpass(temp); + if ((x = strlen(temp)) >= CFG.password_length) { + Enter(1); + /* Please enter password again: */ + language(7, 0, 40); + fflush(stdout); + alarm_on(); + Getpass(temp1); + if ((i = strcmp(temp, temp1)) != 0) { + Enter(2); + /* Passwords do not match */ + language(7,0,41); + Enter(1); + } else { + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", temp); + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", temp); + crc = StringCRC32(tu(temp)); + usrconfig.iPassword = crc; + break; + } + } else { + z++; + if (z == CFG.iCRLoginCount) { + Syslog('!', "User did not enter new password"); + Enter(1); + language(CFG.HiliteF, CFG.HiliteB, 2); + Enter(2); + free(Passwd); + Quick_Bye(0); + } + + Enter(2); + /* Your password must contain at least */ + language(7, 0, 42); + printf("%d ", CFG.password_length); + /* characters! Try again */ + language(7, 0, 43); + Enter(1); + } + } + } else { + if ((ieLogin) && (iePassword == usrconfig.iPassword)) { + crc = iePassword; + } else { + /* Pasword: */ + language(7, 0, 8); + fflush(stdout); + alarm_on(); + Getpass(sGetPassword); + /* + * Password is CRC32 of uppercase string + */ + memset(Passwd, 0, 16); + sprintf(Passwd, "%s", sGetPassword); + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", sGetPassword); + crc = StringCRC32(tu(sGetPassword)); + } + } + } else { + crc = usrconfig.iPassword; + sprintf(Passwd, "%s", usrconfig.Password); + } + + IsDoing("Just Logged In"); + + /* + * If password already OK, give pause prompt so the bbs logo + * will stay on the users screen. + */ + if ((iUnixMode) || ((ieLogin) && (iePassword == usrconfig.iPassword))) { + alarm_on(); + Pause(); + } + + if (usrconfig.Archiver[0] == '\0') { + usrconfig.Archiver[0] = 'Z'; + usrconfig.Archiver[1] = 'I'; + usrconfig.Archiver[2] = 'P'; + Syslog('+', "Setup default archiver ZIP"); + } + + if (usrconfig.iPassword == crc) { + recno = 0; + free(sGetPassword); + + /* + * Check if user has an Unix account, if not create one + */ + if (usrconfig.Name[0] == '\0') { + alarm_on(); + sprintf(usrconfig.Name, "%s", (char *)NameCreate(NameGen(UserName), UserName, Passwd)); + sprintf(sUnixName, "%s", usrconfig.Name); + Pause(); + } + + /* + * Check users date format. We do it strict as we + * need this to be good for several other purposes. + * If it is correct, the users age is set in UserAge + */ + if (!Test_DOB(usrconfig.sDateOfBirth)) { + Syslog('!', "Error in Date of Birth"); + Chg_DOB(); + strcpy(usrconfig.sDateOfBirth, exitinfo.sDateOfBirth); + } + + /* + * Check to see if user must expire + */ + sprintf(temp,"%s", (char *) GetDateDMY()); + SwapDate(temp, usrconfig.sExpiryDate); + + /* Convert Date1 & Date2 to longs for compare */ + l1 = atol(Date1); + l2 = atol(Date2); + + if(l1 >= l2 && l2 != 0) { + /* + * If Expiry Date is the same as today expire to + * Expire Sec level + */ + usrconfig.Security = usrconfig.ExpirySec; + Syslog('!', "User is expired, resetting level"); + /* + * Show texfile to user telling him about this. + */ + DisplayFile((char *)"expired"); + } + + free(Date1); + free(Date2); + + /* + * Copy limits.data into memory + */ + FileName = calloc(84, sizeof(char)); + sprintf(FileName, "%s/etc/limits.data", getenv("MBSE_ROOT")); + + if(( pLimits = fopen(FileName,"rb")) == NULL) { + perror(""); + WriteError("Can't open file: %s", FileName); + } else { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, pLimits); + + while (fread(&LIMIT, sizeof(LIMIT), 1, pLimits) == 1) { + if (LIMIT.Security == usrconfig.Security.level) { + iFoundLimit = TRUE; + break; + } else + lrecno++; + } + fclose(pLimits); + } + free(FileName); + + if(!iFoundLimit) { + Syslog('?', "Unknown Security Level in limits.data"); + usrconfig.iTimeLeft = 0; /* Could not find limit, so set to Zero */ + usrconfig.iTimeUsed = 0; /* Set to Zero as well */ + } else { + /* + * Give user new time limit everyday + */ + sprintf(temp,"%s", (char *) GetDateDMY()); + + if((strcmp(StrDateDMY(usrconfig.tLastLoginDate), temp)) != 0) { + usrconfig.iTimeLeft = LIMIT.Time; /* Copy Sec limit/time to users file */ + usrconfig.iTimeUsed = 0; /* Set time used today to Zero */ + usrconfig.iConnectTime = 0; /* Set connect time to Zero */ + + /* + * Give user new bytes and files every day + */ + usrconfig.DownloadKToday = LIMIT.DownK; + usrconfig.DownloadsToday = LIMIT.DownF; + } + } /* End of else */ + + usrconfig.iConnectTime = 0; + + /* Copy Users Protocol into Memory */ + Set_Protocol(usrconfig.sProtocol); + tlf(usrconfig.sProtocol); + + /* + * Set last login Date and Time, copy previous session + * values in memory. + */ + sprintf(LastLoginDate, "%s", StrDateDMY(usrconfig.tLastLoginDate)); + sprintf(LastLoginTime, "%s", StrTimeHMS(usrconfig.tLastLoginDate)); + LastLogin = usrconfig.tLastLoginDate; + usrconfig.tLastLoginDate = ltime; /* Set current login to current date */ + usrconfig.iTotalCalls = ++usrconfig.iTotalCalls; + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + sprintf(usrconfig.Password, "%s", Passwd); + + /* + * If IEMSI login, update some settings + */ + if (ieLogin) { + usrconfig.Cls = ieCLR; + usrconfig.HotKeys = ieHOT; + usrconfig.ieNEWS = ieNEWS; + usrconfig.MailScan = ieMAIL; + usrconfig.ieFILE = ieFILE; + usrconfig.Chat = ieCHT; + usrconfig.ieASCII8 = ieASCII8; + usrconfig.DoNotDisturb = ieHUSH; + usrconfig.FsMsged = ieFSED; + } + + /* + * Update user record. + */ + if(fseek(pUsrConfig, offset, 0) != 0) + WriteError("Can't move pointer in file: %s", temp); + else { + fwrite(&usrconfig, sizeof(usrconfig), 1, pUsrConfig); + fclose(pUsrConfig); + } + + /* + * Write users structure to tmp file in ~/tmp + */ + InitExitinfo(); + GetLastUser(); + GetLastCallers(); + ChangeHomeDir(exitinfo.Name, exitinfo.Email); + + Syslog('+', "User successfully logged into BBS"); + Syslog('+', "Level %d (%s), %d mins. left, port %s", usrconfig.Security.level, LIMIT.Description, usrconfig.iTimeLeft, pTTY); + time(&Time2Go); + Time2Go += usrconfig.iTimeLeft * 60; + iUserTimeLeft = usrconfig.iTimeLeft; + + DisplayFile((char *)"welcome"); + + /* + * The following files are only displayed if the user has + * turned the Bulletins on. + */ + if (exitinfo.ieNEWS) { + DisplayFile((char *)"welcome1"); + + sprintf(temp, "%s", (char *) GetDateDMY() ); + if ((strcmp(usrconfig.sDateOfBirth, temp)) == 0) + DisplayFile((char *)"birthday"); + + /* + * Displays file if it exists DD-MM.A?? + */ + sprintf(temp, "%s", (char *) GetDateDMY()); + strcpy(temp1, ""); + strncat(temp1, temp, 5); + sprintf(temp, "%s", temp1); + DisplayFile(temp); + + /* + * Displays users security file if it exists + */ + sprintf(temp, "sec%d", usrconfig.Security.level); + DisplayFile(temp); + + /* + * Display News file + */ + DisplayFile((char *)"news"); + } + + /* + * Display Onceonly file, first get the date of that + * file, search order is the same as in DisplayFile() + */ + st.st_mtime = 0; + if (usrconfig.GraphMode) { + sprintf(temp, "%s/onceonly.ans", lang.TextPath); + stat(temp, &st); + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.ans", CFG.bbs_txtfiles); + stat(temp, &st); + } + } + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.asc", lang.TextPath); + stat(temp, &st); + if (st.st_mtime == 0) { + sprintf(temp, "%s/onceonly.asc", CFG.bbs_txtfiles); + stat(temp, &st); + } + } + + if ((st.st_mtime != 0) && (LastLogin < st.st_mtime)) + DisplayFile((char *)"onceonly"); + + LoginPrompt = FALSE; + OLR_SyncTags(); + + if (usrconfig.MailScan) + CheckMail(); + + /* + * We don't show new files to new users, their lastlogin + * date is not yet set so they would see all the files + * which can be boring... + */ + if (usrconfig.ieFILE && (!IsNew)) + NewfileScan(FALSE); + + /* + * Copy last file Area in to current Area + */ + SetFileArea(usrconfig.iLastFileArea); + + /* + * Copy Last Message Area in to Current Msg Area + */ + SetMsgArea(usrconfig.iLastMsgArea); + SetEmailArea((char *)"mailbox"); + + /* + * Set or Reset the DoNotDisturb flag, now is the time + * we may be interrupted. + */ + UserSilent(usrconfig.DoNotDisturb); + + /* + * Start the menu, but first, wipe the password. + */ + memset(Passwd, 0, sizeof(Passwd)); + free(Passwd); + menu(); + } else { + Syslog('+',"Login attempt: %d, password: %s", iMaxLogin, sGetPassword); + free(sGetPassword); + iMaxLogin++; + if(iMaxLogin == CFG.max_login + 1) { + Enter(2); + language(7, 0, 9); + Enter(1); + Syslog('!', "Exceeded maximum login attempts, user disconnected"); + ExitClient(1); + } + Enter(2); + language(7, 0, 10); + Enter(2); + alarm_on(); + Pause(); + printf("\n"); + user(); + } +} + + diff --git a/mbsebbs/user.h b/mbsebbs/user.h new file mode 100644 index 00000000..08a5c6df --- /dev/null +++ b/mbsebbs/user.h @@ -0,0 +1,19 @@ +#ifndef _USER_H +#define _USER_H + + +#define EMSI_ACK **EMSI_ACKA490 +#define EMSI_NAK **EMSI_NAKEEC3 +#define EMSI_IRQ **EMSI_IRQ8E08 +#define EMSI_IIR **EMSI_IIR +#define EMSI_ICI **EMSI_ICI +#define EMSI_ISI **EMSI_ISI +#define EMSI_CHT **EMSI_CHT +#define EMSI_TCH **EMSI_TCH +#define EMSI_CLI **EMSI_CLIFA8C + + +void user(void); + +#endif + diff --git a/mbsebbs/xmalloc.c b/mbsebbs/xmalloc.c new file mode 100644 index 00000000..89d1f6ce --- /dev/null +++ b/mbsebbs/xmalloc.c @@ -0,0 +1,71 @@ +/***************************************************************************** + * + * File ..................: mbuseradd/xmalloc.c + * Purpose ...............: MBSE BBS Shadow Password Suite + * Last modification date : 25-Jul-2000 + * Original Source .......: Shadow Password Suite + * Original Copyrioght ...: Julianne Frances Haugh and others. + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + + +/* Replacements for malloc and strdup with error checking. Too trivial + to be worth copyrighting :-). I did that because a lot of code used + malloc and strdup without checking for NULL pointer, and I like some + message better than a core dump... --marekm + + Yeh, but. Remember that bailing out might leave the system in some + bizarre state. You really want to put in error checking, then add + some back-out failure recovery code. -- jfh */ + + +#include "../config.h" +#include +#include +#include +#include "xmalloc.h" + + + +char *xmalloc(size_t size) +{ + char *ptr; + + ptr = malloc(size); + if (!ptr && size) { + fprintf(stderr, "malloc(%d) failed\n", (int) size); + exit(13); + } + return ptr; +} + + + +char *xstrdup(const char *str) +{ + return strcpy(xmalloc(strlen(str) + 1), str); +} + diff --git a/mbsebbs/xmalloc.h b/mbsebbs/xmalloc.h new file mode 100644 index 00000000..dc92d0cf --- /dev/null +++ b/mbsebbs/xmalloc.h @@ -0,0 +1,8 @@ +#ifndef _XMALLOC_H +#define _XMALLOC_H + +char *xmalloc(size_t); +char *xstrdup(const char *); + +#endif + diff --git a/mbsetup/Makefile.am b/mbsetup/Makefile.am new file mode 100644 index 00000000..119651ba --- /dev/null +++ b/mbsetup/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +noinst_PROGRAMS = mbsetup + +mbsetup_SOURCES = screen.c mutil.c ledit.c m_bbs.c m_global.c m_mail.c m_tic.c \ +m_fido.c m_archive.c m_virus.c m_tty.c m_users.c m_protocol.c \ +m_limits.c m_lang.c m_ol.c m_node.c m_marea.c m_mgroup.c m_ff.c \ +m_ticarea.c m_magic.c m_menu.c m_new.c m_modem.c grlist.c \ +m_fgroup.c m_farea.c m_fdb.c m_hatch.c stlist.c mbsetup.c \ +m_ngroup.c m_service.c m_domain.c m_task.c \ +screen.h mutil.h ledit.h m_bbs.h m_global.h m_mail.h m_tic.h \ +m_fido.h m_archive.h m_virus.h m_tty.h m_users.h m_protocol.h \ +m_limits.h m_lang.h m_ol.h m_node.h m_marea.h m_mgroup.h m_ff.h \ +m_ticarea.h m_magic.h m_menu.h m_new.h m_modem.h grlist.h \ +m_fgroup.h m_farea.h m_fdb.h m_hatch.h stlist.h \ +m_ngroup.h m_service.h m_domain.h m_task.h + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbsetup $(bindir) + diff --git a/mbsetup/Makefile.in b/mbsetup/Makefile.in new file mode 100644 index 00000000..99d596a9 --- /dev/null +++ b/mbsetup/Makefile.in @@ -0,0 +1,502 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +noinst_PROGRAMS = mbsetup + +mbsetup_SOURCES = screen.c mutil.c ledit.c m_bbs.c m_global.c m_mail.c m_tic.c m_fido.c m_archive.c m_virus.c m_tty.c m_users.c m_protocol.c m_limits.c m_lang.c m_ol.c m_node.c m_marea.c m_mgroup.c m_ff.c m_ticarea.c m_magic.c m_menu.c m_new.c m_modem.c grlist.c m_fgroup.c m_farea.c m_fdb.c m_hatch.c stlist.c mbsetup.c m_ngroup.c m_service.c m_domain.c m_task.c screen.h mutil.h ledit.h m_bbs.h m_global.h m_mail.h m_tic.h m_fido.h m_archive.h m_virus.h m_tty.h m_users.h m_protocol.h m_limits.h m_lang.h m_ol.h m_node.h m_marea.h m_mgroup.h m_ff.h m_ticarea.h m_magic.h m_menu.h m_new.h m_modem.h grlist.h m_fgroup.h m_farea.h m_fdb.h m_hatch.h stlist.h m_ngroup.h m_service.h m_domain.h m_task.h + + +LDADD = ../lib/libmemwatch.a ../lib/libclcomm.a ../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbsetup_OBJECTS = screen.o mutil.o ledit.o m_bbs.o m_global.o m_mail.o \ +m_tic.o m_fido.o m_archive.o m_virus.o m_tty.o m_users.o m_protocol.o \ +m_limits.o m_lang.o m_ol.o m_node.o m_marea.o m_mgroup.o m_ff.o \ +m_ticarea.o m_magic.o m_menu.o m_new.o m_modem.o grlist.o m_fgroup.o \ +m_farea.o m_fdb.o m_hatch.o stlist.o mbsetup.o m_ngroup.o m_service.o \ +m_domain.o m_task.o +mbsetup_LDADD = $(LDADD) +mbsetup_DEPENDENCIES = ../lib/libmemwatch.a ../lib/libclcomm.a \ +../lib/libcommon.a ../lib/libmsgbase.a ../lib/libdbase.a +mbsetup_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbsetup_SOURCES) +OBJECTS = $(mbsetup_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbsetup/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbsetup: $(mbsetup_OBJECTS) $(mbsetup_DEPENDENCIES) + @rm -f mbsetup + $(LINK) $(mbsetup_LDFLAGS) $(mbsetup_OBJECTS) $(mbsetup_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbsetup + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +grlist.o: grlist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h screen.h grlist.h ledit.h +ledit.o: ledit.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h ../lib/msg.h screen.h mutil.h \ + ledit.h +m_archive.o: m_archive.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_archive.h +m_bbs.o: m_bbs.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + screen.h mutil.h ledit.h m_lang.h m_protocol.h m_ol.h \ + m_fgroup.h m_farea.h m_menu.h m_bbs.h m_limits.h +m_domain.o: m_domain.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_menu.h m_domain.h +m_farea.o: m_farea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_fgroup.h m_archive.h m_farea.h m_ngroup.h +m_fdb.o: m_fdb.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_farea.h m_fdb.h +m_ff.o: m_ff.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/clcomm.h \ + ../lib/common.h screen.h mutil.h ledit.h stlist.h m_global.h \ + m_ff.h m_lang.h m_marea.h +m_fgroup.o: m_fgroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_node.h m_ticarea.h m_fgroup.h +m_fido.o: m_fido.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_fido.h +m_global.o: m_global.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_node.h m_marea.h m_ticarea.h m_global.h +m_hatch.o: m_hatch.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_fgroup.h m_ticarea.h m_hatch.h +m_lang.o: m_lang.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_lang.h +m_limits.o: m_limits.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_limits.h +m_magic.o: m_magic.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_ticarea.h m_global.h m_magic.h +m_mail.o: m_mail.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h screen.h mutil.h ledit.h m_global.h m_marea.h \ + m_mgroup.h m_mail.h +m_marea.o: m_marea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + grlist.h m_global.h m_node.h m_mgroup.h m_marea.h +m_menu.o: m_menu.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h mutil.h screen.h ledit.h \ + m_lang.h m_menu.h +m_mgroup.o: m_mgroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_node.h m_marea.h m_mgroup.h +m_modem.o: m_modem.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_modem.h +m_new.o: m_new.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h grlist.h m_new.h m_lang.h m_marea.h \ + m_ngroup.h +m_ngroup.o: m_ngroup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_ngroup.h +m_node.o: m_node.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + grlist.h stlist.h m_global.h m_lang.h m_ticarea.h m_marea.h \ + m_node.h +m_ol.o: m_ol.c ../lib/libs.h ../lib/../config.h ../lib/../lib/memwatch.h \ + ../lib/structs.h ../lib/records.h ../lib/common.h \ + ../lib/clcomm.h screen.h mutil.h ledit.h m_global.h m_ol.h +m_protocol.o: m_protocol.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_protocol.h +m_service.o: m_service.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_service.h +m_task.o: m_task.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_task.h +m_tic.o: m_tic.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + screen.h mutil.h ledit.h m_fgroup.h m_ticarea.h m_magic.h \ + m_hatch.h m_tic.h +m_ticarea.o: m_ticarea.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h grlist.h m_global.h m_node.h m_fgroup.h m_farea.h \ + m_archive.h m_ticarea.h +m_tty.o: m_tty.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + stlist.h m_modem.h m_global.h m_tty.h +m_users.o: m_users.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_archive.h m_protocol.h m_users.h +m_virus.o: m_virus.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/clcomm.h ../lib/common.h screen.h mutil.h ledit.h \ + stlist.h m_global.h m_virus.h +mbsetup.o: mbsetup.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/records.h \ + ../lib/common.h ../lib/clcomm.h screen.h mutil.h ledit.h \ + m_global.h m_bbs.h m_mail.h m_tic.h m_fido.h m_archive.h \ + m_virus.h m_tty.h m_limits.h m_users.h m_node.h m_fdb.h m_new.h \ + m_ff.h m_modem.h m_marea.h m_ngroup.h m_service.h m_domain.h \ + m_task.h +mutil.o: mutil.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h screen.h mutil.h +screen.o: screen.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/ansi.h \ + ../lib/common.h screen.h +stlist.o: stlist.c ../lib/libs.h ../lib/../config.h \ + ../lib/../lib/memwatch.h ../lib/structs.h ../lib/common.h \ + ../lib/clcomm.h stlist.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + $(INSTALL) -s -o @OWNER@ -g @GROUP@ -m 0711 mbsetup $(bindir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbsetup/grlist.c b/mbsetup/grlist.c new file mode 100644 index 00000000..8a93ba51 --- /dev/null +++ b/mbsetup/grlist.c @@ -0,0 +1,177 @@ +/***************************************************************************** + * + * File ..................: grlist.c + * Purpose ...............: Group Listing utils + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "grlist.h" +#include "ledit.h" + + +/* + * Tidy the groupnames array + */ +void tidy_grlist(gr_list ** fdp) +{ + gr_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + *fdp = NULL; +} + + + +/* + * Add a group to the array + */ +void fill_grlist(gr_list **fdp, char *groupname) +{ + gr_list *tmp; + + tmp = (gr_list *)malloc(sizeof(gr_list)); + tmp->next = *fdp; + sprintf(tmp->group, "%s", groupname); + tmp->tagged = FALSE; + *fdp = tmp; +} + + + +int compgroup(gr_list **, gr_list **); + +/* + * Sort the array of groups + */ +void sort_grlist(gr_list **fdp) +{ + gr_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (gr_list **)malloc(n * sizeof(gr_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) { + vector[i++] = ta; + } + + qsort(vector, n, sizeof(gr_list*), (int(*)(const void*, const void*))compgroup); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compgroup(gr_list **fdp1, gr_list **fdp2) +{ + return strcmp((*fdp1)->group, (*fdp2)->group); +} + + + +int E_Group(gr_list **fdp, char *title) +{ + int n = 0, i, j, x, y, rc = FALSE; + gr_list *tmp; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 5, (char *)"%s", title); + set_color(CYAN, BLACK); + + for (tmp = *fdp; tmp; tmp = tmp->next) + n++; + + for (;;) { + set_color(CYAN, BLACK); + y = 7; + x = 5; + j = 0; + + for (tmp = *fdp; tmp; tmp = tmp->next) { + j++; + if (tmp->tagged) + mvprintw(y, x, (char *)"%2d. + %s", j, tmp->group); + else + mvprintw(y, x, (char *)"%2d. %s", j, tmp->group); + y++; + if (y == 18) { + y = 7; + x += 20; + } + } + + i = select_tag(n); + + if (i == 0) { + clr_index(); + return rc; + } + + if ((i >= 1) && (i <= n)) { + j = 0; + rc = TRUE; + for (tmp = *fdp; tmp; tmp = tmp->next) { + j++; + if (j == i) { + if (tmp->tagged) + tmp->tagged = FALSE; + else + tmp->tagged = TRUE; + } + } + } + } +} + + diff --git a/mbsetup/grlist.h b/mbsetup/grlist.h new file mode 100644 index 00000000..3fc4bbbe --- /dev/null +++ b/mbsetup/grlist.h @@ -0,0 +1,18 @@ +#ifndef _GRLIST_H +#define _GRLIST_H + +typedef struct _gr_list { + struct _gr_list *next; + char group[13]; + int tagged; +} gr_list; + + +void tidy_grlist(gr_list **); +void fill_grlist(gr_list **, char *); +void sort_grlist(gr_list **); +int E_Group(gr_list **, char *); + + +#endif + diff --git a/mbsetup/ledit.c b/mbsetup/ledit.c new file mode 100644 index 00000000..512215e5 --- /dev/null +++ b/mbsetup/ledit.c @@ -0,0 +1,1598 @@ +/***************************************************************************** + * + * File ..................: ledit.c + * Purpose ...............: Line Editor + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "../lib/msg.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" + + + +int sock; /* Connected socket */ + + +int yes_no(char *T_) +{ + char t[256]; + int ch; + + strcpy(t, T_); + strcat(t, " Y/n "); + set_color(LIGHTGRAY, BLACK); + locate(LINES - 3, 1); + clrtoeol(); + mvprintw(LINES -3, 6, t); + do { + ch = toupper(readkey(LINES - 3, strlen(t) + 6, LIGHTGRAY, BLACK)); + } while (ch != KEY_ENTER && ch != 'Y' && ch != 'N' && ch != '\012'); + locate(LINES - 3, 6); + clrtoeol(); + if (ch == KEY_ENTER || ch == 'Y' || ch == KEY_LINEFEED) + return 1; + else + return 0; +} + + + +void errmsg(const char *format, ...) +{ + char *t; + int ch; + va_list va_ptr; + + t = calloc(256, sizeof(char)); + + va_start(va_ptr, format); + vsprintf(t, format, va_ptr); + va_end(va_ptr); + + t = xstrcat(t, (char *)", Press any key "); + set_color(LIGHTGRAY, BLACK); + locate(LINES - 3, 1); + clrtoeol(); + mvprintw(LINES - 3, 6, t); + putchar(7); + ch = readkey(LINES - 3, strlen(t) + 6, LIGHTGRAY, BLACK); + locate(LINES - 3, 6); + clrtoeol(); + free(t); +} + + + +void show_field(int y, int x, char *str, int length, int fill) +{ + mvprintw(y, x, padleft(str, length, fill)); +} + + + +int insertflag = 0; + +void newinsert(int i, int fg, int bg) +{ + insertflag = i; + set_color(YELLOW, RED); + if (insertflag != 0) { + mvprintw(2,36," INS "); + } else { + mvprintw(2,36," OVR "); + } + set_color(fg, bg); +} + + + + +char *edit_field(int y, int x, int w, int p, char *s_) +{ + int i, charok, first, curpos, AllSpaces; + static char s[256]; + unsigned int ch; + + memset((char *)s, 0, 256); + sprintf(s, "%s", s_); + curpos = 0; + first = 1; + newinsert(1, YELLOW, BLUE); + + do { + set_color(YELLOW, BLUE); + show_field(y, x, s, w, '_'); + locate(y, x + curpos); + do { + ch = readkey(y, x + curpos, YELLOW, BLUE); + set_color(YELLOW, BLUE); + + /* + * Test if the pressed key is a valid key. + */ + charok = 0; + if ((ch >= ' ') && (ch <= '~')) { + switch(p) { + case '!': + ch = toupper(ch); + charok = 1; + break; + case 'X': + charok = 1; + break; + case '9': + if (ch == ' ' || ch == '-' || ch == ',' || + ch == '.' || isdigit(ch)) + charok = 1; + break; + case 'U': + ch = toupper(ch); + if (isupper(ch)) + charok = 1; + break; + default: + putchar(7); + break; + } + } + + } while (charok == 0 && ch != KEY_ENTER && ch != KEY_LINEFEED && + ch != KEY_DEL && ch != KEY_INS && ch != KEY_HOME && + ch != KEY_LEFT && ch != KEY_RIGHT && ch != KEY_ESCAPE && + ch != KEY_BACKSPACE && ch != KEY_RUBOUT && ch != KEY_END); + + + if (charok == 1) { + if (first == 1) { + first = 0; + memset((char *)s, 0, 256); + curpos = 0; + } + if (curpos < w) { + if (insertflag == 1) { + /* + * Insert mode + */ + if (strlen(s) < w) { + if (curpos < strlen(s)) { + for (i = strlen(s); i >= curpos; i--) + s[i+1] = s[i]; + } + s[curpos] = ch; + if (curpos < w) + curpos++; + } else { + putchar(7); + } + } else { + /* + * Overwrite mode + */ + s[curpos] = ch; + if (curpos < w) + curpos++; + } + } else { + /* + * The field is full + */ + putchar(7); + } + } /* if charok */ + + first = 0; + switch (ch) { + case KEY_HOME: + curpos = 0; + break; + case KEY_END: + curpos = strlen(s); + break; + case KEY_LEFT: + if (curpos > 0) + curpos--; + else + putchar(7); + break; + case KEY_RIGHT: + if (curpos < strlen(s)) + curpos++; + else + putchar(7); + break; + case KEY_INS: + if (insertflag == 1) + newinsert(0, YELLOW, BLUE); + else + newinsert(1, YELLOW, BLUE); + break; + case KEY_BACKSPACE: + if (strlen(s) > 0) { + if (curpos >= strlen(s)) { + curpos--; + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + case KEY_RUBOUT: + case KEY_DEL: + if (strlen(s) > 0) { + if ((curpos) == (strlen(s) -1)) { + s[curpos] = '\0'; + } else { + for (i = curpos; i < strlen(s); i++) + s[i] = s[i+1]; + s[i] = '\0'; + } + } else + putchar(7); + break; + } + } while ((ch != KEY_ENTER) && (ch != KEY_LINEFEED) && (ch != KEY_ESCAPE)); + + set_color(LIGHTGRAY, BLUE); + mvprintw(2,36, " "); + set_color(LIGHTGRAY, BLACK); + if (strlen(s)) { + AllSpaces = TRUE; + for (i = 0; i < strlen(s); i++) { + if (s[i] != ' ') + AllSpaces = FALSE; + } + if (AllSpaces) + s[0] = '\0'; + } + return s; +} + + + +char *select_show(int max) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level"); + else + if (max > 10) + sprintf(help, "Select ^\"-\"^ for previous level, ^\"P\" or \"N\"^ to page"); + else + sprintf(help, "Select ^\"-\"^ for previous level"); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + break; + if (max > 10) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + +char *select_record(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level, ^\"A\"^ to append first record"); + else + if (max > items) + sprintf(help, "Record (1..%d), ^\"-\"^ prev. level, ^\"A\"^ Append record, ^\"P\" or \"N\"^ to page", max); + else + sprintf(help, "Select record (1..%d), ^\"-\"^ for previous level, ^\"A\"^ to append a new record", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if (strncmp(menu, "M", 1) == 0) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + +char *select_area(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "^\"-\"^ back, ^A^ppend"); + else + if (max > items) + sprintf(help, "Record (1..%d), ^\"-\"^ back, ^A^ppend, ^G^lobal, ^M^ove, ^N^ext, ^P^revious", max); + else + sprintf(help, "Record (1..%d), ^\"-\"^ back, ^A^ppend, ^G^lobal, ^M^ove", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if ((strncmp(menu, "M", 1) == 0) && max) + break; + if ((strncmp(menu, "G", 1) == 0) && max) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + } + + return menu; +} + + + +char *select_pick(int max, int items) +{ + static char s[12]; + static char *menu=(char *)"-"; + char help[81]; + int pick; + + memset((char *)s, 0, 12); + + if (max == 0) + sprintf(help, "Select ^\"-\"^ for previous level"); + else + if (max > 20) + sprintf(help, "Record (1..%d), ^\"-\"^ prev. level, ^\"P\" or \"N\"^ to page", max); + else + sprintf(help, "Select record (1..%d), ^\"-\"^ for previous level", max); + showhelp(help); + + /* + * Loop until the answer is right + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES - 3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + break; + if (max > items) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + + return menu; +} + + + + +/* Select menu, max is the highest item to pick. Returns zero if + * "-" (previous level) is selected. + */ +int select_menu_sub(int, char *); + +int select_menu(int max) +{ + return select_menu_sub(max, (char *)"Select menu item"); +} + +int select_tag(int max) +{ + return select_menu_sub(max, (char *)"Toggle item"); +} + + +int select_menu_sub(int max, char *hlp) +{ + static char *menu=(char *)"-"; + char help[80]; + int pick; + + sprintf(help, "%s (1..%d) or ^\"-\"^ for previous level.", hlp, max); + showhelp(help); + + /* Loop forever until it's right. + */ + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 3, '9', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) + return 0; + + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + return pick; + + working(2, 0, 0); + working(0, 0, 0); + } +} + + + +void show_str(int y, int x, int l, char *line) +{ + show_field(y, x, line, l, ' '); +} + + + +char *edit_str(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_pth(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + char *temp; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + temp = xstrcpy(s); + if (strlen(temp)) { + temp = xstrcat(temp, (char *)"/foobar"); + if (access(s, R_OK)) { + if (yes_no((char *)"Path doesn't exist, create")) + if (! mkdirs(temp)) + errmsg((char *)"Can't create path"); + } + } + free(temp); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_jam(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + char *temp; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, 'X', line)); + + /* + * Check if the messagebase exists, if not, create it. + */ + temp = xstrcpy(s); + temp = xstrcat(temp, (char *)".jhr"); + if (access(temp, W_OK)) { + if (mkdirs(s)) { + if (yes_no((char *)"Messagebase doesn't exist, create")) { + if (Msg_Open(s)) + Msg_Close(); + } + } else { + errmsg((char *)"Can't create directory"); + } + } + free(temp); + + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *edit_ups(int y, int x, int l, char *line, char *help) +{ + static char s[256]; + + showhelp(help); + memset((char *)s, 0, 256); + strcpy(s, edit_field(y, x, l, '!', line)); + set_color(WHITE, BLACK); + show_str(y, x, l, s); + return s; +} + + + +char *getboolean(int val) +{ + if (val) + return (char *)"Yes"; + else + return (char *)"No "; +} + + + +void show_bool(int y, int x, int val) +{ + mvprintw(y, x, getboolean(val)); +} + + + +int edit_bool(int y, int x, int val, char *help) +{ + int ch; + char *temp; + + temp = calloc(81, sizeof(char)); + sprintf(temp, "%s (Spacebar = toggle)", help); + showhelp(temp); + free(temp); + + do { + set_color(YELLOW, BLUE); + show_bool(y, x, val); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= 1; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_bool(y, x, val); + fflush(stdout); + return val; +} + + + +char *getloglevel(long val) +{ + char *p; + + p = xstrcpy((char *)"?"); + + if (val & DLOG_ATTENT) p = xstrcat(p, (char *)"!"); + if (val & DLOG_NORMAL) p = xstrcat(p, (char *)"+"); + if (val & DLOG_VERBOSE) p = xstrcat(p, (char *)"-"); + if (val & DLOG_TCP) p = xstrcat(p, (char *)"A"); + if (val & DLOG_BBS) p = xstrcat(p, (char *)"B"); + if (val & DLOG_CHAT) p = xstrcat(p, (char *)"C"); + if (val & DLOG_DEVIO) p = xstrcat(p, (char *)"D"); + if (val & DLOG_EXEC) p = xstrcat(p, (char *)"E"); + if (val & DLOG_FILEFWD) p = xstrcat(p, (char *)"F"); + if (val & DLOG_HYDRA) p = xstrcat(p, (char *)"H"); + if (val & DLOG_IEMSI) p = xstrcat(p, (char *)"I"); + if (val & DLOG_LOCK) p = xstrcat(p, (char *)"L"); + if (val & DLOG_MAIL) p = xstrcat(p, (char *)"M"); + if (val & DLOG_NEWS) p = xstrcat(p, (char *)"N"); + if (val & DLOG_OUTSCAN) p = xstrcat(p, (char *)"O"); + if (val & DLOG_PACK) p = xstrcat(p, (char *)"P"); + if (val & DLOG_ROUTE) p = xstrcat(p, (char *)"R"); + if (val & DLOG_SESSION) p = xstrcat(p, (char *)"S"); + if (val & DLOG_TTY) p = xstrcat(p, (char *)"T"); + if (val & DLOG_XMODEM) p = xstrcat(p, (char *)"X"); + if (val & DLOG_ZMODEM) p = xstrcat(p, (char *)"Z"); + + return p; +} + + + +void show_logl(int y, int x, long val) +{ + char *p; + + p = getloglevel(val); + show_field(y, x, p, 21, ' '); + free(p); +} + + + +long edit_logl(long val, char *txt) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 5, (char *)"%s EDIT LOGLEVEL", txt); + set_color(CYAN, BLACK); + mvprintw( 5,45, "Logflags"); + + mvprintw( 7, 5, "1. ! Attention"); + mvprintw( 8, 5, "2. + Normal"); + mvprintw( 9, 5, "3. - Verbose"); + mvprintw(10, 5, "4. A Debug TCP"); + mvprintw(11, 5, "5. B Debug BBS/binkp"); + mvprintw(12, 5, "6. C Chat modems"); + mvprintw(13, 5, "7. D Device IO"); + mvprintw(14, 5, "8. E Execute"); + mvprintw(15, 5, "9. F File forward"); + mvprintw(16, 5, "10. H Hydra debug"); + mvprintw(17, 5, "11. I EMSI debug"); + mvprintw( 7,45, "12. L Locking"); + mvprintw( 8,45, "13. M Mail debug"); + mvprintw( 9,45, "14. N News debug"); + mvprintw(10,45, "15. O Outboundscan"); + mvprintw(11,45, "16. P Packing"); + mvprintw(12,45, "17. R Routing"); + mvprintw(13,45, "18. S Session"); + mvprintw(14,45, "19. T TTY debug"); + mvprintw(15,45, "20. X Xmodem debug"); + mvprintw(16,45, "21. Z Zmodem debug"); + + for (;;) { + set_color(WHITE, BLACK); + show_logl(5, 54, val); + show_lbit( 7,24, val, DLOG_ATTENT); + show_lbit( 8,24, val, DLOG_NORMAL); + show_lbit( 9,24, val, DLOG_VERBOSE); + show_lbit(10,24, val, DLOG_TCP); + show_lbit(11,24, val, DLOG_BBS); + show_lbit(12,24, val, DLOG_CHAT); + show_lbit(13,24, val, DLOG_DEVIO); + show_lbit(14,24, val, DLOG_EXEC); + show_lbit(15,24, val, DLOG_FILEFWD); + show_lbit(16,24, val, DLOG_HYDRA); + show_lbit(17,24, val, DLOG_IEMSI); + show_lbit( 7,64, val, DLOG_LOCK); + show_lbit( 8,64, val, DLOG_MAIL); + show_lbit( 9,64, val, DLOG_NEWS); + show_lbit(10,64, val, DLOG_OUTSCAN); + show_lbit(11,64, val, DLOG_PACK); + show_lbit(12,64, val, DLOG_ROUTE); + show_lbit(13,64, val, DLOG_SESSION); + show_lbit(14,64, val, DLOG_TTY); + show_lbit(15,64, val, DLOG_XMODEM); + show_lbit(16,64, val, DLOG_ZMODEM); + + switch(select_menu(21)) { + case 0: return val; + case 1: val ^= DLOG_ATTENT; break; + case 2: val ^= DLOG_NORMAL; break; + case 3: val ^= DLOG_VERBOSE; break; + case 4: val ^= DLOG_TCP; break; + case 5: val ^= DLOG_BBS; break; + case 6: val ^= DLOG_CHAT; break; + case 7: val ^= DLOG_DEVIO; break; + case 8: val ^= DLOG_EXEC; break; + case 9: val ^= DLOG_FILEFWD; break; + case 10:val ^= DLOG_HYDRA; break; + case 11:val ^= DLOG_IEMSI; break; + case 12:val ^= DLOG_LOCK; break; + case 13:val ^= DLOG_MAIL; break; + case 14:val ^= DLOG_NEWS; break; + case 15:val ^= DLOG_OUTSCAN; break; + case 16:val ^= DLOG_PACK; break; + case 17:val ^= DLOG_ROUTE; break; + case 18:val ^= DLOG_SESSION; break; + case 19:val ^= DLOG_TTY; break; + case 20:val ^= DLOG_XMODEM; break; + case 21:val ^= DLOG_ZMODEM; break; + } + } + + return val; +} + + + +void show_int(int y, int x, int val) +{ + mvprintw(y, x, (char *)" "); + mvprintw(y, x, (char *)"%d", val); +} + + + +int edit_int(int y, int x, int val, char *help) +{ + static char s[6]; + static char line[6]; + + showhelp(help); + memset((char *)s, 0, 6); + sprintf(line, "%d", val); + strcpy(s, edit_field(y, x, 7, '9', line)); + set_color(WHITE, BLACK); + show_int(y, x, atoi(s)); + fflush(stdout); + return atoi(s); +} + + + +void show_ushort(int y, int x, unsigned short val) +{ + mvprintw(y, x, (char *)"%d", val); +} + + + +unsigned short edit_ushort(int y, int x, unsigned short val, char *help) +{ + unsigned short r; + static char s[6]; + static char line[6]; + + showhelp(help); + memset((char *)s, 0, 6); + do { + sprintf(line, "%d", val); + strcpy(s, edit_field(y, x, 5, '9', line)); + r = atoi(s); + if (r >= 65535L) { + working(2, y, x); + working(0, y, x); + } + } while (r >= 65535L); + set_color(WHITE, BLACK); + show_int(y, x, val); + fflush(stdout); + return r; +} + + + +void show_sbit(int y, int x, unsigned short val, unsigned short mask) +{ + show_bool(y, x, (val & mask) != 0); +} + + + +unsigned short toggle_sbit(int y, int x, unsigned short val, unsigned short mask, char *help) +{ + int ch; + + showhelp(help); + do { + set_color(YELLOW, BLUE); + show_sbit(y, x, val, mask); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= mask; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_sbit(y, x, val, mask); + fflush(stdout); + return val; +} + + + +void show_lbit(int y, int x, long val, long mask) +{ + show_bool(y, x, (val & mask) != 0); +} + + + +long toggle_lbit(int y, int x, long val, long mask, char *help) +{ + int ch; + + showhelp(help); + do { + set_color(YELLOW, BLUE); + show_lbit(y, x, val, mask); + ch = readkey(y, x, YELLOW, BLUE); + if (ch == ' ') + val ^= mask; + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_lbit(y, x, val, mask); + fflush(stdout); + return val; +} + + + +char *getflag(unsigned long flag, unsigned long not) +{ + static char temp[33]; + int i; + + memset(temp, 0, 33); + memset(temp, '-', 32); + + for (i = 0; i < 32; i++) { + if ((flag >> i) & 1) + temp[i] = 'X'; + if ((not >> i) & 1) + temp[i] = 'O'; + /* + * The next one may never show up! + */ + if (((flag >> i) & 1) && ((not >> i) & 1)) + temp[i] = '!'; + } + + return temp; +} + + + +void show_sec(int y, int x, securityrec sec) +{ + show_int(y, x, sec.level); + mvprintw(y, x + 6, getflag(sec.flags, sec.notflags)); +} + + + +securityrec edit_sec(int y, int x, securityrec sec, char *shdr) +{ + int c, i, xx, yy, s; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(4,3,shdr); + set_color(CYAN, BLACK); + xx = 3; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 28; + yy = 6; + } + if (i == 22) { + xx = 53; + yy = 6; + } + set_color(CYAN,BLACK); + mvprintw(yy, xx, (char *)"%2d. %-16s", i+1, CFG.fname[i]); + yy++; + } + mvprintw(16,53, "33. Security level"); + + for (;;) { + set_color(WHITE, BLACK); + xx = 24; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 49; + yy = 6; + } + if (i == 22) { + xx = 74; + yy = 6; + } + c = '-'; + if ((sec.flags >> i) & 1) + c = 'X'; + if ((sec.notflags >> i) & 1) + c = 'O'; + /* + * The next one may never show up + */ + if (((sec.flags >> i) & 1) && ((sec.notflags >> i) & 1)) + c = '!'; + mvprintw(yy,xx,(char *)"%c", c); + yy++; + } + show_int(16,74, sec.level); + s = select_menu(33); + + switch(s) { + case 0: + return sec; + case 33: + sec.level = edit_int(16,74, sec.level, (char *)"^Security level^ 0..65535"); + break; + default: + if ((sec.notflags >> (s - 1)) & 1) { + sec.notflags = (sec.notflags ^ (1 << (s - 1))); + break; + } + if ((sec.flags >> (s - 1)) & 1) { + sec.flags = (sec.flags ^ (1 << (s - 1))); + sec.notflags = (sec.notflags | (1 << (s - 1))); + break; + } + sec.flags = (sec.flags | (1 << (s - 1))); + break; + } + } +} + + + +securityrec edit_usec(int y, int x, securityrec sec, char *shdr) +{ + int c, i, xx, yy, s; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(4,3,shdr); + set_color(CYAN, BLACK); + xx = 3; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 28; + yy = 6; + } + if (i == 22) { + xx = 53; + yy = 6; + } + set_color(CYAN,BLACK); + mvprintw(yy, xx, (char *)"%2d. %-16s", i+1, CFG.fname[i]); + yy++; + } + mvprintw(16,53, "33. Security level"); + + for (;;) { + set_color(WHITE, BLACK); + xx = 24; + yy = 6; + + for (i = 0; i < 32; i++) { + if (i == 11) { + xx = 49; + yy = 6; + } + if (i == 22) { + xx = 74; + yy = 6; + } + c = '-'; + if ((sec.flags >> i) & 1) + c = 'X'; + if ((sec.notflags >> i) & 1) + c = 'O'; + /* + * The next one may never show up + */ + if (((sec.flags >> i) & 1) && ((sec.notflags >> i) & 1)) + c = '!'; + mvprintw(yy,xx,(char *)"%c", c); + yy++; + } + show_int(16,74, sec.level); + s = select_menu(33); + + switch(s) { + case 0: + return sec; + case 33: + sec.level = edit_int(16,74, sec.level, (char *)"^Security level^ 0..65535"); + break; + default: + if ((sec.flags >> (s - 1)) & 1) { + sec.flags = (sec.flags ^ (1 << (s - 1))); + break; + } + sec.flags = (sec.flags | (1 << (s - 1))); + break; + } + } +} + + + +char *get_secstr(securityrec S) +{ + static char temp[45]; + + memset(&temp, 0, sizeof(temp)); + sprintf(temp, "%-5d %s", S.level, getflag(S.flags, S.notflags)); + return temp; +} + + + +char *getmsgtype(int val) +{ + switch (val) { + case LOCALMAIL: return (char *)"Local "; + case NETMAIL: return (char *)"Netmail "; + case ECHOMAIL: return (char *)"Echomail"; + case NEWS: return (char *)"News "; + default: return NULL; + } +} + + + +void show_msgtype(int y, int x, int val) +{ + mvprintw(y, x, getmsgtype(val)); +} + + + +int edit_msgtype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Message Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_msgtype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < NEWS) + val++; + else + val = LOCALMAIL; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_msgtype(y, x, val); + fflush(stdout); + return val; +} + + +char *getemailmode(int val) +{ + switch (val) { + case E_NOISP: return (char *)"No ISP "; + case E_TMPISP: return (char *)"Dial. ISP"; + case E_PRMISP: return (char *)"Perm. ISP"; + default: return NULL; + } +} + + + +void show_emailmode(int y, int x, int val) +{ + mvprintw(y, x, getemailmode(val)); +} + + + +int edit_emailmode(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^ISP Email Mode^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_emailmode(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < E_PRMISP) + val++; + else + val = E_NOISP; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_emailmode(y, x, val); + return val; +} + + + +char *getmsgkinds(int val) +{ + switch (val) { + case BOTH: return (char *)"Private/Public "; + case PRIVATE: return (char *)"Private only "; + case PUBLIC: return (char *)"Public only "; + case RONLY: return (char *)"Read Only "; + case FTNMOD: return (char *)"FTN moderated "; + case USEMOD: return (char *)"Usenet moderated"; + default: return NULL; + } +} + + + +void show_msgkinds(int y, int x, int val) +{ + mvprintw(y, x, getmsgkinds(val)); +} + + + +int edit_msgkinds(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Message Kinds^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_msgkinds(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < USEMOD) + val++; + else + val = BOTH; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_msgkinds(y, x, val); + return val; +} + + + +char *getlinetype(int val) +{ + switch (val) { + case POTS: return (char *)"POTS "; + case ISDN: return (char *)"ISDN "; + case NETWORK: return (char *)"Network"; + case LOCAL: return (char *)"Local "; + default: return NULL; + } +} + + + +void show_linetype(int y, int x, int val) +{ + mvprintw(y, x, getlinetype(val)); +} + + + +int edit_linetype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Line Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_linetype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < LOCAL) + val++; + else + val = POTS; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_linetype(y, x, val); + return val; +} + + + +char *getservice(int val) +{ + switch (val) { + case AREAMGR: return (char *)"AreaMgr"; + case FILEMGR: return (char *)"FileMgr"; + case EMAIL: return (char *)"Email "; + default: return NULL; + } +} + + + +void show_service(int y, int x, int val) +{ + mvprintw(y, x, getservice(val)); +} + + + +int edit_service(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Service Type^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_service(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < EMAIL) + val++; + else + val = AREAMGR; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_service(y, x, val); + return val; +} + + + +char *getnewsmode(int val) +{ + switch (val) { + case FEEDINN: return (char *)"NNTP feed "; + case FEEDRNEWS: return (char *)"rnews feed"; + case FEEDUUCP: return (char *)"UUCP feed "; + default: return NULL; + } +} + + + +void show_newsmode(int y, int x, int val) +{ + mvprintw(y, x, getnewsmode(val)); +} + + + +int edit_newsmode(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Newsfeed mode^ with spacebar, press whene done."); + do { + set_color(YELLOW, BLUE); + show_newsmode(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < FEEDUUCP) + val++; + else + val = FEEDINN; + } + } while (ch != KEY_ENTER && ch != '\012'); + set_color(WHITE, BLACK); + show_newsmode(y, x, val); + return val; +} + + + +void show_magictype(int y, int x, int val) +{ + mvprintw(y, x, getmagictype(val)); +} + + + +int edit_magictype(int y, int x, int val) +{ + int ch; + + showhelp((char *)"Toggle ^Magic type^ with spacebar, press whene done"); + + do { + set_color(YELLOW, BLUE); + show_magictype(y, x, val); + + ch = readkey(y, x, YELLOW, BLUE); + + if (ch == ' ') { + if (val < MG_DELETE) + val++; + else + val = 0; + } + + } while ((ch != KEY_ENTER) && (ch != '\012')); + + set_color(WHITE, BLACK); + show_magictype(y, x, val); + return val; +} + + + +char *getmagictype(int val) +{ + switch(val) { + case MG_EXEC: return (char *)"Execute "; + case MG_COPY: return (char *)"Copy file "; + case MG_UNPACK: return (char *)"Unpack file "; + case MG_KEEPNUM: return (char *)"Keep number "; + case MG_MOVE: return (char *)"Move file "; + case MG_UPDALIAS: return (char *)"Update alias"; + case MG_ADOPT: return (char *)"Adopt file "; + case MG_OTHER: return (char *)"Other path "; + case MG_DELETE: return (char *)"Delete file "; + default: return NULL; + } +} + + + +void show_aka(int y, int x, fidoaddr aka) +{ + char temp[24]; + + if (aka.point == 0) + sprintf(temp, "%d:%d/%d@%s", aka.zone, aka.net, aka.node, aka.domain); + else + sprintf(temp, "%d:%d/%d.%d@%s", aka.zone, aka.net, aka.node, aka.point, aka.domain); + mvprintw(y, x, temp); +} + + + +void edit_color(int *fg, int *bg, char *help) +{ + int ch, f, b; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 6, "1.7 EDIT COLORS"); + + sprintf(temp, "Change ^%s^ color with arrow keys, press whene done", help); + showhelp(help); + + for (f = 0; f < 16; f++) + for (b = 0; b < 8; b++) { + set_color(f, b); + mvprintw(b + 9, f + 33, "."); + } + f = (* fg); + b = (* bg); + + for (;;) { + set_color(f, b); + mvprintw(7, 6, "This is an example..."); + fflush(stdout); + mvprintw(b + 9, f + 33, "*"); + ch = readkey(10,10,f,b); + mvprintw(b + 9, f + 33, "."); + switch(ch) { + case KEY_LINEFEED: + case KEY_ENTER: (* fg) = f; + (* bg) = b; + return; + case KEY_LEFT: if (f > 0) + f--; + break; + case KEY_RIGHT: if (f < 15) + f++; + break; + case KEY_UP: if (b > 0) + b--; + break; + case KEY_DOWN: if (b < 7) + b++; + break; + } + } +} + + + +char *getmenutype(int val) +{ + switch (val) { + case 1: return (char *)"Goto another menu"; + case 2: return (char *)"Gosub another menu"; + case 3: return (char *)"Return from gosub"; + case 4: return (char *)"Return to top menu"; + case 5: return (char *)"Display A?? file w/Ctrl codes"; + case 6: return (char *)"Display menu prompt"; + case 7: return (char *)"Run external program in shell"; + case 8: return (char *)"Show product information"; + case 9: return (char *)"Display todays callers list"; + case 10: return (char *)"Display user list"; + case 11: return (char *)"Display time statistics"; + case 12: return (char *)"Page sysop for a chat"; + case 13: return (char *)"Terminate call"; + case 14: return (char *)"Make a log entry"; + case 15: return (char *)"Print text to screen"; + case 16: return (char *)"Who's currently on-line"; + case 17: return (char *)"Comment to sysop"; + case 18: return (char *)"Send an on-line message"; + case 19: return (char *)"Display textfile with more"; + case 20: return (char *)"Display .A?? file with Enter"; + + case 22: return (char *)"Message to nextuser door"; + case 23: return (char *)"Time banking system"; + + case 25: return (char *)"Safe cracker door"; + + case 101: return (char *)"Select new file area"; + case 102: return (char *)"List files in current area"; + case 103: return (char *)"View a textfile"; + case 104: return (char *)"Download tagged files"; + case 105: return (char *)"Raw directory listing"; + case 106: return (char *)"Search file on keyword"; + case 107: return (char *)"Search file on filename"; + case 108: return (char *)"Scan for new files"; + case 109: return (char *)"Upload a file"; + case 110: return (char *)"Edit the taglist"; + case 111: return (char *)"View file in home directory"; + case 112: return (char *)"Download a specific file"; + case 113: return (char *)"Copy file to home directory"; + case 114: return (char *)"List files in home directory"; + case 115: return (char *)"Delete file in home directory"; + case 116: return (char *)"Unpack file in home directory"; + case 117: return (char *)"Pack files in home directory"; + case 118: return (char *)"Download from home directory"; + case 119: return (char *)"Upload to home directory"; + + case 201: return (char *)"Select new message area"; + case 202: return (char *)"Post a new message"; + case 203: return (char *)"Read messages"; + case 204: return (char *)"Check for new mail"; + case 205: return (char *)"Quick-scan messages"; + case 206: return (char *)"Delete a specific message"; + case 207: return (char *)"Show mail status"; + case 208: return (char *)"OLR Tag Area"; + case 209: return (char *)"OLR Remove Area"; + case 210: return (char *)"OLR View Areas"; + case 211: return (char *)"OLR Restrict Date"; + case 212: return (char *)"OLR Upload"; + case 213: return (char *)"OLR Download BlueWave"; + case 214: return (char *)"OLR Download QWK"; + case 215: return (char *)"OLR Download ASCII"; + case 216: return (char *)"Read email"; + case 217: return (char *)"Post email"; + case 218: return (char *)"Trash email"; + case 219: return (char *)"Choose mailbox"; + case 220: return (char *)"Quick-scan email's"; + case 301: return (char *)"Change transfer protocol"; + case 302: return (char *)"Change password"; + case 303: return (char *)"Change location"; + case 304: return (char *)"Change graphics mode"; + case 305: return (char *)"Change voice phone"; + case 306: return (char *)"Change data phone"; + case 307: return (char *)"Change show news bulletins"; + case 308: return (char *)"Change screen length"; + case 309: return (char *)"Change date of birth"; + case 310: return (char *)"Change language"; + case 311: return (char *)"Change hot-keys"; + case 312: return (char *)"Change handle (alias)"; + case 313: return (char *)"Change check for new mail"; + case 314: return (char *)"Change do-not-disturb"; + case 315: return (char *)"Change check for new files"; + case 316: return (char *)"Change fullscreen editor"; + + case 401: return (char *)"Add oneliner"; + case 402: return (char *)"List oneliners"; + case 403: return (char *)"Show a oneliner"; + case 404: return (char *)"Mark oneliner for deletion"; + case 405: return (char *)"Print a random oneliner"; + + case 501: return (char *)"Add a BBS"; + case 502: return (char *)"List BBS's"; + case 503: return (char *)"Show a BBS"; + case 504: return (char *)"Mark a BBS for deletion"; + case 505: return (char *)"Print a BBS"; + case 506: return (char *)"Search for a BBS"; + + default: return (char *)"Unknown menu"; + } +} + + + diff --git a/mbsetup/ledit.h b/mbsetup/ledit.h new file mode 100644 index 00000000..c86a1e4b --- /dev/null +++ b/mbsetup/ledit.h @@ -0,0 +1,80 @@ +#ifndef _LEDIT_H +#define _LEDIT_H + +int yes_no(char *); +void errmsg(const char *, ...); +void show_field(int, int, char *, int, int); +void newinsert(int, int, int); +char *edit_field(int, int, int, int, char *); +char *select_record(int, int); +char *select_area(int, int); +char *select_pick(int, int); +char *select_show(int); +int select_menu(int); +int select_tag(int); +void show_str(int, int, int, char *); +char *edit_str(int, int, int, char *, char *); +char *edit_pth(int, int, int, char *, char *); +char *edit_jam(int, int, int, char *, char *); +char *edit_ups(int, int, int, char *, char *); +char *getboolean(int val); +void show_bool(int, int, int); +int edit_bool(int, int, int, char *); +char *getloglevel(long val); +void show_logl(int, int, long); +long edit_logl(long, char *); +char *getflag(unsigned long, unsigned long); +void show_sec(int, int, securityrec); +securityrec edit_sec(int, int, securityrec, char *); +securityrec edit_usec(int, int, securityrec, char *); +char *get_secstr(securityrec); +void show_int(int, int, int); +int edit_int(int, int, int, char *); +void show_ushort(int, int, unsigned short); +unsigned short edit_ushort(int, int, unsigned short, char *); +void show_sbit(int, int, unsigned short, unsigned short); +unsigned short toggle_sbit(int, int, unsigned short, unsigned short, char *); +void show_lbit(int, int, long, long); +long toggle_lbit(int, int, long, long, char *); +char *getmsgtype(int); +void show_msgtype(int, int, int); +int edit_msgtype(int, int, int); +char *getemailmode(int); +void show_emailmode(int, int, int); +int edit_emailmode(int, int, int); +char *getmsgkinds(int); +void show_msgkinds(int, int, int); +int edit_msgkinds(int, int, int); +char *getservice(int); +void show_service(int, int, int); +int edit_service(int, int, int); +char *getnewsmode(int); +void show_newsmode(int, int, int); +int edit_newsmode(int, int, int); +char *getlinetype(int); +void show_linetype(int, int, int); +int edit_linetype(int, int, int); +char *getmagictype(int); +void show_magictype(int, int, int); +int edit_magictype(int, int, int); +void show_aka(int, int, fidoaddr); +void edit_color(int *, int *, char *); +char *getmenutype(int); + + +/* + * Macro's for the edit functions + */ +#define E_STR(y,x,l,str,help) strcpy(str, edit_str(y,x,l,str,(char *)help)); break; +#define E_PTH(y,x,l,str,help) strcpy(str, edit_pth(y,x,l,str,(char *)help)); break; +#define E_UPS(y,x,l,str,help) strcpy(str, edit_ups(y,x,l,str,(char *)help)); break; +#define E_JAM(y,x,l,str,help) strcpy(str, edit_jam(y,x,l,str,(char *)help)); break; +#define E_BOOL(y,x,bool,help) bool = edit_bool(y,x,bool,(char *)help); break; +#define E_INT(y,x,value,help) value = edit_int(y,x,value,(char *)help); break; +#define E_LOGL(grade,txt,af) grade = edit_logl(grade,(char *)txt); af(); break; +#define S_COL(y,x,name,fg,bg) set_color(fg,bg); mvprintw(y,x,name); +#define E_SEC(y,x,sec,hdr,af) sec = edit_sec(y,x,sec,(char *)hdr); af(); break; +#define E_USEC(y,x,sec,hdr,af) sec = edit_usec(y,x,sec,(char *)hdr); af(); break; + +#endif /* _LEDIT_H */ + diff --git a/mbsetup/m_archive.c b/mbsetup/m_archive.c new file mode 100644 index 00000000..6cbe58e9 --- /dev/null +++ b/mbsetup/m_archive.c @@ -0,0 +1,577 @@ +/***************************************************************************** + * + * File ..................: setup/m_archive.c + * Purpose ...............: Setup Archive structure. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_archive.h" + + + +int ArchUpdated = 0; + + +/* + * Count nr of archiver records in the database. + * Creates the database if it doesn't exist. + */ +int CountArchive(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + archiverhdr.hdrsize = sizeof(archiverhdr); + archiverhdr.recsize = sizeof(archiver); + fwrite(&archiverhdr, sizeof(archiverhdr), 1, fil); + /* + * Create default records + */ + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ARC Version 5.21"); + sprintf(archiver.name, "ARC"); + archiver.available = TRUE; + sprintf(archiver.marc, "/usr/bin/arc anw"); + sprintf(archiver.tarc, "/usr/bin/arc tnw"); + sprintf(archiver.funarc, "/usr/bin/arc xnw"); + sprintf(archiver.munarc, "/usr/bin/arc enw"); + sprintf(archiver.iunarc, "/usr/bin/arc enw"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "LHarc"); + sprintf(archiver.name, "LHA"); + archiver.available = TRUE; + sprintf(archiver.marc, "/usr/bin/lha aq"); + sprintf(archiver.tarc, "/usr/bin/lha tq"); + sprintf(archiver.funarc, "/usr/bin/lha xqf"); + sprintf(archiver.munarc, "/usr/bin/lha eqf"); + sprintf(archiver.iunarc, "/usr/bin/lha eqf"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "RAR by Eugene Roshal"); + sprintf(archiver.name, "RAR"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/rar a -y -r"); + sprintf(archiver.marc, "/usr/bin/rar a -y"); + sprintf(archiver.barc, "/usr/bin/rar c -y"); + sprintf(archiver.tarc, "/usr/bin/rar t -y"); + sprintf(archiver.funarc, "/usr/bin/unrar x -o+ -y -r"); + sprintf(archiver.munarc, "/usr/bin/unrar e -o+ -y"); + sprintf(archiver.iunarc, "/usr/bin/unrar e"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "TAR the GNU version"); + sprintf(archiver.name, "TAR"); + archiver.available = TRUE; + sprintf(archiver.farc, "/bin/tar cfz"); + sprintf(archiver.marc, "/bin/tar Afz"); + sprintf(archiver.tarc, "/bin/tar tfz"); + sprintf(archiver.funarc, "/bin/tar xfz"); + sprintf(archiver.munarc, "/bin/tar xfz"); + sprintf(archiver.iunarc, "/bin/tar xfz"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "UNARJ by Robert K Jung"); + sprintf(archiver.name, "ARJ"); + archiver.available = TRUE; + sprintf(archiver.tarc, "/usr/bin/unarj t"); + sprintf(archiver.funarc, "/usr/bin/unarj x"); + sprintf(archiver.munarc, "/usr/bin/unarj e"); + sprintf(archiver.iunarc, "/usr/bin/unarj e"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ZIP and UNZIP by Info-ZIP"); + sprintf(archiver.name, "ZIP"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/zip -r -q"); + sprintf(archiver.marc, "/usr/bin/zip -q"); + sprintf(archiver.barc, "/usr/bin/zip -z"); + sprintf(archiver.tarc, "/usr/bin/zip -T"); + sprintf(archiver.funarc, "/usr/bin/unzip -o -q"); + sprintf(archiver.munarc, "/usr/bin/unzip -o -j -L"); + sprintf(archiver.iunarc, "/usr/bin/unzip -o -j"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + memset(&archiver, 0, sizeof(archiver)); + sprintf(archiver.comment, "ZOO archiver"); + sprintf(archiver.name, "ZOO"); + archiver.available = TRUE; + sprintf(archiver.farc, "/usr/bin/zoo aq"); + sprintf(archiver.marc, "/usr/bin/zoo aq:O"); + sprintf(archiver.barc, "/usr/bin/zoo aqC"); + sprintf(archiver.funarc, "/usr/bin/zoo xqO"); + sprintf(archiver.munarc, "/usr/bin/zoo eq:O"); + sprintf(archiver.iunarc, "/usr/bin/zoo eqO"); + fwrite(&archiver, sizeof(archiver), 1, fil); + + fclose(fil); + return 7; + } else + return -1; + } + + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - archiverhdr.hdrsize) / archiverhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenArchive(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = archiverhdr.recsize; + if (oldsize != sizeof(archiver)) + ArchUpdated = 1; + else + ArchUpdated = 0; + archiverhdr.hdrsize = sizeof(archiverhdr); + archiverhdr.recsize = sizeof(archiver); + fwrite(&archiverhdr, sizeof(archiverhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&archiver, 0, sizeof(archiver)); + while (fread(&archiver, oldsize, 1, fin) == 1) { + fwrite(&archiver, sizeof(archiver), 1, fout); + memset(&archiver, 0, sizeof(archiver)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseArchive(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *arc = NULL, *tmp; + + sprintf(fin, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/archiver.temp", getenv("MBSE_ROOT")); + + if (ArchUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&archiverhdr, archiverhdr.hdrsize, 1, fi); + fwrite(&archiverhdr, archiverhdr.hdrsize, 1, fo); + + while (fread(&archiver, archiverhdr.recsize, 1, fi) == 1) + if (!archiver.deleted) + fill_stlist(&arc, archiver.comment, ftell(fi) - archiverhdr.recsize); + sort_stlist(&arc); + + for (tmp = arc; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&archiver, archiverhdr.recsize, 1, fi); + fwrite(&archiver, archiverhdr.recsize, 1, fo); + } + + tidy_stlist(&arc); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"archiver.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendArchive(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&archiver, 0, sizeof(archiver)); + fwrite(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + ArchUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditArchRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Archiver"); + + sprintf(mfile, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(archiverhdr) + ((Area -1) * sizeof(archiver)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&archiver, crc, sizeof(archiver)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "3. EDIT ARCHIVER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Name"); + mvprintw( 9, 2, "3. Available"); + mvprintw(10, 2, "4. Deleted"); + mvprintw(11, 2, "5. Arc files"); + mvprintw(12, 2, "6. Arc mail"); + mvprintw(13, 2, "7. Banners"); + mvprintw(14, 2, "8. Arc test"); + mvprintw(15, 2, "9. Un. files"); + mvprintw(16, 2, "10. Un. mail"); + mvprintw(17, 2, "11. FILE_ID"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,40, archiver.comment); + show_str( 8,16, 5, archiver.name); + show_bool(9,16, archiver.available); + show_bool(10,16, archiver.deleted); + show_str(11,16,64, archiver.farc); + show_str(12,16,64, archiver.marc); + show_str(13,16,64, archiver.barc); + show_str(14,16,64, archiver.tarc); + show_str(15,16,64, archiver.funarc); + show_str(16,16,64, archiver.munarc); + show_str(17,16,64, archiver.iunarc); + + j = select_menu(11); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&archiver, crc1, sizeof(archiver)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&archiver, sizeof(archiver), 1, fil); + fclose(fil); + ArchUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,16,40,archiver.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,16,5, archiver.name, "The ^name^ of this archiver") + case 3: E_BOOL( 9,16, archiver.available,"Switch if this archiver is ^Available^ for use.") + case 4: E_BOOL(10,16, archiver.deleted, "Is this archiver ^deleted^") + case 5: E_STR( 11,16,64,archiver.farc, "The ^Archive^ command for files") + case 6: E_STR( 12,16,64,archiver.marc, "The ^Archive^ command for mail packets") + case 7: E_STR( 13,16,64,archiver.barc, "The ^Archive^ command to insert/replace banners") + case 8: E_STR( 14,16,64,archiver.tarc, "The ^Archive^ command to test an archive") + case 9: E_STR( 15,16,64,archiver.funarc, "The ^Unarchive^ command for files") + case 10:E_STR( 16,16,64,archiver.munarc, "The ^Unarchive^ command for mail packets") + case 11:E_STR( 17,16,64,archiver.iunarc, "The ^Unarchive^ command to extract the FILE_ID.DIZ file") + } + } + + return 0; +} + + + +void EditArchive(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountArchive(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenArchive() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "3. ARCHIVER SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/archiver.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(archiverhdr) + ((i - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (archiver.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, archiver.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseArchive(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendArchive() == 0) { + records++; + working(3, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditArchRec(atoi(pick)); + } +} + + + +char *PickArchive(char *shdr) +{ + static char Arch[6] = ""; + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Arch; + } + + records = CountArchive(); + if (records == -1) { + working(2, 0, 0); + return Arch; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. ARCHIVER SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&archiverhdr, sizeof(archiverhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(archiverhdr) + ((i - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + if (i == 11) { + x = 41; + y = 7; + } + if (archiver.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, archiver.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(archiverhdr) + ((atoi(pick) - 1) * archiverhdr.recsize); + fseek(fil, offset, 0); + fread(&archiver, archiverhdr.recsize, 1, fil); + strcpy(Arch, archiver.name); + } + fclose(fil); + } + } + return Arch; +} + + +int archive_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *arch; + int j; + + sprintf(temp, "%s/etc/archiver.data", getenv("MBSE_ROOT")); + if ((arch = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 3, 0, page, (char *)"Archiver programs"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&archiverhdr, sizeof(archiverhdr), 1, arch); + while ((fread(&archiver, archiverhdr.recsize, 1, arch)) == 1) { + + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Comment %s\n", archiver.comment); + fprintf(fp, " Short name %s\n", archiver.name); + fprintf(fp, " Available %s\n", getboolean(archiver.available)); + fprintf(fp, " Pack files %s\n", archiver.farc); + fprintf(fp, " Pack mail %s\n", archiver.marc); + fprintf(fp, " Pack banners %s\n", archiver.barc); + fprintf(fp, " Test archive %s\n", archiver.tarc); + fprintf(fp, " Unpack files %s\n", archiver.funarc); + fprintf(fp, " Unpack mail %s\n", archiver.munarc); + fprintf(fp, " Get FILE_ID.DIZ %s\n", archiver.iunarc); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(arch); + return page; +} + + + diff --git a/mbsetup/m_archive.h b/mbsetup/m_archive.h new file mode 100644 index 00000000..fe06c300 --- /dev/null +++ b/mbsetup/m_archive.h @@ -0,0 +1,13 @@ +/* m_archive.h */ + +#ifndef _ARCHIVE_H +#define _ARCHIVE_H + + +int CountArchive(void); +void EditArchive(void); +char *PickArchive(char *); +int archive_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_bbs.c b/mbsetup/m_bbs.c new file mode 100644 index 00000000..68766a9c --- /dev/null +++ b/mbsetup/m_bbs.c @@ -0,0 +1,120 @@ +/***************************************************************************** + * + * File ..................: m_bbs.c + * Purpose ...............: BBS Setup Program + * Last modification date : 17-Jul-1999 + * Todo ..................: + * Edit BBS lists + * Edit timebank data + * Edit safe data + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_lang.h" +#include "m_protocol.h" +#include "m_ol.h" +#include "m_fgroup.h" +#include "m_farea.h" +#include "m_menu.h" +#include "m_bbs.h" +#include "m_limits.h" + + +void bbs_menu(void) +{ + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8. BBS SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Security Limits"); + mvprintw( 8, 6, "2. Edit Language Setup"); + mvprintw( 9, 6, "3. Edit BBS Menus"); + mvprintw(10, 6, "4. Edit File Areas"); + mvprintw(11, 6, "5. Edit Transfer Protocols"); + mvprintw(12, 6, "6. Edit BBS List Data"); + mvprintw(13, 6, "7. Edit Oneliners"); + mvprintw(14, 6, "8. Edit TimeBank data"); + mvprintw(15, 6, "9. Edit Safe Cracker data"); + + switch(select_menu(9)) { + case 0: + return; + + case 1: + EditLimits(); + break; + + case 2: + EditLanguage(); + break; + + case 3: + EditMenus(); + break; + + case 4: + EditFilearea(); + break; + + case 5: + EditProtocol(); + break; + + case 6: + break; + + case 7: + ol_menu(); + break; + } + } +} + + + +int bbs_doc(FILE *fp, FILE *toc, int page) +{ + page = newpage(fp, page); + addtoc(fp, toc, 8, 0, page, (char *)"BBS setup"); + + page = bbs_limits_doc(fp, toc, page); + page = bbs_lang_doc(fp, toc, page); + page = bbs_menu_doc(fp, toc, page); + page = bbs_file_doc(fp, toc, page); + page = bbs_prot_doc(fp, toc, page); + + return page; +} + + diff --git a/mbsetup/m_bbs.h b/mbsetup/m_bbs.h new file mode 100644 index 00000000..9c9e53e2 --- /dev/null +++ b/mbsetup/m_bbs.h @@ -0,0 +1,8 @@ +#ifndef _MBBS_H +#define _MBBS_H + +void bbs_menu(void); +int bbs_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_domain.c b/mbsetup/m_domain.c new file mode 100644 index 00000000..b8a3de39 --- /dev/null +++ b/mbsetup/m_domain.c @@ -0,0 +1,485 @@ +/***************************************************************************** + * + * File ..................: m_domain.c + * Purpose ...............: Domain Setup + * Last modification date : 23-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_menu.h" +#include "m_domain.h" + + +int DomainUpdated; + + +/* + * Count nr of domtrans records in the database. + * Creates the database if it doesn't exist. + */ +int CountDomain(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + domainhdr.hdrsize = sizeof(domainhdr); + domainhdr.recsize = sizeof(domtrans); + domainhdr.lastupd = time(NULL); + fwrite(&domainhdr, sizeof(domainhdr), 1, fil); + memset(&domtrans, 0, sizeof(domtrans)); + domtrans.Active = TRUE; + sprintf(domtrans.ftndom, ".z1.fidonet"); + sprintf(domtrans.intdom, ".z1.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z2.fidonet"); + sprintf(domtrans.intdom, ".z2.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z3.fidonet"); + sprintf(domtrans.intdom, ".z3.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z4.fidonet"); + sprintf(domtrans.intdom, ".z4.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z5.fidonet"); + sprintf(domtrans.intdom, ".z5.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".z6.fidonet"); + sprintf(domtrans.intdom, ".z6.fidonet.org"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + sprintf(domtrans.ftndom, ".fidonet"); + sprintf(domtrans.intdom, ".ftn"); + fwrite(&domtrans, sizeof(domtrans), 1, fil); + fclose(fil); + return 7; + } else + return -1; + } + + fread(&domainhdr, sizeof(domainhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - domainhdr.hdrsize) / domainhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenDomain(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/domain.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&domainhdr, sizeof(domainhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = domainhdr.recsize; + if (oldsize != sizeof(domtrans)) + DomainUpdated = 1; + else + DomainUpdated = 0; + domainhdr.hdrsize = sizeof(domainhdr); + domainhdr.recsize = sizeof(domtrans); + fwrite(&domainhdr, sizeof(domainhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&domtrans, 0, sizeof(domtrans)); + while (fread(&domtrans, oldsize, 1, fin) == 1) { + fwrite(&domtrans, sizeof(domtrans), 1, fout); + memset(&domtrans, 0, sizeof(domtrans)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseDomain(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + + sprintf(fin, "%s/etc/domain.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/domain.temp", getenv("MBSE_ROOT")); + + if (DomainUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&domainhdr, domainhdr.hdrsize, 1, fi); + fwrite(&domainhdr, domainhdr.hdrsize, 1, fo); + + while (fread(&domtrans, domainhdr.recsize, 1, fi) == 1) { + if (!domtrans.Deleted) + fwrite(&domtrans, domainhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"domtrans.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendDomain(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&domtrans, 0, sizeof(domtrans)); + /* + * Fill in default values + */ + fwrite(&domtrans, sizeof(domtrans), 1, fil); + fclose(fil); + DomainUpdated = 1; + return 0; + } else + return -1; +} + + + +void DomainScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "17. EDIT DOMAINS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Fidonet"); + mvprintw( 8, 2, "2. Internet"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditDomainRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Domain"); + + sprintf(mfile, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&domainhdr, sizeof(domainhdr), 1, fil); + offset = domainhdr.hdrsize + ((Area -1) * domainhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&domtrans, domainhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&domtrans, crc, domainhdr.recsize); + working(0, 0, 0); + + for (;;) { + DomainScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,60, domtrans.ftndom); + show_str( 8,18,60, domtrans.intdom); + show_bool( 9,18, domtrans.Active); + show_bool(10,18, domtrans.Deleted); + + switch(select_menu(4)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&domtrans, crc1, domainhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + fclose(fil); + DomainUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,60, domtrans.ftndom, "Enter the ^fidonet^ side of this ^domain^.") + case 2: E_STR( 8,18,60, domtrans.intdom, "Enter the ^internet^ side of this ^domain^.") + case 3: E_BOOL( 9,18, domtrans.Active, "If this domain is ^active^") + case 4: E_BOOL(10,18, domtrans.Deleted, "If this record is ^Deleted^") + } + } +} + + + +void EditDomain(void) +{ + int records, i, o, y, from, too; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + struct domrec tdomtrans; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountDomain(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenDomain() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "17. DOMAIN MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&domainhdr, sizeof(domainhdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(domainhdr) + (((o + i) - 1) * domainhdr.recsize); + fseek(fil, offset, 0); + fread(&domtrans, domainhdr.recsize, 1, fil); + if (domtrans.Deleted) + set_color(LIGHTRED, BLACK); + else if (domtrans.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s %-31s", o+i, domtrans.ftndom, domtrans.intdom); + temp[75] = 0; + mvprintw(y, 3, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_menurec(records)); + + if (strncmp(pick, "-", 1) == 0) { + CloseDomain(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendDomain() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "D", 1) == 0) { + mvprintw(LINES -3, 6, "Enter domain number (1..%d) to delete >", records); + y = 0; + y = edit_int(LINES -3, 44, y, (char *)"Enter record number"); + if ((y > 0) && (y <= records) && yes_no((char *)"Remove record")) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r+")) != NULL) { + offset = ((y - 1) * domainhdr.recsize) + domainhdr.hdrsize; + fseek(fil, offset, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + domtrans.Deleted = TRUE; + fseek(fil, offset, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + DomainUpdated = TRUE; + fclose(fil); + } + } + } + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 6, "Enter domain number (1..%d) to move >", records); + from = edit_int(LINES -3, 42, from, (char *)"Enter record number"); + locate(LINES -3, 6); + clrtoeol(); + mvprintw(LINES -3, 6, "Enter new position (1..%d) >", records); + too = edit_int(LINES -3, 36, too, (char *)"Enter destination record number, other will move away"); + if ((from == too) || (from == 0) || (too == 0) || (from > records) || (too > records)) { + errmsg("That makes no sense"); + } else if (yes_no((char *)"Proceed move")) { + sprintf(temp, "%s/etc/domain.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r+")) != NULL) { + fseek(fil, ((from -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&tdomtrans, domainhdr.recsize, 1, fil); + if (from > too) { + for (i = from; i > too; i--) { + fseek(fil, ((i -2) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + fseek(fil, ((i -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + } + } else { + for (i = from; i < too; i++) { + fseek(fil, (i * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fread(&domtrans, domainhdr.recsize, 1, fil); + fseek(fil, ((i -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&domtrans, domainhdr.recsize, 1, fil); + } + } + fseek(fil, ((too -1) * domainhdr.recsize) + domainhdr.hdrsize, SEEK_SET); + fwrite(&tdomtrans, domainhdr.recsize, 1, fil); + fclose(fil); + DomainUpdated = TRUE; + } + } + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditDomainRec(atoi(pick)); + } +} + + + +int domain_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/domain.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 15, 0, page, (char *)"Domain manager"); + j = 0; + + fprintf(fp, "\n"); + fprintf(fp, " Fidonet Internet Active\n"); + fprintf(fp, " ------------------------------ ------------------------------ ------\n"); + fread(&domainhdr, sizeof(domainhdr), 1, no); + + while ((fread(&domtrans, domainhdr.recsize, 1, no)) == 1) { + + if (j == 50) { + page = newpage(fp, page); + fprintf(fp, "\n"); + fprintf(fp, " Fidonet Internet Active\n"); + fprintf(fp, " ------------------------------ ------------------------------ ------\n"); + j = 0; + } + + fprintf(fp, " %-30s %-30s %s\n", domtrans.ftndom, domtrans.intdom, getboolean(domtrans.Active)); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_domain.h b/mbsetup/m_domain.h new file mode 100644 index 00000000..80aaefcf --- /dev/null +++ b/mbsetup/m_domain.h @@ -0,0 +1,10 @@ +#ifndef _DOMAIN_H +#define _DOMAIN_H + + +int CountDomain(void); +void EditDomain(void); +int domain_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_farea.c b/mbsetup/m_farea.c new file mode 100644 index 00000000..3b9c42a6 --- /dev/null +++ b/mbsetup/m_farea.c @@ -0,0 +1,587 @@ +/***************************************************************************** + * + * File ..................: m_farea.c + * Purpose ...............: File Setup Program + * Last modification date : 28-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_fgroup.h" +#include "m_archive.h" +#include "m_farea.h" +#include "m_fgroup.h" +#include "m_ngroup.h" + + +int FileUpdated = 0; + + +/* + * Count nr of area records in the database. + * Creates the database if it doesn't exist. + */ +int CountFilearea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + areahdr.hdrsize = sizeof(areahdr); + areahdr.recsize = sizeof(area); + fwrite(&areahdr, sizeof(areahdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&areahdr, sizeof(areahdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - areahdr.hdrsize) / areahdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFilearea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = areahdr.recsize; + if (oldsize != sizeof(area)) + FileUpdated = 1; + else + FileUpdated = 0; + areahdr.hdrsize = sizeof(areahdr); + areahdr.recsize = sizeof(area); + fwrite(&areahdr, sizeof(areahdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&area, 0, sizeof(area)); + while (fread(&area, oldsize, 1, fin) == 1) { + fwrite(&area, sizeof(area), 1, fout); + memset(&area, 0, sizeof(area)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFilearea(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fareas.temp", getenv("MBSE_ROOT")); + + if (FileUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"fareas.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFilearea(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&area, 0, sizeof(area)); + /* + * Fill in default values + */ + area.New = TRUE; + area.Dupes = TRUE; + area.FileFind = TRUE; + area.AddAlpha = TRUE; + area.FileReq = TRUE; + fwrite(&area, sizeof(area), 1, fil); + fclose(fil); + FileUpdated = 1; + return 0; + } else + return -1; +} + + + +void FileScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "8.4 EDIT FILE AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Area Name"); + mvprintw( 7, 2, "2. Path"); + mvprintw( 8, 2, "3. Down Sec."); + mvprintw( 9, 2, "4. Upl. Sec."); + mvprintw(10, 2, "5. List Sec."); + mvprintw(11, 2, "6. Files.bbs"); + mvprintw(12, 2, "7. Available"); + mvprintw(13, 2, "8. Check new"); + mvprintw(14, 2, "9. Dupecheck"); + mvprintw(15, 2, "10. Free area"); + mvprintw(16, 2, "11. Direct DL"); + mvprintw(17, 2, "12. Pwd upl."); + mvprintw(18, 2, "13. Filefind"); + + mvprintw(12,30, "14. Add alpha"); + mvprintw(13,30, "15. CDrom"); + mvprintw(14,30, "16. File req."); + mvprintw(15,30, "17. BBS Group"); + mvprintw(16,30, "18. New group"); + mvprintw(17,30, "19. Min. age"); + mvprintw(18,30, "20. Password"); + + mvprintw(12,59, "21. DL days"); + mvprintw(13,59, "22. FD days"); + mvprintw(14,59, "23. Move area"); + mvprintw(15,59, "24. Cost"); + mvprintw(16,59, "25. Archiver"); + mvprintw(17,59, "26. Upload"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditFileRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit File Area"); + + sprintf(mfile, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&areahdr, sizeof(areahdr), 1, fil); + offset = areahdr.hdrsize + ((Area -1) * areahdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&area, areahdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&area, crc, areahdr.recsize); + working(0, 0, 0); + FileScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,44, area.Name); + show_str( 7,16,64, area.Path); + show_sec( 8,16, area.DLSec); + show_sec( 9,16, area.UPSec); + show_sec(10,16, area.LTSec); + show_str(11,16,64, area.FilesBbs); + show_bool(12,16, area.Available); + show_bool(13,16, area.New); + show_bool(14,16, area.Dupes); + show_bool(15,16, area.Free); + show_bool(16,16, area.DirectDL); + show_bool(17,16, area.PwdUP); + show_bool(18,16, area.FileFind); + + show_bool(12,44, area.AddAlpha); + show_bool(13,44, area.CDrom); + show_bool(14,44, area.FileReq); + show_str(15,44,12, area.BbsGroup); + show_str(16,44,12, area.NewGroup); + show_int(17,44, area.Age); + show_str(18,44,20, (char *)"********************"); + + show_int(12,73, area.DLdays); + show_int(13,73, area.FDdays); + show_int(14,73, area.MoveArea); + show_int(15,73, area.Cost); + show_str(16,73, 5, area.Archiver); + show_int(17,73, area.Upload); + + switch(select_menu(26)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&area, crc1, areahdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&area, areahdr.recsize, 1, fil); + fclose(fil); + FileUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 6,16,44, area.Name, "The ^name^ for this area") + case 2: E_PTH( 7,16,64, area.Path, "The ^path^ for the files in this area") + case 3: E_SEC( 8,16, area.DLSec, "8.4.3 DOWNLOAD SECURITY", FileScreen) + case 4: E_SEC( 9,16, area.UPSec, "8.4.4 UPLOAD SECURITY", FileScreen) + case 5: E_SEC( 10,16, area.LTSec, "8.4.5 LIST SECURITY", FileScreen) + case 6: E_STR( 11,16,64, area.FilesBbs, "The path and name of \"files.bbs\" if area is on CDROM") + case 7: E_BOOL(12,16, area.Available, "Is this area ^available^") + case 8: E_BOOL(13,16, area.New, "Include this area in ^new files^ check") + case 9: E_BOOL(14,16, area.Dupes, "Check this area for ^duplicates^ during upload") + case 10:E_BOOL(15,16, area.Free, "Are all files ^free^ in this area") + case 11:E_BOOL(16,16, area.DirectDL, "Allow ^direct download^ from this area") + case 12:E_BOOL(17,16, area.PwdUP, "Allow ^password^ on uploads") + case 13:E_BOOL(18,16, area.FileFind, "Search this area for ^filefind^ requests") + case 14:E_BOOL(12,44, area.AddAlpha, "Add new files ^alphabetic^ or at the end") + case 15:E_BOOL(13,44, area.CDrom, "Is this area on a ^CDROM^") + case 16:E_BOOL(14,44, area.FileReq, "Allow ^file requests^ from this area") + case 17:strcpy(area.BbsGroup, PickFGroup((char *)"8.4.17")); + FileScreen(); + break; + case 18:strcpy(area.NewGroup, PickNGroup((char *)"8.4.18")); + FileScreen(); + break; + case 19:E_INT( 17,44, area.Age, "The ^minimum age^ to access this area") + case 20:E_STR( 18,44,20, area.Password, "The ^password^ to access this area") + case 21:E_INT( 12,73, area.DLdays, "The not ^downloaded days^ to move/kill files") + case 22:E_INT( 13,73, area.FDdays, "The ^file age^ in days to move/kill files") + case 23:E_INT( 14,73, area.MoveArea, "The ^area to move^ files to, 0 is kill") + case 24:E_INT( 15,73, area.Cost, "The ^cost^ to download a file") + case 25:strcpy(area.Archiver, PickArchive((char *)"8.4")); + FileScreen(); + break; + case 26:E_INT( 17,73, area.Upload, "The ^upload^ area, 0 if upload in this area") + } + } +} + + + +void EditFilearea(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFilearea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFilearea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "8.4 FILE AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fareas.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(areahdr) + (((o + i) - 1) * areahdr.recsize); + fseek(fil, offset, 0); + fread(&area, areahdr.recsize, 1, fil); + if (area.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, area.Name); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFilearea(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFilearea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFileRec(atoi(pick)); + } +} + + + +long PickFilearea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return 0; + } + + records = CountFilearea(); + if (records == -1) { + working(2, 0, 0); + return 0; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. FILE AREA SELECT", shdr); + mvprintw(5,3,temp); + set_color(CYAN, BLACK); + if (records) { + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&areahdr, sizeof(areahdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(areahdr) + (((o + i) - 1) * areahdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&area, areahdr.recsize, 1, fil); + if (area.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, area.Name); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return 0; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = areahdr.hdrsize + ((atoi(pick) - 1) * areahdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&area, areahdr.recsize, 1, fil); + fclose(fil); + if (area.Available) + return atoi(pick); + } + } + } +} + + + +int bbs_file_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int i = 0, j = 0; + + sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&areahdr, sizeof(areahdr), 1, no); + page = newpage(fp, page); + addtoc(fp, toc, 8, 4, page, (char *)"BBS File areas"); + + while ((fread(&area, areahdr.recsize, 1, no)) == 1) { + + i++; + if (area.Available) { + + if (j == 1) { + page = newpage(fp, page); + j = 0; + } else { + j++; + } + fprintf(fp, "\n\n"); + fprintf(fp, " Area number %d\n", i); + fprintf(fp, " Area name %s\n", area.Name); + fprintf(fp, " Files path %s\n", area.Path); + fprintf(fp, " Download sec. %s\n", get_secstr(area.DLSec)); + fprintf(fp, " Upload security %s\n", get_secstr(area.UPSec)); + fprintf(fp, " List seccurity %s\n", get_secstr(area.LTSec)); + fprintf(fp, " Path to files.bbs %s\n", area.FilesBbs); + fprintf(fp, " Newfiles scan %s\n", getboolean(area.New)); + fprintf(fp, " Check upl. dupes %s\n", getboolean(area.Dupes)); + fprintf(fp, " Files are free %s\n", getboolean(area.Free)); + fprintf(fp, " Allow direct DL %s\n", getboolean(area.DirectDL)); + fprintf(fp, " Allow pwd upl. %s\n", getboolean(area.PwdUP)); + fprintf(fp, " Filefind on %s\n", getboolean(area.FileFind)); + fprintf(fp, " Add files sorted %s\n", getboolean(area.AddAlpha)); + fprintf(fp, " Files in CDROM %s\n", getboolean(area.CDrom)); + fprintf(fp, " Allow filerequst %s\n", getboolean(area.FileReq)); + fprintf(fp, " BBS group %s\n", area.BbsGroup); + fprintf(fp, " Newfiles group %s\n", area.NewGroup); + fprintf(fp, " Minimum age %d\n", area.Age); + fprintf(fp, " Area password %s\n", area.Password); + fprintf(fp, " Kill DL days %d\n", area.DLdays); + fprintf(fp, " Kill FD days %d\n", area.FDdays); + fprintf(fp, " Move to area %d\n", area.MoveArea); + fprintf(fp, " Archiver %s\n", area.Archiver); + fprintf(fp, " Upload area %d\n", area.Upload); + } + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_farea.h b/mbsetup/m_farea.h new file mode 100644 index 00000000..db102cf0 --- /dev/null +++ b/mbsetup/m_farea.h @@ -0,0 +1,11 @@ +#ifndef _FAREA_H +#define _FAREA_H + + +int CountFilearea(void); +void EditFilearea(void); +long PickFilearea(char *); +int bbs_file_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_fdb.c b/mbsetup/m_fdb.c new file mode 100644 index 00000000..187efbfb --- /dev/null +++ b/mbsetup/m_fdb.c @@ -0,0 +1,282 @@ +/***************************************************************************** + * + * File ..................: setup/m_fdb.c + * Purpose ...............: Edit Files DataBase. + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1999-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_farea.h" +#include "m_fdb.h" + + +void E_F(long); +void EditFile(void); + + +void FHeader(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "14. EDIT FILE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, " FileName"); + mvprintw( 8, 2, " Long fn"); + mvprintw( 9, 2, " FileSize"); + mvprintw(10, 2, " FileDate"); + mvprintw(11, 2, " Last DL."); + mvprintw(12, 2, " Upl.Date"); + mvprintw(13, 2, "1. Uploader"); + mvprintw(14, 2, "2. Times DL"); + mvprintw(15, 2, "3. Times FTP"); + mvprintw(16, 2, "4. Times Req"); + mvprintw(17, 2, "5. Password"); + mvprintw(18, 2, "6. Cost"); + + mvprintw(14,42, "7. Free"); + mvprintw(15,42, "8. Deleted"); + mvprintw(16,42, " Missing"); + mvprintw(17,42, "9. No Kill"); + mvprintw(18,42, "10. Announced"); +} + + + +void EditFile() +{ + FHeader(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,12, file.Name); + show_str( 8,16,64, file.LName); + show_int( 9,16, file.Size); + mvprintw(10,16, (char *)"%s %s", StrDateDMY(file.FileDate), StrTimeHM(file.FileDate)); + mvprintw(11,16, (char *)"%s %s", StrDateDMY(file.LastDL), StrTimeHM(file.LastDL)); + mvprintw(12,16, (char *)"%s %s", StrDateDMY(file.UploadDate), StrTimeHM(file.UploadDate)); + show_str(13,16,36, file.Uploader); + show_int(14,16, file.TimesDL); + show_int(15,16, file.TimesFTP); + show_int(16,16, file.TimesReq); + show_str(17,16,15, file.Password); + show_int(18,16, file.Cost); + + show_bool(14,56, file.Free); + show_bool(15,56, file.Deleted); + show_bool(16,56, file.Missing); + show_bool(17,56, file.NoKill); + show_bool(18,56, file.Announced); + + switch(select_menu(10)) { + case 0: return; + case 1: E_STR( 13,16,35, file.Uploader, "The ^uploader^ of this file") + case 2: E_INT( 14,16, file.TimesDL, "The number of times file is sent with ^download^") + case 3: E_INT( 15,16, file.TimesFTP, "The number of times file is sent with ^FTP or WWW^") + case 4: E_INT( 16,16, file.TimesReq, "The number of times file is sent with ^filerequest^") + case 5: E_STR( 17,16,15, file.Password, "The ^password^ to protect this file with") + case 6: E_INT( 18,16, file.Cost, "The ^cost^ of this file") + case 7: E_BOOL(14,56, file.Free, "If this file is a ^free^ download") + case 8: E_BOOL(15,56, file.Deleted, "Should this this file be ^deleted^") + case 9: E_BOOL(17,56, file.NoKill, "File can't be ^killed^ automatic") + case 10:E_BOOL(18,56, file.Announced, "File is ^announced^ as new file") + } + } +} + + + +void E_F(long areanr) +{ + FILE *fil; + char temp[81]; + int i, y, o, records, Ondisk; + char help[81]; + static char *menu = (char *)"0"; + long offset; + time_t Time; + struct stat statfile; + unsigned long crc, crc1; + + clr_index(); + + sprintf(temp, "%s/fdb/fdb%ld.data", getenv("MBSE_ROOT"), areanr); + if ((fil = fopen(temp, "r+")) == NULL) { + working(2, 0, 0); + return; + } + + fseek(fil, 0, SEEK_END); + records = ftell(fil) / sizeof(file); + o = 0; + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 4, "14. EDIT FILES DATABASE"); + + y = 8; + working(1, 0, 0); + + set_color(YELLOW, BLUE); + mvprintw(7, 1, " Nr Filename Size Date Time Description "); +/* 1234 12345678901234 12345678 12-34-1998 12:45 123456789012345678901234567890*/ + set_color(CYAN, BLACK); + + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = ((o + i) - 1) * sizeof(file); + fseek(fil, offset, SEEK_SET); + fread(&file, sizeof(file), 1, fil); + + set_color(WHITE, BLACK); + mvprintw(y, 1, (char *)"%4d.", o + i); + + sprintf(temp, "%s/%s", area.Path, file.Name); + Ondisk = ((stat(temp, &statfile)) != -1); + + if (Ondisk) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + mvprintw(y, 8, (char *)"%-14s", file.Name); + + if (Ondisk) { + if (file.Size == statfile.st_size) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + mvprintw(y,23, (char *)"%8ld", file.Size); + + if (file.FileDate == statfile.st_mtime) + set_color(CYAN, BLACK); + else + set_color(LIGHTRED, BLACK); + Time = file.FileDate; + mvprintw(y,32, (char *)"%s %s", StrDateDMY(Time), StrTimeHM(Time)); + } + + set_color(CYAN, BLACK); + sprintf(temp, "%s", file.Desc[0]); + temp[30] = '\0'; + mvprintw(y,49, (char *)"%s", temp); + y++; + } + } + working(0, 0, 0); + + if (records) + if (records > 10) + sprintf(help, "^1..%d^ Edit, ^-^ Return, ^N^/^P^ Page", records); + else + sprintf(help, "^1..%d^ Edit, ^-^ Return", records); + else + sprintf(help, "^-^ Return"); + + showhelp(help); + + while(TRUE) { + mvprintw(LINES - 4, 6, "Enter your choice >"); + menu = (char *)"0"; + menu = edit_field(LINES - 4, 26, 6, '!', menu); + locate(LINES - 4, 6); + clrtoeol(); + + if (strncmp(menu, "-", 1) == 0) { + fclose(fil); + return; + } + + if (records > 10) { + if (strncmp(menu, "N", 1) == 0) + if ((o + 10) < records) { + o += 10; + break; + } + + if (strncmp(menu, "P", 1) == 0) + if ((o - 10) >= 0) { + o -= 10; + break; + } + } + + if ((atoi(menu) > 0) && (atoi(menu) <= records)) { + working(1, 0, 0); + offset = (atoi(menu) - 1) * sizeof(file); + fseek(fil, offset, SEEK_SET); + fread(&file, sizeof(file), 1, fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&file, crc, sizeof(file)); + + sprintf(temp, "%s/%s", area.Path, file.Name); + if (stat(temp, &statfile) == -1) + file.Missing = TRUE; + + EditFile(); + + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&file, crc1, sizeof(file)); + + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + fseek(fil, offset, SEEK_SET); + fwrite(&file, sizeof(file), 1, fil); + } + } + break; + } + } + + } +} + + + +void EditFDB() +{ + long areanr; + + IsDoing("Browsing Menu"); + + for (;;) { + if ((areanr = PickFilearea((char *)"14")) == 0) + return; + E_F(areanr); + } +} + + diff --git a/mbsetup/m_fdb.h b/mbsetup/m_fdb.h new file mode 100644 index 00000000..1cf3ffcc --- /dev/null +++ b/mbsetup/m_fdb.h @@ -0,0 +1,8 @@ +#ifndef _M_FDB_H +#define _M_FDB_H + +void EditFDB(void); + +#endif + + diff --git a/mbsetup/m_ff.c b/mbsetup/m_ff.c new file mode 100644 index 00000000..112c6584 --- /dev/null +++ b/mbsetup/m_ff.c @@ -0,0 +1,449 @@ +/***************************************************************************** + * + * File ..................: m_ff.c + * Purpose ...............: Filefind Setup + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_ff.h" +#include "m_lang.h" +#include "m_marea.h" + + +int FilefindUpdated = 0; + + +/* + * Count nr of scanmgr records in the database. + * Creates the database if it doesn't exist. + */ +int CountFilefind(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + scanmgrhdr.hdrsize = sizeof(scanmgrhdr); + scanmgrhdr.recsize = sizeof(scanmgr); + fwrite(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - scanmgrhdr.hdrsize) / scanmgrhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFilefind(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = scanmgrhdr.recsize; + if (oldsize != sizeof(scanmgr)) + FilefindUpdated = 1; + else + FilefindUpdated = 0; + scanmgrhdr.hdrsize = sizeof(scanmgrhdr); + scanmgrhdr.recsize = sizeof(scanmgr); + fwrite(&scanmgrhdr, sizeof(scanmgrhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&scanmgr, 0, sizeof(scanmgr)); + while (fread(&scanmgr, oldsize, 1, fin) == 1) { + fwrite(&scanmgr, sizeof(scanmgr), 1, fout); + memset(&scanmgr, 0, sizeof(scanmgr)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFilefind(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *fff = NULL, *tmp; + + sprintf(fin, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + + if (FilefindUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&scanmgrhdr, scanmgrhdr.hdrsize, 1, fi); + fwrite(&scanmgrhdr, scanmgrhdr.hdrsize, 1, fo); + + while (fread(&scanmgr, scanmgrhdr.recsize, 1, fi) == 1) + if (!scanmgr.Deleted) + fill_stlist(&fff, scanmgr.Comment, ftell(fi) - scanmgrhdr.recsize); + sort_stlist(&fff); + + for (tmp = fff; tmp; tmp=tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&scanmgr, scanmgrhdr.recsize, 1, fi); + fwrite(&scanmgr, scanmgrhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + tidy_stlist(&fff); + unlink(fout); + Syslog('+', "Updated \"scanmgr.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFilefind(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&scanmgr, 0, sizeof(scanmgr)); + /* + * Fill in default values + */ + fwrite(&scanmgr, sizeof(scanmgr), 1, fil); + fclose(fil); + FilefindUpdated = 1; + return 0; + } else + return -1; +} + + + +void FFScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "13. EDIT FILEFIND AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Origin"); + mvprintw( 9, 2, "3. Aka to use"); + mvprintw(10, 2, "4. Scan area"); + mvprintw(11, 2, "5. Reply area"); + mvprintw(12, 2, "6. Language"); + mvprintw(13, 2, "7. Template"); + mvprintw(14, 2, "8. Active"); + mvprintw(15, 2, "9. Deleted"); + mvprintw(16, 2, "10. Net. reply"); + mvprintw(17, 2, "11. Hi Ascii"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditFfRec(int Area) +{ + FILE *fil; + char mfile[81], temp1[2]; + long offset; + unsigned long crc, crc1; + int i; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Filefind"); + + sprintf(mfile, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + offset = scanmgrhdr.hdrsize + ((Area -1) * scanmgrhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&scanmgr, scanmgrhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&scanmgr, crc, scanmgrhdr.recsize); + working(0, 0, 0); + + for (;;) { + FFScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, scanmgr.Comment); + show_str( 8,18,50, scanmgr.Origin); + show_str( 9,18,35, aka2str(scanmgr.Aka)); + show_str( 10,18,50, scanmgr.ScanBoard); + show_str( 11,18,50, scanmgr.ReplBoard); + sprintf(temp1, "%c", scanmgr.Language); + show_str( 12,18,2, temp1); + show_str( 13,18,14, scanmgr.template); + show_bool(14,18, scanmgr.Active); + show_bool(15,18, scanmgr.Deleted); + show_bool(16,18, scanmgr.NetReply); + show_bool(17,18, scanmgr.HiAscii); + + switch(select_menu(11)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&scanmgr, crc1, scanmgrhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&scanmgr, scanmgrhdr.recsize, 1, fil); + fclose(fil); + FilefindUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, scanmgr.Comment, "The ^comment^ for this area") + case 2: E_STR( 8,18,50, scanmgr.Origin, "The ^origin^ line to append, leave blank for random lines") + case 3: i = PickAka((char *)"13.3", TRUE); + if (i != -1) + scanmgr.Aka = CFG.aka[i]; + break; + case 4: strcpy(scanmgr.ScanBoard, PickMsgarea((char *)"13.4")); + break; + case 5: strcpy(scanmgr.ReplBoard, PickMsgarea((char *)"13.5")); + break; + case 6: scanmgr.Language = PickLanguage((char *)"13.6"); + break; + case 7: E_STR( 13,18,14, scanmgr.template, "The ^template^ file to use for the report") + case 8: E_BOOL(14,18, scanmgr.Active, "If this report is ^active^") + case 9: E_BOOL(15,18, scanmgr.Deleted, "If this record is ^deleted^") + case 10:E_BOOL(16,18, scanmgr.NetReply, "If reply's via ^netmail^ instead of echomail") + case 11:E_BOOL(17,18, scanmgr.HiAscii, "Allow ^Hi ASCII^ in this area") + } + } +} + + + +void EditFilefind(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFilefind(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFilefind() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "13. FILEFIND AREAS"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/scanmgr.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(scanmgrhdr) + (((o + i) - 1) * scanmgrhdr.recsize); + fseek(fil, offset, 0); + fread(&scanmgr, scanmgrhdr.recsize, 1, fil); + if (scanmgr.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, scanmgr.Comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFilefind(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFilefind() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFfRec(atoi(pick)); + } +} + + + +int ff_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/scanmgr.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 13, 0, page, (char *)"Filefind areas"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, no); + + while ((fread(&scanmgr, scanmgrhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Area comment %s\n", scanmgr.Comment); + fprintf(fp, " Origin line %s\n", scanmgr.Origin); + fprintf(fp, " Aka to use %s\n", aka2str(scanmgr.Aka)); + fprintf(fp, " Scan msg board %s\n", scanmgr.ScanBoard); + fprintf(fp, " Reply msg board %s\n", scanmgr.ReplBoard); + fprintf(fp, " Language %c\n", scanmgr.Language); + fprintf(fp, " Active %s\n", getboolean(scanmgr.Active)); + fprintf(fp, " Netmail reply %s\n", getboolean(scanmgr.NetReply)); + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_ff.h b/mbsetup/m_ff.h new file mode 100644 index 00000000..c7b5b47c --- /dev/null +++ b/mbsetup/m_ff.h @@ -0,0 +1,10 @@ +#ifndef _FILEFIND_H +#define _FILEFIND_H + + +int CountFilefind(void); +void EditFilefind(void); +int ff_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_fgroup.c b/mbsetup/m_fgroup.c new file mode 100644 index 00000000..07d8bcb9 --- /dev/null +++ b/mbsetup/m_fgroup.c @@ -0,0 +1,585 @@ +/***************************************************************************** + * + * File ..................: setup/m_fgroups.c + * Purpose ...............: Setup FGroups. + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_ticarea.h" +#include "m_fgroup.h" + + + +int FGrpUpdated = 0; + + +/* + * Count nr of fgroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountFGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.recsize = sizeof(fgroup); + fwrite(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - fgrouphdr.hdrsize) / fgrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + FGrpUpdated = 0; + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fin); + if (fgrouphdr.hdrsize != sizeof(fgrouphdr)) { + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.lastupd = time(NULL); + FGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = fgrouphdr.recsize; + if (oldsize != sizeof(fgroup)) + FGrpUpdated = 1; + fgrouphdr.hdrsize = sizeof(fgrouphdr); + fgrouphdr.recsize = sizeof(fgroup); + fwrite(&fgrouphdr, sizeof(fgrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&fgroup, 0, sizeof(fgroup)); + while (fread(&fgroup, oldsize, 1, fin) == 1) { + fwrite(&fgroup, sizeof(fgroup), 1, fout); + memset(&fgroup, 0, sizeof(fgroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *fgr = NULL, *tmp; + + sprintf(fin, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + + if (FGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, fi); + fwrite(&fgrouphdr, fgrouphdr.hdrsize, 1, fo); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fi) == 1) + if (!fgroup.Deleted) + fill_stlist(&fgr, fgroup.Name, ftell(fi) - fgrouphdr.recsize); + sort_stlist(&fgr); + + for (tmp = fgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&fgroup, fgrouphdr.recsize, 1, fi); + fwrite(&fgroup, fgrouphdr.recsize, 1, fo); + } + + tidy_stlist(&fgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"fgroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&fgroup, 0, sizeof(fgroup)); + time(&fgroup.StartDate); + fgroup.DivideCost = TRUE; + fwrite(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + FGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Check if field can be edited without screwing up the database + */ +int CheckFgroup(void); +int CheckFgroup(void) +{ + int ncnt, tcnt; + + working(1, 0, 0); + ncnt = GroupInNode(fgroup.Name, FALSE); + tcnt = GroupInTic(fgroup.Name); + working(0, 0, 0); + if (ncnt || tcnt) { + errmsg((char *)"Error, %d node(s) and/or %d tic area(s) connected", ncnt, tcnt); + return TRUE; + } + return FALSE; +} + + + +void FgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.1 EDIT FILE GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Use Aka"); + mvprintw(11, 6, "5. Uplink"); + mvprintw(12, 6, "6. Areas"); + mvprintw(13, 6, "7. Unit Cost"); + mvprintw(14, 6, "8. Unit Size"); + mvprintw(15, 6, "9. Add Prom."); + mvprintw(16, 6, "10. Divide"); + mvprintw(17, 6, "11. Deleted"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditFGrpRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j, tmp; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit FileGroup"); + + sprintf(mfile, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(fgrouphdr) + ((Area -1) * sizeof(fgroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&fgroup, crc, sizeof(fgroup)); + working(0, 0, 0); + FgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,20,12, fgroup.Name); + show_str( 8,20,55, fgroup.Comment); + show_bool( 9,20, fgroup.Active); + show_aka( 10,20, fgroup.UseAka); + show_aka( 11,20, fgroup.UpLink); + show_str( 12,20,12, fgroup.AreaFile); + show_int( 13,20, fgroup.UnitCost); + show_int( 14,20, fgroup.UnitSize); + show_int( 15,20, fgroup.AddProm); + show_bool(16,20, fgroup.DivideCost); + show_bool(17,20, fgroup.Deleted); + + j = select_menu(11); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&fgroup, crc1, sizeof(fgroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&fgroup, sizeof(fgroup), 1, fil); + fclose(fil); + FGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: if (CheckFgroup()) + break; + E_UPS( 7,20,12,fgroup.Name, "The ^name^ of this file group") + case 2: E_STR( 8,20,55,fgroup.Comment, "The ^description^ of this file group") + case 3: if (CheckFgroup()) + break; + E_BOOL( 9,20, fgroup.Active, "Is this file group ^active^") + case 4: tmp = PickAka((char *)"10.1.4", TRUE); + if (tmp != -1) + fgroup.UseAka = CFG.aka[tmp]; + FgScreen(); + break; + case 5: fgroup.UpLink = PullUplink((char *)"10.1.5"); + FgScreen(); + break; + case 6: E_STR( 12,20,12,fgroup.AreaFile, "The name of the ^Areas File^ from the uplink") + case 7: E_INT( 13,20, fgroup.UnitCost, "The ^cost per size unit^ for this file") + case 8: E_INT( 14,20, fgroup.UnitSize, "The ^unit size^ in KBytes, 0 means cost per file") + case 9: E_INT( 15,20, fgroup.AddProm, "The ^Promillage^ to add or substract of the filecost") + case 10:E_BOOL(16,20, fgroup.DivideCost, "^Divide^ the cost over all downlinks or charge each link full cost") + case 11:if (CheckFgroup()) + break; + E_BOOL(17,20, fgroup.Deleted, "Is this file group ^Deleted^") + } + } + + return 0; +} + + + +void EditFGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "10.1 FILE GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fgroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(fgrouphdr) + (((o + i) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + if (fgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, fgroup.Name, fgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFGrpRec(atoi(pick)); + } +} + + + +char *PickFGroup(char *shdr) +{ + static char FGrp[21] = ""; + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return FGrp; + } + + records = CountFGroup(); + if (records == -1) { + working(2, 0, 0); + return FGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. FILE GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(fgrouphdr) + (((o + i) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + if (fgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, fgroup.Name, fgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FGrp; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = fgrouphdr.hdrsize + ((atoi(pick) - 1) * fgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&fgroup, fgrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(FGrp, fgroup.Name); + return (FGrp); + } + } +} + + + +int tic_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 10, 1, page, (char *)"File processing groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&fgrouphdr, sizeof(fgrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&fgrouphdr, fgrouphdr.hdrsize, 1, no); + + while ((fread(&fgroup, fgrouphdr.recsize, 1, no)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", fgroup.Name); + fprintf(fp, " Comment %s\n", fgroup.Comment); + fprintf(fp, " Active %s\n", getboolean(fgroup.Active)); + fprintf(fp, " Use Aka %s\n", aka2str(fgroup.UseAka)); + fprintf(fp, " Uplink %s\n", aka2str(fgroup.UpLink)); + fprintf(fp, " Areas file %s\n", fgroup.AreaFile); + fprintf(fp, " Start date %s", ctime(&fgroup.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&fgroup.LastDate)); + +// fprintf(fp, " Total This month Last month\n"); +// fprintf(fp, " ---------- ---------- ----------\n"); +// fprintf(fp, " Files %-10ld %-10ld %-10ld\n", fgroup.Total.files, fgroup.ThisMonth.files, fgroup.LastMonth.files); +// fprintf(fp, " KBytes %-10ld %-10ld %-10ld\n", fgroup.Total.kbytes, fgroup.ThisMonth.kbytes, fgroup.LastMonth.kbytes); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_fgroup.h b/mbsetup/m_fgroup.h new file mode 100644 index 00000000..bf429b95 --- /dev/null +++ b/mbsetup/m_fgroup.h @@ -0,0 +1,12 @@ +#ifndef _FGROUP_H +#define _FGROUP_H + + +int CountFGroup(void); +void EditFGroup(void); +char *PickFGroup(char *); +int tic_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_fido.c b/mbsetup/m_fido.c new file mode 100644 index 00000000..0128a4e6 --- /dev/null +++ b/mbsetup/m_fido.c @@ -0,0 +1,558 @@ +/***************************************************************************** + * + * File ..................: setup/m_fido.c + * Purpose ...............: Setup Fidonet structure. + * Last modification date : 13-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_fido.h" + + + +int FidoUpdated = 0; + + +/* + * Count nr of fidonet records in the database. + * Creates the database if it doesn't exist. + */ +int CountFidonet(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + fidonethdr.hdrsize = sizeof(fidonethdr); + fidonethdr.recsize = sizeof(fidonet); + fwrite(&fidonethdr, sizeof(fidonethdr), 1, fil); + /* + * Fill in the defaults + */ + memset(&fidonet, 0, sizeof(fidonet)); + sprintf(fidonet.comment, "Fidonet network"); + sprintf(fidonet.domain, "fidonet"); + sprintf(fidonet.nodelist, "NODELIST"); + sprintf(fidonet.seclist[0].nodelist, "REGION28"); + fidonet.seclist[0].zone = 2; + fidonet.seclist[0].net = 28; + fidonet.zone[0] = 2; + fidonet.zone[1] = 1; + fidonet.zone[2] = 3; + fidonet.zone[3] = 4; + fidonet.zone[4] = 5; + fidonet.zone[5] = 6; + fidonet.available = TRUE; + fwrite(&fidonet, sizeof(fidonet), 1, fil); + memset(&fidonet, 0, sizeof(fidonet)); + sprintf(fidonet.comment, "Virus network"); + sprintf(fidonet.domain, "virnet"); + sprintf(fidonet.nodelist, "VIRNODES"); + fidonet.zone[0] = 9; + fidonet.available = TRUE; + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + return 2; + } else + return -1; + } + + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - fidonethdr.hdrsize) / fidonethdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenFidonet(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = fidonethdr.recsize; + if (oldsize != sizeof(fidonet)) + FidoUpdated = 1; + else + FidoUpdated = 0; + fidonethdr.hdrsize = sizeof(fidonethdr); + fidonethdr.recsize = sizeof(fidonet); + fwrite(&fidonethdr, sizeof(fidonethdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&fidonet, 0, sizeof(fidonet)); + while (fread(&fidonet, oldsize, 1, fin) == 1) { + fwrite(&fidonet, sizeof(fidonet), 1, fout); + memset(&fidonet, 0, sizeof(fidonet)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseFidonet(void) +{ + char fin[81], fout[81], temp[10]; + FILE *fi, *fo; + st_list *fid = NULL, *tmp; + + sprintf(fin, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + + if (FidoUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&fidonethdr, fidonethdr.hdrsize, 1, fi); + fwrite(&fidonethdr, fidonethdr.hdrsize, 1, fo); + + while (fread(&fidonet, fidonethdr.recsize, 1, fi) == 1) + if (!fidonet.deleted) { + sprintf(temp, "%05d", fidonet.zone[0]); + fill_stlist(&fid, temp, ftell(fi) - fidonethdr.recsize); + } + sort_stlist(&fid); + + for (tmp = fid; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&fidonet, fidonethdr.recsize, 1, fi); + fwrite(&fidonet, fidonethdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&fid); + + Syslog('+', "Updated \"fidonet.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendFidonet(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&fidonet, 0, sizeof(fidonet)); + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + FidoUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditFidoRec(int Area) +{ + FILE *fil; + char mfile[81], *temp; + long offset; + int i, j = 0; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Fidonet"); + + sprintf(mfile, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(fidonethdr) + ((Area -1) * sizeof(fidonet)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&fidonet, crc, sizeof(fidonet)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "2. EDIT FIDONET NETWORK"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Comment"); + mvprintw( 8, 6, "2. Domain name"); + mvprintw( 9, 6, "3. Available"); + mvprintw(10, 6, "4. Deleted"); + mvprintw(11, 6, "5. Main Nodelist"); + mvprintw(12, 6, "6. Merge list #1"); + mvprintw(13, 6, "7. Merge list #2"); + mvprintw(14, 6, "8. Merge list #3"); + mvprintw(15, 6, "9. Merge list #4"); + mvprintw(16, 6, "10. Merge list #5"); + mvprintw(17, 6, "11. Merge list #6"); + mvprintw(12,55, "12. Primary zone"); + mvprintw(13,55, "13. Zone number #2"); + mvprintw(14,55, "14. Zone number #3"); + mvprintw(15,55, "15. Zone number #4"); + mvprintw(16,55, "16. Zone number #5"); + mvprintw(17,55, "17. Zone number #6"); + temp = calloc(18, sizeof(char)); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,26,40, fidonet.comment); + show_str( 8,26,12, fidonet.domain); + show_bool(9,26, fidonet.available); + show_bool(10,26, fidonet.deleted); + show_str(11,26,8, fidonet.nodelist); + for (i = 0; i < 6; i++) { + if ((fidonet.seclist[i].zone) || strlen(fidonet.seclist[i].nodelist)) { + show_str(i + 12,26,8, fidonet.seclist[i].nodelist); + sprintf(temp, "%d:%d/%d", fidonet.seclist[i].zone, fidonet.seclist[i].net, fidonet.seclist[i].node); + show_str(i + 12, 36,17, temp); + } else + show_str(i + 12,26,27, (char *)" "); + show_int(i + 12,74, fidonet.zone[i]); + } + + j = select_menu(17); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&fidonet, crc1, sizeof(fidonet)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + free(temp); + return -1; + } + fseek(fil, offset, 0); + fwrite(&fidonet, sizeof(fidonet), 1, fil); + fclose(fil); + FidoUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + free(temp); + return 0; + case 1: + E_STR(7,26,40, fidonet.comment, "The ^Comment^ for this network name") + + case 2: + E_STR(8, 26,12, fidonet.domain, "The ^Name^ of the network without dots") + + case 3: + E_BOOL(9,26, fidonet.available, "Is this network ^Available^ for use") + + case 4: + E_BOOL(10,26, fidonet.deleted, "Is this netword ^Deleted^") + + case 5: + E_STR(11,26,8, fidonet.nodelist, "The name of the ^Primary Nodelist^ for this network") + + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + strcpy(fidonet.seclist[j-6].nodelist, edit_str(j+6,26,8, fidonet.seclist[j-6].nodelist, (char *)"The secondary ^nodelist^ or ^pointlist^ name for this domain")); + if (strlen(fidonet.seclist[j-6].nodelist)) { + do { + sprintf(temp, "%d:%d/%d", fidonet.seclist[j-6].zone, fidonet.seclist[j-6].net, fidonet.seclist[j-6].node); + strcpy(temp, edit_str(j+6,36,17, temp, (char *)"The top ^fidonet aka^ for this nodelist (zone:net/node)")); + if ((strstr(temp, ":") == NULL) || (strstr(temp, "/") == NULL)) { + working(2, 0, 0); + working(0, 0, 0); + } + } while ((strstr(temp, ":") == NULL) || (strstr(temp, "/") == NULL)); + fidonet.seclist[j-6].zone = atoi(strtok(temp, ":")); + fidonet.seclist[j-6].net = atoi(strtok(NULL, "/")); + fidonet.seclist[j-6].node = atoi(strtok(NULL, "")); + } else { + fidonet.seclist[j-6].zone = 0; + fidonet.seclist[j-6].net = 0; + fidonet.seclist[j-6].node = 0; + } + break; + + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + E_INT(j,74, fidonet.zone[j-12], "A ^Zone number^ which belongs to this domain (1..4095)") + } + } + + return 0; +} + + + +void EditFidonet(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountFidonet(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenFidonet() == -1) { + working(2, 0, 0); + return; + } + IsDoing("Browsing Menu"); + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "2. FIDONET SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/fidonet.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(fidonethdr) + ((i - 1) * fidonethdr.recsize); + fseek(fil, offset, 0); + fread(&fidonet, fidonethdr.recsize, 1, fil); + if (fidonet.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + if (i == 11) { + x = 42; + y = 7; + } + sprintf(temp, "%3d. z%d: %-32s", i, fidonet.zone[0], fidonet.comment); + temp[38] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseFidonet(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendFidonet() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditFidoRec(atoi(pick)); + } +} + + + +void gold_akamatch(FILE *fp) +{ + char temp[81]; + FILE *fido; + faddr *want; + int i; + + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fido = fopen(temp, "r")) == NULL) + return; + + fprintf(fp, "; AKA Matching\n;\n"); + want = (faddr *)malloc(sizeof(faddr)); + + fread(&fidonethdr, sizeof(fidonethdr), 1, fido); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + + for (i = 0; i < 6; i++) + if (fidonet.zone[i]) { + want->zone = fidonet.zone[0]; + want->net = 0; + want->node = 0; + want->point = 0; + want->name = NULL; + want->domain = NULL; + fprintf(fp, "AKAMATCH %d:* %s\n", fidonet.zone[i], ascfnode(bestaka_s(want), 0xf)); + } + } + + free(want); + fprintf(fp, ";\n"); + fprintf(fp, "AKAMATCHNET YES\n"); + fprintf(fp, "AKAMATCHECHO YES\n"); /* On request, should work better */ + fprintf(fp, "AKAMATCHLOCAL NO\n\n"); + + fprintf(fp, "; NODELISTS\n;\n"); + fprintf(fp, "NODEPATH %s/\n", CFG.nodelists); + fseek(fido, fidonethdr.hdrsize, SEEK_SET); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + fprintf(fp, "NODELIST %s.*\n", fidonet.nodelist); + for (i = 0; i < 6; i++) + if (strlen(fidonet.seclist[i].nodelist) || fidonet.seclist[i].zone) + fprintf(fp, "NODELIST %s.*\n", fidonet.seclist[i].nodelist); + } +// fprintf(fp, "USERLIST golded.lst\n"); + fprintf(fp, "LOOKUPNET YES\n"); + fprintf(fp, "LOOKUPECHO NO\n"); + fprintf(fp, "LOOKUPLOCAL NO\n\n"); + fclose(fido); +} + + + +int fido_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *fido; + int i, j; + + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fido = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 2, 0, page, (char *)"Fidonet networks"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&fidonethdr, sizeof(fidonethdr), 1, fido); + while ((fread(&fidonet, fidonethdr.recsize, 1, fido)) == 1) { + + if (j == 6) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Comment %s\n", fidonet.comment); + fprintf(fp, " Domain %s\n", fidonet.domain); + fprintf(fp, " Available %s\n", getboolean(fidonet.available)); + fprintf(fp, " Nodelist %s\n", fidonet.nodelist); + for (i = 0; i < 6; i++) + if (strlen(fidonet.seclist[i].nodelist) || fidonet.seclist[i].zone) { + fprintf(fp, " Merge list %d %-8s %d:%d/%d\n", i+1, + fidonet.seclist[i].nodelist, fidonet.seclist[i].zone, + fidonet.seclist[i].net, fidonet.seclist[i].node); + } + fprintf(fp, " Zone(s) "); + for (i = 0; i < 6; i++) + if (fidonet.zone[i]) + fprintf(fp, "%d ", fidonet.zone[i]); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(fido); + return page; +} + + + diff --git a/mbsetup/m_fido.h b/mbsetup/m_fido.h new file mode 100644 index 00000000..06f4119e --- /dev/null +++ b/mbsetup/m_fido.h @@ -0,0 +1,11 @@ +#ifndef _FIDO_H +#define _FIDO_H + + +int CountFidonet(void); +void EditFidonet(void); +void gold_akamatch(FILE *); +int fido_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_global.c b/mbsetup/m_global.c new file mode 100644 index 00000000..90323f4a --- /dev/null +++ b/mbsetup/m_global.c @@ -0,0 +1,1995 @@ +/**************************************************************************** + * + * File ..................: m_global.c + * Purpose ...............: Global Setup Program + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_node.h" +#include "m_marea.h" +#include "m_ticarea.h" +#include "m_global.h" + + +char *some_fn; +int some_fd; + +#define WRLONG cnt = write(some_fd, &longvar, sizeof(longvar)); + + + +void config_check(char *path) +{ + static char buf[PATH_MAX]; + + sprintf(buf, "%s/etc/config.data", path); + some_fn = buf; + + /* + * Check if the configuration file exists. If not, exit. + */ + some_fd = open(some_fn, O_RDONLY); + if (some_fd == -1) { + perror(""); + fprintf(stderr, "Fatal, %s/etc/config.data not found, is mbtask running?\n", path); + exit(1); + } + close(some_fd); +} + + + +int config_read(void) +{ + some_fd = open(some_fn, O_RDONLY); + if (some_fd == -1) + return -1; + + memset(&CFG, 0, sizeof(CFG)); + read(some_fd, &CFG, sizeof(CFG)); + close(some_fd); + return 0; +} + + + +int config_write(void) +{ + some_fd = open(some_fn, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (some_fd == -1) + return -1; + + write(some_fd, &CFG, sizeof(CFG)); + close(some_fd); + return 0; +} + + + +int cf_open(void) +{ + clr_index(); + working(1, 0, 0); + IsDoing("Edit Global"); + working(1, 0, 0); + if (0 == config_read()) { + working(0, 0, 0); + return 0; + } + + working(2, 0, 0); + return -1; +} + + + +void cf_close(void) +{ + working(1, 0, 0); + if (config_write() != 0) + working(2, 0, 0); + working(0, 0, 0); +} + + + +void e_reginfo(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.1 EDIT REGISTRATION INFO"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. System name"); + mvprintw( 8, 6, "2. Domain name"); + mvprintw( 9, 6, "3. Sysop uid"); + mvprintw(10, 6, "4. Sysop Fido"); + mvprintw(11, 6, "5. Location"); + mvprintw(12, 6, "6. QWK/Bluewave"); + mvprintw(13, 6, "7. Omen id"); + mvprintw(14, 6, "8. Comment"); + mvprintw(15, 6, "9. Origin line"); + mvprintw(16, 6, "10. Startup uid"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,35, CFG.bbs_name); + show_str( 8,25,35, CFG.sysdomain); + show_str( 9,25, 8, CFG.sysop); + show_str(10,25,35, CFG.sysop_name); + show_str(11,25,35, CFG.location); + show_str(12,25, 8, CFG.bbsid); + show_str(13,25, 2, CFG.bbsid2); + show_str(14,25,55, CFG.comment); + show_str(15,25,50, CFG.origin); + show_str(16,25, 8, CFG.startname); + + switch(select_menu(10)) { + case 0: return; + case 1: E_STR( 7,25,35, CFG.bbs_name, "Name of this ^BBS^ system") + case 2: E_STR( 8,25,35, CFG.sysdomain, "Full internet ^domain^ name of this system") + case 3: E_STR( 9,25, 8, CFG.sysop, "^Unix name^ of the sysop") + case 4: E_STR(10,25,35, CFG.sysop_name, "^Fidonet name^ of the sysop") + case 5: E_STR(11,25,35, CFG.location, "^Location^ (city) of this system") + case 6: E_UPS(12,25, 8, CFG.bbsid, "^QWK/Bluewave^ packets name") + case 7: E_UPS(13,25, 2, CFG.bbsid2, "^Omen offline^ reader ID characters") + case 8: E_STR(14,25,55, CFG.comment, "Some ^comment^ you may like to give") + case 9: E_STR(15,25,50, CFG.origin, "Default ^origin^ line under echomail messages") + case 10:E_STR(16,25, 8, CFG.startname, "The ^Unix username^ that is used to start the bbs") + } + }; +} + + + + +void e_filenames(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.2 EDIT GLOBAL FILENAMES"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. System logfile"); + mvprintw( 8, 6, "2. Error logfile"); + mvprintw( 9, 6, "3. Default Menu"); + mvprintw(10, 6, "4. Default Language"); + mvprintw(11, 6, "5. Chat Logfile"); + mvprintw(12, 6, "6. Welcome Logo"); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,28,14, CFG.logfile); + show_str( 8,28,14, CFG.error_log); + show_str( 9,28,14, CFG.default_menu); + show_str(10,28,14, CFG.current_language); + show_str(11,28,14, CFG.chat_log); + show_str(12,28,14, CFG.welcome_logo); + + switch(select_menu(6)) { + case 0: return; + case 1: E_STR( 7,28,14, CFG.logfile, "The name of the ^system^ logfile.") + case 2: E_STR( 8,28,14, CFG.error_log, "The name of the ^errors^ logfile.") + case 3: E_STR( 9,28,14, CFG.default_menu, "The name of the ^default^ (top) ^menu^.") + case 4: E_STR(10,28,14, CFG.current_language, "The name of the ^default language^.") + case 5: E_STR(11,28,14, CFG.chat_log, "The name of the ^chat^ logfile.") + case 6: E_STR(12,28,14, CFG.welcome_logo, "The name of the ^BBS logo^ file.") + } + }; +} + + + +void e_global(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 6, "1.3 EDIT GLOBAL PATHS"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. BBS menus"); + mvprintw( 7, 2, "2. Txtfiles"); + mvprintw( 8, 2, "3. Home dirs"); + mvprintw( 9, 2, "4. Nodelists"); + mvprintw(10, 2, "5. Inbound"); + mvprintw(11, 2, "6. Prot inb."); + mvprintw(12, 2, "7. Outbound"); + mvprintw(13, 2, "8. Bad TIC's"); + mvprintw(14, 2, "9. TIC queue"); + mvprintw(15, 2, "10. Magic's"); + mvprintw(16, 2, "11. DOS path"); + mvprintw(17, 2, "12. Unix path"); + mvprintw(18, 2, "13. LeaveCase"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,64, CFG.bbs_menus); + show_str( 7,16,64, CFG.bbs_txtfiles); + show_str( 8,16,64, CFG.bbs_usersdir); + show_str( 9,16,64, CFG.nodelists); + show_str(10,16,64, CFG.inbound); + show_str(11,16,64, CFG.pinbound); + show_str(12,16,64, CFG.outbound); + show_str(13,16,64, CFG.badtic); + show_str(14,16,64, CFG.ticout); + show_str(15,16,64, CFG.req_magic); + show_str(16,16,64, CFG.dospath); + show_str(17,16,64, CFG.uxpath); + show_bool(18,16, CFG.leavecase); + + switch(select_menu(13)) { + case 0: return; + case 1: E_PTH( 6,16,64, CFG.bbs_menus, "The path to the ^default menus^.") + case 2: E_PTH( 7,16,64, CFG.bbs_txtfiles, "The path to the ^default textfiles^.") + case 3: E_PTH( 8,16,64, CFG.bbs_usersdir, "The path to the ^users home^ directories.") + case 4: E_PTH( 9,16,64, CFG.nodelists, "The path to the ^nodelists^.") + case 5: E_PTH(10,16,64, CFG.inbound, "The path to the ^inbound^ for unknown systems.") + case 6: E_PTH(11,16,64, CFG.pinbound, "The path to the ^nodelists^ for protected systems.") + case 7: E_PTH(12,16,64, CFG.outbound, "The path to the base ^outbound^ directory.") + case 8: E_PTH(13,16,64, CFG.badtic, "The path to the ^bad tic files^.") + case 9: E_PTH(14,16,64, CFG.ticout, "The path to the ^outgoing TIC^ files.") + case 10:E_PTH(15,16,64, CFG.req_magic, "The path to the ^magic filerequest^ files.") + case 11:E_STR(16,16,64, CFG.dospath, "The translated ^DOS^ drive and path.") + case 12:E_PTH(17,16,64, CFG.uxpath, "The translated ^Unix^ path.") + case 13:E_BOOL(18,16, CFG.leavecase, "^Leave^ outbound flo filenames as is, ^No^ forces uppercase.") + } + }; +} + + + +void b_screen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.4 EDIT GLOBAL SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Private system"); + mvprintw( 8, 2, "2. Exclude Sysop"); + mvprintw( 9, 2, "3. Show Connect"); + mvprintw(10, 2, "4. Ask Protocols"); + mvprintw(11, 2, "5. Sysop Level"); + mvprintw(12, 2, "6. Password Length"); + mvprintw(13, 2, "7. Passwd Character"); + mvprintw(14, 2, "8. Idle timeout"); + mvprintw(15, 2, "9. Login Enters"); + mvprintw(16, 2, "10. Login Attempts"); + mvprintw(17, 2, "11. Homedir Quota"); + + mvprintw( 7,37, "12. Location length"); + mvprintw( 8,37, "13. Show new msgarea"); + mvprintw( 9,37, "14. OLR Max. msgs."); + mvprintw(10,37, "15. OLR Newfile days"); + mvprintw(11,37, "16. OLR Max Filereq"); + mvprintw(12,37, "17. BBS Log Level"); + mvprintw(13,37, "18. Utils loglevel"); + mvprintw(14,37, "19. Utils slowly"); + mvprintw(15,37, "20. CrashMail level"); + mvprintw(16,37, "21. FileAttach level"); + mvprintw(17,37, "22. Min diskspace MB"); + + set_color(WHITE, BLACK); + show_bool( 7,24, CFG.elite_mode); + show_bool( 8,24, CFG.exclude_sysop); + show_bool( 9,24, CFG.iConnectString); + show_bool(10,24, CFG.iAskFileProtocols); + show_int( 11,24, CFG.sysop_access); + show_int( 12,24, CFG.password_length); + show_int( 13,24, CFG.iPasswd_Char); + show_int( 14,24, CFG.idleout); + show_int( 15,24, CFG.iCRLoginCount); + show_int( 16,24, CFG.max_login); + show_int( 17,24, CFG.iQuota); + + show_int( 7,59, CFG.CityLen); + show_bool( 8,59, CFG.NewAreas); + show_int( 9,59, CFG.OLR_MaxMsgs); + show_int( 10,59, CFG.OLR_NewFileLimit); + show_int( 11,59, CFG.OLR_MaxReq); + show_logl(12,59, CFG.bbs_loglevel); + show_logl(13,59, CFG.util_loglevel); + show_bool(14,59, CFG.slow_util); + show_int( 15,59, CFG.iCrashLevel); + show_int( 16,59, CFG.iAttachLevel); + show_int( 17,59, CFG.freespace); +} + + + +void e_bbsglob(void) +{ + b_screen(); + + for (;;) { + switch(select_menu(22)) { + case 0: return; + case 1: E_BOOL( 7,24, CFG.elite_mode, "^Private^ system.") + case 2: E_BOOL( 8,24, CFG.exclude_sysop, "^Exclude^ sysop from lists.") + case 3: E_BOOL( 9,24, CFG.iConnectString, "Show ^connect string^ at logon") + case 4: E_BOOL(10,24, CFG.iAskFileProtocols, "Ask ^file protocol^ before every up- download") + case 5: E_INT( 11,24, CFG.sysop_access, "Sysop ^access level^") + case 6: E_INT( 12,24, CFG.password_length, "Mimimum ^password^ length.") + case 7: E_INT( 13,24, CFG.iPasswd_Char, "Ascii number of ^password^ character") + case 8: E_INT( 14,24, CFG.idleout, "^Idle timeout^ in minutes") + case 9: E_INT( 15,24, CFG.iCRLoginCount, "Maximum ^Login Return^ count") + case 10:E_INT( 16,24, CFG.max_login, "Maximum ^Login^ attempts") + case 11:E_INT( 17,24, CFG.iQuota, "Maximum ^Quota^ in MBytes in users homedirectory"); + + case 12:E_INT( 7,59, CFG.CityLen, "Minimum ^Location name^ length (3..6)") + case 13:E_BOOL( 8,59, CFG.NewAreas, "Show ^new^ or ^deleted^ message areas to the user at login.") + case 14:E_INT( 9,59, CFG.OLR_MaxMsgs, "^Maximum messages^ to pack for download (0=unlimited)") + case 15:E_INT( 10,59, CFG.OLR_NewFileLimit, "^Limit Newfiles^ listing for maximum days") + case 16:E_INT( 11,59, CFG.OLR_MaxReq, "Maximum ^Filerequests^ to honor") + case 17:E_LOGL(CFG.bbs_loglevel, "1.4.17", b_screen) + case 18:E_LOGL(CFG.util_loglevel, "1.4.18", b_screen) + case 19:E_BOOL(14,59, CFG.slow_util, "Let background utilities run ^slowly^") + case 20:E_INT( 15,59, CFG.iCrashLevel, "The user level to allow sending ^CrashMail^") + case 21:E_INT( 16,59, CFG.iAttachLevel, "The user level to allow sending ^File Attaches^") + case 22:E_INT( 17,59, CFG.freespace, "Minimum ^free diskspace^ in MBytes on filesystems") + } + }; +} + + + +void s_newuser(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.5 EDIT NEW USERS DEFAULTS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Access level"); + mvprintw( 8, 6, "2. Cap. Username"); + mvprintw( 9, 6, "3. Ask ANSI"); + mvprintw(10, 6, "4. Ask Sex"); + mvprintw(11, 6, "5. Ask Voicephone"); + mvprintw(12, 6, "6. Ask Dataphone"); + mvprintw(13, 6, "7. Telephone scan"); + mvprintw(14, 6, "8. Ask Handle"); + + mvprintw( 8,46, "9. Ask Birth date"); + mvprintw( 9,46, "10. Ask Location"); + mvprintw(10,46, "11. Ask Hot-Keys"); + mvprintw(11,46, "12. One word names"); + mvprintw(12,46, "13. Ask Address"); + mvprintw(13,46, "14. Give email"); +} + + + +void e_newuser(void) +{ + s_newuser(); + for (;;) { + set_color(WHITE, BLACK); + show_sec( 7,28, CFG.newuser_access); + show_bool( 8,28, CFG.iCapUserName); + show_bool( 9,28, CFG.iAnsi); + show_bool(10,28, CFG.iSex); + show_bool(11,28, CFG.iVoicePhone); + show_bool(12,28, CFG.iDataPhone); + show_bool(13,28, CFG.iTelephoneScan); + show_bool(14,28, CFG.iHandle); + + show_bool( 8,68, CFG.iDOB); + show_bool( 9,68, CFG.iLocation); + show_bool(10,68, CFG.iHotkeys); + show_bool(11,68, CFG.iOneName); + show_bool(12,68, CFG.AskAddress); + show_bool(13,68, CFG.GiveEmail); + + switch(select_menu(14)) { + case 0: return; + case 1: E_SEC( 7,28, CFG.newuser_access, "1.6.1 NEWUSER SECURITY", s_newuser) + case 2: E_BOOL( 8,28, CFG.iCapUserName, "^Capitalize^ username") + case 3: E_BOOL( 9,28, CFG.iAnsi, "Ask user if he wants ^ANSI^ colors") + case 4: E_BOOL(10,28, CFG.iSex, "Ask users ^sex^") + case 5: E_BOOL(11,28, CFG.iVoicePhone, "Ask users ^Voice^ phone number") + case 6: E_BOOL(12,28, CFG.iDataPhone, "Ask users ^Data^ phone number") + case 7: E_BOOL(13,28, CFG.iTelephoneScan, "Perform ^Telephone^ number scan") + case 8: E_BOOL(14,28, CFG.iHandle, "Ask users ^handle^") + + case 9: E_BOOL( 8,68, CFG.iDOB, "Ask users ^Date of Birth^") + case 10:E_BOOL( 9,68, CFG.iLocation, "Ask users ^Location^") + case 11:E_BOOL(10,68, CFG.iHotkeys, "Ask user if he wants ^Hot-Keys^") + case 12:E_BOOL(11,68, CFG.iOneName, "Allow ^one word^ (not in Unixmode) usernames") + case 13:E_BOOL(12,68, CFG.AskAddress, "Aks users ^home address^ in 3 lines") + case 14:E_BOOL(13,68, CFG.GiveEmail, "Give new users an ^private email^ box") + } + }; +} + + + +void e_colors(void) +{ + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.6 EDIT TEXT COLOURS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Normal text"); + mvprintw( 8, 6, "2. Underline"); + mvprintw( 9, 6, "3. Input lines"); + mvprintw(10, 6, "4. CR text"); + mvprintw(11, 6, "5. More prompt"); + mvprintw(12, 6, "6. Hilite text"); + mvprintw(13, 6, "7. File name"); + mvprintw(14, 6, "8. File size"); + mvprintw(15, 6, "9. File date"); + mvprintw(16, 6, "10. File descr."); + mvprintw(17, 6, "11. Msg. input"); + S_COL( 7,24, "Normal Text ", CFG.TextColourF, CFG.TextColourB) + S_COL( 8,24, "Underline Text ", CFG.UnderlineColourF, CFG.UnderlineColourB) + S_COL( 9,24, "Input Text ", CFG.InputColourF, CFG.InputColourB) + S_COL(10,24, "CR Text ", CFG.CRColourF, CFG.CRColourB) + S_COL(11,24, "More Prompt ", CFG.MoreF, CFG.MoreB) + S_COL(12,24, "Hilite Text ", CFG.HiliteF, CFG.HiliteB) + S_COL(13,24, "File Name ", CFG.FilenameF, CFG.FilenameB) + S_COL(14,24, "File Size ", CFG.FilesizeF, CFG.FilesizeB) + S_COL(15,24, "File Date ", CFG.FiledateF, CFG.FiledateB) + S_COL(16,24, "File Description", CFG.FiledescF, CFG.FiledescB) + S_COL(17,24, "Message Input ", CFG.MsgInputColourF, CFG.MsgInputColourB) + + switch(select_menu(11)) { + case 0: return; + case 1: edit_color(&CFG.TextColourF, &CFG.TextColourB, (char *)"normal text"); break; + case 2: edit_color(&CFG.UnderlineColourF, &CFG.UnderlineColourB, (char *)"underline"); break; + case 3: edit_color(&CFG.InputColourF, &CFG.InputColourB, (char *)"input"); break; + case 4: edit_color(&CFG.CRColourF, &CFG.CRColourB, (char *)""); break; + case 5: edit_color(&CFG.MoreF, &CFG.MoreB, (char *)"more prompt"); break; + case 6: edit_color(&CFG.HiliteF, &CFG.HiliteB, (char *)"hilite text"); break; + case 7: edit_color(&CFG.FilenameF, &CFG.FilenameB, (char *)"file name"); break; + case 8: edit_color(&CFG.FilesizeF, &CFG.FilesizeB, (char *)"file size"); break; + case 9: edit_color(&CFG.FiledateF, &CFG.FiledateB, (char *)"file date"); break; + case 10:edit_color(&CFG.FiledescF, &CFG.FiledescB, (char *)"file description"); break; + case 11:edit_color(&CFG.MsgInputColourF, &CFG.MsgInputColourB, (char *)"message input"); break; + } + }; +} + + + +void e_nu_door(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.7 EDIT NEXT USER DOOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Text file"); + mvprintw( 8, 2, "2. Quote"); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,17,49, CFG.sNuScreen); + show_str( 8,17,64, CFG.sNuQuote); + + switch(select_menu(2)) { + case 0: return; + case 1: E_STR(7,17,49, CFG.sNuScreen, "The ^text file^ to display to the next user.") + case 2: E_STR(8,17,64, CFG.sNuQuote, "The ^quote^ to insert in the next user text.") + } + }; +} + + + +void e_safe_door(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.8 EDIT SAFE DOOR"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Digit 1"); + mvprintw( 8, 2, "2. Digit 2"); + mvprintw( 9, 2, "3. Digit 3"); + mvprintw(10, 2, "4. Max trys"); + mvprintw(11, 2, "5. Max numb"); + mvprintw(12, 2, "6. Num gen"); + mvprintw(13, 2, "7. Prize"); + mvprintw(14, 2, "8. Welcome"); + mvprintw(15, 2, "9. Opened"); + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,15, CFG.iSafeFirstDigit); + show_int( 8,15, CFG.iSafeSecondDigit); + show_int( 9,15, CFG.iSafeThirdDigit); + show_int(10,15, CFG.iSafeMaxTrys); + show_int(11,15, CFG.iSafeMaxNumber); + show_bool(12,15, CFG.iSafeNumGen); + show_str(13,15,64, CFG.sSafePrize); + show_str(14,15,64, CFG.sSafeWelcome); + show_str(15,15,64, CFG.sSafeOpened); + + switch(select_menu(9)) { + case 0: return; + case 1: E_INT( 7,15, CFG.iSafeFirstDigit, "Enter ^first^ digit of the safe") + case 2: E_INT( 8,15, CFG.iSafeSecondDigit, "Enter ^second^ digit of the safe") + case 3: E_INT( 9,15, CFG.iSafeThirdDigit, "Enter ^third^ digit of the safe") + case 4: E_INT( 10,15, CFG.iSafeMaxTrys, "Maximum ^trys^ per day") + case 5: E_INT( 11,15, CFG.iSafeMaxNumber, "^Maximum number^ of each digit") + case 6: E_BOOL(12,15, CFG.iSafeNumGen, "^Automatic^ number generation") + case 7: E_STR( 13,15,64, CFG.sSafePrize, "The ^prize^ the user wins when he opens the safe") + case 8: E_STR( 14,15,64, CFG.sSafeWelcome, "The ^welcome^ screen for the safe door") + case 9: E_STR( 15,15,64, CFG.sSafeOpened, "The file to display when the safe is ^opened^") + } + }; +} + + + +void e_timebank(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.9 EDIT TIME BANK"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Users time balance"); + mvprintw( 8, 6, "2. Max time withdraw"); + mvprintw( 9, 6, "3. Max time deposit"); + mvprintw(10, 6, "4. Users Kb. balance"); + mvprintw(11, 6, "5. Max Kb. withdraw"); + mvprintw(12, 6, "6. Max Kb. deposit"); + mvprintw(13, 6, "7. Users time ratio"); + mvprintw(14, 6, "8. Users Kb. ratio"); + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,31, CFG.iMaxTimeBalance); + show_int( 8,31, CFG.iMaxTimeWithdraw); + show_int( 9,31, CFG.iMaxTimeDeposit); + show_int(10,31, CFG.iMaxByteBalance); + show_int(11,31, CFG.iMaxByteWithdraw); + show_int(12,31, CFG.iMaxByteDeposit); + show_str(13,31,6, CFG.sTimeRatio); + show_str(14,31,6, CFG.sByteRatio); + + switch(select_menu(8)) { + case 0: return; + case 1: E_INT( 7,31, CFG.iMaxTimeBalance, "Maximum ^time balance^") + case 2: E_INT( 8,31, CFG.iMaxTimeWithdraw, "Maximum ^time withdraw^") + case 3: E_INT( 9,31, CFG.iMaxTimeDeposit, "Maximum ^time deposit^") + case 4: E_INT(10,31, CFG.iMaxByteBalance, "Maximum ^bytes balance^") + case 5: E_INT(11,31, CFG.iMaxByteWithdraw, "Maximum ^bytes withdraw^") + case 6: E_INT(12,31, CFG.iMaxByteDeposit, "Maximum ^bytes deposit^") + case 7: E_STR(13,31,6, CFG.sTimeRatio, "^Time ratio^") + case 8: E_STR(14,31,6, CFG.sByteRatio, "^Bytes ratio^") + } + }; +} + + + +void e_paging(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.10 EDIT SYSOP PAGING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Ext. Chat"); + mvprintw( 8, 2, "2. Chat Device"); + mvprintw( 9, 2, "3. Call Script"); + mvprintw(10, 2, "4. Page Length"); + mvprintw(11, 2, "5. Page Times"); + mvprintw(12, 2, "6. Sysop Area"); + mvprintw(13, 2, "7. Ask Reason"); + mvprintw(14, 2, "8. Use Extern"); + mvprintw(15, 2, "9. Log Chat"); + mvprintw(16, 2, "10. Prompt Chk."); + mvprintw(17, 2, "11. Freeze Time"); + + mvprintw(11,42, "12. Sunday"); + mvprintw(12,42, "13. Monday"); + mvprintw(13,42, "14. Tuesday"); + mvprintw(14,42, "15. Wednesday"); + mvprintw(15,42, "16. Thursday"); + mvprintw(16,42, "17. Friday"); + mvprintw(17,42, "18. Saterday"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,20,49, CFG.sExternalChat); + show_str( 8,20,19, CFG.sChatDevice); + show_str( 9,20,50, CFG.sCallScript); + show_int(10,20, CFG.iPageLength); + show_int(11,20, CFG.iMaxPageTimes); + show_int(12,20, CFG.iSysopArea); + show_bool(13,20, CFG.iAskReason); + show_bool(14,20, CFG.iExternalChat); + show_bool(15,20, CFG.iAutoLog); + show_bool(16,20, CFG.iChatPromptChk); + show_bool(17,20, CFG.iStopChatTime); + + show_str(11,58,5, CFG.cStartTime[0]); + show_str(12,58,5, CFG.cStartTime[1]); + show_str(13,58,5, CFG.cStartTime[2]); + show_str(14,58,5, CFG.cStartTime[3]); + show_str(15,58,5, CFG.cStartTime[4]); + show_str(16,58,5, CFG.cStartTime[5]); + show_str(17,58,5, CFG.cStartTime[6]); + + show_str(11,65,5, CFG.cStopTime[0]); + show_str(12,65,5, CFG.cStopTime[1]); + show_str(13,65,5, CFG.cStopTime[2]); + show_str(14,65,5, CFG.cStopTime[3]); + show_str(15,65,5, CFG.cStopTime[4]); + show_str(16,65,5, CFG.cStopTime[5]); + show_str(17,65,5, CFG.cStopTime[6]); + + switch(select_menu(18)) { + case 0: return; + + case 1: E_STR( 7,20,49, CFG.sExternalChat, "The name of the ^External Chat^ program.") + case 2: E_STR( 8,20,19, CFG.sChatDevice, "The ^device^ to use for chat") + case 3: E_STR( 9,20,50, CFG.sCallScript, "The ^Call Script^ to connect to remote sysop") + case 4: E_INT( 10,20, CFG.iPageLength, "The ^Length^ of paging in seconds") + case 5: E_INT( 11,20, CFG.iMaxPageTimes, "The ^Maximum times^ a user may page in a session") + case 6: E_INT( 12,20, CFG.iSysopArea, "The ^Message Area^ for ^Message to sysop^ when page fails") + case 7: E_BOOL(13,20, CFG.iAskReason, "Ask the user the ^reason for chat^") + case 8: E_BOOL(14,20, CFG.iExternalChat, "Use ^External Chat^ program") + case 9: E_BOOL(15,20, CFG.iAutoLog, "^Automatic log^ chat sessions") + case 10:E_BOOL(16,20, CFG.iChatPromptChk, "Check for chat at the ^prompt^") + case 11:E_BOOL(17,20, CFG.iStopChatTime, "^Stop^ users time during chat") + case 12:strcpy(CFG.cStartTime[0], edit_str(11,58,5, CFG.cStartTime[0], (char *)"Start Time paging on ^Sunday^")); + strcpy(CFG.cStopTime[0], edit_str(11,65,5, CFG.cStopTime[0], (char *)"Stop Time paging on ^Sunday^")); + break; + case 13:strcpy(CFG.cStartTime[1], edit_str(12,58,5, CFG.cStartTime[1], (char *)"Start Time paging on ^Monday^")); + strcpy(CFG.cStopTime[1], edit_str(12,65,5, CFG.cStopTime[1], (char *)"Stop Time paging on ^Monday^")); + break; + case 14:strcpy(CFG.cStartTime[2], edit_str(13,58,5, CFG.cStartTime[2], (char *)"Start Time paging on ^Tuesday^")); + strcpy(CFG.cStopTime[2], edit_str(13,65,5, CFG.cStopTime[2], (char *)"Stop Time paging on ^Tuesday^")); + break; + case 15:strcpy(CFG.cStartTime[3], edit_str(14,58,5, CFG.cStartTime[3], (char *)"Start Time paging on ^Wednesday^")); + strcpy(CFG.cStopTime[3], edit_str(14,65,5, CFG.cStopTime[3], (char *)"Stop Time paging on ^Wednesday^")); + break; + case 16:strcpy(CFG.cStartTime[4], edit_str(15,58,5, CFG.cStartTime[4], (char *)"Start Time paging on ^Thursday^")); + strcpy(CFG.cStopTime[4], edit_str(15,65,5, CFG.cStopTime[4], (char *)"Stop Time paging on ^Thursday^")); + break; + case 17: + strcpy(CFG.cStartTime[5], edit_str(16,58,5, CFG.cStartTime[5], (char *)"Start Time paging on ^Friday^")); + strcpy(CFG.cStopTime[5], edit_str(16,65,5, CFG.cStopTime[5], (char *)"Stop Time paging on ^Friday^")); + break; + case 18:strcpy(CFG.cStartTime[6], edit_str(17,58,5, CFG.cStartTime[6], (char *)"Start Time paging on ^Saterday^")); + strcpy(CFG.cStopTime[6], edit_str(17,65,5, CFG.cStopTime[6], (char *)"Stop Time paging on ^Saterday^")); + break; + } + }; +} + + + +void e_flags(void) +{ + int i, x, y, z; + char temp[80]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.11 EDIT FLAG DESCRIPTIONS"); + set_color(CYAN, BLACK); + for (i = 0; i < 32; i++) { + if (i < 11) + mvprintw(i + 7, 2, (char *)"%d.", i+1); + else + if (i < 22) + mvprintw(i - 4, 28, (char *)"%d.", i+1); + else + mvprintw(i - 15, 54, (char *)"%d.", i+1); + } + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 32; i++) { + if (i < 11) + show_str(i + 7, 6, 16, CFG.fname[i]); + else + if (i < 22) + show_str(i - 4, 32, 16, CFG.fname[i]); + else + show_str(i -15, 58, 16, CFG.fname[i]); + } + + z = select_menu(32); + if (z == 0) + return; + + if (z < 12) { + x = 6; + y = z + 6; + } else + if (z < 23) { + x = 32; + y = z - 5; + } else { + x = 58; + y = z - 16; + } + sprintf(temp, "Enter a short ^description^ of flag bit %d", z); + strcpy(CFG.fname[z-1], edit_str(y, x, 16, CFG.fname[z-1], temp)); + }; +} + + + +void e_ticconf(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.12 EDIT FILEECHO PROCESSING"); + set_color(CYAN, BLACK); + + mvprintw( 7, 2, "1. Keep days"); + mvprintw( 8, 2, "2. Hatch pwd"); + mvprintw( 9, 2, "3. Drv space"); + mvprintw(10, 2, "4. Systems"); + mvprintw(11, 2, "5. Groups"); + mvprintw(12, 2, "6. Max. dupes"); + mvprintw(13, 2, "7. Keep date"); + mvprintw(14, 2, "8. Keep netm"); + mvprintw(15, 2, "9. Res future"); + mvprintw(16, 2, "10. Loc resp"); + + mvprintw( 7,42, "11. Repl ext"); + mvprintw( 8,42, "12. Plus all"); + mvprintw( 9,42, "13. Notify"); + mvprintw(10,42, "14. Passwd"); + mvprintw(11,42, "15. Message"); + mvprintw(12,42, "16. Tic on/off"); + mvprintw(13,42, "17. Pause"); + + for (;;) { + set_color(WHITE, BLACK); + + show_int( 7,18, CFG.tic_days); + show_str( 8,18,20, (char *)"********************"); + show_int( 9,18, CFG.drspace); + show_int(10,18, CFG.tic_systems); + show_int(11,18, CFG.tic_groups); + show_int(12,18, CFG.tic_dupes); + show_bool(13,18, CFG.ct_KeepDate); + show_bool(14,18, CFG.ct_KeepMgr); + show_bool(15,18, CFG.ct_ResFuture); + show_bool(16,18, CFG.ct_LocalRep); + show_bool( 7,58, CFG.ct_ReplExt); + show_bool( 8,58, CFG.ct_PlusAll); + show_bool( 9,58, CFG.ct_Notify); + show_bool(10,58, CFG.ct_Passwd); + show_bool(11,58, CFG.ct_Message); + show_bool(12,58, CFG.ct_TIC); + show_bool(13,58, CFG.ct_Pause); + + switch(select_menu(17)) { + case 0: return; + + case 1: E_INT( 7,18, CFG.tic_days, "Number of days to ^keep^ files on hold.") + case 2: E_STR( 8,18,20, CFG.hatchpasswd, "Enter the internal ^hatch^ password.") + case 3: E_INT( 9,18, CFG.drspace, "Enter the minimal ^free drivespace^ in KBytes.") + case 4: CFG.tic_systems = edit_int(10,18, CFG.tic_systems, (char *)"Enter the maximum number of ^connected systems^ in the database."); + if ((OpenTicarea() == 0)) + CloseTicarea(TRUE); + working(0, 0, 0); + break; + case 5: CFG.tic_groups = edit_int(11,18, CFG.tic_groups, (char *)"Enter the maximum number of ^fileecho groups^ in the database."); + if ((OpenNoderec() == 0)) + CloseNoderec(TRUE); + working(0, 0, 0); + break; + case 6: E_INT( 12,18, CFG.tic_dupes, "Enter the maximum number of ^dupes^ in the dupe database.") + + case 7: E_BOOL(13,18, CFG.ct_KeepDate, "^Keep^ original filedate on import") + case 8: E_BOOL(14,18, CFG.ct_KeepMgr, "Keep ^Areamgr^ netmails.") + case 9: E_BOOL(15,18, CFG.ct_ResFuture, "Reset ^future^ filedates.") + case 10:E_BOOL(16,18, CFG.ct_LocalRep, "Respond to local ^filesearch^ requests.") + case 11:E_BOOL( 7,58, CFG.ct_ReplExt, "Replace file ^extention^ to * during filesearch") + case 12:E_BOOL( 8,58, CFG.ct_PlusAll, "Allow ^+%*^ (Plus all) in areamgr requests.") + case 13:E_BOOL( 9,58, CFG.ct_Notify, "Allow turning ^notify^ messages on or off.") + case 14:E_BOOL(10,58, CFG.ct_Passwd, "Allow changing the areamgr ^password^.") + case 15:E_BOOL(11,58, CFG.ct_Message, "Allow turning areamgr ^messages^ on or off.") + case 16:E_BOOL(12,58, CFG.ct_TIC, "Allow turning ^TIC^ files on or off.") + case 17:E_BOOL(13,58, CFG.ct_Pause, "Allow the ^pause^ areamgr command.") + } + }; +} + + + +void s_fidomailcfg(void); +void s_fidomailcfg(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "1.13 EDIT FIDONET MAIL AND ECHOMAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Badboard"); + mvprintw( 8, 2, "2. Dupeboard"); + mvprintw( 9, 2, "3. Pktdate"); + mvprintw(10, 2, "4. Max pkts."); + mvprintw(11, 2, "5. Max arcs."); + mvprintw(12, 2, "6. Keep days"); + mvprintw(13, 2, "7. Echo dupes"); + mvprintw(14, 2, "8. Reject old"); + mvprintw(15, 2, "9. Max msgs"); + mvprintw(16, 1, "10. Days old"); + + mvprintw(12,42, "11. Max systems"); + mvprintw(13,42, "12. Max groups"); + mvprintw(14,42, "13. 4d address"); + mvprintw(15,42, "14. Split at"); + mvprintw(16,42, "15. Force at"); + + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.badboard); + show_str( 8,16,64, CFG.dupboard); + show_str( 9,16,64, CFG.pktdate); + show_int( 10,16, CFG.maxpktsize); + show_int( 11,16, CFG.maxarcsize); + show_int( 12,16, CFG.toss_days); + show_int( 13,16, CFG.toss_dupes); + show_int( 14,16, CFG.toss_old); + show_int( 15,16, CFG.defmsgs); + show_int( 16,16, CFG.defdays); + + show_int( 12,58, CFG.toss_systems); + show_int( 13,58, CFG.toss_groups); + show_bool(14,58, CFG.addr4d); + show_int( 15,58, CFG.new_split); + show_int( 16,58, CFG.new_force); +} + + + +void e_fidomailcfg(void) +{ + s_fidomailcfg(); + for (;;) { + switch(select_menu(15)) { + case 0: return; + case 1: E_JAM( 7,16,64, CFG.badboard, "The path to the ^bad echomail^ board.") + case 2: E_JAM( 8,16,64, CFG.dupboard, "The path to the ^dupe echomail^ board.") + case 3: E_STR( 9,16,64, CFG.pktdate, "The filename and parameters to the ^pktdate^ program.") + case 4: E_INT( 10,16, CFG.maxpktsize, "The maximum size in KB for mail ^packets^, 0 if unlimited.") + case 5: E_INT( 11,16, CFG.maxarcsize, "The maximum size in KB for ^arcmail^ archives, 0 if unlimited.") + case 6: E_INT( 12,16, CFG.toss_days, "The number of ^days^ to keep mail on hold.") + case 7: E_INT( 13,16, CFG.toss_dupes, "The number of ^dupes^ to store in the echomail dupes database.") + case 8: E_INT( 14,16, CFG.toss_old, "^Reject^ mail older then days, 0 means never reject.") + case 9: E_INT( 15,16, CFG.defmsgs, "The default maximum number of ^messages^ in each mail area.") + case 10:E_INT( 16,16, CFG.defdays, "The default maximum ^age in days^ in each mail area.") + + case 11:CFG.toss_systems = edit_int(12,58, CFG.toss_systems, (char *)"The maximum number of connected ^systems^ in the database."); + if ((OpenMsgarea() == 0)) + CloseMsgarea(TRUE); + working(0, 0, 0); + break; + case 12:CFG.toss_groups = edit_int(13,58, CFG.toss_groups, (char *)"The maximum number of ^groups^ in the database."); + if ((OpenNoderec() == 0)) + CloseNoderec(TRUE); + working(0, 0, 0); + break; + case 13:E_BOOL(14,58, CFG.addr4d, "Use ^4d^ addressing instead of ^5d^ addressing.") + case 14:E_INT( 15,58, CFG.new_split, "Gently ^split^ newfiles reports after n kilobytes (12..60).") + case 15:E_INT( 16,58, CFG.new_force, "Force ^split^ of newfiles reports after n kilobytes (16..64).") + } + }; +} + + + +void s_intmailcfg(void); +void s_intmailcfg(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "1.14 EDIT INTERNET MAIL AND NEWS PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. POP3 node"); + mvprintw( 8, 2, "2. SMTP node"); + switch (CFG.newsfeed) { + case FEEDINN: mvprintw( 9, 2, "3. N/A"); + mvprintw(10, 2, "4. NNTP node"); + mvprintw(11, 2, "5. NNTP m.r."); + mvprintw(12, 2, "6. NNTP user"); + mvprintw(13, 2, "7. NNTP pass"); + break; + case FEEDRNEWS: mvprintw( 9, 2, "3. Path rnews"); + mvprintw(10, 2, "4. N/A"); + mvprintw(11, 2, "5. N/A"); + mvprintw(12, 2, "6. N/A"); + mvprintw(13, 2, "7. N/A"); + break; + case FEEDUUCP: mvprintw( 9, 2, "3. UUCP path"); + mvprintw(10, 2, "4. UUCP node"); + mvprintw(11, 2, "5. N/A"); + mvprintw(12, 2, "6. N/A"); + mvprintw(13, 2, "7. N/A"); + break; + } + mvprintw(14, 2, "8. News dupes"); + mvprintw(15, 2, "9. Email aka"); + mvprintw(16, 1, "10. UUCP aka"); + mvprintw(17, 1, "11. Emailmode"); + + mvprintw(13,42, "12. News mode"); + mvprintw(14,42, "13. Split at"); + mvprintw(15,42, "14. Force at"); + mvprintw(16,42, "15. Control ok"); + mvprintw(17,42, "16. No regate"); + + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.popnode); + show_str( 8,16,64, CFG.smtpnode); + show_str( 9,16,64, CFG.rnewspath); + show_str(10,16,64, CFG.nntpnode); + show_bool(11,16, CFG.modereader); + show_str(12,16,15, CFG.nntpuser); + show_str(13,16,15, (char *)"**************"); + + show_int(14,16, CFG.nntpdupes); + show_aka(15,16, CFG.EmailFidoAka); + show_aka(16,16, CFG.UUCPgate); + show_emailmode(17,16, CFG.EmailMode); + + show_newsmode(13,57, CFG.newsfeed); + show_int( 14,57, CFG.new_split); + show_int( 15,57, CFG.new_force); + show_bool(16,57, CFG.allowcontrol); + show_bool(17,57, CFG.dontregate); +} + + + +/* + * Edit UUCP gateway, return -1 if there are errors, 0 if ok. + */ +void e_uucp(void) +{ + int j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.14 EDIT UUCP GATEWAY"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, "5. Domain"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,19, CFG.UUCPgate.zone); + show_int( 8,19, CFG.UUCPgate.net); + show_int( 9,19, CFG.UUCPgate.node); + show_int(10,19, CFG.UUCPgate.point); + show_str(11,19,12, CFG.UUCPgate.domain); + + j = select_menu(5); + switch(j) { + case 0: return; + case 1: E_INT( 7,19, CFG.UUCPgate.zone, "The ^zone^ number for the UUCP gateway") + case 2: E_INT( 8,19, CFG.UUCPgate.net, "The ^Net^ number for the UUCP gateway") + case 3: E_INT( 9,19, CFG.UUCPgate.node, "The ^Node^ number for the UUCP gateway") + case 4: E_INT( 10,19, CFG.UUCPgate.point, "The ^Point^ number for the UUCP gateway") + case 5: E_STR( 11,19,11, CFG.UUCPgate.domain, "The ^FTN Domain^ for the UUCP gateway without a dot") + } + } +} + + + +void e_intmailcfg(void) +{ + int tmp; + + s_intmailcfg(); + for (;;) { + switch(select_menu(16)) { + case 0: return; + case 1: E_STR( 7,16,64, CFG.popnode, "The ^FQDN^ of the node where the ^POP3^ server runs.") + case 2: E_STR( 8,16,64, CFG.smtpnode, "The ^FQDN^ of the node where the ^SMTP^ server runs.") + case 3: if (CFG.newsfeed == FEEDRNEWS) + strcpy(CFG.rnewspath, edit_pth(9,16,64, CFG.rnewspath, (char *)"The path and filename to the ^rnews^ command.")); + if (CFG.newsfeed == FEEDUUCP) + strcpy(CFG.rnewspath, edit_pth(9,16,64, CFG.rnewspath, (char *)"The path to the ^uucppublic^ directory.")); + break; + case 4: if (CFG.newsfeed == FEEDINN) + strcpy(CFG.nntpnode, edit_str(10,16,64, CFG.nntpnode, (char *)"The ^FQDN^ of the node where the ^NNTP^ server runs.")); + if (CFG.newsfeed == FEEDUUCP) + strcpy(CFG.nntpnode, edit_str(10,16,64, CFG.nntpnode, (char *)"The ^UUCP^ nodename of the remote UUCP system")); + break; + case 5: E_BOOL(11,16, CFG.modereader, "Does the NNTP server needs the ^Mode Reader^ command.") + case 6: E_STR( 12,16,15, CFG.nntpuser, "The ^Username^ for the NNTP server if needed.") + case 7: E_STR( 13,16,15, CFG.nntppass, "The ^Password^ for the NNTP server if needed.") + case 8: E_INT( 14,16, CFG.nntpdupes, "The number of ^dupes^ to store in the news articles dupes database.") + case 9: tmp = PickAka((char *)"1.14.8", FALSE); + if (tmp != -1) + CFG.EmailFidoAka = CFG.aka[tmp]; + s_intmailcfg(); + break; + case 10:e_uucp(); + s_intmailcfg(); + break; + case 11:CFG.EmailMode = edit_emailmode(17,16, CFG.EmailMode); + s_intmailcfg(); + break; + + case 12:CFG.newsfeed = edit_newsmode(13,57, CFG.newsfeed); + s_intmailcfg(); + break; + case 13:E_INT( 14,57, CFG.new_split, "Gently ^split^ messages after n kilobytes (12..60).") + case 14:E_INT( 15,57, CFG.new_force, "Force ^split^ of messages after n kilobytes (16..64).") + case 15:E_BOOL(16,57, CFG.allowcontrol, "^Allow control^ messages for news to be gated.") + case 16:E_BOOL(17,57, CFG.dontregate, "Don't ^regate^ already gated messages.") + } + }; +} + + + +void s_newfiles(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.15 ALLFILES & NEWFILES LISTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Ftp base"); + mvprintw( 8, 2, "2. New days"); + mvprintw( 9, 2, "3. Security"); + mvprintw(10, 2, "4. Groups"); +} + + + +void e_newfiles(void) +{ + s_newfiles(); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,64, CFG.ftp_base); + show_int( 8,16, CFG.newdays); + show_sec( 9,16, CFG.security); + show_int(10,16, CFG.new_groups); + + switch(select_menu(4)) { + case 0: return; + case 1: E_PTH(7,16,64, CFG.ftp_base, "The ^FTP home^ directory to strip of the real directory") + case 2: E_INT(8,16, CFG.newdays, "Add files younger than this in newfiles report.") + case 3: E_SEC(9,16, CFG.security, "1.14 NEWFILES REPORTS SECURITY", s_newfiles) + case 4: E_INT(10,16, CFG.new_groups, "The maximum of ^newfiles^ groups in the newfiles database") + } + }; +} + + + +/* + * Edit one aka, return -1 if there are errors, 0 if ok. + */ +void e_aka(int Area) +{ + int j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.16 EDIT AKA"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, "5. Domain"); + mvprintw(12, 6, "6. Active"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,19, CFG.aka[Area].zone); + show_int( 8,19, CFG.aka[Area].net); + show_int( 9,19, CFG.aka[Area].node); + show_int(10,19, CFG.aka[Area].point); + show_str(11,19,12, CFG.aka[Area].domain); + show_bool(12,19, CFG.akavalid[Area]); + + j = select_menu(6); + switch(j) { + case 0: return; + case 1: E_INT( 7,19, CFG.aka[Area].zone, "The ^zone^ number for this aka") + case 2: E_INT( 8,19, CFG.aka[Area].net, "The ^Net^ number for this aka") + case 3: E_INT( 9,19, CFG.aka[Area].node, "The ^Node^ number for this aka") + case 4: E_INT( 10,19, CFG.aka[Area].point, "The ^Point^ number for this node (if any)") + case 5: E_STR( 11,19,11, CFG.aka[Area].domain, "The ^FTN Domain^ for this aka without a dot (ie no .org)") + case 6: E_BOOL(12,19, CFG.akavalid[Area], "Is this aka ^available^") + } + } +} + + + +void e_fidoakas(void) +{ + int i, x, y, o; + char pick[12]; + char temp[121]; + + o = 0; + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.16 EDIT FIDONET AKA'S"); + set_color(CYAN, BLACK); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= 40) { + if (CFG.akavalid[o+i-1]) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + if (CFG.akavalid[o+i-1]) { + sprintf(temp, "%3d %s", o+i, aka2str(CFG.aka[o+i-1])); + temp[38] = '\0'; + } else + sprintf(temp, "%3d", o+i); + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(40, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < 40) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= 40)) + e_aka(atoi(pick)-1); + } +} + + + +void s_mailer(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.17 EDIT MAILER SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Mailer logl."); + mvprintw( 8, 2, "2. Default phone"); + mvprintw( 9, 2, "3. TCP/IP flags"); + mvprintw(10, 2, "4. Default speed"); + mvprintw(11, 2, "5. Timeout reset"); + mvprintw(12, 2, "6. Timeout connect"); + mvprintw(13, 2, "7. Dial delay"); + mvprintw(14, 2, "8. No Filerequests"); + mvprintw(15, 2, "9. No callout"); + mvprintw(16, 2, "10. No Hold mail"); + mvprintw(17, 2, "11. No pickup all"); + + mvprintw(12,31, "12. No EMSI session"); + mvprintw(13,31, "13. No Yooho/2U2"); + mvprintw(14,31, "14. No Zmodem"); + mvprintw(15,31, "15. No Zedzap"); + mvprintw(16,31, "16. No Hydra"); + mvprintw(17,31, "17. No TCP/IP"); + + mvprintw(12,59, "18. Phonetrans 1-10"); + mvprintw(13,59, "19. Phonetrans 11-20"); + mvprintw(14,59, "20. Phonetrans 21-30"); + mvprintw(15,59, "21. Phonetrans 31-40"); + mvprintw(16,59, "22. Max. files"); + mvprintw(17,59, "23. Max. MB."); +} + + + +void e_trans(int start) +{ + int i, j; + char temp[21]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1.17 EDIT PHONE TRANSLATION"); + set_color(CYAN, BLACK); + mvprintw( 7, 12, "String to match String to replace"); + for (i = 0; i < 10; i++) { + sprintf(temp, "%2d.", i+1); + mvprintw( 9+i, 6, temp); + } + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 9+i,12,20,CFG.phonetrans[i+start].match); + show_str( 9+i,34,20,CFG.phonetrans[i+start].repl); + } + + j = select_menu(10); + if (j == 0) { + s_mailer(); + return; + } + strcpy(CFG.phonetrans[j+start-1].match, edit_str(j+8,12,20, CFG.phonetrans[j+start-1].match, (char *)"The phone entry to ^match^")); + strcpy(CFG.phonetrans[j+start-1].repl, edit_str(j+8,34,20, CFG.phonetrans[j+start-1].repl, (char *)"The phone string to ^replace^")); + } +} + + + +void e_mailer(void) +{ + s_mailer(); + for (;;) { + set_color(WHITE, BLACK); + show_logl( 7,23, CFG.cico_loglevel); + show_str( 8,23,20,CFG.Phone); + show_str( 9,23,30,CFG.Flags); + show_int( 10,23, CFG.Speed); + show_int( 11,23, CFG.timeoutreset); + show_int( 12,23, CFG.timeoutconnect); + show_int( 13,23, CFG.dialdelay); + show_bool(14,23, CFG.NoFreqs); + show_bool(15,23, CFG.NoCall); + show_bool(16,23, CFG.NoHold); + show_bool(17,23, CFG.NoPUA); + + show_bool(12,52, CFG.NoEMSI); + show_bool(13,52, CFG.NoWazoo); + show_bool(14,52, CFG.NoZmodem); + show_bool(15,52, CFG.NoZedzap); + show_bool(16,52, CFG.NoHydra); + show_bool(17,52, CFG.NoTCP); + + show_int( 16,75, CFG.Req_Files); + show_int( 17,75, CFG.Req_MBytes); + + switch(select_menu(23)) { + case 0: return; + case 1: E_LOGL(CFG.cico_loglevel, "1.17.1", s_mailer) + case 2: E_STR( 8,23,20,CFG.Phone, "The mailer default ^phone number^ for this system") + case 3: E_STR( 9,23,30,CFG.Flags, "The mailer ^TCP/IP capability flags^ for this system") + case 4: E_INT( 10,23, CFG.Speed, "The mailer ^default linespeed^ for this system") + case 5: E_INT( 11,23, CFG.timeoutreset, "The modem ^reset timeout^ in seconds") + case 6: E_INT( 12,23, CFG.timeoutconnect, "The modem ^wait for connect timeout^ in seconds") + case 7: E_INT( 13,23, CFG.dialdelay, "The ^random dialdelay^ in seconds ((^n^ <= delay) and (^n^ > (delay / 10)))") + case 8: E_BOOL(14,23, CFG.NoFreqs, "Set to true if ^No Filerequests^ are allowed") + case 9: E_BOOL(15,23, CFG.NoCall, "Set to true if ^No Calls^ are allowed") + case 10:E_BOOL(16,23, CFG.NoHold, "Set to true if we send ^Hold packets^ when we initiate the session") + case 11:E_BOOL(17,23, CFG.NoPUA, "Set to true for ^pickup mail^ only from the primary address") + + case 12:E_BOOL(12,52, CFG.NoEMSI, "If set then ^EMSI handshake^ is diabled") + case 13:E_BOOL(13,52, CFG.NoWazoo, "If set then ^YooHoo/2U2^ (FTSC-0006) is disabled") + case 14:E_BOOL(14,52, CFG.NoZmodem, "If set then the ^Zmodem^ protocol is disabled") + case 15:E_BOOL(15,52, CFG.NoZedzap, "If set then the ^Zedzap^ protocol is disabled") + case 16:E_BOOL(16,52, CFG.NoHydra, "If set then the ^Hydra^ protocol is disabled") + case 17:E_BOOL(17,52, CFG.NoTCP, "If set then the ^TCP/IP^ protocol is disabled"); + case 18:e_trans(0); + break; + case 19:e_trans(10); + break; + case 20:e_trans(20); + break; + case 21:e_trans(30); + break; + case 22:E_INT(16,75, CFG.Req_Files, "Maximum ^files^ to request, 0 is unlimited") + case 23:E_INT(17,75, CFG.Req_MBytes, "Maximum ^MBytes^ to request, 0 is unlimited") + } + }; +} + + + +void e_ftpd(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.18 EDIT FTPD SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Base path"); + mvprintw( 8, 2, "2. Upload pth"); + mvprintw( 9, 2, "3. Banner msg"); + mvprintw(10, 2, "4. Pth filter"); + mvprintw(11, 2, "5. Pth msg"); + mvprintw(12, 2, "6. Email addr"); + mvprintw(13, 2, "7. Shutdown"); + mvprintw(14, 2, "8. Rdm login"); + mvprintw(15, 2, "9. Rdm cwd*"); + mvprintw(16, 1,"10. Msg login"); + mvprintw(17, 1,"11. Msg cwd*"); + mvprintw(18, 1,"12. Userslimit"); + mvprintw(19, 1,"13. Loginfails"); + + mvprintw(14,60,"14. Compress"); + mvprintw(15,60,"15. Tar"); + mvprintw(16,60,"16. Mkdir ok"); + mvprintw(17,60,"17. Log cmds"); + mvprintw(18,60,"18. Anonymous"); + mvprintw(19,60,"19. User mbse"); + + set_color(WHITE, BLACK); + show_str( 7,18,59, CFG.ftp_base); + show_str( 8,18,59, CFG.ftp_upl_path); + show_str( 9,18,59, CFG.ftp_banner); + show_str(10,18,40, CFG.ftp_pth_filter); + show_str(11,18,59, CFG.ftp_pth_message); + show_str(12,18,40, CFG.ftp_email); + show_str(13,18,40, CFG.ftp_msg_shutmsg); + show_str(14,18,20, CFG.ftp_readme_login); + show_str(15,18,20, CFG.ftp_readme_cwd); + show_str(16,18,20, CFG.ftp_msg_login); + show_str(17,18,20, CFG.ftp_msg_cwd); + show_int(18,18, CFG.ftp_limit); + show_int(19,18, CFG.ftp_loginfails); + + show_bool(14,75, CFG.ftp_compress); + show_bool(15,75, CFG.ftp_tar); + show_bool(16,75, CFG.ftp_upl_mkdir); + show_bool(17,75, CFG.ftp_log_cmds); + show_bool(18,75, CFG.ftp_anonymousok); + show_bool(19,75, CFG.ftp_mbseok); + + for (;;) { + set_color(WHITE, BLACK); + + switch(select_menu(19)) { + case 0: return; + case 1: E_STR( 7,18,59, CFG.ftp_base, "Public ^base path^ to the files") + case 2: E_STR( 8,18,59, CFG.ftp_upl_path, "Public ^upload^ path, must be in the base path") + case 3: E_STR( 9,18,59, CFG.ftp_banner, "^Banner^ file to show before login") + case 4: E_STR(10,18,40, CFG.ftp_pth_filter, "^Filter^ with allowed characters in upload filename") + case 5: E_STR(11,18,59, CFG.ftp_pth_message, "^Message^ to display if illegal characters in filename") + case 6: E_STR(12,18,40, CFG.ftp_email, "^Email^ address of the ftp server administrator") + case 7: E_STR(13,18,40, CFG.ftp_msg_shutmsg, "^Shutdown message^, if this file is present, login if forbidden") + case 8: E_STR(14,18,20, CFG.ftp_readme_login,"^README^ file to display at login") + case 9: E_STR(15,18,20, CFG.ftp_readme_cwd, "^README^ file to display when entering a new directory") + case 10:E_STR(16,18,20, CFG.ftp_msg_login, "^Message^ file to display at login") + case 11:E_STR(17,18,20, CFG.ftp_msg_cwd, "^Message^ file to display when entering a new directory") + case 12:E_INT(18,18, CFG.ftp_limit, "^Limit^ the number of concurent ftp users") + case 13:E_INT(19,18, CFG.ftp_loginfails, "Maximum ^login fails^ before a user is disconnected") + case 14:E_BOOL(14,75, CFG.ftp_compress, "Allow the use of the ^compress^ command") + case 15:E_BOOL(15,75, CFG.ftp_tar, "Allow the use if the ^tar^ command") + case 16:E_BOOL(16,75, CFG.ftp_upl_mkdir, "Allow ^mkdir^ in the upload directory") + case 17:E_BOOL(17,75, CFG.ftp_log_cmds, "^Log^ all user ^commands^") + case 18:E_BOOL(18,75, CFG.ftp_anonymousok, "Allow ^anonymous^ users to login") + case 19:E_BOOL(19,75, CFG.ftp_mbseok, "Allow the ^mbse^ user to login") + } + }; +} + + + +void e_html(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "1.19 EDIT HTML SETTINGS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Docs root"); + mvprintw( 8, 2, "2. Link to ftp"); + mvprintw( 9, 2, "3. URL name"); + mvprintw(10, 2, "4. Charset"); + mvprintw(11, 2, "5. Table color"); + mvprintw(12, 2, "6. Hdr. color"); + mvprintw(13, 2, "7. Author name"); + mvprintw(14, 2, "8. Convert cmd"); + mvprintw(15, 2, "9. Files/page"); + mvprintw(16, 1,"10. Icon Home"); + mvprintw(17, 1,"11. Text Home"); + mvprintw(18, 1,"12. Icon Back"); + mvprintw(19, 1,"13. Text Back"); + mvprintw(16,41,"14. Icon Prev."); + mvprintw(17,41,"15. Text Prev."); + mvprintw(18,41,"16. Icon Next"); + mvprintw(19,41,"17. Text Next"); + + set_color(WHITE, BLACK); + show_str( 7,18,59, CFG.www_root); + show_str( 8,18,20, CFG.www_link2ftp); + show_str( 9,18,40, CFG.www_url); + show_str(10,18,20, CFG.www_charset); + show_str(11,18,20, CFG.www_tbgcolor); + show_str(12,18,20, CFG.www_hbgcolor); + show_str(13,18,40, CFG.www_author); + show_str(14,18,59, CFG.www_convert); + show_int(15,18, CFG.www_files_page); + show_str(16,18,20, CFG.www_icon_home); + show_str(17,18,20, CFG.www_name_home); + show_str(18,18,20, CFG.www_icon_back); + show_str(19,18,20, CFG.www_name_back); + show_str(16,58,20, CFG.www_icon_prev); + show_str(17,58,20, CFG.www_name_prev); + show_str(18,58,20, CFG.www_icon_next); + show_str(19,58,20, CFG.www_name_next); + + for (;;) { + set_color(WHITE, BLACK); + + switch(select_menu(17)) { + case 0: return; + case 1: E_STR( 7,18,59, CFG.www_root, "The ^Document root^ of your http server") + case 2: E_STR( 8,18,20, CFG.www_link2ftp, "The ^link^ name from the Document root to the FTP base directory") + case 3: E_STR( 9,18,40, CFG.www_url, "The ^URL^ name of your http server") + case 4: E_STR(10,18,20, CFG.www_charset, "The ^ISO character set^ name to include in the web pages") + case 5: E_STR(11,18,20, CFG.www_tbgcolor, "The ^Tables background color^ to use") + case 6: E_STR(12,18,20, CFG.www_hbgcolor, "The ^Table headers background color^ to use") + case 7: E_STR(13,18,40, CFG.www_author, "The ^Author name^ to include in the http headers") + case 8: E_STR(14,18,59, CFG.www_convert, "The ^convert^ command to create thumbnails") + case 9: E_INT(15,18, CFG.www_files_page, "The number of files on each web page") + case 10:E_STR(16,18,20, CFG.www_icon_home, "The ^Home icon^ filename") + case 11:E_STR(17,18,20, CFG.www_name_home, "The ^Home text^ to appear") + case 12:E_STR(18,18,20, CFG.www_icon_back, "The ^Back icon^ filename") + case 13:E_STR(19,18,20, CFG.www_name_back, "The ^Back text^ to appear") + case 14:E_STR(16,58,20, CFG.www_icon_prev, "The ^Previous page icon^ filename") + case 15:E_STR(17,58,20, CFG.www_name_prev, "The ^Previous page text^ to appear") + case 16:E_STR(18,58,20, CFG.www_icon_next, "The ^Next Page icon^ filename") + case 17:E_STR(19,58,20, CFG.www_name_next, "The ^Next Page text^ to appear") + } + }; +} + + + +void global_menu(void) +{ + unsigned long crc, crc1; + + if (cf_open() == -1) + return; + + Syslog('+', "Opened main config"); + crc = 0xffffffff; + crc = upd_crc32((char *)&CFG, crc, sizeof(CFG)); + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "1. GLOBAL SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Registration Info"); + mvprintw( 8, 6, "2. Edit Global Filenames"); + mvprintw( 9, 6, "3. Edit Global Paths"); + mvprintw(10, 6, "4. Edit Global Settings"); + mvprintw(11, 6, "5. Edit New Users defaults"); + mvprintw(12, 6, "6. Edit Text Colors"); + mvprintw(13, 6, "7. Edit Next User Door"); + mvprintw(14, 6, "8. Edit Safe Door"); + mvprintw(15, 6, "9. Edit Time Bank Door"); + mvprintw(16, 6, "10. Edit Sysop Paging"); + + mvprintw( 7,46, "11. Edit Flag Descriptions"); + mvprintw( 8,46, "12. Edit Files Processing"); + mvprintw( 9,46, "13. Edit Fidonet Mail/Echomail"); + mvprintw(10,46, "14. Edit Internet Mail/News"); + mvprintw(11,46, "15. Edit All-/Newfiles lists"); + mvprintw(12,46, "16. Edit Fidonet Aka's"); + mvprintw(13,46, "17. Edit Mailer setup"); + mvprintw(14,46, "18. Edit Ftp daemon setup"); + mvprintw(15,46, "19. Edit HTML pages setup"); + + switch(select_menu(19)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&CFG, crc1, sizeof(CFG)); + if (crc != crc1) { + if (yes_no((char *)"Configuration is changed, save") == 1) { + cf_close(); + Syslog('+', "Saved main config"); + } + } + return; + case 1: + e_reginfo(); + break; + case 2: + e_filenames(); + break; + case 3: + e_global(); + break; + case 4: + e_bbsglob(); + break; + case 5: + e_newuser(); + break; + case 6: + e_colors(); + break; + case 7: + e_nu_door(); + break; + case 8: + e_safe_door(); + break; + case 9: + e_timebank(); + break; + case 10: + e_paging(); + break; + case 11: + e_flags(); + break; + case 12: + e_ticconf(); + break; + case 13: + e_fidomailcfg(); + break; + case 14: + e_intmailcfg(); + break; + case 15: + e_newfiles(); + break; + case 16: + e_fidoakas(); + break; + case 17: + e_mailer(); + break; + case 18: + e_ftpd(); + break; + case 19: + e_html(); + break; + } + } +} + + + +int PickAka(char *msg, int openit) +{ + char temp[81]; + static char pick[12]; + int i, o = 0, x, y; + + if (openit) { + if (cf_open() == -1) + return -1; + cf_close(); + } + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. AKA SELECT", msg); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + x = 2; + y = 7; + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= 40) { + if (CFG.akavalid[o+i-1]) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d %s", o+i, aka2str(CFG.aka[o+i-1])); + temp[38] = '\0'; + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(40, 20)); + + if (strncmp(pick, "-", 1) == 0) + return -1; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < 40) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= 40) && (CFG.akavalid[atoi(pick)-1])) + return (atoi(pick) -1); + } +} + + +char Co[16][16] = { + "Black", "Blue", "Green", "Cyan", + "Red", "Magenta", "Brown", "Lightgray", + "Darkgary", "Lightblue", "Lightgreen", "Lightcyan", + "Lightred", "Lightmagenta", "Yellow", "White" }; + + +int global_doc(FILE *fp, FILE *toc, int page) +{ + int i, j; + struct utsname utsbuf; + time_t now; + char *p; + + if (config_read()) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 1, 0, page, (char *)"Global system setup"); + addtoc(fp, toc, 1, 1, page, (char *)"Host system information"); + + memset(&utsbuf, 0, sizeof(utsbuf)); + if (uname(&utsbuf) == 0) { + fprintf(fp, " Node name %s\n", utsbuf.nodename); +#ifdef __USE_GNU + fprintf(fp, " Domain name %s\n", utsbuf.domainname); +#else + fprintf(fp, " Domain name %s\n", utsbuf.__domainname); +#endif + fprintf(fp, " Operating system %s %s\n", utsbuf.sysname, utsbuf.release); + fprintf(fp, " Kernel version %s\n", utsbuf.version); + fprintf(fp, " Machine type %s\n", utsbuf.machine); + } + fprintf(fp, " MBSE_ROOT %s\n", getenv("MBSE_ROOT")); + time(&now); + fprintf(fp, " Date created %s", ctime(&now)); + + addtoc(fp, toc, 1, 2, page, (char *)"Registration information"); + + fprintf(fp, " System name %s\n", CFG.bbs_name); + fprintf(fp, " Domain name %s\n", CFG.sysdomain); + fprintf(fp, " Sysop unix name %s\n", CFG.sysop); + fprintf(fp, " Sysop fido name %s\n", CFG.sysop_name); + fprintf(fp, " System location %s\n", CFG.location); + fprintf(fp, " QWK/Bluewave id %s\n", CFG.bbsid); + fprintf(fp, " Omen id %s\n", CFG.bbsid2); + fprintf(fp, " Comment %s\n", CFG.comment); + fprintf(fp, " Origin line %s\n", CFG.origin); + fprintf(fp, " Start unix name %s\n", CFG.startname); + + addtoc(fp, toc, 1, 3, page, (char *)"Global filenames"); + + fprintf(fp, " System logfile %s\n", CFG.logfile); + fprintf(fp, " Error logfile %s\n", CFG.error_log); + fprintf(fp, " Default menu %s\n", CFG.default_menu); + fprintf(fp, " Default language %s\n", CFG.current_language); + fprintf(fp, " Chat logfile %s\n", CFG.chat_log); + fprintf(fp, " Welcome logo %s\n", CFG.welcome_logo); + + addtoc(fp, toc, 1, 4, page, (char *)"Pathnames"); + + fprintf(fp, " Menufiles %s\n", CFG.bbs_menus); + fprintf(fp, " Textfiles %s\n", CFG.bbs_txtfiles); + fprintf(fp, " Users homedirs %s\n", CFG.bbs_usersdir); + fprintf(fp, " Nodelists %s\n", CFG.nodelists); + fprintf(fp, " Unsafe inbound %s\n", CFG.inbound); + fprintf(fp, " Known inbound %s\n", CFG.pinbound); + fprintf(fp, " Bad TIC's %s\n", CFG.badtic); + fprintf(fp, " TIC queue %s\n", CFG.ticout); + fprintf(fp, " Magic filereq. %s\n", CFG.req_magic); + fprintf(fp, " DOS path %s\n", CFG.dospath); + fprintf(fp, " Unix path %s\n", CFG.uxpath); + fprintf(fp, " Leave case as is %s\n", getboolean(CFG.leavecase)); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 5, page, (char *)"Global settings"); + + fprintf(fp, " Private system %s\n", getboolean(CFG.elite_mode)); + fprintf(fp, " Show new msgarea %s\n", getboolean(CFG.NewAreas)); + fprintf(fp, " Exclude sysop %s\n", getboolean(CFG.exclude_sysop)); + fprintf(fp, " Show connect %s\n", getboolean(CFG.iConnectString)); + fprintf(fp, " Ask protocols %s\n", getboolean(CFG.iAskFileProtocols)); + fprintf(fp, " Sysop level %d\n", CFG.sysop_access); + fprintf(fp, " Password length %d\n", CFG.password_length); + p = getloglevel(CFG.bbs_loglevel); + fprintf(fp, " BBS loglevel %s\n", p); + free(p); + p = getloglevel(CFG.util_loglevel); + fprintf(fp, " Util loglevel %s\n", p); + free(p); + fprintf(fp, " Password char %c\n", CFG.iPasswd_Char); + fprintf(fp, " Idle timeout %d mins\n", CFG.idleout); + fprintf(fp, " Login enters %d\n", CFG.iCRLoginCount); + fprintf(fp, " Login attempts %d\n", CFG.max_login); + fprintf(fp, " Homedir quota %d MB.\n", CFG.iQuota); + fprintf(fp, " Location length %d\n", CFG.CityLen); + fprintf(fp, " OLR Max. msgs. %d\n", CFG.OLR_MaxMsgs); + fprintf(fp, " OLR Newfile days %d\n", CFG.OLR_NewFileLimit); + fprintf(fp, " OLR Max Freq's %d\n", CFG.OLR_MaxReq); + fprintf(fp, " Slow utilities %s\n", getboolean(CFG.slow_util)); + fprintf(fp, " CrashMail level %d\n", CFG.iCrashLevel); + fprintf(fp, " FileAttach level %d\n", CFG.iAttachLevel); + fprintf(fp, " Free diskspace %d MB.\n", CFG.freespace); + + addtoc(fp, toc, 1, 6, page, (char *)"New users defaults"); + + fprintf(fp, " Access level %s\n", get_secstr(CFG.newuser_access)); + fprintf(fp, " Cap. username %s\n", getboolean(CFG.iCapUserName)); + fprintf(fp, " Ask ANSI %s\n", getboolean(CFG.iAnsi)); + fprintf(fp, " Ask Sex %s\n", getboolean(CFG.iSex)); + fprintf(fp, " Ask voicephone %s\n", getboolean(CFG.iVoicePhone)); + fprintf(fp, " Ask dataphone %s\n", getboolean(CFG.iDataPhone)); + fprintf(fp, " Telephone scan %s\n", getboolean(CFG.iTelephoneScan)); + fprintf(fp, " Ask handle %s\n", getboolean(CFG.iHandle)); + fprintf(fp, " Ask birthdate %s\n", getboolean(CFG.iDOB)); + fprintf(fp, " Ask location %s\n", getboolean(CFG.iLocation)); + fprintf(fp, " Ask hotkeys %s\n", getboolean(CFG.iHotkeys)); + fprintf(fp, " One word names %s\n", getboolean(CFG.iOneName)); + fprintf(fp, " Ask address %s\n", getboolean(CFG.AskAddress)); + fprintf(fp, " Give email box %s\n", getboolean(CFG.GiveEmail)); + + addtoc(fp, toc, 1, 7, page, (char *)"Text colors"); + + fprintf(fp, " Normal text %s on %s\n", Co[CFG.TextColourF], Co[CFG.TextColourB]); + fprintf(fp, " Underline text %s on %s\n", Co[CFG.UnderlineColourF], Co[CFG.UnderlineColourB]); + fprintf(fp, " Input text %s on %s\n", Co[CFG.InputColourF], Co[CFG.InputColourB]); + fprintf(fp, " CR text %s on %s\n", Co[CFG.CRColourF], Co[CFG.CRColourB]); + fprintf(fp, " More prompt %s on %s\n", Co[CFG.MoreF], Co[CFG.MoreB]); + fprintf(fp, " Hilite text %s on %s\n", Co[CFG.HiliteF], Co[CFG.HiliteB]); + fprintf(fp, " File name %s on %s\n", Co[CFG.FilenameF], Co[CFG.FilenameB]); + fprintf(fp, " File size %s on %s\n", Co[CFG.FilesizeF], Co[CFG.FilesizeB]); + fprintf(fp, " File date %s on %s\n", Co[CFG.FiledateF], Co[CFG.FiledateB]); + fprintf(fp, " File description %s on %s\n", Co[CFG.FiledescF], Co[CFG.FiledescB]); + fprintf(fp, " Message input %s on %s\n", Co[CFG.MsgInputColourF], Co[CFG.MsgInputColourB]); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 8, page, (char *)"Next user door"); + + fprintf(fp, " Text file %s\n", CFG.sNuScreen); + fprintf(fp, " Quote %s\n", CFG.sNuQuote); + + addtoc(fp, toc, 1, 9, page, (char *)"Safecracker door"); + + fprintf(fp, " Digit nr 1 %d\n", CFG.iSafeFirstDigit); + fprintf(fp, " Digit nr 2 %d\n", CFG.iSafeSecondDigit); + fprintf(fp, " Digit nr 3 %d\n", CFG.iSafeThirdDigit); + fprintf(fp, " Maximum tries %d\n", CFG.iSafeMaxTrys); + fprintf(fp, " Maximum number %d\n", CFG.iSafeMaxNumber); + fprintf(fp, " Show generator %s\n", getboolean(CFG.iSafeNumGen)); + fprintf(fp, " Prize %s\n", CFG.sSafePrize); + fprintf(fp, " Safe welcome %s\n", CFG.sSafeWelcome); + fprintf(fp, " Safe opened file %s\n", CFG.sSafeOpened); + + addtoc(fp, toc, 1, 10, page, (char *)"Timebank door"); + + fprintf(fp, " Users time balance %d\n", CFG.iMaxTimeBalance); + fprintf(fp, " Max. time withdraw %d\n", CFG.iMaxTimeWithdraw); + fprintf(fp, " Max. time deposit %d\n", CFG.iMaxTimeDeposit); + fprintf(fp, " Users kb. balance %d\n", CFG.iMaxByteBalance); + fprintf(fp, " Max. Kb. withdraw %d\n", CFG.iMaxByteWithdraw); + fprintf(fp, " Max. Kb. deposit %d\n", CFG.iMaxByteDeposit); + fprintf(fp, " Users time ratio %s\n", CFG.sTimeRatio); + fprintf(fp, " Users Kb. ratio %s\n", CFG.sByteRatio); + + addtoc(fp, toc, 1, 11, page, (char *)"Sysop paging"); + + fprintf(fp, " Ext. Chat program %s\n", CFG.sExternalChat); + fprintf(fp, " Chat device %s\n", CFG.sChatDevice); + fprintf(fp, " Call sysop script %s\n", CFG.sCallScript); + fprintf(fp, " Page length %d seconds\n", CFG.iPageLength); + fprintf(fp, " Page times %d\n", CFG.iMaxPageTimes); + fprintf(fp, " Sysop msg area %d\n", CFG.iSysopArea); + fprintf(fp, " Ask chat reason %s\n", getboolean(CFG.iAskReason)); + fprintf(fp, " Use external chat %s\n", getboolean(CFG.iExternalChat)); + fprintf(fp, " Log chat %s\n", getboolean(CFG.iAutoLog)); + fprintf(fp, " Check at prompt %s\n", getboolean(CFG.iChatPromptChk)); + fprintf(fp, " Freeze online time %s\n", getboolean(CFG.iStopChatTime)); + + fprintf(fp, "\n Weekday Start Stop\n"); + fprintf(fp, " ------------- ----- -----\n"); + fprintf(fp, " Sunday %s %s\n", CFG.cStartTime[0], CFG.cStopTime[0]); + fprintf(fp, " Monday %s %s\n", CFG.cStartTime[1], CFG.cStopTime[1]); + fprintf(fp, " Tuesday %s %s\n", CFG.cStartTime[2], CFG.cStopTime[2]); + fprintf(fp, " Wednesday %s %s\n", CFG.cStartTime[3], CFG.cStopTime[3]); + fprintf(fp, " Thursday %s %s\n", CFG.cStartTime[4], CFG.cStopTime[4]); + fprintf(fp, " Friday %s %s\n", CFG.cStartTime[5], CFG.cStopTime[5]); + fprintf(fp, " Saterday %s %s\n", CFG.cStartTime[6], CFG.cStopTime[6]); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 12, page, (char *)"Flag descriptions"); + + fprintf(fp, " 1 1 2 2 3 3\n"); + fprintf(fp, " 1 5 0 5 0 5 0 2\n"); + fprintf(fp, " --------------------------------\n"); + fprintf(fp, " ||||||||||||||||||||||||||||||||\n"); + + for (i = 0; i < 32; i++) { + fprintf(fp, " "); + + for (j = 0; j < (31 - i); j++) + fprintf(fp, "|"); + fprintf(fp, "+"); + for (j = (32 - i); j < 32; j++) + fprintf(fp, "-"); + + fprintf(fp, " %s\n", CFG.fname[31 - i]); + } + + page = newpage(fp, page); + addtoc(fp, toc, 1, 13, page, (char *)"Fileecho processing"); + + fprintf(fp, " Keep days on hold %d\n", CFG.tic_days); + fprintf(fp, " Hatch password %s\n", CFG.hatchpasswd); + fprintf(fp, " Free drivespave %lu\n", CFG.drspace); + fprintf(fp, " Max. systems %ld\n", CFG.tic_systems); + fprintf(fp, " Max. groups %ld\n", CFG.tic_groups); + fprintf(fp, " Max. dupes %ld\n", CFG.tic_dupes); + fprintf(fp, " Keep filedate %s\n", getboolean(CFG.ct_KeepDate)); + fprintf(fp, " Keep mgr netmail %s\n", getboolean(CFG.ct_KeepMgr)); + fprintf(fp, " Reset future dates %s\n", getboolean(CFG.ct_ResFuture)); + fprintf(fp, " Local requests %s\n", getboolean(CFG.ct_LocalRep)); + fprintf(fp, " Replace extention %s\n", getboolean(CFG.ct_ReplExt)); + fprintf(fp, " Areamgr: allow +%%* %s\n", getboolean(CFG.ct_PlusAll)); + fprintf(fp, " Areamgr: notify %s\n", getboolean(CFG.ct_Notify)); + fprintf(fp, " Areamgr: passwd %s\n", getboolean(CFG.ct_Passwd)); + fprintf(fp, " Areamgr: message %s\n", getboolean(CFG.ct_Message)); + fprintf(fp, " Areamgr: TIC %s\n", getboolean(CFG.ct_TIC)); + fprintf(fp, " Areamgr: pause %s\n", getboolean(CFG.ct_Pause)); + + addtoc(fp, toc, 1, 14, page, (char *)"Fidonet Mail and Echomail processing"); + + fprintf(fp, " Max .pkt size %d Kb.\n", CFG.maxpktsize); + fprintf(fp, " Max archive size %d Kb.\n", CFG.maxarcsize); + fprintf(fp, " Bad mail board %s\n", CFG.badboard); + fprintf(fp, " Dupe mail board %s\n", CFG.dupboard); + fprintf(fp, " Pktdate program %s\n", CFG.pktdate); + fprintf(fp, " Keep on hold %d days\n", CFG.toss_days); + fprintf(fp, " Dupes in database %d\n", CFG.toss_dupes); + fprintf(fp, " Default max msgs %d\n", CFG.defmsgs); + fprintf(fp, " Default days %d\n", CFG.defdays); + fprintf(fp, " Reject older then %d days\n", CFG.toss_old); + fprintf(fp, " Maximum systems %ld\n", CFG.toss_systems); + fprintf(fp, " Maximum groups %ld\n", CFG.toss_groups); + fprintf(fp, " Use 4d addressing %s\n", getboolean(CFG.addr4d)); + + addtoc(fp, toc, 1, 15, page, (char *)"Internet Mail and News processing"); + + fprintf(fp, " Split messages at %d KBytes\n", CFG.new_split); + fprintf(fp, " Force split at %d KBytes\n", CFG.new_force); + fprintf(fp, " ISP Email Mode %s\n", getemailmode(CFG.EmailMode)); + fprintf(fp, " Email fido aka %s\n", aka2str(CFG.EmailFidoAka)); + fprintf(fp, " UUCP gateway %s\n", aka2str(CFG.UUCPgate)); + fprintf(fp, " POP3 host %s\n", CFG.popnode); + fprintf(fp, " SMTP host %s\n", CFG.smtpnode); + fprintf(fp, " News transfermode %s\n", getnewsmode(CFG.newsfeed)); + switch (CFG.newsfeed) { + case FEEDINN: fprintf(fp, " NNTP host %s\n", CFG.nntpnode); + fprintf(fp, " NNTP mode reader %s\n", getboolean(CFG.modereader)); + fprintf(fp, " NNTP username %s\n", CFG.nntpuser); + fprintf(fp, " NNTP password %s\n", getboolean(strlen(CFG.nntppass))); + break; + case FEEDRNEWS: fprintf(fp, " Path to rnews %s\n", CFG.rnewspath); + break; + case FEEDUUCP: fprintf(fp, " NNTP host %s\n", CFG.nntpnode); + fprintf(fp, " Path to rnews %s\n", CFG.rnewspath); + break; + } + fprintf(fp, " Allow control msgs %s\n", getboolean(CFG.allowcontrol)); + fprintf(fp, " Don't regate msgs %s\n", getboolean(CFG.dontregate)); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 16, page, (char *)"Newfile reports"); + + fprintf(fp, " FTP base path %s\n", CFG.ftp_base); + fprintf(fp, " New files days %d\n", CFG.newdays); + fprintf(fp, " Highest sec. level %s\n", get_secstr(CFG.security)); + fprintf(fp, " Max. newfile grps %ld\n", CFG.new_groups); + + addtoc(fp, toc, 1, 17, page, (char *)"System fidonet addresses"); + for (i = 0; i < 40; i++) + if (CFG.akavalid[i]) + fprintf(fp, " Aka %2d %s\n", i+1, aka2str(CFG.aka[i])); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 18, page, (char *)"Mailer setup"); + + p = getloglevel(CFG.cico_loglevel); + fprintf(fp, " Mailer loglevel %s\n", p); + free(p); + fprintf(fp, " Res. modem timeout %ld\n", CFG.timeoutreset); + fprintf(fp, " Connect timeout %ld\n", CFG.timeoutconnect); + fprintf(fp, " Random dialdelay %ld\n", CFG.dialdelay); + fprintf(fp, " Default phone nr. %s\n", CFG.Phone); + fprintf(fp, " Default speed %lu\n", CFG.Speed); + fprintf(fp, " TCP/IP flags %s\n", CFG.Flags); + fprintf(fp, " No Filerequests %s\n", getboolean(CFG.NoFreqs)); + fprintf(fp, " No Calls %s\n", getboolean(CFG.NoCall)); + fprintf(fp, " No Hold %s\n", getboolean(CFG.NoHold)); + fprintf(fp, " No Pickup All %s\n", getboolean(CFG.NoPUA)); + fprintf(fp, " No EMSI %s\n", getboolean(CFG.NoEMSI)); + fprintf(fp, " No YooHoo/2U2 %s\n", getboolean(CFG.NoWazoo)); + fprintf(fp, " No Zmodem %s\n", getboolean(CFG.NoZmodem)); + fprintf(fp, " No Zedzap %s\n", getboolean(CFG.NoZedzap)); + fprintf(fp, " No Hydra %s\n", getboolean(CFG.NoHydra)); + fprintf(fp, " No TCP/IP %s\n", getboolean(CFG.NoTCP)); + fprintf(fp, " Max request files %d\n", CFG.Req_Files); + fprintf(fp, " Max request MBytes %d\n", CFG.Req_MBytes); + + for (i = 0; i < 40; i++) + if ((CFG.phonetrans[i].match[0] != '\0') || + (CFG.phonetrans[i].repl[0] != '\0')) + fprintf(fp, " Translate %-20s %s\n", CFG.phonetrans[i].match, CFG.phonetrans[i].repl); + + page = newpage(fp, page); + addtoc(fp, toc, 1, 19, page, (char *)"FTP server setup"); + + fprintf(fp, " Connections limit %d\n", CFG.ftp_limit); + fprintf(fp, " Login fails %d\n", CFG.ftp_loginfails); + fprintf(fp, " Allow compress %s\n", getboolean(CFG.ftp_compress)); + fprintf(fp, " Allow tar %s\n", getboolean(CFG.ftp_tar)); + fprintf(fp, " Log commands %s\n", getboolean(CFG.ftp_log_cmds)); + fprintf(fp, " Anonymous login %s\n", getboolean(CFG.ftp_anonymousok)); + fprintf(fp, " User mbse login %s\n", getboolean(CFG.ftp_mbseok)); + fprintf(fp, " Base path %s\n", CFG.ftp_base); + fprintf(fp, " Shutdown message %s\n", CFG.ftp_msg_shutmsg); + fprintf(fp, " Upload path %s\n", CFG.ftp_upl_path); + fprintf(fp, " README login %s\n", CFG.ftp_readme_login); + fprintf(fp, " README cwd* %s\n", CFG.ftp_readme_cwd); + fprintf(fp, " Message login %s\n", CFG.ftp_msg_login); + fprintf(fp, " Message cwd* %s\n", CFG.ftp_msg_cwd); + fprintf(fp, " Login banner %s\n", CFG.ftp_banner); + fprintf(fp, " Email address %s\n", CFG.ftp_email); + fprintf(fp, " Path filter %s\n", CFG.ftp_pth_filter); + fprintf(fp, " Path message %s\n", CFG.ftp_pth_message); + + addtoc(fp, toc, 1, 20, page, (char *)"WWW server setup"); + + fprintf(fp, " HTML root %s\n", CFG.www_root); + fprintf(fp, " Link to FTP base %s\n", CFG.www_link2ftp); + fprintf(fp, " Webserver URL %s\n", CFG.www_url); + fprintf(fp, " Character set %s\n", CFG.www_charset); + fprintf(fp, " Table bgcolor %s\n", CFG.www_tbgcolor); + fprintf(fp, " Header bgcolor %s\n", CFG.www_hbgcolor); + fprintf(fp, " Author name %s\n", CFG.www_author); + fprintf(fp, " Convert command %s\n", CFG.www_convert); + fprintf(fp, " Icon Home %s\n", CFG.www_icon_home); + fprintf(fp, " String for Home %s\n", CFG.www_name_home); + fprintf(fp, " Icon Back %s\n", CFG.www_icon_back); + fprintf(fp, " String for Back %s\n", CFG.www_name_back); + fprintf(fp, " Icon Previous %s\n", CFG.www_icon_home); + fprintf(fp, " String for Prev. %s\n", CFG.www_name_home); + fprintf(fp, " Icon Next %s\n", CFG.www_icon_back); + fprintf(fp, " String for Next %s\n", CFG.www_name_back); + fprintf(fp, " File per webpage %d\n", CFG.www_files_page); + + return page; +} + + + diff --git a/mbsetup/m_global.h b/mbsetup/m_global.h new file mode 100644 index 00000000..c5028904 --- /dev/null +++ b/mbsetup/m_global.h @@ -0,0 +1,16 @@ +/* m_global.h */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +void config_check(char *path); +int config_open(void); +void config_close(void); +int config_read(void); +int config_write(void); +void global_menu(void); +int PickAka(char *, int); +int global_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_hatch.c b/mbsetup/m_hatch.c new file mode 100644 index 00000000..ef990f1e --- /dev/null +++ b/mbsetup/m_hatch.c @@ -0,0 +1,625 @@ +/***************************************************************************** + * + * File ..................: m_hatch.c + * Purpose ...............: Hatch Setup + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_fgroup.h" +#include "m_ticarea.h" +#include "m_hatch.h" + + +int HatchUpdated = 0; +char *Days[] = {(char *)"Sun",(char *)"Mon",(char *)"Tue",(char *)"Wed", + (char *)"Thu",(char *)"Fri",(char *)"Sat"}; +char *Month[] = {(char *)"1", (char *)"2", (char *)"3", (char *)"4", + (char *)"5", (char *)"6", (char *)"7", (char *)"8", + (char *)"9", (char *)"10",(char *)"11",(char *)"12", + (char *)"13",(char *)"14",(char *)"15",(char *)"16", + (char *)"17",(char *)"18",(char *)"19",(char *)"20", + (char *)"21",(char *)"22",(char *)"23",(char *)"24", + (char *)"25",(char *)"26",(char *)"27",(char *)"28", + (char *)"29",(char *)"30",(char *)"31",(char *)"Last"}; + +/* + * Count nr of hatch records in the database. + * Creates the database if it doesn't exist. + */ +int CountHatch(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + hatchhdr.hdrsize = sizeof(hatchhdr); + hatchhdr.recsize = sizeof(hatch); + hatchhdr.lastupd = time(NULL); + fwrite(&hatchhdr, sizeof(hatchhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - hatchhdr.hdrsize) / hatchhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenHatch(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int FieldPatch = FALSE; + + sprintf(fnin, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = hatchhdr.recsize; + if (oldsize != sizeof(hatch)) { + HatchUpdated = 1; + if ((oldsize + 8) == sizeof(hatch)) { + FieldPatch = TRUE; + Syslog('?', "Hatch: performing FieldPatch"); + } + } else + HatchUpdated = 0; + hatchhdr.hdrsize = sizeof(hatchhdr); + hatchhdr.recsize = sizeof(hatch); + fwrite(&hatchhdr, sizeof(hatchhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&hatch, 0, sizeof(hatch)); + while (fread(&hatch, oldsize, 1, fin) == 1) { + if (FieldPatch) { + memmove(&hatch.Replace, &hatch.Name[13], oldsize-12); + memset(&hatch.Name[13], 0, 8); + } + fwrite(&hatch, sizeof(hatch), 1, fout); + memset(&hatch, 0, sizeof(hatch)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseHatch(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *hat = NULL, *tmp; + + sprintf(fin, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/hatch.temp", getenv("MBSE_ROOT")); + + if (HatchUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&hatchhdr, hatchhdr.hdrsize, 1, fi); + fwrite(&hatchhdr, hatchhdr.hdrsize, 1, fo); + + while (fread(&hatch, hatchhdr.recsize, 1, fi) == 1) + if (!hatch.Deleted) + fill_stlist(&hat, hatch.Spec, ftell(fi) - hatchhdr.recsize); + sort_stlist(&hat); + + for (tmp = hat; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&hatch, hatchhdr.recsize, 1, fi); + fwrite(&hatch, hatchhdr.recsize, 1, fo); + } + + tidy_stlist(&hat); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"hatch.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendHatch(void) +{ + FILE *fil; + char ffile[81]; + int i; + + sprintf(ffile, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&hatch, 0, sizeof(hatch)); + /* + * Fill in default values + */ + hatch.DupeCheck = TRUE; + for (i = 0; i < 7; i++) + hatch.Days[i] = TRUE; + fwrite(&hatch, sizeof(hatch), 1, fil); + fclose(fil); + HatchUpdated = 1; + return 0; + } else + return -1; +} + + + +void HatchScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.3 EDIT HATCH MANAGER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Mask"); + mvprintw( 8, 2, "2. Area"); + mvprintw( 9, 2, "3. Replace"); + mvprintw(10, 2, "4. Magic"); + mvprintw(11, 2, "5. Desc"); + mvprintw(12, 2, "6. Dupe"); + mvprintw(13, 2, "7. Active"); + mvprintw(14, 2, "8. Deleted"); + mvprintw(15, 2, "9. Days"); + mvprintw(16, 2, "10. Month"); +} + + + +void EditDates(void); +void EditDates(void) +{ + int i, x, y; + + clr_index(); + for (;;) { + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.3.9 EDIT DATES IN MONTH"); + set_color(CYAN, BLACK); + y = 7; + x = 5; + for (i = 0; i < 32; i++) { + mvprintw(y, x, (char *)"%2d. %s", i+1, Month[i]); + y++; + if (y == 17) { + y = 7; + x += 20; + } + } + set_color(WHITE, BLACK); + y = 7; + x = 15; + for (i = 0; i < 32; i++) { + show_bool(y,x, hatch.Month[i]); + y++; + if (y == 17) { + y = 7; + x += 20; + } + } + + i = select_menu(32); + if (i == 0) + return; + if (i < 11) { + y = 6 + i; + x = 15; + } else if (i < 21) { + y = i - 4; + x = 35; + } else if (i < 31) { + y = i - 14; + x = 55; + } else { + y = i - 24; + x = 75; + } + if (i == 32) + hatch.Month[i-1] = edit_bool(y, x, hatch.Month[i-1], (char *)"Hatch file in the ^last^ day of the month"); + else + hatch.Month[i-1] = edit_bool(y, x, hatch.Month[i-1], (char *)"Hatch file on this date"); + } +} + + + +void EditDays(void); +void EditDays(void) +{ + int i; + + clr_index(); + for (;;) { + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.3.8 EDIT DAYS IN WEEK"); + set_color(CYAN, BLACK); + for (i = 0; i < 7; i++) + mvprintw(7+i, 6, (char *)"%d. %s", i+1, Days[i]); + set_color(WHITE, BLACK); + for (i = 0; i < 7; i++) + show_bool(7+i,14, hatch.Days[i]); + + i = select_menu(7); + if (i == 0) + return; + hatch.Days[i-1] = edit_bool(6+i, 14, hatch.Days[i-1], (char *)"Hatch file on this day"); + } +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditHatchRec(int Area) +{ + FILE *fil; + char mfile[81]; + static char *tmp = NULL; + long offset; + unsigned long crc, crc1; + int i, All; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Hatch"); + + sprintf(mfile, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + offset = hatchhdr.hdrsize + ((Area -1) * hatchhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&hatch, hatchhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&hatch, crc, hatchhdr.recsize); + working(0, 0, 0); + + for (;;) { + HatchScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, hatch.Spec); + show_str( 8,18,20, hatch.Name); + show_str( 9,18,14, hatch.Replace); + show_str( 10,18,14, hatch.Magic); + show_str( 11,18,55, hatch.Desc); + show_bool(12,18, hatch.DupeCheck); + show_bool(13,18, hatch.Active); + show_bool(14,18, hatch.Deleted); + + for (i = 0; i < 7; i++) + if (hatch.Days[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Days[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Days[i]); + } + } + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + show_str( 15,18,55, tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + All = TRUE; + for (i = 0; i < 32; i++) + if (!hatch.Month[i]) + All = FALSE; + if (!All) { + for (i = 0; i < 32; i++) + if (hatch.Month[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Month[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Month[i]); + } + } + } else + tmp = xstrcpy((char *)"All dates"); + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + show_str( 16,18,55, tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + + switch(select_menu(10)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&hatch, crc1, hatchhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&hatch, hatchhdr.recsize, 1, fil); + fclose(fil); + HatchUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, hatch.Spec, "Hatch ^path/filespec^. ^?^ is any char, '@' is any alpha, '#' is any number") + case 2: strcpy(hatch.Name, PickTicarea((char *)"10.3.2")); + break; + case 3: E_UPS( 9,18,14, hatch.Replace, "The ^filename^ to replace by this file") + case 4: E_UPS( 10,18,14, hatch.Magic, "The ^magic^ filename for this file") + case 5: E_STR( 11,18,55, hatch.Desc, "The ^description^ for this file") + case 6: E_BOOL(12,18, hatch.DupeCheck, "Check if this files is a ^duplicate^ hatch") + case 7: E_BOOL(13,18, hatch.Active, "If this file is ^active^") + case 8: E_BOOL(14,18, hatch.Deleted, "If this record is ^Deleted^") + case 9: EditDays(); + break; + case 10:EditDates(); + break; + } + } +} + + + +void EditHatch(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountHatch(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenHatch() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "10.3. HATCH MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/hatch.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&hatchhdr, sizeof(hatchhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(hatchhdr) + (((o + i) - 1) * hatchhdr.recsize); + fseek(fil, offset, 0); + fread(&hatch, hatchhdr.recsize, 1, fil); + if (hatch.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, hatch.Spec); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseHatch(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendHatch() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditHatchRec(atoi(pick)); + } +} + + + +int tic_hatch_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], *tmp = NULL; + FILE *no; + int i, j, All; + + sprintf(temp, "%s/etc/hatch.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 3, page, (char *)"Hatch manager"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&hatchhdr, sizeof(hatchhdr), 1, no); + + while ((fread(&hatch, hatchhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " File spec %s\n", hatch.Spec); + fprintf(fp, " File echo %s\n", hatch.Name); + fprintf(fp, " Replace file %s\n", hatch.Replace); + fprintf(fp, " Magic filename %s\n", hatch.Magic); + fprintf(fp, " Description %s\n", hatch.Desc); + fprintf(fp, " Dupe check %s\n", getboolean(hatch.DupeCheck)); + fprintf(fp, " Active %s\n", getboolean(hatch.Active)); + tmp = NULL; + for (i = 0; i < 7; i++) + if (hatch.Days[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Days[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Days[i]); + } + } + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + fprintf(fp, " Hatch on days %s\n", tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + All = TRUE; + for (i = 0; i < 32; i++) + if (!hatch.Month[i]) + All = FALSE; + if (!All) { + for (i = 0; i < 32; i++) + if (hatch.Month[i]) { + if (tmp == NULL) { + tmp = xstrcpy(Month[i]); + } else { + tmp = xstrcat(tmp, (char *)", "); + tmp = xstrcat(tmp, Month[i]); + } + } + } else + tmp = xstrcpy((char *)"All dates"); + if (tmp == NULL) + tmp = xstrcpy((char *)"None"); + fprintf(fp, " Hatch on dates %s\n", tmp); + if (tmp != NULL) { + free(tmp); + tmp = NULL; + } + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_hatch.h b/mbsetup/m_hatch.h new file mode 100644 index 00000000..aa0f35f8 --- /dev/null +++ b/mbsetup/m_hatch.h @@ -0,0 +1,10 @@ +#ifndef _HATCH_H +#define _HATCH_H + + +int CountHatch(void); +void EditHatch(void); +int tic_hatch_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_lang.c b/mbsetup/m_lang.c new file mode 100644 index 00000000..23025572 --- /dev/null +++ b/mbsetup/m_lang.c @@ -0,0 +1,527 @@ +/***************************************************************************** + * + * File ..................: setup/m_language.c + * Purpose ...............: Setup Languages. + * Last modification date : 25-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_lang.h" + + + +int LangUpdated = 0; + + +/* + * Count nr of lang records in the database. + * Creates the database if it doesn't exist. + */ +int CountLanguage(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + langhdr.hdrsize = sizeof(langhdr); + langhdr.recsize = sizeof(lang); + fwrite(&langhdr, sizeof(langhdr), 1, fil); + + /* + * Setup default records + */ + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "English"); + sprintf(lang.LangKey, "E"); + sprintf(lang.MenuPath, "%s/english/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/english/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/english/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "english.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Nederlands"); + sprintf(lang.LangKey, "N"); + sprintf(lang.MenuPath, "%s/dutch/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/dutch/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/dutch/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "dutch.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Italian"); + sprintf(lang.LangKey, "I"); + sprintf(lang.MenuPath, "%s/italian/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/italian/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/italian/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "italian.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + memset(&lang, 0, sizeof(lang)); + sprintf(lang.Name, "Spanish"); + sprintf(lang.LangKey, "S"); + sprintf(lang.MenuPath, "%s/spanish/menus", getenv("MBSE_ROOT")); + sprintf(lang.TextPath, "%s/spanish/txtfiles", getenv("MBSE_ROOT")); + sprintf(lang.MacroPath, "%s/spanish/macro", getenv("MBSE_ROOT")); + sprintf(lang.Filename, "spanish.lang"); + lang.Available = TRUE; + fwrite(&lang, sizeof(lang), 1, fil); + + fclose(fil); + return 2; + } else + return -1; + } + + fread(&langhdr, sizeof(langhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - langhdr.hdrsize) / langhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenLanguage(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/language.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = langhdr.recsize; + if (oldsize != sizeof(lang)) + LangUpdated = 1; + else + LangUpdated = 0; + langhdr.hdrsize = sizeof(langhdr); + langhdr.recsize = sizeof(lang); + fwrite(&langhdr, sizeof(langhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&lang, 0, sizeof(lang)); + while (fread(&lang, oldsize, 1, fin) == 1) { + fwrite(&lang, sizeof(lang), 1, fout); + memset(&lang, 0, sizeof(lang)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseLanguage(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *lan = NULL, *tmp; + + sprintf(fin, "%s/etc/language.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/language.temp", getenv("MBSE_ROOT")); + + if (LangUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&langhdr, langhdr.hdrsize, 1, fi); + fwrite(&langhdr, langhdr.hdrsize, 1, fo); + + while (fread(&lang, langhdr.recsize, 1, fi) == 1) + if (!lang.Deleted) + fill_stlist(&lan, lang.LangKey , ftell(fi) - langhdr.recsize); + sort_stlist(&lan); + + for (tmp = lan; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&lang, langhdr.recsize, 1, fi); + fwrite(&lang, langhdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&lan); + Syslog('+', "Updated \"language.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendLanguage(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&lang, 0, sizeof(lang)); + fwrite(&lang, sizeof(lang), 1, fil); + fclose(fil); + LangUpdated = 1; + return 0; + } else + return -1; +} + + + +void s_lang(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.2 EDIT LANGUAGE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Select"); + mvprintw( 8, 2, "2. Name"); + mvprintw( 9, 2, "3. Menupath"); + mvprintw(10, 2, "4. Textpath"); + mvprintw(11, 2, "5. Macropath"); + mvprintw(12, 2, "6. Available"); + mvprintw(13, 2, "7. Datafile"); + mvprintw(14, 2, "8. Security"); + mvprintw(15, 2, "9. Deleted"); +} + + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditLangRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Language"); + + sprintf(mfile, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(langhdr) + ((Area -1) * sizeof(lang)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&lang, sizeof(lang), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&lang, crc, sizeof(lang)); + working(0, 0, 0); + + s_lang(); + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16, 1, lang.LangKey); + show_str( 8,16,30, lang.Name); + show_str( 9,16,64, lang.MenuPath); + show_str( 10,16,64, lang.TextPath); + show_str( 11,16,64, lang.MacroPath); + show_bool(12,16, lang.Available); + show_str( 13,16,24, lang.Filename); + show_sec( 14,16, lang.Security); + show_bool(15,16, lang.Deleted); + + j = select_menu(9); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&lang, crc1, sizeof(lang)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&lang, sizeof(lang), 1, fil); + fclose(fil); + LangUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,16,1, lang.LangKey, "The ^Key^ to select this language") + case 2: E_STR( 8,16,30,lang.Name, "The ^name^ of this language") + case 3: E_PTH( 9,16,64,lang.MenuPath, "The ^Menus Path^ of this language") + case 4: E_PTH( 10,16,64,lang.TextPath, "The ^Textfile path^ of this language") + case 5: E_PTH( 11,16,64,lang.MacroPath,"The ^Macro template path^ if this language") + case 6: E_BOOL(12,16, lang.Available,"Is this language ^available^") + case 7: E_STR( 13,16,24,lang.Filename, "The ^Filename^ (without path) of the language datafile") + case 8: E_SEC( 14,16, lang.Security, "8.2. LANGUAGE SECURITY", s_lang) + case 9: E_BOOL(15,16, lang.Deleted, "Is this language record ^Deleted^") + } + } + + return 0; +} + + + +void EditLanguage(void) +{ + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountLanguage(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenLanguage() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.2 LANGUAGE SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/language.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fil); + x = 4; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(langhdr) + ((i - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + if (i == 11) + x = 44; + if (lang.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, lang.LangKey, lang.Name); + mvprintw(i + 6, x, temp); + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseLanguage(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendLanguage() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditLangRec(atoi(pick)); + } +} + + + +int PickLanguage(char *nr) +{ + int Lang = '\0'; + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Lang; + } + + records = CountLanguage(); + if (records == -1) { + working(2, 0, 0); + return Lang; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. LANGUAGE SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&langhdr, sizeof(langhdr), 1, fil); + x = 2; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(langhdr) + ((i - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + if (i == 11) + x = 42; + if (lang.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-28s", i, lang.LangKey, lang.Name); + mvprintw(i + 6, x, temp); + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(langhdr) + ((atoi(pick) - 1) * langhdr.recsize); + fseek(fil, offset, 0); + fread(&lang, langhdr.recsize, 1, fil); + Lang = lang.LangKey[0]; + } + fclose(fil); + } + } + return Lang; +} + + + +int bbs_lang_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 2, page, (char *)"BBS Language setup"); + j = 0; + fprintf(fp, "\n\n"); + fread(&langhdr, sizeof(langhdr), 1, no); + + while ((fread(&lang, langhdr.recsize, 1, no)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Language key %s\n", lang.LangKey); + fprintf(fp, " Language name %s\n", lang.Name); + fprintf(fp, " Available %s\n", getboolean(lang.Available)); + fprintf(fp, " Menu path %s\n", lang.MenuPath); + fprintf(fp, " Textfiles path %s\n", lang.TextPath); + fprintf(fp, " Macrofiles path %s\n", lang.MacroPath); + fprintf(fp, " Language file %s\n", lang.Filename); + fprintf(fp, " Security level %s\n", get_secstr(lang.Security)); + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_lang.h b/mbsetup/m_lang.h new file mode 100644 index 00000000..64654c33 --- /dev/null +++ b/mbsetup/m_lang.h @@ -0,0 +1,12 @@ +#ifndef _LANG_H +#define _LANG_H + + +int CountLanguage(void); +void EditLanguage(void); +int PickLanguage(char *); +int bbs_lang_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_limits.c b/mbsetup/m_limits.c new file mode 100644 index 00000000..090a688c --- /dev/null +++ b/mbsetup/m_limits.c @@ -0,0 +1,593 @@ +/***************************************************************************** + * + * File ..................: setup/m_limits.c + * Purpose ...............: Setup Limits. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_limits.h" + + + +int LimUpdated = 0; + + +/* + * Count nr of LIMIT records in the database. + * Creates the database if it doesn't exist. + */ +int CountLimits(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + LIMIThdr.hdrsize = sizeof(LIMIThdr); + LIMIThdr.recsize = sizeof(LIMIT); + fwrite(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + + /* + * Create default limits + */ + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 0; + LIMIT.Time = 5; + LIMIT.DownK = 1; + LIMIT.DownF = 1; + sprintf(LIMIT.Description, "Twit"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 5; + LIMIT.Time = 15; + LIMIT.DownK = 100; + LIMIT.DownF = 2; + sprintf(LIMIT.Description, "New User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 20; + LIMIT.Time = 60; + LIMIT.DownK = 10240; + LIMIT.DownF = 25; + sprintf(LIMIT.Description, "Normal User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 50; + LIMIT.Time = 90; + LIMIT.DownK = 20480; + LIMIT.DownF = 100; + sprintf(LIMIT.Description, "V.I.P. User"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 80; + LIMIT.Time = 120; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Fellow Sysop or Point"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 100; + LIMIT.Time = 180; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Co-Sysop"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + memset(&LIMIT, 0, sizeof(LIMIT)); + LIMIT.Security = 32000; + LIMIT.Time = 240; + LIMIT.DownK = 40960; + sprintf(LIMIT.Description, "Sysop"); + LIMIT.Available = TRUE; + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + + fclose(fil); + return 7; + } else + return -1; + } + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - LIMIThdr.hdrsize) / LIMIThdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenLimits(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/limits.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = LIMIThdr.recsize; + if (oldsize != sizeof(LIMIT)) + LimUpdated = 1; + else + LimUpdated = 0; + LIMIThdr.hdrsize = sizeof(LIMIThdr); + LIMIThdr.recsize = sizeof(LIMIT); + fwrite(&LIMIThdr, sizeof(LIMIThdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&LIMIT, 0, sizeof(LIMIT)); + while (fread(&LIMIT, oldsize, 1, fin) == 1) { + fwrite(&LIMIT, sizeof(LIMIT), 1, fout); + memset(&LIMIT, 0, sizeof(LIMIT)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseLimits(void) +{ + char fin[81], fout[81], temp[20]; + FILE *fi, *fo; + st_list *lim = NULL, *tmp; + + sprintf(fin, "%s/etc/limits.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/limits.temp", getenv("MBSE_ROOT")); + + if (LimUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&LIMIThdr, LIMIThdr.hdrsize, 1, fi); + fwrite(&LIMIThdr, LIMIThdr.hdrsize, 1, fo); + + while (fread(&LIMIT, LIMIThdr.recsize, 1, fi) == 1) + if (!LIMIT.Deleted) { + sprintf(temp, "%014ld", LIMIT.Security); + fill_stlist(&lim, temp, ftell(fi) - LIMIThdr.recsize); + } + sort_stlist(&lim); + + for (tmp = lim; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&LIMIT, LIMIThdr.recsize, 1, fi); + fwrite(&LIMIT, LIMIThdr.recsize, 1, fo); + } + + tidy_stlist(&lim); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"limits.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendLimits(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&LIMIT, 0, sizeof(LIMIT)); + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + LimUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditLimRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Limits"); + + sprintf(mfile, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(LIMIThdr) + ((Area -1) * sizeof(LIMIT)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&LIMIT, crc, sizeof(LIMIT)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.1 EDIT SECURITY LIMIT"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Access Level"); + mvprintw( 8, 6, "2. Maximum Time"); + mvprintw( 9, 6, "3. Download Kb."); + mvprintw(10, 6, "4. Download Files"); + mvprintw(11, 6, "5. Description"); + mvprintw(12, 6, "6. Available"); + mvprintw(13, 6, "7. Deleted"); + + for (;;) { + set_color(WHITE, BLACK); + show_int( 7,25, LIMIT.Security); + show_int( 8,25, LIMIT.Time); + show_int( 9,25, LIMIT.DownK); + show_int(10,25, LIMIT.DownF); + show_str(11,25,40, LIMIT.Description); + show_bool(12,25, LIMIT.Available); + show_bool(13,25, LIMIT.Deleted); + + j = select_menu(7); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&LIMIT, crc1, sizeof(LIMIT)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&LIMIT, sizeof(LIMIT), 1, fil); + fclose(fil); + LimUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_INT( 7,25, LIMIT.Security, "The ^Security^ level for this limit") + case 2: E_INT( 8,25, LIMIT.Time, "The maxmimum ^Time online^ per day for this limit") + case 3: E_INT( 9,25, LIMIT.DownK, "The ^Kilobytes^ download limit per day, 0 = don't care") + case 4: E_INT( 10,25, LIMIT.DownF, "The ^nr of files^ to download per day, 0 = don't care") + case 5: E_STR( 11,25,40,LIMIT.Description,"A short ^description^ for this limit") + case 6: E_BOOL(12,25, LIMIT.Available, "Is this record ^avaiable^") + case 7: E_BOOL(13,25, LIMIT.Deleted, "Is this level ^Deleted^") + } + } + + return 0; +} + + + +void EditLimits(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountLimits(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenLimits() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 7, "8.1 LIMITS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/limits.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + x = 5; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(LIMIThdr) + ((i - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + if (i == 11) { + x = 45; + y = 7; + } + if (LIMIT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6ld %-40s", i, LIMIT.Security, LIMIT.Description); + temp[37] = '\0'; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseLimits(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendLimits() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditLimRec(atoi(pick)); + } +} + + + +char *PickLimits(int nr) +{ + static char Lim[21] = ""; + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Lim; + } + + records = CountLimits(); + if (records == -1) { + working(2, 0, 0); + return Lim; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%d. LIMITS SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&LIMIThdr, sizeof(LIMIThdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(LIMIThdr) + ((i - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (LIMIT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6ld %-40s", i, LIMIT.Security, LIMIT.Description); + temp[37] = '\0'; + mvprintw(y, x, temp); + y++; + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(LIMIThdr) + ((atoi(pick) - 1) * LIMIThdr.recsize); + fseek(fil, offset, 0); + fread(&LIMIT, LIMIThdr.recsize, 1, fil); + sprintf(Lim, "%ld", LIMIT.Security); + } + fclose(fil); + } + } + return Lim; +} + + + +int bbs_limits_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 8, 1, page, (char *)"BBS user limits"); + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, no); + + fprintf(fp, "\n"); + fprintf(fp, " Access Max. Down Down\n"); + fprintf(fp, " Level time Kb. files Active Description\n"); + fprintf(fp, " ------ ------ ------ ------ ------ ------------------------------\n"); + + while ((fread(&LIMIT, LIMIThdr.recsize, 1, no)) == 1) { + fprintf(fp, " %6ld %6ld %6ld %6d %s %s\n", LIMIT.Security, LIMIT.Time, LIMIT.DownK, + LIMIT.DownF, getboolean(LIMIT.Available), LIMIT.Description); + } + + fclose(no); + return page; +} + + + +int limit_users_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no, *us; + int line = 0, j; + + sprintf(temp, "%s/etc/limits.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + sprintf(temp, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((us = fopen(temp, "r")) == NULL) { + fclose(no); + return page; + } + + page = newpage(fp, page); + addtoc(fp, toc, 1, 0, page, (char *)"Access limits and users"); + + fread(&LIMIThdr, sizeof(LIMIThdr), 1, no); + fread(&usrconfighdr, sizeof(usrconfighdr), 1, us); + + while (fread(&LIMIT, LIMIThdr.recsize, 1, no) == 1) { + if (LIMIT.Available) { + if (line > 52) { + page = newpage(fp, page); + line = 0; + } + fprintf(fp, "\n\n"); + fprintf(fp, " Level %ld - %s\n\n", LIMIT.Security, LIMIT.Description); + line += 4; + j = 2; + fseek(us, usrconfighdr.hdrsize, SEEK_SET); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, us) == 1) { + if ((!usrconfig.Deleted) && strlen(usrconfig.sUserName) && + (usrconfig.Security.level == LIMIT.Security)) { + if (j == 2) { + j = 0; + fprintf(fp, " %-35s", usrconfig.sUserName); + } else { + fprintf(fp, " %s\n", usrconfig.sUserName); + line++; + if (line > 56) { + page = newpage(fp, page); + line = 0; + } + } + j++; + } + } + if (j != 2) + fprintf(fp, "\n"); + } + } + + fclose(us); + fclose(no); + return page; +} + + diff --git a/mbsetup/m_limits.h b/mbsetup/m_limits.h new file mode 100644 index 00000000..ddd54c5b --- /dev/null +++ b/mbsetup/m_limits.h @@ -0,0 +1,13 @@ +#ifndef _LIMITSS_H +#define _LIMITSS_H + + +int CountLimits(void); +void EditLimits(void); +char *PickLimits(int); +int bbs_limits_doc(FILE *, FILE *, int); +int limit_users_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_magic.c b/mbsetup/m_magic.c new file mode 100644 index 00000000..f5df63a8 --- /dev/null +++ b/mbsetup/m_magic.c @@ -0,0 +1,537 @@ +/***************************************************************************** + * + * File ..................: setup/m_magic.c + * Purpose ...............: Edit Magics + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_ticarea.h" +#include "m_global.h" +#include "m_magic.h" + + + +int MagicUpdated = 0; + + +/* + * Count nr of magic records in the database. + * Creates the database if it doesn't exist. + */ +int CountMagics(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + magichdr.hdrsize = sizeof(magichdr); + magichdr.recsize = sizeof(magic); + fwrite(&magichdr, sizeof(magichdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&magichdr, sizeof(magichdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - magichdr.hdrsize) / magichdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMagics(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int FieldPatch = FALSE; + + sprintf(fnin, "%s/etc/magic.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&magichdr, sizeof(magichdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = magichdr.recsize; + if (oldsize != sizeof(magic)) { + MagicUpdated = 1; + if ((oldsize + 16) == sizeof(magic)) { + FieldPatch = TRUE; + Syslog('?', "Magic: performing FieldPatch"); + } + } else + MagicUpdated = 0; + magichdr.hdrsize = sizeof(magichdr); + magichdr.recsize = sizeof(magic); + fwrite(&magichdr, sizeof(magichdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&magic, 0, sizeof(magic)); + while (fread(&magic, oldsize, 1, fin) == 1) { + if (FieldPatch) { + memmove(&magic.Path, &magic.From[13], oldsize-12); + memset(&magic.From[13], 0, 8); + } + fwrite(&magic, sizeof(magic), 1, fout); + memset(&magic, 0, sizeof(magic)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMagics(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mag = NULL, *tmp; + + sprintf(fin, "%s/etc/magic.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/magic.temp", getenv("MBSE_ROOT")); + + if (MagicUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&magichdr, magichdr.hdrsize, 1, fi); + fwrite(&magichdr, magichdr.hdrsize, 1, fo); + + while (fread(&magic, magichdr.recsize, 1, fi) == 1) + if (!magic.Deleted) + fill_stlist(&mag, magic.Mask, ftell(fi) - magichdr.recsize); + sort_stlist(&mag); + + for (tmp = mag; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&magic, magichdr.recsize, 1, fi); + fwrite(&magic, magichdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + tidy_stlist(&mag); + unlink(fout); + Syslog('+', "Updated \"magic.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendMagics(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&magic, 0, sizeof(magic)); + fwrite(&magic, sizeof(magic), 1, fil); + fclose(fil); + MagicUpdated = 1; + return 0; + } else + return -1; +} + + + +void ScreenM(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.4. EDIT MAGIC"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Magic"); + mvprintw( 8, 2, "2. Filemask"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); + mvprintw(11, 2, "5. Area"); + + switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + mvprintw(12, 2, "6. To Area"); + break; + + case MG_EXEC: + mvprintw(12, 2, "6. Command"); + mvprintw(13, 2, "7. Compile"); + break; + + case MG_COPY: + case MG_OTHER: + case MG_UNPACK: + mvprintw(12, 2, "6. To path"); + if (magic.Attrib != MG_OTHER) + mvprintw(13, 2, "7. Compile"); + break; + + case MG_KEEPNUM: + mvprintw(12, 2, "6. Keep Num"); + break; + } +} + + + +void FieldsM(void) +{ + set_color(WHITE, BLACK); + show_str( 7,16,20, getmagictype(magic.Attrib)); + show_str( 8,16,14, magic.Mask); + show_str( 9,16, 3, getboolean(magic.Active)); + show_str(10,16, 3, getboolean(magic.Deleted)); + show_str(11,16,20, magic.From); + + switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + show_str(12,16,20, magic.ToArea); + break; + case MG_EXEC: + show_str(12,16,64, magic.Cmd); + show_bool(13,16, magic.Compile); + break; + case MG_UNPACK: + case MG_COPY: + show_bool(13,16, magic.Compile); + case MG_OTHER: + show_str(12,16,64, magic.Path); + break; + case MG_KEEPNUM: + show_int(12,16, magic.KeepNum); + break; + } +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditMagicRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j, choices; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Magics"); + + sprintf(mfile, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(magichdr) + ((Area -1) * sizeof(magic)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&magic, sizeof(magic), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&magic, crc, sizeof(magic)); + working(0, 0, 0); + + for (;;) { + ScreenM(); + FieldsM(); + + switch(magic.Attrib) { + case MG_UPDALIAS: + case MG_DELETE: + choices = 5; + break; + case MG_EXEC: + case MG_COPY: + case MG_UNPACK: + choices = 7; + break; + default: + choices = 6; + } + + j = select_menu(choices); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&magic, crc1, sizeof(magic)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&magic, sizeof(magic), 1, fil); + fclose(fil); + MagicUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: magic.Attrib = edit_magictype(7,16, magic.Attrib); + break; + + case 2: E_STR( 8,16,14, magic.Mask, "File ^mask^ to test for this magic") + case 3: E_BOOL( 9,16, magic.Active, "Is this magic ^active^") + case 4: E_BOOL(10,16, magic.Deleted,"Is this record ^deleted^") + case 5: strcpy(magic.From, PickTicarea((char *)"10.4.5")); + break; + case 6: switch(magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + strcpy(magic.ToArea, PickTicarea((char *)"10.4.6")); + break; + + case MG_COPY: + case MG_OTHER: + case MG_UNPACK: + E_PTH(12,16,64, magic.Path, "The ^path^ to use") + + case MG_EXEC: + E_STR(12,16,64, magic.Cmd, "The ^command^ to execute") + + case MG_KEEPNUM: + E_INT(12,16, magic.KeepNum,"The number of files to ^keep^") + } + break; + + case 7: E_BOOL(13,16, magic.Compile, "Trigger the ^compile nodelist^ flag") + } + } + return 0; +} + + + +void EditMagics(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMagics(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMagics() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "10.4. MAGICS EDITOR"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/magic.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&magichdr, sizeof(magichdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(magichdr) + (((i + o) - 1) * magichdr.recsize); + fseek(fil, offset, 0); + fread(&magic, magichdr.recsize, 1, fil); + if (magic.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %s", o + i, getmagictype(magic.Attrib), magic.Mask); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMagics(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMagics() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditMagicRec(atoi(pick)); + } +} + + + +int tic_magic_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/magic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 4, page, (char *)"File Magic processing"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&magichdr, sizeof(magichdr), 1, no); + while (fread(&magic, magichdr.recsize, 1, no) == 1) { + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Filemask %s\n", magic.Mask); + fprintf(fp, " Type %s\n", getmagictype(magic.Attrib)); + fprintf(fp, " Active %s\n", getboolean(magic.Active)); + fprintf(fp, " Area %s\n", magic.From); + + switch (magic.Attrib) { + case MG_ADOPT: + case MG_MOVE: + fprintf(fp, " To area %s\n", magic.ToArea); + break; + + case MG_EXEC: + fprintf(fp, " Command %s\n", magic.Cmd); + fprintf(fp, " Compile NL %s\n", getboolean(magic.Compile)); + break; + + case MG_UNPACK: + case MG_COPY: + fprintf(fp, " Compile NL %s\n", getboolean(magic.Compile)); + case MG_OTHER: + fprintf(fp, " Path %s\n", magic.Path); + break; + + case MG_KEEPNUM:fprintf(fp, " Keep # file %d\n", magic.KeepNum); + break; + } + + fprintf(fp, "\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_magic.h b/mbsetup/m_magic.h new file mode 100644 index 00000000..fa8fe150 --- /dev/null +++ b/mbsetup/m_magic.h @@ -0,0 +1,11 @@ +#ifndef _MAGIC_H +#define _MAGIC_H + + +int CountMagics(void); +void EditMagics(void); +int tic_magic_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_mail.c b/mbsetup/m_mail.c new file mode 100644 index 00000000..ce5109ac --- /dev/null +++ b/mbsetup/m_mail.c @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * File ..................: m_mail.c + * Purpose ...............: Mail Setup Program + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_marea.h" +#include "m_mgroup.h" +#include "m_mail.h" + + + + +void mail_menu(void) +{ + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9. MAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Echomail Groups"); + mvprintw( 8, 6, "2. Edit Echomail Areas"); + + switch(select_menu(2)) { + case 0: + return; + case 1: + EditMGroup(); + break; + case 2: + EditMsgarea(); + break; + } + } +} + + + +int mail_doc(FILE *fp, FILE *toc, int page) +{ + page = newpage(fp, page); + addtoc(fp, toc, 9, 0, page, (char *)"Mail setup"); + + page = mail_group_doc(fp, toc, page); + page = mail_area_doc(fp, toc, page); + + return page; +} + + diff --git a/mbsetup/m_mail.h b/mbsetup/m_mail.h new file mode 100644 index 00000000..c5eae97c --- /dev/null +++ b/mbsetup/m_mail.h @@ -0,0 +1,12 @@ +#ifndef _MAIL_H +#define _MAIL_H + + +int CountMsgarea(void); +void EditMsgarea(void); +void mail_menu(void); +int mail_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_marea.c b/mbsetup/m_marea.c new file mode 100644 index 00000000..863a293a --- /dev/null +++ b/mbsetup/m_marea.c @@ -0,0 +1,1469 @@ +/***************************************************************************** + * + * File ..................: m_mail.c + * Purpose ...............: Mail Setup Program + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "grlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_mgroup.h" +#include "m_marea.h" + + +int MsgUpdated = 0; +unsigned long MsgCrc; +FILE *tfil = NULL; + + + +/* + * Count nr of msgs records in the database. + * Creates the database if it doesn't exist. + */ +int CountMsgarea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + Syslog('+', "Created mareas.data"); + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.recsize = sizeof(msgs); + msgshdr.syssize = CFG.toss_systems * sizeof(sysconnect); + msgshdr.lastupd = time(NULL); + fwrite(&msgshdr, sizeof(msgshdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMsgarea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize, oldsys; + struct _sysconnect syscon; + int i, oldsystems; + + sprintf(fnin, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened \"mareas.data\""); + MsgUpdated = 0; + fread(&msgshdr, sizeof(msgshdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, fin); + if (msgshdr.hdrsize != sizeof(msgshdr)) { + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.lastupd = time(NULL); + MsgUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = msgshdr.recsize; + oldsys = msgshdr.syssize; + oldsystems = oldsys / sizeof(syscon); + if ((oldsize != sizeof(msgs)) || (CFG.toss_systems != oldsystems)) { + MsgUpdated = 1; + Syslog('+', "\"mareas.data\" nr of systems is changed"); + } + msgshdr.hdrsize = sizeof(msgshdr); + msgshdr.recsize = sizeof(msgs); + msgshdr.syssize = sizeof(syscon) * CFG.toss_systems; + fwrite(&msgshdr, sizeof(msgshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&msgs, 0, sizeof(msgs)); + while (fread(&msgs, oldsize, 1, fin) == 1) { + if ((oldsize != sizeof(msgs)) && !msgs.Rfccode) { + msgs.Rfccode = CHRS_DEFAULT_RFC; + msgs.Ftncode = CHRS_DEFAULT_FTN; + } + fwrite(&msgs, sizeof(msgs), 1, fout); + memset(&msgs, 0, sizeof(msgs)); + /* + * Copy the existing connections + */ + for (i = 1; i <= oldsystems; i++) { + fread(&syscon, sizeof(syscon), 1, fin); + /* + * Write only valid records + */ + if (i <= CFG.toss_systems) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + if (oldsystems < CFG.toss_systems) { + /* + * The size is increased, fill with + * blank records. + */ + memset(&syscon, 0, sizeof(syscon)); + for (i = (oldsystems + 1); i <= CFG.toss_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + } + + fclose(fin); + fclose(fout); + Syslog('+', "Opended \"mareas.data\""); + if (MsgUpdated) + Syslog('+', "Updated \"mareas.data\" data format"); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMsgarea(int Force) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/mareas.temp", getenv("MBSE_ROOT")); + + if (MsgUpdated == 1) { + if (Force || (yes_no((char *)"Messages database is changed, save changes") == 1)) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"mareas.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); + Syslog('+', "No update of \"mareas.data\""); +} + + + +void InitMsgRec(void); +void InitMsgRec(void) +{ + memset(&msgs, 0, sizeof(msgs)); + /* + * Fill in default values + */ + msgs.DaysOld = CFG.defdays; + msgs.MaxMsgs = CFG.defmsgs; + msgs.Type = ECHOMAIL; + msgs.MsgKinds = PUBLIC; + msgs.UsrDelete = TRUE; + msgs.Rfccode = CHRS_DEFAULT_RFC; + msgs.Ftncode = CHRS_DEFAULT_FTN; + strcpy(msgs.Origin, CFG.origin); +} + + + +int AppendMsgarea(void); +int AppendMsgarea() +{ + FILE *fil; + char ffile[81]; + struct _sysconnect syscon; + int i; + + sprintf(ffile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + InitMsgRec(); + fwrite(&msgs, sizeof(msgs), 1, fil); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1; i <= CFG.toss_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fil); + fclose(fil); + MsgUpdated = 1; + return 0; + } else + return -1; +} + + + +void EditSystem(sysconnect *); +void EditSystem(sysconnect *Sys) +{ + sysconnect S; + unsigned short zone = 0; + int refresh = TRUE; + + S = (* Sys); + for (;;) { + if (refresh) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5,6, "9.2.26 EDIT CONNECTION"); + set_color(CYAN, BLACK); + mvprintw( 7,6, "1. Aka"); + mvprintw( 8,6, "2. Send to"); + mvprintw( 9,6, "3. Recv from"); + mvprintw(10,6, "4. Pause"); + mvprintw(11,6, "5. Excluded"); + mvprintw(12,6, "6. Delete"); + refresh = FALSE; + } + set_color(WHITE, BLACK); + show_str( 7,23,23, aka2str(S.aka)); + show_bool( 8,23, S.sendto); + show_bool( 9,23, S.receivefrom); + show_bool(10,23, S.pause); + show_bool(11,23, S.cutoff); + zone = S.aka.zone; + + switch(select_menu(6)) { + case 0: (* Sys) = S; + return; + case 1: S.aka = PullUplink((char *)"9.2.29"); + refresh = TRUE; + break; + case 2: E_BOOL( 8,23, S.sendto, "^Send^ mail ^to^ this node") + case 3: E_BOOL( 9,23, S.receivefrom, "^Receive^ mail ^from^ this node") + case 4: E_BOOL(10,23, S.pause, "Is this node ^paused^") + case 5: E_BOOL(11,23, S.cutoff, "Is this node ^excluded (cutoff)^ by a moderator") + case 6: if (yes_no((char *)"Delete this entry")) { + memset(&S, 0, sizeof(sysconnect)); + (* Sys) = S; + return; + } + break; + } + + /* + * Set sendto and receivefrom to on when a new + * zone is entered. + */ + if ((S.aka.zone) && (!zone)) { + S.sendto = 1; + S.receivefrom = 1; + } + } +} + + + +int EditConnections(FILE *); +int EditConnections(FILE *fil) +{ + int systems, o = 0, i, y, x; + long offset; + char pick[12]; + sysconnect System; + char status[5]; + char temp[41]; + + systems = msgshdr.syssize / sizeof(sysconnect); + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "9.2.29 MESSAGE AREA CONNECTIONS"); + set_color(CYAN, BLACK); + y = 7; + x = 2; + for (i = 1; i <= 20; i++) { + if ((o+i-1) < systems) { + if (i == 11) { + y = 7; + x = 42; + } + offset = (o+i-1) * sizeof(sysconnect); + if ((fseek(fil, offset, 0)) != 0) { + working(2, 0, 0); + return FALSE; + } + fread(&System, sizeof(sysconnect), 1, fil); + memset(&status, 0, 5); + memset(&status, '-', 4); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.cutoff) + status[3] = 'C'; + + if (System.aka.zone) { + set_color(CYAN,BLACK); + sprintf(temp, "%3d. %s %d:%d/%d.%d@%s", o+i, status, System.aka.zone, System.aka.net, System.aka.node, System.aka.point, System.aka.domain); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(systems, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FALSE; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < systems) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if (((atoi(pick) > 0) && (atoi(pick) <= systems))) { + offset = (atoi(pick) -1) * sizeof(sysconnect); + fseek(fil, offset, 0); + fread(&System, sizeof(sysconnect), 1, fil); + EditSystem(&System); + fseek(fil, offset, 0); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + } +} + + + +void SetScreen(void); +void SetScreen() +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "9.2 EDIT MESSAGE AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Area Name"); + mvprintw( 7, 2, "2. FTN area"); + mvprintw( 8, 2, "3. Newsgroup"); + mvprintw( 9, 2, "4. Moderator"); + mvprintw(10, 2, "5. JAM base"); + mvprintw(11, 2, "6. Origin"); + mvprintw(12, 2, "7. Fido Aka"); + mvprintw(13, 2, "8. QWK name"); + mvprintw(14, 2, "9. Group"); + mvprintw(15, 2, "10. Distrib."); + mvprintw(16, 2, "11. Area Type"); + mvprintw(17, 2, "12. Msg Kinds"); + mvprintw(18, 2, "13. FTN chars"); + mvprintw(19, 2, "14. RFC chars"); + + mvprintw(13,36, "15. Days Old"); + mvprintw(14,36, "16. Max. Msgs"); + mvprintw(15,36, "17. Netreply"); + mvprintw(16,36, "18. Active"); + mvprintw(17,36, "19. Read Sec."); + mvprintw(18,36, "20. Write Sec."); + mvprintw(19,36, "21. Sysop Sec."); + + mvprintw(12,60, "22. User Del."); + mvprintw(13,60, "23. Aliases"); + mvprintw(14,60, "24. Quotes"); + mvprintw(15,60, "25. Mandatory"); + mvprintw(16,60, "26. UnSecure"); + mvprintw(17,60, "27. OLR Default"); + mvprintw(18,60, "28. OLR Forced"); + mvprintw(19,60, "29. Connections"); +} + + + +long LoadMsgRec(int, int); +long LoadMsgRec(int Area, int work) +{ + FILE *fil; + char mfile[81]; + long offset; + sysconnect System; + int i; + + if (work) + working(1, 0, 0); + + sprintf(mfile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + if ((tfil = tmpfile()) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + offset = msgshdr.hdrsize + (((Area -1) * (msgshdr.recsize + msgshdr.syssize))); + if (fseek(fil, offset, SEEK_SET) != 0) { + fclose(tfil); + tfil = NULL; + working(2, 0, 0); + return -1; + } + + fread(&msgs, msgshdr.recsize, 1, fil); + MsgCrc = 0xffffffff; + MsgCrc = upd_crc32((char *)&msgs, MsgCrc, msgshdr.recsize); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, fil); + fwrite(&System, sizeof(sysconnect), 1, tfil); + MsgCrc = upd_crc32((char *)&System, MsgCrc, sizeof(sysconnect)); + } + fclose(fil); + if (work) + working(0, 0, 0); + + return offset; +} + + + +int SaveMsgRec(int, int); +int SaveMsgRec(int Area, int work) +{ + int i; + FILE *fil; + long offset; + char mfile[81]; + sysconnect System; + + if (work) + working(1, 0, 0); + sprintf(mfile, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r+")) == 0) { + working(2, 0, 0); + return -1; + } + + fread(&msgshdr, sizeof(msgshdr), 1, fil); + offset = msgshdr.hdrsize + (((Area -1) * (msgshdr.recsize + msgshdr.syssize))); + if (fseek(fil, offset, SEEK_SET)) { + fclose(fil); + working(2, 0, 0); + return -1; + } + + fwrite(&msgs, msgshdr.recsize, 1, fil); + fseek(tfil, 0, SEEK_SET); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, tfil); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + fclose(fil); + fclose(tfil); + tfil = NULL; + if (work) + working(0, 0, 0); + return 0; +} + + + +void ShowStatus(sysconnect); +void ShowStatus(sysconnect S) +{ + clr_index(); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "Aka"); + mvprintw( 8, 6, "Send to"); + mvprintw( 9, 6, "Recv from"); + mvprintw(10, 6, "Pause"); + mvprintw(11, 6, "Excluded"); + set_color(WHITE, BLACK); + show_str( 7,16,23, aka2str(S.aka)); + show_bool( 8,16, S.sendto); + show_bool( 9,16, S.receivefrom); + show_bool(10,16, S.pause); + show_bool(11,16, S.cutoff); +} + + + +void MsgGlobal(void); +void MsgGlobal(void) +{ + gr_list *mgr = NULL, *tmp; + char *p, mfile[128]; + FILE *fil; + fidoaddr a1, a2; + int menu = 0, marea, Areas, akan = 0, Found; + int Total, Done, netbrd, daysold, maxmsgs; + long offset; + securityrec rs, ws, ss; + sysconnect S, Sc; + + /* + * Build the groups select array + */ + working(1, 0, 0); + sprintf(mfile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&mgr, mgroup.Name); + + fclose(fil); + sort_grlist(&mgr); + } + working(0, 0, 0); + + /* + * Initialize some variables + */ + memset(&rs, 0, sizeof(securityrec)); + memset(&ws, 0, sizeof(securityrec)); + memset(&ss, 0, sizeof(securityrec)); + memset(&S, 0, sizeof(sysconnect)); + S.sendto = TRUE; + S.receivefrom = TRUE; + memset(&mfile, 0, sizeof(mfile)); + sprintf(mfile, "%s", CFG.origin); + daysold = CFG.defdays; + maxmsgs = CFG.defmsgs; + netbrd = 1; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.2 GLOBAL EDIT MESSAGE AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Delete connection"); + mvprintw( 8, 6, "2. Add new connection"); + mvprintw( 9, 6, "3. Replace connection"); + mvprintw(10, 6, "4. Change connection status"); + mvprintw(11, 6, "5. Change days old"); + mvprintw(12, 6, "6. Change max. messages"); + mvprintw(13, 6, "7. Change security"); + mvprintw(14, 6, "8. Change aka to use"); + mvprintw(15, 6, "9. Change origin line"); + mvprintw(16, 6, "10. Change netmail reply"); + mvprintw(17, 6, "11. Delete message area"); + + memset(&a1, 0, sizeof(fidoaddr)); + memset(&a2, 0, sizeof(fidoaddr)); + + menu = select_menu(11); + switch (menu) { + case 0: return; + case 1: a1 = PullUplink((char *)"AKA TO DELETE"); + break; + case 2: a2 = PullUplink((char *)"AKA TO ADD"); + break; + case 3: a1 = PullUplink((char *)"AKA TO REPLACE"); + a2 = PullUplink((char *)"NEW AKA"); + break; + case 4: S.aka = PullUplink((char *)"AKA TO CHANGE STATUS"); + ShowStatus(S); + S.sendto = edit_bool(8,16,S.sendto, (char *)"^Send^ mail to this node"); + S.receivefrom = edit_bool(9,16,S.receivefrom, (char *)"^Receive^ mail from this node"); + S.pause = edit_bool(10,16,S.pause, (char *)"Is this node ^paused^"); + S.cutoff = edit_bool(11,16,S.cutoff, (char *)"Is this node ^excluded^"); + break; + case 5: mvprintw(LINES -3, 5, "Days old"); + E_INT(LINES -3, 14, daysold, (char *)"Enter new number of ^days old^") + case 6: mvprintw(LINES -3, 5, "Max. messages"); + E_INT(LINES -3, 19, maxmsgs, (char *)"Enter ^maximum messages^") + case 7: rs = edit_sec(6, 5, rs, (char *)"9.2.7 READ SECURITY"); + ws = edit_sec(7, 5, ws, (char *)"9.2.7 WRITE SECURITY"); + ss = edit_sec(8, 5, ss, (char *)"9.2.7 SYSOP SECURITY"); + break; + case 8: akan = PickAka((char *)"9.2.8", TRUE); + break; + case 9: E_STR(LINES -3, 5, 64, mfile, "Enter new ^origin^ line"); + case 10:mvprintw(LINES -3, 5, "Netmail reply board"); + E_INT(LINES -3, 25, netbrd, (char *)"The ^netmail reply^ board number") + } + + E_Group(&mgr, (char *)"SELECT MESSAGE GROUPS TO CHANGE"); + + /* + * Show settings before proceeding + */ + switch (menu) { + case 1: mvprintw(7, 6, "Delete aka %s", aka2str(a1)); + break; + case 2: mvprintw(7, 6, "Add aka %s", aka2str(a2)); + break; + case 3: p = xstrcpy(aka2str(a1)); + mvprintw(7, 6, "Replace aka %s with %s", p, aka2str(a2)); + free(p); + break; + case 4: ShowStatus(S); + mvprintw(14, 6, "Change the link status"); + break; + case 5: mvprintw(7, 6, "Change days old to %d", daysold); + break; + case 6: mvprintw(7, 6, "Change maximum messages to %d", maxmsgs); + break; + case 7: set_color(CYAN, BLACK); + mvprintw(7, 6, "Read security"); + mvprintw(8, 6, "Write security"); + mvprintw(9, 6, "Sysop security"); + set_color(WHITE, BLACK); + show_sec(7, 21, rs); + show_sec(8, 21, ws); + show_sec(9, 21, ss); + break; + case 8: if (akan != -1) + mvprintw( 7, 6, "Set %s as new aka to use", aka2str(CFG.aka[akan])); + break; + case 9: mvprintw(7, 6, "Origin: %s", mfile); + break; + case 10:mvprintw(7, 6, "New netmail reply board %d", netbrd); + break; + case 11:mvprintw(7, 6, "Delete message areas"); + break; + } + + if (yes_no((char *)"Perform changes")) { + working(1, 0, 0); + Areas = CountMsgarea(); + Total = Done = 0; + + for (marea = 1; marea <= Areas; marea++) { + offset = LoadMsgRec(marea, FALSE); + if (msgs.Active && strlen(msgs.Group)) { + for (tmp = mgr; tmp; tmp = tmp->next) { + if (tmp->tagged && (strcmp(tmp->group, msgs.Group) == 0)) { + Total++; + switch (menu) { + case 1: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Deleted %s from %s", aka2str(a1), msgs.Tag); + } + break; + } + } + break; + case 2: fseek(tfil, 0, SEEK_SET); + Found = FALSE; + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) + if ((Sc.aka.zone == a2.zone) && + (Sc.aka.net == a2.net) && + (Sc.aka.node == a2.node) && + (Sc.aka.point == a2.point)) { + Found = TRUE; + break; + } + if (Found) + break; + fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if (Sc.aka.zone == 0) { + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + Sc.sendto = TRUE; + Sc.receivefrom = TRUE; + sprintf(Sc.aka.domain, "%s", a2.domain); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Added %s to area %s", aka2str(a2), msgs.Tag); + } + break; + } + } + break; + case 3: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + sprintf(Sc.aka.domain, "%s", a2.domain); + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + p = xstrcpy(aka2str(a1)); + Syslog('+', "Changed %s into %s in area %s", p, aka2str(a2), msgs.Tag); + free(p); + } + break; + } + } + break; + case 4: fseek(tfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, tfil) == 1) { + if ((Sc.aka.zone == S.aka.zone) && + (Sc.aka.net == S.aka.net) && + (Sc.aka.node == S.aka.node) && + (Sc.aka.point == S.aka.point)) { + Sc.sendto = S.sendto; + Sc.receivefrom = S.receivefrom; + Sc.pause = S.pause; + Sc.cutoff = S.cutoff; + fseek(tfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, tfil); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed status of %s in area %s", aka2str(S.aka), msgs.Tag); + } + break; + } + } + break; + case 5: if (daysold != msgs.DaysOld) { + msgs.DaysOld = daysold; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed days old to %d in area %s", daysold, msgs.Tag); + } + } + break; + case 6: if (maxmsgs != msgs.MaxMsgs) { + msgs.MaxMsgs = maxmsgs; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed max. messages to %d in area %s", maxmsgs, msgs.Tag); + } + } + break; + case 7: if ((msgs.RDSec.level != rs.level) || + (msgs.RDSec.flags != rs.flags) || + (msgs.RDSec.notflags != rs.notflags) || + (msgs.WRSec.level != ws.level) || + (msgs.WRSec.flags != ws.flags) || + (msgs.WRSec.notflags != ws.notflags) || + (msgs.SYSec.level != ss.level) || + (msgs.SYSec.flags != ss.flags) || + (msgs.SYSec.notflags != ss.notflags)) { + memcpy(&msgs.RDSec, &rs, sizeof(securityrec)); + memcpy(&msgs.WRSec, &ws, sizeof(securityrec)); + memcpy(&msgs.SYSec, &ss, sizeof(securityrec)); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Updated security levels in area %s", msgs.Tag); + } + } + break; + case 8: if (akan != -1) { + if ((msgs.Aka.zone != CFG.aka[akan].zone) || + (msgs.Aka.net != CFG.aka[akan].net) || + (msgs.Aka.node != CFG.aka[akan].node) || + (msgs.Aka.point != CFG.aka[akan].point)) { + msgs.Aka.zone = CFG.aka[akan].zone; + msgs.Aka.net = CFG.aka[akan].net; + msgs.Aka.node = CFG.aka[akan].node; + msgs.Aka.point = CFG.aka[akan].point; + sprintf(msgs.Aka.domain, "%s", CFG.aka[akan].domain); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Area %s now uses aka %s", msgs.Tag, aka2str(msgs.Aka)); + } + } + } + break; + case 9: if (strcmp(msgs.Origin, mfile)) { + sprintf(msgs.Origin, "%s", mfile); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed origin line in area %s", msgs.Tag); + } + } + break; + case 10:if (netbrd != msgs.NetReply) { + msgs.NetReply = netbrd; + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Changed netmail board to %d in area %s", netbrd, msgs.Tag); + } + } + break; + case 11:if (msgs.Active) { + msgs.Active = FALSE; + memset(&msgs.Name, 0, sizeof(msgs.Name)); + if (SaveMsgRec(marea, FALSE) == 0) { + Done++; + Syslog('+', "Deleted message area %s", msgs.Tag); + } + } + break; + } + } + } + } + if (tfil != NULL) + fclose(tfil); + } + + working(0, 0, 0); + mvprintw(LINES -3, 6,"Made %d changes in %d possible areas", Done, Total); + (void)readkey(LINES -3, 50, LIGHTGRAY, BLACK); + if (Done) + MsgUpdated = TRUE; + } + } + + tidy_grlist(&mgr); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditMsgRec(int); +int EditMsgRec(int Area) +{ + unsigned long crc1; + int tmp, i, changed = FALSE; + sysconnect System; + + clr_index(); + IsDoing("Edit Msg Area"); + + if (LoadMsgRec(Area, TRUE) == -1) + return -1; + + SetScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,40, msgs.Name); + show_str( 7,16,50, msgs.Tag); + show_str( 8,16,64, msgs.Newsgroup); + show_str( 9,16,64, msgs.Moderator); + show_str(10,16,64, msgs.Base); + show_str(11,16,64, msgs.Origin); + show_aka(12,16, msgs.Aka); + show_str(13,16,13, msgs.QWKname); + show_str(14,16,12, msgs.Group); + show_str(15,16,16, msgs.Distribution); + show_msgtype(16,16, msgs.Type); + show_msgkinds(17,16, msgs.MsgKinds); + show_str(18,16,16, printable(getchrs(msgs.Ftncode), 0)); + show_str(19,16,16, printable(getchrs(msgs.Rfccode), 0)); + + show_int( 13,52, msgs.DaysOld); + show_int( 14,52, msgs.MaxMsgs); + show_int( 15,52, msgs.NetReply); + show_bool(16,52, msgs.Active); + show_int( 17,52, msgs.RDSec.level); + show_int( 18,52, msgs.WRSec.level); + show_int( 19,52, msgs.SYSec.level); + + show_bool(12,76, msgs.UsrDelete); + show_bool(13,76, msgs.Aliases); + show_bool(14,76, msgs.Quotes); + show_bool(15,76, msgs.Mandatory); + show_bool(16,76, msgs.UnSecure); + show_bool(17,76, msgs.OLR_Default); + show_bool(18,76, msgs.OLR_Forced); + + switch(select_menu(29)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&msgs, crc1, msgshdr.recsize); + fseek(tfil, 0, 0); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, tfil); + crc1 = upd_crc32((char *)&System, crc1, sizeof(sysconnect)); + } + if ((MsgCrc != crc1) || (changed)) { + if (yes_no((char *)"Record is changed, save") == 1) { + if (SaveMsgRec(Area, TRUE) == -1) + return -1; + MsgUpdated = 1; + Syslog('+', "Saved record %d", Area); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 6,16,40,msgs.Name, "The ^Name^ of this area") + case 2: strcpy(msgs.Tag, edit_ups(7,16,50, msgs.Tag, (char *)"The ^Area Tag^ for Echomail")); + if (!strlen(msgs.QWKname)) { + memset(&msgs.QWKname, '\0', strlen(msgs.QWKname)); + strncpy(msgs.QWKname, msgs.Tag, 13); + } + break; + case 3: E_STR( 8,16,64,msgs.Newsgroup, "The ^Newsgroup^ name of this area") + case 4: E_STR( 9,16,64,msgs.Moderator, "The ^Moderator^ if this is a moderated area") + case 5: E_JAM( 10,16,64,msgs.Base, "The path to the ^JAM Message Base^") + case 6: E_STR( 11,16,64,msgs.Origin, "The ^Origin line^ to append to Echomail messages") + case 7: tmp = PickAka((char *)"9.2.7", TRUE); + if (tmp != -1) + msgs.Aka = CFG.aka[tmp]; + SetScreen(); break; + case 8: E_UPS( 13,16,13,msgs.QWKname, "The name for ^QWK or Bluewave^ message packets") + case 9: strcpy(msgs.Group, PickMGroup((char *)"9.2.9")); + if (strlen(msgs.Group)) { + msgs.Aka = mgroup.UseAka; + msgs.Active = TRUE; + /* + * If there is an uplink defined in the group, + * and the first connected system is empty, + * copy the uplink as default connection. + */ + if (mgroup.UpLink.zone) { + fseek(tfil, 0, SEEK_SET); + fread(&System, sizeof(sysconnect), 1, tfil); + if (!System.aka.zone) { + memset(&System, 0, sizeof(sysconnect)); + System.aka = mgroup.UpLink; + System.sendto = TRUE; + System.receivefrom = TRUE; + fseek(tfil, 0, SEEK_SET); + fwrite(&System, sizeof(sysconnect), 1, tfil); + } + } + } + SetScreen(); + break; + case 10:E_STR( 15,16,16,msgs.Distribution, "The ^Distribution^ name if this is a newsgroup") + case 11:msgs.Type = edit_msgtype(16,16, msgs.Type); break; + case 12:msgs.MsgKinds = edit_msgkinds(17,16, msgs.MsgKinds); break; + + case 15:E_INT( 13,52, msgs.DaysOld, "Maximum ^days^ to keep mail in this area") + case 16:E_INT( 14,52, msgs.MaxMsgs, "The ^maximum^ amount of messages in this area") + case 17:E_INT( 15,52, msgs.NetReply, "The ^Area Number^ for netmail replies") + case 18:E_BOOL(16,52, msgs.Active, "Is this area ^Active^") + case 19:E_SEC( 17,52, msgs.RDSec, "9.2 EDIT READ SECURITY", SetScreen) + case 20:E_SEC( 18,52, msgs.WRSec, "9.2 EDIT WRITE SECURITY", SetScreen) + case 21:E_SEC( 19,52, msgs.SYSec, "9.2 EDIT SYSOP SECURITY", SetScreen) + + case 22:E_BOOL(12,76, msgs.UsrDelete, "Allow users to ^Delete^ their messages") + case 23:E_BOOL(13,76, msgs.Aliases, "Allow ^aliases^ or real names only") + case 24:E_BOOL(14,76, msgs.Quotes, "Add random ^quotes^ to new messages") + case 25:E_BOOL(15,76, msgs.Mandatory, "Is this area ^mandatory^ for nodes") + case 26:E_BOOL(16,76, msgs.UnSecure, "Toss messages ^UnSecure^, ie: no originating check") + case 27:E_BOOL(17,76, msgs.OLR_Default, "Area is ^default^ for ^offline^ users.") + case 28:E_BOOL(18,76, msgs.OLR_Forced, "Area is ^always on^ for ^offline^ users.") + case 29:if (EditConnections(tfil)) + changed = TRUE; + SetScreen(); break; + } + } +} + + + +void EditMsgarea(void) +{ + int records, i, o, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + int from, too; + sysconnect System; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMsgarea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMsgarea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "9.2 MESSAGE AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mareas.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(msgshdr) + (((o + i) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, 0); + fread(&msgs, msgshdr.recsize, 1, fil); + if (msgs.Active) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d. %-8s %-25s %-40s", o + i, getmsgtype(msgs.Type), msgs.Tag, msgs.Name); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, 2, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_area(records, 10)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMsgarea(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMsgarea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "G", 1) == 0) { + MsgGlobal(); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 5, "From"); + from = edit_int(LINES -3, 10, from, (char *)"Wich ^area^ you want to move"); + mvprintw(LINES -3,15, "To"); + too = edit_int(LINES -3, 18, too, (char *)"Too which ^area^ to move"); + if ((LoadMsgRec(from, TRUE) == -1) || (!msgs.Active)) { + errmsg((char *)"The originating area is invalid"); + fclose(tfil); + } else { + fclose(tfil); + if ((LoadMsgRec(too, TRUE) == -1) || (msgs.Active)) { + errmsg((char *)"The destination area is invalid"); + fclose(tfil); + } else { + fclose(tfil); + LoadMsgRec(from, TRUE); + SaveMsgRec(too, TRUE); + LoadMsgRec(from, TRUE); + InitMsgRec(); + fseek(tfil, 0, SEEK_SET); + memset(&System, 0, sizeof(sysconnect)); + for (i = 0; i < (msgshdr.syssize / sizeof(sysconnect)); i++) { + fwrite(&System, sizeof(sysconnect), 1, tfil); + } + SaveMsgRec(from, TRUE); + MsgUpdated = 1; + } + } + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditMsgRec(atoi(pick)); + o = ((atoi(pick) - 1) / 10) * 10; + } + } +} + + + +char *PickMsgarea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char Buf[81]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountMsgarea(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MESSAGE AREA SELECT", shdr); + mvprintw(5, 3, temp); + set_color(CYAN, BLACK); + + if (records) { + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&msgshdr, sizeof(msgshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(msgshdr) + (((o + i) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, fil); + if (msgs.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, msgs.Name); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = msgshdr.hdrsize + ((atoi(pick) - 1) * (msgshdr.recsize + msgshdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&msgs, msgshdr.recsize, 1, fil); + fclose(fil); + if (msgs.Active) { + memset(&Buf, 0, sizeof(Buf)); + sprintf(Buf, "%s", msgs.Base); + return Buf; + } + } + } + } +} + + + +int GroupInMarea(char *Group) +{ + int Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + Area++; + + if (msgs.Active && !strcmp(msgs.Group, Group) && strlen(msgs.Group)) { + RetVal++; + Syslog('-', "Group %s in msg area %d: %s", Group, Area, msgs.Tag); + } + + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + return RetVal; +} + + + +int NodeInMarea(fidoaddr A) +{ + int i, Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + sysconnect S; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + Area++; + for (i = 0; i < systems; i++) { + fread(&S, sizeof(sysconnect), 1, no); + if (S.aka.zone && (S.aka.zone == A.zone) && (S.aka.net == A.net) && + (S.aka.node == A.node) && (S.aka.point == A.point) && msgs.Active) { + RetVal++; + Syslog('-', "Node %s connected to msg area %d: %s", aka2str(A), Area, msgs.Tag); + } + } + } + + fclose(no); + return RetVal; +} + + + +void gold_areas(FILE *fp) +{ + char *temp; + FILE *no; + int i = 0; + + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + + fprintf(fp, "; Message Areas\n;\n"); + fprintf(fp, "AREASCAN *\n"); + fprintf(fp, "AREATYPEORDER Net Email Echo News Local\n"); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + + i++; + if (msgs.Active) { + fprintf(fp, "AREADEF "); + if (strlen(msgs.Tag)) + fprintf(fp, "%s", msgs.Tag); + else + fprintf(fp, "AREA%d", i); + fprintf(fp, " \"%s\" ", msgs.Name); + switch (msgs.Type) { + case LOCALMAIL : fprintf(fp, "0 Local"); break; + case NETMAIL : fprintf(fp, "N Net"); break; + case ECHOMAIL : fprintf(fp, "C Echo"); break; + case NEWS : fprintf(fp, "I News"); break; + } + fprintf(fp, " JAM %s . ", msgs.Base); + if (msgs.Type == NETMAIL) + fprintf(fp, "(Loc Pvt)"); + else + fprintf(fp, "(Loc)"); + fprintf(fp, " \"%s\"\n", msgs.Origin); + } + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + free(temp); + fprintf(fp, "\n"); +} + + + +int mail_area_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], status[5]; + FILE *no; + int i = 0, j, systems, First = TRUE; + sysconnect System; + int LMiy; + struct tm *t; + time_t Now; + + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + if (Miy == 0) + LMiy = 11; + else + LMiy = Miy - 1; + + sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&msgshdr, sizeof(msgshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&msgshdr, msgshdr.hdrsize, 1, no); + systems = msgshdr.syssize / sizeof(sysconnect); + + while (fread(&msgs, msgshdr.recsize, 1, no) == 1) { + + i++; + if (msgs.Active) { + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 9, 2, page, (char *)"Mail areas"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Area number %d\n", i); + fprintf(fp, " Area name %s\n", msgs.Name); + fprintf(fp, " Area tag %s\n", msgs.Tag); + fprintf(fp, " Newsgroup name %s\n", msgs.Newsgroup); + fprintf(fp, " Distribution %s\n", msgs.Distribution); + fprintf(fp, " Moderator %s\n", msgs.Moderator); + fprintf(fp, " JAM message base %s\n", msgs.Base); + fprintf(fp, " Offline name %s\n", msgs.QWKname); + fprintf(fp, " Area type %s\n", getmsgtype(msgs.Type)); + fprintf(fp, " Messages type %s\n", getmsgkinds(msgs.MsgKinds)); + fprintf(fp, " FTN charset %s\n", printable(getchrs(msgs.Ftncode), 0)); + fprintf(fp, " RFC charset %s\n", printable(getchrs(msgs.Rfccode), 0)); + fprintf(fp, " Days old msgs. %d\n", msgs.DaysOld); + fprintf(fp, " Maximum msgs. %d\n", msgs.MaxMsgs); + fprintf(fp, " Users delete %s\n", getboolean(msgs.UsrDelete)); + fprintf(fp, " Read security %s\n", get_secstr(msgs.RDSec)); + fprintf(fp, " Write security %s\n", get_secstr(msgs.WRSec)); + fprintf(fp, " Sysop security %s\n", get_secstr(msgs.SYSec)); + fprintf(fp, " Minimum age %d\n", msgs.Age); + fprintf(fp, " Password %s\n", msgs.Password); + fprintf(fp, " Group %s\n", msgs.Group); + fprintf(fp, " Fido address %s\n", aka2str(msgs.Aka)); + fprintf(fp, " Netmail board %d\n", msgs.NetReply); + fprintf(fp, " Origin line %s\n", msgs.Origin); + fprintf(fp, " Allow aliases %s\n", getboolean(msgs.Aliases)); + fprintf(fp, " OLR mandatory %s\n", getboolean(msgs.OLR_Forced)); + fprintf(fp, " OLR default on %s\n", getboolean(msgs.OLR_Default)); + fprintf(fp, " Append quotes %s\n", getboolean(msgs.Quotes)); + fprintf(fp, " Nodes mandatory %s\n", getboolean(msgs.Mandatory)); + fprintf(fp, " UnSecure toss %s\n", getboolean(msgs.UnSecure)); + fprintf(fp, " Last msg rcvd. %s", ctime(&msgs.LastRcvd)); + fprintf(fp, " Last msg posted %s", ctime(&msgs.LastPosted)); + + for (j = 0; j < systems; j++) { + fread(&System, sizeof(sysconnect), 1, no); + if (System.aka.zone) { + memset(&status, 0, 5); + memset(&status, '-', 4); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.cutoff) + status[3] = 'C'; + + fprintf(fp, " Link %2d %s %s\n", j+1, status, aka2str(System.aka)); + } + } + fprintf(fp, "\n"); + fprintf(fp, " Total This Month Last Month\n"); + fprintf(fp, " ---------- ---------- ----------\n"); + fprintf(fp, " Msgs received %-10ld %-10ld %-10ld\n", msgs.Received.total, msgs.Received.month[Miy], msgs.Received.month[LMiy]); + fprintf(fp, " Msgs posted %-10ld %-10ld %-10ld\n", msgs.Posted.total, msgs.Posted.month[Miy], msgs.Posted.month[LMiy]); + + } else + fseek(no, msgshdr.syssize, SEEK_CUR); + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_marea.h b/mbsetup/m_marea.h new file mode 100644 index 00000000..8b22974b --- /dev/null +++ b/mbsetup/m_marea.h @@ -0,0 +1,17 @@ +#ifndef _MAREA_H +#define _MAREA_H + + +int OpenMsgarea(void); +void CloseMsgarea(int); +int GroupInMarea(char *); +int NodeInMarea(fidoaddr); +int CountMsgarea(void); +void EditMsgarea(void); +void gold_areas(FILE *); +int mail_area_doc(FILE *, FILE *, int); +char *PickMsgarea(char *); + + +#endif + diff --git a/mbsetup/m_menu.c b/mbsetup/m_menu.c new file mode 100644 index 00000000..db12d4d8 --- /dev/null +++ b/mbsetup/m_menu.c @@ -0,0 +1,597 @@ +/***************************************************************************** + * + * File ..................: mbsetup/m_menu.c + * Purpose ...............: Edit BBS menus + * Last modification date : 27-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "mutil.h" +#include "screen.h" +#include "ledit.h" +#include "m_lang.h" +#include "m_menu.h" + + + +char *select_menurec(int max) +{ + static char *menu=(char *)"-"; + char help[81]; + int pick; + + if (max > 10) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete, ^M^ove, ^P^revious, ^N^ext", max); + else if (max > 1) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete, ^M^ove", max); + else if (max == 1) + sprintf(help, "Rec. (1..%d), ^\"-\"^ Back, ^A^ppend, ^D^elete", max); + else + sprintf(help, "Select ^\"-\"^ for previous level, ^A^ppend a record"); + + showhelp(help); + + for (;;) { + mvprintw(LINES - 3, 6, "Enter your choice >"); + menu = (char *)"-"; + menu = edit_field(LINES - 3, 26, 6, '!', menu); + locate(LINES -3, 6); + clrtoeol(); + + if (strncmp(menu, "A", 1) == 0) + break; + if (strncmp(menu, "-", 1) == 0) + break; + if (strncmp(menu, "D", 1) == 0) + break; + if ((max > 1) && (strncmp(menu, "M", 1) == 0)) + break; + + if (max > 10) { + if (strncmp(menu, "N", 1) == 0) + break; + if (strncmp(menu, "P", 1) == 0) + break; + } + pick = atoi(menu); + if ((pick >= 1) && (pick <= max)) + break; + + working(2, 0, 0); + working(0, 0, 0); + } + return menu; +} + + + +void Show_A_Menu(void); +void Show_A_Menu(void) +{ + char *p; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.3. EDIT MENU ITEM"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Sel. key"); + mvprintw( 8, 2, "2. Type nr."); + mvprintw( 9, 2, "3. Opt. data"); + mvprintw(10, 2, "4. Display"); + mvprintw(11, 2, "5. Security"); + mvprintw(12, 2, "6. Min. age"); + mvprintw(13, 2, "7. Max. lvl"); + mvprintw(14, 2, "8. Password"); + mvprintw(15, 2, "9. Credit"); + mvprintw(16, 2, "10. Colors"); + mvprintw(12,42, "11. Autoexec"); + mvprintw(13,42, "12. Menu open"); + if (menus.MenuType == 7) { + mvprintw(14,42, "13. No door.sys"); + mvprintw(15,42, "14. Y2K style"); + mvprintw(16,42, "15. Use Comport"); + } + + set_color(WHITE, BLACK); + show_str( 7,16, 1, menus.MenuKey); + show_int( 8,16, menus.MenuType); show_str( 8, 26,29, menus.TypeDesc); + show_str( 9,16,64, menus.OptionalData); + show_str(10,16,64, menus.Display); + show_sec(11,16, menus.MenuSecurity); + show_int(12,16, menus.Age); + show_int(13,16, menus.MaxSecurity); + if (strlen(menus.Password)) + show_str(14,16,14, (char *)"**************"); + else + show_str(14,16,14, (char *)""); + show_int(15,16, menus.Credit); + S_COL(16,16, "Display color", menus.ForeGnd, menus.BackGnd) + set_color(WHITE, BLACK); + show_bool(12,58, menus.AutoExec); + if ((menus.OpenFrom == 0) && (menus.OpenTo == 0)) + show_str(13,58, 6, (char *)"Always"); + else { + p = calloc(40, sizeof(char)); + sprintf(p, "%02d:%02d - %02d:%02d", menus.OpenFrom / 60, menus.OpenFrom % 60, + menus.OpenTo / 60, menus.OpenTo % 60); + show_str(13, 58, 13, p); + free(p); + } + if (menus.MenuType == 7) { + show_bool(14,58, menus.NoDoorsys); + show_bool(15,58, menus.Y2Kdoorsys); + show_bool(16,58, menus.Comport); + } +} + + + +int GetSubmenu(int, int); +int GetSubmenu(int Base, int Max) +{ + int i, x, y; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "8.3 EDIT MENU - SELECT MENUTYPE"); + set_color(CYAN, BLACK); + y = 6; + x = 2; + + for (i = 1; i <= Max; i++) { + sprintf(temp, "%2d. %s", i, getmenutype(i - 1 + Base)); + mvprintw(y, x, temp); + y++; + if ((i % 13) == 0) { + y = 6; + x = 42; + } + } + i = select_menu(Max); + + if (i) + return (i + Base - 1); + else + return 0; +} + + + +int GetMenuType(void); +int GetMenuType(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.3 EDIT MENU - SELECT MENUTYPE"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Global system menus"); + mvprintw( 8, 6, "2. File areas menus"); + mvprintw( 9, 6, "3. Message areas menus"); + mvprintw(10, 6, "4. User setting menus"); + mvprintw(11, 6, "5. Oneliner menus"); + mvprintw(12, 6, "6. BBS List menus"); + + switch (select_menu(6)) { + case 1: return GetSubmenu(1, 25); + case 2: return GetSubmenu(101, 19); + case 3: return GetSubmenu(201, 20); + case 4: return GetSubmenu(301, 16); + case 5: return GetSubmenu(401, 5); + case 6: return GetSubmenu(501, 6); + default: return 0; + } +} + + + +void Edit_A_Menu(void); +void Edit_A_Menu(void) +{ + Show_A_Menu(); + + for (;;) { + switch(select_menu(15)) { + case 0: + return; + break; + + case 1: E_UPS( 7,16, 1, menus.MenuKey, "The ^key^ to select this menu item") + case 2: menus.MenuType = GetMenuType(); + memset(&menus.TypeDesc, 0, sizeof(menus.TypeDesc)); + if (menus.MenuType) + strcpy(menus.TypeDesc, getmenutype(menus.MenuType)); + Show_A_Menu(); + break; + case 3: E_STR( 9,16,64, menus.OptionalData, "The ^optional data^ for this menu item") + case 4: E_STR(10,16,64, menus.Display, "The text to ^display^ for this menu") + case 5: E_SEC(11,16, menus.MenuSecurity, "7.3.5 MENU ACCESS SECURITY", Show_A_Menu) + case 6: E_INT(12,16, menus.Age, "The minimum ^Age^ to select this menu, 0 is don't care") + case 7: E_INT(13,16, menus.MaxSecurity, "The maximum ^Security level^ to access this menu") + case 8: E_STR(14,16,14, menus.Password, "The ^password^ to access this menu item") + case 9: E_INT(15,16, menus.Credit, "The ^credit cost^ for this menu item") + case 10:edit_color(&menus.ForeGnd, &menus.BackGnd, (char *)"Display color"); + Show_A_Menu(); + break; + case 11:E_BOOL(12,58, menus.AutoExec, "Is this an ^Autoexecute^ menu item") + case 13:if (menus.MenuType == 7) { + E_BOOL(14,58, menus.NoDoorsys, "Suppress writing ^door.sys^ dropfile") + } else + break; + case 14:if (menus.MenuType == 7) { + E_BOOL(15,58, menus.Y2Kdoorsys, "Create ^door.sys^ with 4 digit yearnumbers") + } else + break; + case 15:if (menus.MenuType == 7) { + E_BOOL(16,58, menus.Comport, "Write real ^COM port^ in door.sys for Vmodem patch") + } else + break; + } + } +} + + + +void EditMenu(char *); +void EditMenu(char *Name) +{ + char mtemp[81], temp[161]; + FILE *fil, *tmp; + int records = 0, i, o, y; + char pick[12]; + long offset; + unsigned long crc, crc1; + int MenuUpdated = FALSE, from, too; + struct menufile tmenus; + + clr_index(); + IsDoing("Edit Menu"); + working(1, 0, 0); + + sprintf(mtemp, "%s/%s.tmp", lang.MenuPath, Name); + tmp = fopen(mtemp, "w+"); + + sprintf(temp, "%s/%s.mnu", lang.MenuPath, Name); + if ((fil = fopen(temp, "r")) != NULL) { + while (fread(&menus, sizeof(menus), 1, fil) == 1) { + fwrite(&menus, sizeof(menus), 1, tmp); + records++; + } + fclose(fil); + } + + o = 0; + for (;;) { + clr_index(); + working(1, 0, 0); + sprintf(temp, "8.3 EDIT MENU \"%s\" (%s)", Name, lang.Name); + mvprintw( 5, 6, tu(temp)); + set_color(CYAN, BLACK); + fseek(tmp, 0, SEEK_SET); + + if (records) { + y = 7; + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = ((o + i) - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + if ((menus.MenuKey[0]) || menus.AutoExec) { + set_color(CYAN, BLACK); + mvprintw(y, 5, "%3d. ", o + i); + if (menus.AutoExec) { + set_color(LIGHTRED, BLACK); + mvprintw(y, 10, "a"); + set_color(CYAN, BLACK); + } else + mvprintw(y, 10, "%1s", menus.MenuKey); + mvprintw(y, 12, "%-29s %5d %s", menus.TypeDesc, + menus.MenuSecurity.level, menus.OptionalData); + } else { + set_color(LIGHTBLUE, BLACK); + mvprintw(y, 5, "%3d.", o + i); + } + y++; + } + } + } + + working(0, 0, 0); + strcpy(pick, select_menurec(records)); + + if (strncmp(pick, "-", 1) == 0) { + if (MenuUpdated) { + if (yes_no((char *)"Menu is changed, save changes") == 1) { + working(1, 0, 0); + sprintf(temp, "%s/%s.mnu", lang.MenuPath, Name); + if ((fil = fopen(temp, "w+")) == NULL) { + working(2, 0, 0); + } else { + fseek(tmp, 0, SEEK_SET); + while (fread(&menus, sizeof(menus), 1, tmp) == 1) { + if (menus.MenuKey[0] || menus.AutoExec) + fwrite(&menus, sizeof(menus), 1, fil); + } + fclose(fil); + } + working(0, 0, 0); + } + } + fclose(tmp); + unlink(mtemp); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + memset(&menus, 0, sizeof(menus)); + fseek(tmp, 0, SEEK_END); + fwrite(&menus, sizeof(menus), 1, tmp); + records++; + working(0, 0, 0); + } + + if (strncmp(pick, "D", 1) == 0) { + mvprintw(LINES -3, 6, "Enter menu number (1..%d) to delete >", records); + y = 0; + y = edit_int(LINES -3, 44, y, (char *)"Enter record number"); + if ((y > 0) && (y <= records) && yes_no((char *)"Remove record")) { + offset = (y - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + menus.MenuKey[0] = '\0'; + menus.AutoExec = FALSE; + fseek(tmp, offset, SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + } + } + + if (strncmp(pick, "M", 1) == 0) { + from = too = 0; + mvprintw(LINES -3, 6, "Enter menu number (1..%d) to move >", records); + from = edit_int(LINES -3, 42, from, (char *)"Enter record number"); + locate(LINES -3, 6); + clrtoeol(); + mvprintw(LINES -3, 6, "Enter new position (1..%d) >", records); + too = edit_int(LINES -3, 36, too, (char *)"Enter destination record number, other will move away"); + if ((from == too) || (from == 0) || (too == 0) || (from > records) || (too > records)) { + errmsg("That makes no sense"); + } else if (yes_no((char *)"Proceed move")) { + fseek(tmp, (from -1) * sizeof(menus), SEEK_SET); + fread(&tmenus, sizeof(menus), 1, tmp); + if (from > too) { + for (i = from; i > too; i--) { + fseek(tmp, (i -2) * sizeof(menus), SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + fseek(tmp, (i -1) * sizeof(menus), SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + } + } else { + for (i = from; i < too; i++) { + fseek(tmp, i * sizeof(menus), SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + fseek(tmp, (i -1) * sizeof(menus), SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + } + } + fseek(tmp, (too -1) * sizeof(menus), SEEK_SET); + fwrite(&tmenus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + } + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o += 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o -= 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = (atoi(pick) - 1) * sizeof(menus); + fseek(tmp, offset, SEEK_SET); + fread(&menus, sizeof(menus), 1, tmp); + crc = 0xffffffff; + crc = upd_crc32((char *)&menus, crc, sizeof(menus)); + Edit_A_Menu(); + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&menus, crc1, sizeof(menus)); + if (crc1 != crc) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + fseek(tmp, offset, SEEK_SET); + fwrite(&menus, sizeof(menus), 1, tmp); + MenuUpdated = TRUE; + working(0, 0, 0); + } + } + } + } +} + + + +void EditMenus(void) +{ + int Lang, mcount, err, i, x, y; + DIR *dp; + FILE *fil; + struct dirent *de; + char menuname[50][11]; + char temp[81], pick[12], *p; + + Syslog('+', "Start menu edit"); + memset(&menuname, 0, sizeof(menuname)); + Lang = PickLanguage((char *)"8.3"); + if (Lang == '\0') + return; + + for (;;) { + clr_index(); + mcount = 0; + if ((dp = opendir(lang.MenuPath)) != NULL) { + working(1, 0, 0); + + while ((de = readdir(dp))) { + if (de->d_name[0] != '.') { + strcpy(menuname[mcount], strtok(de->d_name, ".")); + mcount++; + } + } + closedir(dp); + working(0, 0, 0); + } + + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.3 MENU EDIT: %s", lang.Name); + set_color(CYAN, BLACK); + + if (mcount) { + x = 6; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= mcount; i++) { + sprintf(temp, "%2d. %s", i, menuname[i-1]); + mvprintw(y, x, temp); + y++; + if ((i % 10) == 0) { + x+=15; + y = 7; + } + } + } + strcpy(pick, select_record(mcount, 50)); + + if (strncmp(pick, "-", 1) == 0) { + Syslog('+', "Finished menu edit"); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + set_color(WHITE, BLACK); + mvprintw(LINES -3, 6, (char *)"New menu name >"); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, edit_str(LINES -3, 22, 10, temp, (char *)"Enter a new ^menu^ name without extension")); + if (strlen(temp)) { + p = xstrcpy(lang.MenuPath); + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, temp); + p = xstrcat(p, (char *)".mnu"); + if ((err = file_exist(p, F_OK))) { + if ((fil = fopen(p, "a")) == NULL) { + errmsg("Can't create menu %s", temp); + } else { + fclose(fil); + Syslog('+', "Created menufile %s", p); + } + } else { + errmsg("Menu %s already exists", temp); + } + free(p); + } + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= mcount)) + EditMenu(menuname[atoi(pick) -1]); + } +} + + + +int bbs_menu_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no, *mn; + DIR *dp; + struct dirent *de; + int j; + + sprintf(temp, "%s/etc/language.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 3, page, (char *)"BBS Menus"); + + fread(&langhdr, sizeof(langhdr), 1, no); + j =0; + + while ((fread(&lang, langhdr.recsize, 1, no)) == 1) { + if ((dp = opendir(lang.MenuPath)) != NULL) { + while ((de = readdir(dp))) { + if (de->d_name[0] != '.') { + j = 0; + sprintf(temp, "%s/%s", lang.MenuPath, de->d_name); + fprintf(fp, " MENU %s (%s)\n\n", de->d_name, lang.Name); + if ((mn = fopen(temp, "r")) != NULL) { + while (fread(&menus, sizeof(menus), 1, mn) == 1) { + if (menus.MenuKey[0]) + fprintf(fp, " Menu select %s\n", menus.MenuKey); + if (menus.AutoExec) + fprintf(fp, " Menu select Autoexec\n"); + fprintf(fp, " Type %d %s\n", menus.MenuType, menus.TypeDesc); + fprintf(fp, " Opt. data %s\n", menus.OptionalData); + fprintf(fp, " Display %s\n", menus.Display); + fprintf(fp, " Security %s\n", get_secstr(menus.MenuSecurity)); + fprintf(fp, " Minimum age %d\n", menus.Age); + fprintf(fp, " Maximum level %d\n", menus.MaxSecurity); + fprintf(fp, " Password %s\n", menus.Password); + fprintf(fp, " Credits %ld\n", menus.Credit); + if (menus.MenuType == 7) { + fprintf(fp, " No door.sys %s\n", getboolean(menus.NoDoorsys)); + fprintf(fp, " Y2K door.sys %s\n", getboolean(menus.Y2Kdoorsys)); + fprintf(fp, " Use COM port %s\n", getboolean(menus.Comport)); + } + fprintf(fp, "\n\n"); + j++; + if (j == 5) { + j = 0; + page = newpage(fp, page); + } + } + fclose(mn); + } + if (j) + page = newpage(fp, page); + } + } + closedir(dp); + } + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_menu.h b/mbsetup/m_menu.h new file mode 100644 index 00000000..55fc2e8c --- /dev/null +++ b/mbsetup/m_menu.h @@ -0,0 +1,9 @@ +#ifndef _M_MENU_H +#define _M_MENU_H + +char *select_menurec(int); +void EditMenus(void); +int bbs_menu_doc(FILE *, FILE*, int); + +#endif + diff --git a/mbsetup/m_mgroup.c b/mbsetup/m_mgroup.c new file mode 100644 index 00000000..43dfd7ca --- /dev/null +++ b/mbsetup/m_mgroup.c @@ -0,0 +1,570 @@ +/***************************************************************************** + * + * File ..................: setup/m_mgroups.c + * Purpose ...............: Setup MGroups. + * Last modification date : 12-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_marea.h" +#include "m_mgroup.h" + + + +int MGrpUpdated = 0; + + +/* + * Count nr of mgroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountMGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.recsize = sizeof(mgroup); + fwrite(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - mgrouphdr.hdrsize) / mgrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenMGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + MGrpUpdated = 0; + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fin); + if (mgrouphdr.hdrsize != sizeof(mgrouphdr)) { + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.lastupd = time(NULL); + MGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = mgrouphdr.recsize; + if (oldsize != sizeof(mgroup)) + MGrpUpdated = 1; + mgrouphdr.hdrsize = sizeof(mgrouphdr); + mgrouphdr.recsize = sizeof(mgroup); + fwrite(&mgrouphdr, sizeof(mgrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&mgroup, 0, sizeof(mgroup)); + while (fread(&mgroup, oldsize, 1, fin) == 1) { + fwrite(&mgroup, sizeof(mgroup), 1, fout); + memset(&mgroup, 0, sizeof(mgroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseMGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mgr = NULL, *tmp; + + sprintf(fin, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + + if (MGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, fi); + fwrite(&mgrouphdr, mgrouphdr.hdrsize, 1, fo); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fi) == 1) + if (!mgroup.Deleted) + fill_stlist(&mgr, mgroup.Name, ftell(fi) - mgrouphdr.recsize); + sort_stlist(&mgr); + + for (tmp = mgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&mgroup, mgrouphdr.recsize, 1, fi); + fwrite(&mgroup, mgrouphdr.recsize, 1, fo); + } + + tidy_stlist(&mgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"mgroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendMGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&mgroup, 0, sizeof(mgroup)); + time(&mgroup.StartDate); + fwrite(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + MGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +void MgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.1 EDIT MESSAGE GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Use Aka"); + mvprintw(11, 6, "5. Uplink"); + mvprintw(12, 6, "6. Areas"); + mvprintw(13, 6, "7. Deleted"); +} + + + +/* + * Check if field can be edited without screwing up the database. + */ +int CheckMgroup(void); +int CheckMgroup(void) +{ + int ncnt, mcnt; + + working(1, 0, 0); + ncnt = GroupInNode(mgroup.Name, TRUE); + mcnt = GroupInMarea(mgroup.Name); + working(0, 0, 0); + if (ncnt || mcnt) { + errmsg((char *)"Error, %d node(s) and/or %d message area(s) connected", ncnt, mcnt); + return TRUE; + } + return FALSE; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditMGrpRec(int Area) +{ + FILE *fil; + static char mfile[PATH_MAX]; + static long offset; + static int j, tmp; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit MessageGroup"); + + sprintf(mfile, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(mgrouphdr) + ((Area -1) * sizeof(mgroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&mgroup, crc, sizeof(mgroup)); + working(0, 0, 0); + MgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,18,12, mgroup.Name); + show_str( 8,18,55, mgroup.Comment); + show_bool( 9,18, mgroup.Active); + show_aka( 10,18, mgroup.UseAka); + show_aka( 11,18, mgroup.UpLink); + show_str( 12,18,12, mgroup.AreaFile); + show_bool(13,18, mgroup.Deleted); + + j = select_menu(7); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&mgroup, crc1, sizeof(mgroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + WriteError("$Can't reopen %s", mfile); + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&mgroup, sizeof(mgroup), 1, fil); + fclose(fil); + MGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: if (CheckMgroup()) + break; + E_UPS( 7,18,12,mgroup.Name,"The ^name^ for this message group") + case 2: E_STR( 8,18,55,mgroup.Comment,"The ^desription^ for this message group") + case 3: if (CheckMgroup()) + break; + E_BOOL(9,18, mgroup.Active, "Is this message group ^active^") + case 4: tmp = PickAka((char *)"9.1.4", TRUE); + if (tmp != -1) + memcpy(&mgroup.UseAka, &CFG.aka[tmp], sizeof(fidoaddr)); + MgScreen(); + break; + case 5: mgroup.UpLink = PullUplink((char *)"9.1.5"); + MgScreen(); + break; + case 6: E_STR(12,18,12,mgroup.AreaFile,"The name of the ^Areas File^ from the uplink") + case 7: if (CheckMgroup()) + break; + E_BOOL(13,18, mgroup.Deleted, "Is this group ^Deleted^") + } + } + + return 0; +} + + + +void EditMGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountMGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenMGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "9.1 MESSAGE GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mgroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(mgrouphdr) + (((o + i) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + if (mgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, mgroup.Name, mgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseMGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendMGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditMGrpRec(atoi(pick)); + } +} + + + +char *PickMGroup(char *shdr) +{ + static char MGrp[21] = ""; + int records, i, o = 0, y, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return MGrp; + } + + records = CountMGroup(); + if (records == -1) { + working(2, 0, 0); + return MGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MESSAGE GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(mgrouphdr) + (((o + i) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + if (mgroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, mgroup.Name, mgroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return MGrp; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = sizeof(mgrouphdr) + ((atoi(pick) - 1) * mgrouphdr.recsize); + fseek(fil, offset, 0); + fread(&mgroup, mgrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(MGrp, mgroup.Name); + return MGrp; + } + } +} + + + +int mail_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 9, 1, page, (char *)"Mail processing groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&mgrouphdr, sizeof(mgrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&mgrouphdr, mgrouphdr.hdrsize, 1, no); + + while ((fread(&mgroup, mgrouphdr.recsize, 1, no)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", mgroup.Name); + fprintf(fp, " Comment %s\n", mgroup.Comment); + fprintf(fp, " Active %s\n", getboolean(mgroup.Active)); + fprintf(fp, " Use Aka %s\n", aka2str(mgroup.UseAka)); + fprintf(fp, " Uplink %s\n", aka2str(mgroup.UpLink)); + fprintf(fp, " Areas file %s\n", mgroup.AreaFile); + fprintf(fp, " Start date %s", ctime(&mgroup.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&mgroup.LastDate)); + +// fprintf(fp, " Total This month Last month\n"); +// fprintf(fp, " ---------- ---------- ----------\n"); +// fprintf(fp, " Messages %-10ld %-10ld %-10ld\n", mgroup.Total.files, mgroup.ThisMonth.files, mgroup.LastMonth.files); +// fprintf(fp, " Kilobytes %-10ld %-10ld %-10ld\n", mgroup.Total.kbytes, mgroup.ThisMonth.kbytes, mgroup.LastMonth.kbytes); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_mgroup.h b/mbsetup/m_mgroup.h new file mode 100644 index 00000000..6999af0b --- /dev/null +++ b/mbsetup/m_mgroup.h @@ -0,0 +1,12 @@ +#ifndef _MGROUP_H +#define _MGROUP_H + + +int CountMGroup(void); +void EditMGroup(void); +char *PickMGroup(char *); +int mail_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_modem.c b/mbsetup/m_modem.c new file mode 100644 index 00000000..e572dd6f --- /dev/null +++ b/mbsetup/m_modem.c @@ -0,0 +1,716 @@ +/***************************************************************************** + * + * File ..................: setup/m_modem.c + * Purpose ...............: Setup Modem structure. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_modem.h" + + + +int ModemUpdated = 0; + + +/* + * Count nr of modem records in the database. + * Creates the database if it doesn't exist. + */ +int CountModem(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + modemhdr.hdrsize = sizeof(modemhdr); + modemhdr.recsize = sizeof(modem); + fwrite(&modemhdr, sizeof(modemhdr), 1, fil); + + /* + * Create some default modem types + */ + memset(&modem, 0, sizeof(modem)); + sprintf(modem.modem, "Dynalink 1428EXTRA"); + sprintf(modem.init[0], "AT Z\\r"); + sprintf(modem.init[1], "AT &F &C1 &D2 X4 W2 B0 M0 \\\\V1 \\\\G0 &K3 S37=0\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.connect[0], "CONNECT 33600"); + sprintf(modem.connect[1], "CONNECT 31200"); + sprintf(modem.connect[2], "CONNECT 28800"); + sprintf(modem.connect[3], "CONNECT 26400"); + sprintf(modem.connect[4], "CONNECT 24000"); + sprintf(modem.connect[5], "CONNECT 21600"); + sprintf(modem.connect[6], "CONNECT 19200"); + sprintf(modem.connect[7], "CONNECT 16800"); + sprintf(modem.connect[8], "CONNECT 14400"); + sprintf(modem.connect[9], "CONNECT 12000"); + sprintf(modem.connect[10], "CONNECT 9600"); + sprintf(modem.connect[11], "CONNECT 7200"); + sprintf(modem.connect[12], "CONNECT 4800"); + sprintf(modem.connect[13], "CONNECT 2400"); + sprintf(modem.connect[14], "CONNECT 1200"); + sprintf(modem.connect[15], "CONNECT 300"); + sprintf(modem.reset, "AT&F&C1&D2X4W2B0M0&K3\\r"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.error[6], "CONNECT VOICE"); + sprintf(modem.speed, "28800"); + modem.available = TRUE; + modem.costoffset = 6; + fwrite(&modem, sizeof(modem), 1, fil); + + sprintf(modem.modem, "ISDN Dynalink"); + sprintf(modem.init[0], "ATZ\\r"); + sprintf(modem.init[1], "AT&E3306018793\\r"); + sprintf(modem.init[2], "AT&B512\\r"); + sprintf(modem.hangup, "ATH0\\r"); + sprintf(modem.speed, "64000"); + modem.costoffset = 1; + fwrite(&modem, sizeof(modem), 1, fil); + + sprintf(modem.modem, "Standard Hayes V34"); + sprintf(modem.init[0], "ATZ\\r"); + memset(&modem.init[1], 0, sizeof(modem.init[1])); + memset(&modem.init[2], 0, sizeof(modem.init[2])); + memset(&modem.hangup, 0, sizeof(modem.hangup)); + sprintf(modem.speed, "33600"); + modem.costoffset = 6; + fwrite(&modem, sizeof(modem), 1, fil); + + memset(&modem, 0, sizeof(modem)); + sprintf(modem.modem, "ISDN Linux"); + sprintf(modem.init[0], "AT Z\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.info, "ATI2\\r"); + sprintf(modem.hangup, "\\d\\p\\p\\p+++\\d\\p\\p\\pATH0\\r"); + sprintf(modem.connect[0], "CONNECT 64000"); + sprintf(modem.connect[1], "CONNECT"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.speed, "64000"); + modem.available = TRUE; + modem.costoffset = 1; + fwrite(&modem, sizeof(modem), 1, fil); + + fclose(fil); + return 4; + } else + return -1; + } + + fread(&modemhdr, sizeof(modemhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - modemhdr.hdrsize) / modemhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenModem(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/modem.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = modemhdr.recsize; + if (oldsize != sizeof(modem)) + ModemUpdated = 1; + else + ModemUpdated = 0; + modemhdr.hdrsize = sizeof(modemhdr); + modemhdr.recsize = sizeof(modem); + fwrite(&modemhdr, sizeof(modemhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&modem, 0, sizeof(modem)); + while (fread(&modem, oldsize, 1, fin) == 1) { + fwrite(&modem, sizeof(modem), 1, fout); + memset(&modem, 0, sizeof(modem)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseModem(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mdm = NULL, *tmp; + + sprintf(fin, "%s/etc/modem.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/modem.temp", getenv("MBSE_ROOT")); + + if (ModemUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&modemhdr, modemhdr.hdrsize, 1, fi); + fwrite(&modemhdr, modemhdr.hdrsize, 1, fo); + + while (fread(&modem, modemhdr.recsize, 1, fi) == 1) + if (!modem.deleted) + fill_stlist(&mdm, modem.modem, ftell(fi) - modemhdr.recsize); + sort_stlist(&mdm); + + for (tmp = mdm; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fi); + fwrite(&modem, modemhdr.recsize, 1, fo); + } + + tidy_stlist(&mdm); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"modem.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendModem(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&modem, 0, sizeof(modem)); + sprintf(modem.init[0], "ATZ\\r"); + sprintf(modem.ok, "OK"); + sprintf(modem.dial, "ATDT\\T\\r"); + sprintf(modem.connect[0], "CONNECT 33600"); + sprintf(modem.connect[1], "CONNECT 31200"); + sprintf(modem.connect[2], "CONNECT 28800"); + sprintf(modem.connect[3], "CONNECT 26400"); + sprintf(modem.connect[4], "CONNECT 24000"); + sprintf(modem.connect[5], "CONNECT 21600"); + sprintf(modem.connect[6], "CONNECT 19200"); + sprintf(modem.connect[7], "CONNECT 16800"); + sprintf(modem.connect[8], "CONNECT 14400"); + sprintf(modem.connect[9], "CONNECT 12000"); + sprintf(modem.connect[10], "CONNECT 9600"); + sprintf(modem.connect[11], "CONNECT 7200"); + sprintf(modem.connect[12], "CONNECT 4800"); + sprintf(modem.connect[13], "CONNECT 2400"); + sprintf(modem.connect[14], "CONNECT 1200"); + sprintf(modem.connect[15], "CONNECT 300"); + sprintf(modem.error[0], "BUSY"); + sprintf(modem.error[1], "NO CARRIER"); + sprintf(modem.error[2], "NO DIALTONE"); + sprintf(modem.error[3], "NO ANSWER"); + sprintf(modem.error[4], "RING\\r"); + sprintf(modem.error[5], "ERROR"); + sprintf(modem.speed, "28800"); + sprintf(modem.reset, "AT\\r"); + modem.available = TRUE; + fwrite(&modem, sizeof(modem), 1, fil); + fclose(fil); + ModemUpdated = 1; + return 0; + } else + return -1; +} + + + +void Modem_Screen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5. EDIT MODEM TYPE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Type"); + mvprintw( 8, 2, "2. Init 1"); + mvprintw( 9, 2, "3. Init 2"); + mvprintw(10, 2, "4. Init 3"); + mvprintw(11, 2, "5. Reset"); + mvprintw(12, 2, "6. Hangup"); + mvprintw(13, 2, "7. Dial"); + mvprintw(14, 2, "8. Info"); + mvprintw(15, 2, "9. Ok"); + mvprintw(16, 2, "10. Offset"); + mvprintw(17, 2, "11. Speed"); + + mvprintw(15,30, "12. Available"); + mvprintw(16,30, "13. Deleted"); + mvprintw(17,30, "14. Stripdash"); + + mvprintw(15,58, "15. Connect strings"); + mvprintw(16,58, "16. Error strings"); +} + + + +void EditConnect(void) +{ + int i, j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5.15 EDIT MODEM CONNECT STRINGS"); + set_color(CYAN, BLACK); + + for (i = 0; i < 10; i++) { + mvprintw( 7+i, 2, (char *)"%2d.", i+1); + mvprintw( 7+i,42, (char *)"%2d.", i+11); + } + + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 7+i, 8, 30, modem.connect[i]); + show_str( 7+i,48, 30, modem.connect[i+10]); + } + + j = select_menu(20); + if (j == 0) + return; + if (j < 11) + strcpy(modem.connect[j-1], edit_str(6+j, 8,30, modem.connect[j-1], (char *)"^Connect^ string")); + else + strcpy(modem.connect[j-1], edit_str(j-4,48,30, modem.connect[j-1], (char *)"^Connect^ string")); + } +} + + + +void EditError(void) +{ + int i, j; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "5.16 EDIT MODEM ERROR STRINGS"); + set_color(CYAN, BLACK); + + for (i = 0; i < 10; i++) { + mvprintw( 7+i, 2, (char *)"%2d.", i+1); + } + + for (;;) { + set_color(WHITE, BLACK); + for (i = 0; i < 10; i++) { + show_str( 7+i, 8, 20, modem.error[i]); + } + + j = select_menu(10); + if (j == 0) + return; + strcpy(modem.error[j-1], edit_str(6+j, 8,20, modem.error[j-1], (char *)"^Error^ string")); + } +} + + + +int EditModemRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Modem"); + + sprintf(mfile, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(modemhdr) + ((Area -1) * sizeof(modem)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&modem, sizeof(modem), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&modem, crc, sizeof(modem)); + working(0, 0, 0); + Modem_Screen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,14,30, modem.modem); + show_str( 8,14,60, modem.init[0]); + show_str( 9,14,60, modem.init[1]); + show_str(10,14,60, modem.init[2]); + show_str(11,14,60, modem.reset); + show_str(12,14,40, modem.hangup); + show_str(13,14,40, modem.dial); + show_str(14,14,40, modem.info); + show_str(15,14,10, modem.ok); + show_int(16,14, modem.costoffset); + show_str(17,14,15, modem.speed); + + show_bool(15,44, modem.available); + show_bool(16,44, modem.deleted); + show_bool(17,44, modem.stripdash); + + j = select_menu(16); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&modem, crc1, sizeof(modem)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&modem, sizeof(modem), 1, fil); + fclose(fil); + ModemUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,14,30, modem.modem, "The ^Type^ or brand of this modem") + case 2: E_STR( 8,14,60, modem.init[0], "The ^first init^ string for this modem") + case 3: E_STR( 9,14,60, modem.init[1], "The ^second init^ string for this modem") + case 4: E_STR(10,14,60, modem.init[2], "The ^third init^ string for this modem") + case 5: E_STR(11,14,60, modem.reset, "The ^reset^ string for this modem") + case 6: E_STR(12,14,40, modem.hangup, "The ^hangup^ string for this modem (Leave empty for ^DTR-drop^ hangup)") + case 7: E_STR(13,14,40, modem.dial, "The ^dial^ command for this modem, ^\\T^ is translated phonenumber") + case 8: E_STR(14,14,40, modem.info, "The command to get connection ^info^ from this modem after call") + case 9: E_STR(15,14,10, modem.ok, "The ^OK^ string to get from the modem") + case 10:E_INT(16,14, modem.costoffset, "The ^offset^ time in seconds between answer and connect string") + case 11:E_STR(17,14,15, modem.speed, "The ^EMSI speed^ message for this modem") + case 12:E_BOOL(15,44, modem.available, "If this modem is ^available^") + case 13:E_BOOL(16,44, modem.deleted, "If this modem is to be ^deleted^ from the setup") + case 14:E_BOOL(17,44, modem.stripdash, "Stript ^dashes (-)^ from dial command strings if this modem needs it") + case 15: + EditConnect(); + Modem_Screen(); + break; + case 16: + EditError(); + Modem_Screen(); + break; + } + } + + return 0; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +void EditModem(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountModem(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenModem() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "5. MODEM TYPES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/modem.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(modemhdr) + ((i - 1) * modemhdr.recsize); + fseek(fil, offset, 0); + fread(&modem, modemhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (modem.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-30s", i, modem.modem); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseModem(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendModem() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditModemRec(atoi(pick)); + } +} + + + +char *PickModem(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char buf[31]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountModem(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. MODEM SELECT", shdr); + mvprintw(5,3,temp); + set_color(CYAN, BLACK); + if (records) { + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&modemhdr, sizeof(modemhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(modemhdr) + (((o + i) - 1) * modemhdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fil); + if (modem.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-31s", o + i, modem.modem); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o += 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o -= 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = modemhdr.hdrsize + ((atoi(pick) - 1) * modemhdr.recsize); + fseek(fil, offset, SEEK_SET); + fread(&modem, modemhdr.recsize, 1, fil); + fclose(fil); + if (modem.available) { + sprintf(buf, "%s", modem.modem); + return buf; + } + } + } + } +} + + + +int modem_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *mdm; + int i, j; + + sprintf(temp, "%s/etc/modem.data", getenv("MBSE_ROOT")); + if ((mdm = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 5, 0, page, (char *)"Modem types information"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&modemhdr, sizeof(modemhdr), 1, mdm); + + while ((fread(&modem, modemhdr.recsize, 1, mdm)) == 1) { + if (j == 1) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Modem type %s\n", modem.modem); + for (i = 0; i < 3; i++) + fprintf(fp, " Init string %s\n", modem.init[i]); + fprintf(fp, " OK string %s\n", modem.ok); + fprintf(fp, " Hangup %s\n", modem.hangup); + fprintf(fp, " Info command %s\n", modem.info); + fprintf(fp, " Dial command %s\n", modem.dial); + for (i = 0; i < 20; i++) + fprintf(fp, " Connect %s\n", modem.connect[i]); + fprintf(fp, " Reset cmd %s\n", modem.reset); + for (i = 0; i < 10; i++) + fprintf(fp, " Error string %s\n", modem.error[i]); + fprintf(fp, " Cost offset %d\n", modem.costoffset); + fprintf(fp, " EMSI speed %s\n", modem.speed); + fprintf(fp, " Strip dashes %s\n", getboolean(modem.stripdash)); + fprintf(fp, " Available %s\n", getboolean(modem.available)); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(mdm); + return page; +} + + diff --git a/mbsetup/m_modem.h b/mbsetup/m_modem.h new file mode 100644 index 00000000..e24ad3ab --- /dev/null +++ b/mbsetup/m_modem.h @@ -0,0 +1,11 @@ +#ifndef _MODEM_H +#define _MODEM_H + + +int CountModem(void); +void EditModem(void); +char *PickModem(char *); +int modem_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_new.c b/mbsetup/m_new.c new file mode 100644 index 00000000..557f35d2 --- /dev/null +++ b/mbsetup/m_new.c @@ -0,0 +1,556 @@ +/***************************************************************************** + * + * File ..................: m_fnewfiles.c + * Purpose ...............: Newfiles Setup + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "grlist.h" +#include "m_new.h" +#include "m_lang.h" +#include "m_marea.h" +#include "m_ngroup.h" + + +int NewUpdated = 0; + + +/* + * Count nr of newfiles records in the database. + * Creates the database if it doesn't exist. + */ +int CountNewfiles(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + newfileshdr.hdrsize = sizeof(newfileshdr); + newfileshdr.recsize = sizeof(newfiles); + newfileshdr.grpsize = CFG.new_groups * 13; + fwrite(&newfileshdr, sizeof(newfileshdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - newfileshdr.hdrsize) / (newfileshdr.recsize + newfileshdr.grpsize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNewfiles(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + int i, old_groups; + long oldgroup; + char group[13]; + + sprintf(fnin, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&newfileshdr, sizeof(newfileshdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = newfileshdr.recsize; + oldgroup = newfileshdr.grpsize; + old_groups = oldgroup / 13; + if ((oldsize != sizeof(newfiles)) || (CFG.new_groups != old_groups)) + NewUpdated = 1; + else + NewUpdated = 0; + newfileshdr.hdrsize = sizeof(newfileshdr); + newfileshdr.recsize = sizeof(newfiles); + newfileshdr.grpsize = CFG.new_groups * 13; + fwrite(&newfileshdr, sizeof(newfileshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&newfiles, 0, sizeof(newfiles)); + while (fread(&newfiles, oldsize, 1, fin) == 1) { + fwrite(&newfiles, sizeof(newfiles), 1, fout); + memset(&newfiles, 0, sizeof(newfiles)); + /* + * Copy the existing groups + */ + for (i = 1; i <= old_groups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.new_groups) + fwrite(&group, 13, 1, fout); + } + if (old_groups < CFG.new_groups) { + /* + * The size increased, fill with + * blank records. + */ + memset(&group, 0, 13); + for (i = (old_groups + 1); i <= CFG.new_groups; i++) + fwrite(&group, 13, 1, fout); + } + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNewfiles(void) +{ + char fin[81], fout[81], group[13]; + FILE *fi, *fo; + st_list *new = NULL, *tmp; + int i; + + sprintf(fin, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + + if (NewUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&newfileshdr, newfileshdr.hdrsize, 1, fi); + fwrite(&newfileshdr, newfileshdr.hdrsize, 1, fo); + + while (fread(&newfiles, newfileshdr.recsize, 1, fi) == 1) { + if (!newfiles.Deleted) + fill_stlist(&new, newfiles.Comment, ftell(fi) - newfileshdr.recsize); + fseek(fi, newfileshdr.grpsize, SEEK_CUR); + } + sort_stlist(&new); + + for (tmp = new; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&newfiles, newfileshdr.recsize, 1, fi); + fwrite(&newfiles, newfileshdr.recsize, 1, fo); + for (i = 0; i < (newfileshdr.grpsize / sizeof(group)); i++) { + fread(&group, sizeof(group), 1, fi); + fwrite(&group, sizeof(group), 1, fo); + } + } + + fclose(fi); + fclose(fo); + tidy_stlist(&new); + unlink(fout); + Syslog('+', "Updated \"newfiles.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNewfiles(void) +{ + FILE *fil; + char ffile[81], group[13]; + int i; + + sprintf(ffile, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&newfiles, 0, sizeof(newfiles)); + /* + * Fill in default values + */ + sprintf(newfiles.From, "%s", CFG.sysop_name); + fwrite(&newfiles, sizeof(newfiles), 1, fil); + memset(&group, 0, 13); + for (i = 1; i <= CFG.new_groups; i++) + fwrite(&group, 13, 1, fil); + fclose(fil); + NewUpdated = 1; + return 0; + } else + return -1; +} + + + +void NewScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "12. EDIT NEW FILES REPORTS"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Msg area"); + mvprintw( 9, 2, "3. Origin line"); + mvprintw(10, 2, "4. From name"); + mvprintw(11, 2, "5. To name"); + mvprintw(12, 2, "6. Subject"); + mvprintw(13, 2, "7. Language"); + mvprintw(14, 2, "8. Template"); + mvprintw(15, 2, "9. Aka to use"); + mvprintw(16, 2, "10. Active"); + mvprintw(17, 2, "11. Deleted"); + mvprintw(16,42, "12. High ASCII"); + mvprintw(17,42, "13. New groups"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditNewRec(int Area) +{ + FILE *fil; + char mfile[81], temp1[2]; + long offset; + unsigned long crc, crc1; + gr_list *fgr = NULL, *tmp; + char group[13]; + int groups, i, j, GrpChanged = FALSE; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Newfiles"); + + sprintf(mfile, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + + while (fread(&ngroup, ngrouphdr.recsize, 1, fil) == 1) + fill_grlist(&fgr, ngroup.Name); + + fclose(fil); + sort_grlist(&fgr); + } + + sprintf(mfile, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + tidy_grlist(&fgr); + return -1; + } + + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + offset = newfileshdr.hdrsize + ((Area -1) * (newfileshdr.recsize + newfileshdr.grpsize)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + tidy_grlist(&fgr); + return -1; + } + + fread(&newfiles, newfileshdr.recsize, 1, fil); + groups = newfileshdr.grpsize / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + Syslog('+', "New group %s", group); + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&newfiles, crc, newfileshdr.recsize); + working(0, 0, 0); + + for (;;) { + NewScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,55, newfiles.Comment); + show_str( 8,18,50, newfiles.Area); + show_str( 9,18,50, newfiles.Origin); + show_str( 10,18,35, newfiles.From); + show_str( 11,18,35, newfiles.Too); + show_str( 12,18,60, newfiles.Subject); + sprintf(temp1, "%c", newfiles.Language); + show_str( 13,18,2, temp1); + show_str( 14,18,14, newfiles.Template); + show_str( 15,18,35, aka2str(newfiles.UseAka)); + show_bool(16,18, newfiles.Active); + show_bool(17,18, newfiles.Deleted); + show_bool(16,58, newfiles.HiAscii); + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) + i++; + show_int( 17,58, i); + + switch(select_menu(13)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&newfiles, crc1, newfileshdr.recsize); + if ((crc != crc1) || GrpChanged) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&newfiles, newfileshdr.recsize, 1, fil); + + groups = newfileshdr.grpsize / 13; + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + Syslog('+', "Written %d out of %d entries", i, groups); + + memset(&group, 0, 13); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + fclose(fil); + NewUpdated = 1; + working(0, 0, 0); + } + } + tidy_grlist(&fgr); + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,55, newfiles.Comment, "The ^comment^ for this area") + case 2: strcpy(newfiles.Area, PickMsgarea((char *)"12.2")); + break; + case 3: E_STR( 9,18,50, newfiles.Origin, "The ^origin line^ to append, leave blank for random lines") + case 4: E_STR( 10,18,35, newfiles.From, "The ^From^ name to appear above the messages") + case 5: E_STR( 11,18,35, newfiles.Too, "The ^To^ name to appear above the messages") + case 6: E_STR( 12,18,60, newfiles.Subject, "The ^Subject^ of the messages") + case 7: newfiles.Language = PickLanguage((char *)"12.7"); + break; + case 8: E_STR( 14,18,14, newfiles.Template, "The ^template^ file to use for the report") + case 9: i = PickAka((char *)"12.9", TRUE); + if (i != -1) + newfiles.UseAka = CFG.aka[i]; + break; + case 10:E_BOOL(16,18, newfiles.Active, "If this report is ^active^") + case 11:E_BOOL(17,18, newfiles.Deleted, "Is this record ^deleted^") + case 12:E_BOOL(16,58, newfiles.HiAscii, "Allow ^High ASCII^ in this report") + case 13:if (E_Group(&fgr, (char *)"12.12 NEWFILE GROUPS")) + GrpChanged = TRUE; + break; + } + } +} + + + +void EditNewfiles(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNewfiles(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNewfiles() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "12. NEWFILES REPORTS"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/newfiles.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&newfileshdr, sizeof(newfileshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(newfileshdr) + (((o + i) - 1) * (newfileshdr.recsize + newfileshdr.grpsize)); + fseek(fil, offset, 0); + fread(&newfiles, newfileshdr.recsize, 1, fil); + if (newfiles.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, newfiles.Comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNewfiles(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNewfiles() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNewRec(atoi(pick)); + } +} + + + +int new_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], group[13]; + FILE *no; + int groups, i, j; + + sprintf(temp, "%s/etc/newfiles.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 12, 0, page, (char *)"Newfiles reports"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&newfileshdr, sizeof(newfileshdr), 1, no); + + while ((fread(&newfiles, newfileshdr.recsize, 1, no)) == 1) { + + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Area comment %s\n", newfiles.Comment); + fprintf(fp, " Message area %s\n", newfiles.Area); + fprintf(fp, " Origin line %s\n", newfiles.Origin); + fprintf(fp, " From name %s\n", newfiles.From); + fprintf(fp, " To name %s\n", newfiles.Too); + fprintf(fp, " Subject %s\n", newfiles.Subject); + fprintf(fp, " Language %c\n", newfiles.Language); + fprintf(fp, " Aka to use %s\n", aka2str(newfiles.UseAka)); + fprintf(fp, " Active %s\n", getboolean(newfiles.Active)); + fprintf(fp, " Allow High ASCII %s\n", getboolean(newfiles.HiAscii)); + fprintf(fp, "\n File groups:\n "); + groups = newfileshdr.grpsize / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) %5) == 0) + fprintf(fp, "\n "); + } + } + if ((i+1) % 5) + fprintf(fp, "\n"); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_new.h b/mbsetup/m_new.h new file mode 100644 index 00000000..d80ed79b --- /dev/null +++ b/mbsetup/m_new.h @@ -0,0 +1,10 @@ +#ifndef _NEW_H +#define _NEW_H + + +int CountNewfiles(void); +void EditNewfiles(void); +int new_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_ngroup.c b/mbsetup/m_ngroup.c new file mode 100644 index 00000000..665d2d8c --- /dev/null +++ b/mbsetup/m_ngroup.c @@ -0,0 +1,513 @@ +/***************************************************************************** + * + * File ..................: setup/m_ngroups.c + * Purpose ...............: Setup NGroups. + * Last modification date : 28-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_ngroup.h" + + + +int NGrpUpdated = 0; + + +/* + * Count nr of ngroup records in the database. + * Creates the database if it doesn't exist. + */ +int CountNGroup(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + ngrouphdr.hdrsize = sizeof(ngrouphdr); + ngrouphdr.recsize = sizeof(ngroup); + fwrite(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - ngrouphdr.hdrsize) / ngrouphdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNGroup(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + NGrpUpdated = 0; + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fin); + if (ngrouphdr.hdrsize != sizeof(ngrouphdr)) { + ngrouphdr.hdrsize = sizeof(ngrouphdr); + NGrpUpdated = 1; + } + + /* + * In case we are automaitc upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = ngrouphdr.recsize; + if (oldsize != sizeof(ngroup)) + NGrpUpdated = 1; + ngrouphdr.hdrsize = sizeof(ngrouphdr); + ngrouphdr.recsize = sizeof(ngroup); + fwrite(&ngrouphdr, sizeof(ngrouphdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ngroup, 0, sizeof(ngroup)); + while (fread(&ngroup, oldsize, 1, fin) == 1) { + fwrite(&ngroup, sizeof(ngroup), 1, fout); + memset(&ngroup, 0, sizeof(ngroup)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNGroup(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *mgr = NULL, *tmp; + + sprintf(fin, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + + if (NGrpUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, fi); + fwrite(&ngrouphdr, ngrouphdr.hdrsize, 1, fo); + + while (fread(&ngroup, ngrouphdr.recsize, 1, fi) == 1) + if (!ngroup.Deleted) + fill_stlist(&mgr, ngroup.Name, ftell(fi) - ngrouphdr.recsize); + sort_stlist(&mgr); + + for (tmp = mgr; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&ngroup, ngrouphdr.recsize, 1, fi); + fwrite(&ngroup, ngrouphdr.recsize, 1, fo); + } + + tidy_stlist(&mgr); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"ngroups.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNGroup(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ngroup, 0, sizeof(ngroup)); + fwrite(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + NGrpUpdated = 1; + return 0; + } else + return -1; +} + + + +void NgScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "9.1 EDIT NEWFILES GROUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Name"); + mvprintw( 8, 6, "2. Comment"); + mvprintw( 9, 6, "3. Active"); + mvprintw(10, 6, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditNGrpRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit NewfileGroup"); + + sprintf(mfile, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(ngrouphdr) + ((Area -1) * sizeof(ngroup)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ngroup, crc, sizeof(ngroup)); + working(0, 0, 0); + NgScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,18,12, ngroup.Name); + show_str( 8,18,55, ngroup.Comment); + show_bool( 9,18, ngroup.Active); + show_bool(10,18, ngroup.Deleted); + + j = select_menu(4); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ngroup, crc1, sizeof(ngroup)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ngroup, sizeof(ngroup), 1, fil); + fclose(fil); + NGrpUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,18,12,ngroup.Name,"The ^name^ for this message group") + case 2: E_STR( 8,18,55,ngroup.Comment,"The ^desription^ for this message group") + case 3: E_BOOL(9,18, ngroup.Active, "Is this message group ^active^") + case 4: E_BOOL(10,18, ngroup.Deleted, "Is this group ^Deleted^") + } + } + + return 0; +} + + + +void EditNGroup(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNGroup(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNGroup() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "11. NEWFILES GROUPS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ngroups.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11 ) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ngrouphdr) + (((o + i) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + if (ngroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, ngroup.Name, ngroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNGroup(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNGroup() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNGrpRec(atoi(pick)); + } +} + + + +char *PickNGroup(char *shdr) +{ + static char MGrp[21] = ""; + int records, i, o = 0, y, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return MGrp; + } + + records = CountNGroup(); + if (records == -1) { + working(2, 0, 0); + return MGrp; + } + + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. NEWFILES GROUP SELECT", shdr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ngrouphdr, sizeof(ngrouphdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ngrouphdr) + (((o + i) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + if (ngroup.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-12s %-18s", o + i, ngroup.Name, ngroup.Comment); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) + return MGrp; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + fil = fopen(temp, "r"); + offset = sizeof(ngrouphdr) + ((atoi(pick) - 1) * ngrouphdr.recsize); + fseek(fil, offset, 0); + fread(&ngroup, ngrouphdr.recsize, 1, fil); + fclose(fil); + strcpy(MGrp, ngroup.Name); + return MGrp; + } + } +} + + + +int newf_group_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/ngroups.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + addtoc(fp, toc, 11, 0, page, (char *)"Newfiles announce groups"); + j = 0; + fprintf(fp, "\n\n"); + + fread(&ngrouphdr, sizeof(ngrouphdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&ngrouphdr, ngrouphdr.hdrsize, 1, no); + + while ((fread(&ngroup, ngrouphdr.recsize, 1, no)) == 1) { + if (j == 7) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Name %s\n", ngroup.Name); + fprintf(fp, " Comment %s\n", ngroup.Comment); + fprintf(fp, " Active %s\n", getboolean(ngroup.Active)); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_ngroup.h b/mbsetup/m_ngroup.h new file mode 100644 index 00000000..272fef91 --- /dev/null +++ b/mbsetup/m_ngroup.h @@ -0,0 +1,12 @@ +#ifndef _NGROUP_H +#define _NGROUP_H + + +int CountNGroup(void); +void EditNGroup(void); +char *PickNGroup(char *); +int newf_group_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_node.c b/mbsetup/m_node.c new file mode 100644 index 00000000..ece9aabf --- /dev/null +++ b/mbsetup/m_node.c @@ -0,0 +1,1209 @@ +/***************************************************************************** + * + * File ..................: m_node.c + * Purpose ...............: Nodes Setup Program + * Last modification date : 30-Aug-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "grlist.h" +#include "stlist.h" +#include "m_global.h" +#include "m_lang.h" +#include "m_ticarea.h" +#include "m_marea.h" +#include "m_node.h" + + +int NodeUpdated = 0; + + +/* + * Count nr of nodes records in the database. + * Creates the database if it doesn't exist. + */ +int CountNoderec(void); +int CountNoderec(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.recsize = sizeof(nodes); + nodeshdr.filegrp = CFG.tic_groups * 13; + nodeshdr.mailgrp = CFG.toss_groups * 13; + fwrite(&nodeshdr, sizeof(nodeshdr), 1, fil); + fclose(fil); + Syslog('+', "Created nodes.data"); + return 0; + } else + return -1; + } + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - nodeshdr.hdrsize) / (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenNoderec(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + char group[13]; + long oldsize; + int i, old_fgroups, old_mgroups; + long oldfilegrp, oldmailgrp; + + sprintf(fnin, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened nodes.data"); + NodeUpdated = 0; + fread(&nodeshdr, sizeof(nodeshdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fin); + if (nodeshdr.hdrsize != sizeof(nodeshdr)) { + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.lastupd = time(NULL); + NodeUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = nodeshdr.recsize; + oldfilegrp = nodeshdr.filegrp; + oldmailgrp = nodeshdr.mailgrp; + old_fgroups = oldfilegrp / 13; + old_mgroups = oldmailgrp / 13; + if ((oldsize != sizeof(nodes) || + (CFG.tic_groups != old_fgroups) || + (CFG.toss_groups != old_mgroups))) { + NodeUpdated = 1; + Syslog('+', "nodes.data nr of groups is changed"); + } + nodeshdr.hdrsize = sizeof(nodeshdr); + nodeshdr.recsize = sizeof(nodes); + nodeshdr.filegrp = CFG.tic_groups * 13; + nodeshdr.mailgrp = CFG.toss_groups * 13; + fwrite(&nodeshdr, sizeof(nodeshdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&nodes, 0, sizeof(nodes)); + while (fread(&nodes, oldsize, 1, fin) == 1) { + fwrite(&nodes, sizeof(nodes), 1, fout); + memset(&nodes, 0, sizeof(nodes)); + /* + * Copy the existing file groups + */ + for (i = 1; i <= old_fgroups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.tic_groups) + fwrite(&group, 13, 1, fout); + } + if (old_fgroups < CFG.tic_groups) { + /* + * The size increased, fill with + * blank records + */ + memset(&group, 0, 13); + for (i = (old_fgroups + 1); i <= CFG.tic_groups; i++) + fwrite(&group, 13, 1, fout); + } + /* + * Copy the existing mail groups + */ + for (i = 1; i <= old_mgroups; i++) { + fread(&group, 13, 1, fin); + if (i <= CFG.toss_groups) + fwrite(&group, 13, 1, fout); + } + if (old_mgroups < CFG.toss_groups) { + memset(&group, 0, 13); + for (i = (old_mgroups + 1); i <= CFG.toss_groups; i++) + fwrite(&group, 13, 1, fout); + } + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseNoderec(int Force) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + int i; + char group[13]; + st_list *nod = NULL, *tmp; + + sprintf(fin, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/nodes.temp", getenv("MBSE_ROOT")); + + if (NodeUpdated == 1) { + if (Force || (yes_no((char *)"Nodes database is changed, save changes") == 1)) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&nodeshdr, nodeshdr.hdrsize, 1, fi); + fwrite(&nodeshdr, nodeshdr.hdrsize, 1, fo); + + while (fread(&nodes, nodeshdr.recsize, 1, fi) == 1) { + if (!nodes.Deleted) + fill_stlist(&nod, nodes.Sysop, ftell(fi) - nodeshdr.recsize); + fseek(fi, nodeshdr.filegrp + nodeshdr.mailgrp, SEEK_CUR); + } + sort_stlist(&nod); + + for (tmp = nod; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&nodes, nodeshdr.recsize, 1, fi); + fwrite(&nodes, nodeshdr.recsize, 1, fo); + for (i = 0; i < ((nodeshdr.filegrp + nodeshdr.mailgrp) / sizeof(group)); i++) { + fread(&group, sizeof(group), 1, fi); + fwrite(&group, sizeof(group), 1, fo); + } + } + + tidy_stlist(&nod); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"nodes.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendNoderec(void); +int AppendNoderec(void) +{ + FILE *fil; + char ffile[81]; + char group[13]; + int i; + + sprintf(ffile, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&nodes, 0, sizeof(nodes)); + /* + * Fill in the defaults + */ + nodes.Tic = TRUE; + nodes.Notify = FALSE; + nodes.AdvTic = FALSE; + nodes.Hold = TRUE; + nodes.ARCmailCompat = TRUE; + nodes.ARCmailAlpha = TRUE; + nodes.StartDate = time(NULL); + fwrite(&nodes, sizeof(nodes), 1, fil); + memset(&group, 0, 13); + for (i = 1; i <= CFG.tic_groups; i++) + fwrite(&group, 13, 1, fil); + for (i = 1; i <= CFG.toss_groups; i++) + fwrite(&group, 13, 1, fil); + fclose(fil); + NodeUpdated = 1; + return 0; + } else + return -1; +} + + + +int GroupInNode(char *Group, int Mail) +{ + char temp[128], group[13]; + FILE *no; + int i, groups, Area = 0, RetVal = 0; + + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return FALSE; + + fread(&nodeshdr, sizeof(nodeshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, no); + + while ((fread(&nodes, nodeshdr.recsize, 1, no)) == 1) { + Area++; + groups = nodeshdr.filegrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group) && !Mail) { + if (!strcmp(group, Group)) { + RetVal++; + Syslog('-', "File group %s in %d: %s", Group, Area, aka2str(nodes.Aka[0])); + } + } + } + groups = nodeshdr.mailgrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group) && Mail) { + if (!strcmp(group, Group)) { + RetVal++; + Syslog('-', "Mail group %s found in %d: %s", Group, Area, aka2str(nodes.Aka[0])); + } + } + } + } + + fclose(no); + return RetVal; +} + + + +int CheckAka(fidoaddr); +int CheckAka(fidoaddr A) +{ + int mcnt, tcnt; + + working(1, 0, 0); + mcnt = NodeInMarea(A); + tcnt = NodeInTic(A); + working(0, 0, 0); + if (mcnt || tcnt) { + errmsg((char *)"Error aka connected to %d message and/or %d tic areas", mcnt, tcnt); + return TRUE; + } + return FALSE; +} + + + +void E_Mail(void); +void E_Mail(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.14 EDIT NODE - MAIL PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Session pwd"); + mvprintw( 8, 6, "2. Check PKT pwd"); + mvprintw( 9, 6, "3. UplMgr program"); + mvprintw(10, 6, "4. UplMgr passwd"); + mvprintw(11, 6, "5. Mail forward"); + mvprintw(12, 6, "6. ARCmail comp."); + mvprintw(13, 6, "7. ARCmail a..z"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,15, (char *)"***************"); + show_bool(8,25, nodes.MailPwdCheck); + show_str( 9,25, 8, nodes.UplAmgrPgm); + show_str(10,25,15, (char *)"***************"); + show_bool(11,25, nodes.MailFwd); + show_bool(12,25, nodes.ARCmailCompat); + show_bool(13,25, nodes.ARCmailAlpha); + + switch(select_menu(7)) { + case 0: return; + case 1: E_STR( 7,25,15,nodes.Epasswd, "The ^Session/Mail password^ for this node") + case 2: E_BOOL( 8,25, nodes.MailPwdCheck, "Check the ^mail PKT^ password") + case 3: E_STR( 9,25, 8,nodes.UplAmgrPgm, "Name of the uplink ^areamanager program^") + case 4: E_STR( 10,25,15,nodes.UplAmgrPass, "Uplink ^areamanager password^ for this node") + case 5: E_BOOL(11,25, nodes.MailFwd, "^Forward^ echomail for this node") + case 6: E_BOOL(12,25, nodes.ARCmailCompat, "Use ^ARCmail 0.60^ file naming convention for out of zone mail") + case 7: E_BOOL(13,25, nodes.ARCmailAlpha, "Allow ^0..9 and a..z^ filename extensions for ARCmail archives") + } + } +} + + + +void E_Files(void); +void E_Files(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.16 EDIT NODE - FILES PROCESSING"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Files password"); + mvprintw( 8, 6, "2. Mgr password"); + mvprintw( 9, 6, "3. UplMgr program"); + mvprintw(10, 6, "4. UplMgr passwd"); + mvprintw(11, 6, "5. UplMgr Add +"); + mvprintw(12, 6, "6. Incl. message"); + mvprintw(13, 6, "7. Send TIC file"); + mvprintw(14, 6, "8. Advanced TIC"); + mvprintw(15, 6, "9. File forward"); + mvprintw(16, 6, "10. Billing"); + mvprintw( 7,46, "11. Bill direct"); + mvprintw( 8,46, "12. Credit"); + mvprintw( 9,46, "13. Debet"); + mvprintw(10,46, "14. Add %"); + mvprintw(11,46, "15. Warn level"); + mvprintw(12,46, "16. Stop level"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,25,15, (char *)"***************"); + show_str( 8,25,15, (char *)"***************"); + show_str( 9,25, 8, nodes.UplFmgrPgm); + show_str(10,25,15, (char *)"***************"); + show_bool(11,25, nodes.AddPlus); + show_bool(12,25, nodes.Message); + show_bool(13,25, nodes.Tic); + show_bool(14,25, nodes.AdvTic); + show_bool(15,25, nodes.FileFwd); + show_bool(16,25, nodes.Billing); + show_bool( 7,65, nodes.BillDirect); + show_int( 8,65, nodes.Credit); + show_int( 9,65, nodes.Debet); + show_int(10,65, nodes.AddPerc); + show_int(11,65, nodes.WarnLevel); + show_int(12,65, nodes.StopLevel); + + switch(select_menu(16)) { + case 0: return; + case 1: E_STR( 7,25,15,nodes.Fpasswd, "The ^TIC^ files ^password^ for this node") + case 2: E_STR( 8,25,15,nodes.Apasswd, "The filemanager ^password^ for this node") + case 3: E_STR( 9,25,8, nodes.UplFmgrPgm, "The name of the uplink ^filemanager^ program") + case 4: E_STR( 10,25,15,nodes.UplFmgrPass,"The uplink filemanager ^password^") + case 5: E_BOOL(11,25, nodes.AddPlus, "Add ^+^ in uplink manager requests for new areas") + case 6: E_BOOL(12,25, nodes.Message, "Send ^messages^ with files send to this node") + case 7: E_BOOL(13,25, nodes.Tic, "Send ^TIC^ files to this node") + case 8: E_BOOL(14,25, nodes.AdvTic, "Send ^advanced^ TIC files to this node") + case 9: E_BOOL(15,25, nodes.FileFwd, "^Forward TIC^ files for this node") + case 10:E_BOOL(16,25, nodes.Billing, "Send ^bills^ to this node") + case 11:E_BOOL( 7,65, nodes.BillDirect, "Send bills ^direct^ after file processing") + case 12:E_INT( 8,65, nodes.Credit, "The ^credit^ this node has for costsharing") + case 13:E_INT( 9,65, nodes.Debet, "The ^debet^ in cents we have credit from this node") + case 14:E_INT( 10,65, nodes.AddPerc, "The + or - ^promille^ factor for this node") + case 15:E_INT( 11,65, nodes.WarnLevel, "Credit level in cents to ^Warn^ node for low credit") + case 16:E_INT( 12,65, nodes.StopLevel, "Credit level in cents to ^Stop^ sending files") + } + } +} + + + +void S_Stat(void); +void S_Stat(void) +{ + time_t Now; + struct tm *t; + int LMiy; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 7, "7.18 NODE STATISTICS"); + set_color(CYAN, BLACK); + mvprintw( 8,18, " This week Last week This month Last month Total"); + mvprintw( 9,18, "---------- ---------- ---------- ---------- ----------"); + mvprintw(10,6, "Files sent"); + mvprintw(11,6, "Kbytes sent"); + mvprintw(12,6, "Files rcvd"); + mvprintw(13,6, "Kbytes rcvd"); + mvprintw(14,6, "Mail sent"); + mvprintw(15,6, "Mail rcvd"); + set_color(WHITE, BLACK); + + Now = time(NULL); + t = localtime(&Now); + + Diw = t->tm_wday; + Miy = t->tm_mon; + if (Miy == 0) + LMiy = 11; + else + LMiy = Miy - 1; + + mvprintw(10,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.FilesSent.tweek, nodes.FilesSent.lweek, nodes.FilesSent.month[Miy], nodes.FilesSent.month[LMiy], nodes.FilesSent.total); + mvprintw(11,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.F_KbSent.tweek, nodes.F_KbSent.lweek, nodes.F_KbSent.month[Miy], nodes.F_KbSent.month[LMiy], nodes.F_KbSent.total); + mvprintw(12,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.FilesRcvd.tweek, nodes.FilesRcvd.lweek, nodes.FilesRcvd.month[Miy], nodes.FilesRcvd.month[LMiy], nodes.FilesRcvd.total); + mvprintw(13,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.F_KbRcvd.tweek, nodes.F_KbRcvd.lweek, nodes.F_KbRcvd.month[Miy], nodes.F_KbRcvd.month[LMiy], nodes.F_KbRcvd.total); + mvprintw(14,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.MailSent.tweek, nodes.MailSent.lweek, nodes.MailSent.month[Miy], nodes.MailSent.month[LMiy], nodes.MailSent.total); + mvprintw(15,18, (char *)"%10lu %10lu %10lu %10lu %10lu", nodes.MailRcvd.tweek, nodes.MailRcvd.lweek, nodes.MailRcvd.month[Miy], nodes.MailRcvd.month[LMiy], nodes.MailRcvd.total); + set_color(CYAN, BLACK); + center_addstr(LINES - 4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +fidoaddr e_a(fidoaddr, int); +fidoaddr e_a(fidoaddr n, int x) +{ + FILE *fil; + char temp[81]; + int i; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, (char *)"7.%d EDIT AKA", x); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Zone"); + mvprintw( 8, 6, "2. Net"); + mvprintw( 9, 6, "3. Node"); + mvprintw(10, 6, "4. Point"); + mvprintw(11, 6, " Domain"); + set_color(WHITE, BLACK); + show_int( 7,17, n.zone); + show_int( 8,17, n.net); + show_int( 9,17, n.node); + show_int(10,17, n.point); + show_str(11,17,12, n.domain); + + switch(select_menu(4)) { + case 0: return n; + case 1: n.zone = edit_int(7, 17, n.zone, (char *)"The ^zone^ number 1..4095"); + sprintf(temp, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + if (fidonet.available) { + for (i = 0; i < 6; i++) { + if (fidonet.zone[i] == n.zone) { + memset(&n.domain, 0, sizeof(n.domain)); + strcpy(n.domain, fidonet.domain); + } + } + } + } + fclose(fil); + } + break; + case 2: E_INT( 8,17,n.net, "The ^net^ number 1..65535") + case 3: E_INT( 9,17,n.node, "The ^node^ number 1..65535") + case 4: E_INT(10,17,n.point,"The ^point^ number 0..65535") + } + } +} + + + +void N_Akas(void) +{ + int i, j, m, x, y; + fidoaddr a[20]; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.2 EDIT NODES AKA'S"); + set_color(CYAN, BLACK); + y = 7; x = 6; + for (i = 0; i < 20; i++) { + if (i == 10) { + y = 7; x = 46; + } + mvprintw( y, x, (char *)"%d.", i + 1); + if (nodes.Aka[i].zone) + mvprintw(y, x + 5, (char *)"%s", aka2str(nodes.Aka[i])); + y++; + } + + m = select_menu(20); + switch(m) { + case 0: + /* + * Pack the aka's + */ + for (i = 0; i < 20; i++) { + a[i] = nodes.Aka[i]; + memset(&nodes.Aka[i], 0, sizeof(fidoaddr)); + } + j = 0; + for (i = 0; i < 20; i++) { + if (a[i].zone) { + nodes.Aka[j] = a[i]; + j++; + } + } + return; + + default: + if (! CheckAka(nodes.Aka[m - 1])) + nodes.Aka[m - 1] = e_a(nodes.Aka[m - 1], 2); + break; + } + + } +} + + + +void NScreen(void); +void NScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "7. EDIT NODE"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Sysop name"); + mvprintw( 8, 2, "2. Fido aka's"); + mvprintw( 9, 2, "3. Dial command"); + mvprintw(10, 2, "4. Phone number 1"); + mvprintw(11, 2, "5. Phone number 2"); + mvprintw(12, 2, "6. Route via"); + mvprintw(13, 2, "7. Netmail direct"); + mvprintw(14, 2, "8. Netmail crash"); + mvprintw(15, 2, "9. Netmail hold"); + mvprintw(16, 2, "10. Pack netmail"); + mvprintw(17, 2, "11. Send notify"); + mvprintw(18, 2, "12. Language"); + mvprintw(19, 2, "13. Deleted"); + + mvprintw(14,31, "14. Mail setup"); + mvprintw(15,31, "15. Mail groups"); + mvprintw(16,31, "16. File setup"); + mvprintw(17,31, "17. File groups"); + mvprintw(18,31, "18. Statistics"); + mvprintw(19,31, "19. No EMSI"); + + mvprintw(10,51, "20. No YooHoo/2U2"); + mvprintw(11,51, "21. No Filerequest"); + mvprintw(12,51, "22. Don't call"); + mvprintw(13,51, "23. No Hold mail"); + mvprintw(14,51, "24. Pickup primary"); + mvprintw(15,51, "25. No Zmodem"); + mvprintw(16,51, "26. No Zedzap"); + mvprintw(17,51, "27. No Hydra"); + mvprintw(18,51, "28. No TCP/IP"); + mvprintw(19,51, "29. Force FNC"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditNodeRec(int); +int EditNodeRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + gr_list *fgr = NULL, *egr = NULL, *tmp; + char group[13]; + int count, groups, i, j, GrpChanged = FALSE; + char *temp, temp1[32]; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Fido Node"); + + sprintf(mfile, "%s/etc/mgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&mgrouphdr, sizeof(mgrouphdr), 1, fil); + + while (fread(&mgroup, mgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&egr, mgroup.Name); + + fclose(fil); + sort_grlist(&egr); + } + + sprintf(mfile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&fgr, fgroup.Name); + + fclose(fil); + sort_grlist(&fgr); + } + + sprintf(mfile, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + tidy_grlist(&egr); + tidy_grlist(&fgr); + return -1; + } + + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + offset = nodeshdr.hdrsize + ((Area -1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + tidy_grlist(&egr); + tidy_grlist(&fgr); + return -1; + } + + fread(&nodes, nodeshdr.recsize, 1, fil); + groups = nodeshdr.filegrp / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + for (tmp = fgr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + groups = nodeshdr.mailgrp / 13; + + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, fil); + if (strlen(group)) { + for (tmp = egr; tmp; tmp = tmp->next) + if (!strcmp(tmp->group, group)) + tmp->tagged = TRUE; + } + } + + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&nodes, crc, nodeshdr.recsize); + working(0, 0, 0); + NScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21,35, nodes.Sysop); + temp = xstrcpy((char *)""); + for (i = 0; i < 7; i++) { + if (nodes.Aka[i].zone) { + if (nodes.Aka[i].point) + sprintf(temp1, "%d:%d/%d.%d ", nodes.Aka[i].zone, nodes.Aka[i].net, nodes.Aka[i].node, nodes.Aka[i].point); + else + sprintf(temp1, "%d:%d/%d ", nodes.Aka[i].zone, nodes.Aka[i].net, nodes.Aka[i].node); + temp = xstrcat(temp, temp1); + } + } + show_str( 8,21,58, temp); + free(temp); + show_str( 9,21,40, nodes.dial); + show_str(10,21,20, nodes.phone[0]); + show_str(11,21,20, nodes.phone[1]); + if (nodes.RouteVia.zone) + show_aka(12,21,nodes.RouteVia); + show_bool(13,21, nodes.Direct); + show_bool(14,21, nodes.Crash); + show_bool(15,21, nodes.Hold); + show_bool(16,21, nodes.PackNetmail); + show_bool(17,21, nodes.Notify); + sprintf(temp1, "%c", nodes.Language); + show_str(18,21,1, temp1); + show_bool(19,21, nodes.Deleted); + show_bool(19,47, nodes.NoEMSI); + show_bool(10,70, nodes.NoWaZOO); + show_bool(11,70, nodes.NoFreqs); + show_bool(12,70, nodes.NoCall); + show_bool(13,70, nodes.NoHold); + show_bool(14,70, nodes.NoPUA); + show_bool(15,70, nodes.NoZmodem); + show_bool(16,70, nodes.NoZedzap); + show_bool(17,70, nodes.NoHydra); + show_bool(18,70, nodes.NoTCP); + show_bool(19,70, nodes.FNC); + + switch(select_menu(29)) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&nodes, crc1, nodeshdr.recsize); + if ((crc != crc1) || GrpChanged) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + Syslog('+', "Updated node record %s", nodes.Sysop); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&nodes, nodeshdr.recsize, 1, fil); + + groups = nodeshdr.filegrp / 13; + i = 0; + for (tmp = fgr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + + memset(&group, 0, sizeof(group)); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + groups = nodeshdr.mailgrp / 13; + i = 0; + for (tmp = egr; tmp; tmp = tmp->next) + if (tmp->tagged) { + i++; + memset(&group, 0, 13); + sprintf(group, "%s", tmp->group); + fwrite(&group, 13, 1, fil); + } + + memset(&group, 0, sizeof(group)); + for (j = i; j < groups; j++) + fwrite(&group, 13, 1, fil); + + fclose(fil); + NodeUpdated = 1; + working(0, 0, 0); + } + } + tidy_grlist(&egr); + tidy_grlist(&fgr); + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR(7,21,35, nodes.Sysop, "The name of the ^sysop^ for this node") + case 2: N_Akas(); NScreen(); break; + case 3: E_STR( 9,21,40, nodes.dial, "If needed, give a special modem ^dial command^ for this node") + case 4: E_STR(10,21,20, nodes.phone[0], "Enter ^phone number^ to override the nodelist") + case 5: E_STR(11,21,20, nodes.phone[1], "Enter ^phone number^ to override the nodelist") + case 6: nodes.RouteVia = e_a(nodes.RouteVia, 6); NScreen(); break; + case 7: E_BOOL(13,21, nodes.Direct, "Set the ^direct^ flag on netmail") + case 8: nodes.Crash = edit_bool(14,21, nodes.Crash, (char *)"Set the ^crash^ flags for this node"); + if (nodes.Crash) + nodes.Hold = FALSE; + break; + case 9: nodes.Hold = edit_bool(15,21, nodes.Hold, (char *)"Set the ^hold^ flag for this node"); + if (nodes.Hold) + nodes.Crash = FALSE; + break; + case 10:E_BOOL(16,21, nodes.PackNetmail, "^Pack netmail^ for this node") + case 11:E_BOOL(17,21, nodes.Notify, "Send ^notify^ messages to this node") + case 12:nodes.Language = PickLanguage((char *)"7.12"); NScreen(); break; + case 13:count = 0; + working(1, 0, 0); + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + count += NodeInMarea(nodes.Aka[i]); + if (count) { + working(0, 0, 0); + errmsg((char *)"Node is connected to %d message areas", count); + break; + } + count = 0; + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + count += NodeInTic(nodes.Aka[i]); + working(0, 0, 0); + if (count) { + errmsg((char *)"Node is connected to %d tic areas", count); + break; + } + E_BOOL(19,21, nodes.Deleted, "Is this node ^Deleted^") + case 14:E_Mail(); NScreen(); break; + case 15:if (E_Group(&egr, (char *)"7.15 MAIL GROUPS")) + GrpChanged = TRUE; + NScreen(); break; + case 16:E_Files(); + NScreen(); break; + case 17:if (E_Group(&fgr, (char *)"7.17 FILE GROUPS")) + GrpChanged = TRUE; + NScreen(); break; + case 18:S_Stat(); NScreen(); break; + case 19:E_BOOL(19,47, nodes.NoEMSI, "Disable ^EMSI handshake^ with this node") + case 20:E_BOOL(10,70, nodes.NoWaZOO, "Disable ^YooHoo/2U2 handshake^ (FTSC-0006) with this node") + case 21:E_BOOL(11,70, nodes.NoFreqs, "Disallow ^file requests^ from this node") + case 22:E_BOOL(12,70, nodes.NoCall, "Don't ^call^ this node") + case 23:E_BOOL(13,70, nodes.NoHold, "Don't ^hold hold-mail^ when we call (no = only pickup)") + case 24:E_BOOL(14,70, nodes.NoPUA, "Only pickup mail from the ^primary^ address") + case 25:E_BOOL(15,70, nodes.NoZmodem, "Disable ^Zmodem^ protocol with this node") + case 26:E_BOOL(16,70, nodes.NoZedzap, "Disable ^Zedzap^ protocol with this node") + case 27:E_BOOL(17,70, nodes.NoHydra, "Disable ^Hydra^ protocol with this node") + case 28:E_BOOL(18,70, nodes.NoTCP, "Disable ^TCP/IP^ protocol whith this node") + case 29:E_BOOL(19,70, nodes.FNC, "Force ^FileName Conversion^ during binkp sessions"); + } + } +} + + + +void EditNodes(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountNoderec(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenNoderec() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "7. NODES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/nodes.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(nodeshdr) + (((o + i) - 1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + fseek(fil, offset, 0); + fread(&nodes, nodeshdr.recsize, 1, fil); + if (strlen(nodes.Sysop)) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s (%s)", o + i, nodes.Sysop, strtok(aka2str(nodes.Aka[0]), "@")); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseNoderec(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendNoderec() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditNodeRec(atoi(pick)); + } +} + + + +fidoaddr PullUplink(char *Hdr) +{ + static fidoaddr uplink; + int records, m, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + memset(&uplink, 0, sizeof(uplink)); + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return uplink; + } + + records = CountNoderec(); + if (records == -1) { + working(2, 0, 0); + return uplink; + } + + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "%s. UPLINK SELECT", Hdr); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(nodeshdr) + (((o + i) - 1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)); + fseek(fil, offset, 0); + fread(&nodes, nodeshdr.recsize, 1, fil); + if (strlen(nodes.Sysop)) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s (%s)", o + i, nodes.Sysop, strtok(aka2str(nodes.Aka[0]), "@")); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return uplink; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&nodeshdr, sizeof(nodeshdr), 1, fil); + fseek(fil, ((atoi(pick) -1) * (nodeshdr.recsize + nodeshdr.filegrp + nodeshdr.mailgrp)) + nodeshdr.hdrsize, SEEK_SET); + if (fread(&nodes, nodeshdr.recsize, 1, fil) != 1) { + fclose(fil); + return uplink; + } + fclose(fil); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "%s. SELECT NODE AKA", Hdr); + set_color(CYAN, BLACK); + y = 7; x = 6; + for (i = 0; i < 20; i++) { + if (i == 10) { + y = 7; x = 46; + } + mvprintw( y, x, (char *)"%d.", i + 1); + if (nodes.Aka[i].zone) + mvprintw(y, x + 5, (char *)"%s", aka2str(nodes.Aka[i])); + y++; + } + + m = select_menu(20); + switch(m) { + case 0: + return uplink; + + default: + uplink = nodes.Aka[m - 1]; + return uplink; + } + + } + } + return uplink; + } + } +} + + + +int node_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int groups, i, First = TRUE; + char group[13]; + + sprintf(temp, "%s/etc/nodes.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&nodeshdr, sizeof(nodeshdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&nodeshdr, nodeshdr.hdrsize, 1, no); + + while ((fread(&nodes, nodeshdr.recsize, 1, no)) == 1) { + + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 7, 0, page, (char *)"Fidonet nodes"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Sysop %s\n", nodes.Sysop); + fprintf(fp, " First date %s", ctime(&nodes.StartDate)); + fprintf(fp, " Last date %s\n", ctime(&nodes.LastDate)); + for (i = 0; i < 20; i++) + if (nodes.Aka[i].zone) + fprintf(fp, " Aka %2d %s\n", i+1, aka2str(nodes.Aka[i])); + if (nodes.RouteVia.zone) + fprintf(fp, " Route via %s\n", aka2str(nodes.RouteVia)); + + fprintf(fp, " Language %c\n", nodes.Language); + fprintf(fp, " Files passwd %s\n", nodes.Fpasswd); + fprintf(fp, " Session pwd %s\n", nodes.Epasswd); + fprintf(fp, " Areamgr pwd %s\n\n", nodes.Apasswd); + + fprintf(fp, " Uplink mgrs Program Password\n"); + fprintf(fp, " ------------ --------- ---------------\n"); + fprintf(fp, " Files %s %s\n", padleft(nodes.UplFmgrPgm, 9, ' '), nodes.UplFmgrPass); + fprintf(fp, " Mail %s %s\n\n", padleft(nodes.UplAmgrPgm, 9, ' '), nodes.UplAmgrPass); + + fprintf(fp, " Mail direct %s", getboolean(nodes.Direct)); + fprintf(fp, " Mail crash %s", getboolean(nodes.Crash)); + fprintf(fp, " Mail hold %s\n", getboolean(nodes.Hold)); + fprintf(fp, " Send message %s", getboolean(nodes.Message)); + fprintf(fp, " Send .TIC %s", getboolean(nodes.Tic)); + fprintf(fp, " Send notify %s\n", getboolean(nodes.Notify)); + fprintf(fp, " File forward %s", getboolean(nodes.FileFwd)); + fprintf(fp, " Mail forward %s", getboolean(nodes.MailFwd)); + fprintf(fp, " Advanced TIC %s\n", getboolean(nodes.AdvTic)); + fprintf(fp, " Billing %s", getboolean(nodes.Billing)); + fprintf(fp, " Bill direct %s", getboolean(nodes.BillDirect)); + fprintf(fp, " Uplink add + %s\n", getboolean(nodes.AddPlus)); + fprintf(fp, " Check mailpwd %s", getboolean(nodes.MailPwdCheck)); + fprintf(fp, " No EMSI %s", getboolean(nodes.NoEMSI)); + fprintf(fp, " No YooHoo/2U2 %s\n", getboolean(nodes.NoWaZOO)); + fprintf(fp, " No Requests %s", getboolean(nodes.NoFreqs)); + fprintf(fp, " Don't call %s", getboolean(nodes.NoCall)); + fprintf(fp, " No hold mail %s\n", getboolean(nodes.NoHold)); + fprintf(fp, " No Pickup all %s", getboolean(nodes.NoPUA)); + fprintf(fp, " No Zmodem %s", getboolean(nodes.NoZmodem)); + fprintf(fp, " No Zedzap %s\n", getboolean(nodes.NoZedzap)); + fprintf(fp, " No Hydra %s", getboolean(nodes.NoHydra)); + fprintf(fp, " No TCP/IP %s", getboolean(nodes.NoTCP)); + fprintf(fp, " Force FNC %s\n", getboolean(nodes.FNC)); + fprintf(fp, " Pack Netmail %s", getboolean(nodes.PackNetmail)); + fprintf(fp, " ARCmail comp. %s", getboolean(nodes.ARCmailCompat)); + fprintf(fp, " ACRmail a..z %s\n\n", getboolean(nodes.ARCmailAlpha)); + + fprintf(fp, " Statistics Send KBytes Received KBytes\n"); + fprintf(fp, " ------------ -------- -------- -------- --------\n"); + fprintf(fp, " Total files %-8lu %-8lu %-8lu %-8lu\n", nodes.FilesSent.total, nodes.F_KbSent.total, nodes.FilesRcvd.total, nodes.F_KbSent.total); + fprintf(fp, " Total mail %-8lu %-8lu\n", nodes.MailSent.total, nodes.MailRcvd.total); + + fprintf(fp, " Credit units %-8ld Warnlevel %ld\n", nodes.Credit, nodes.WarnLevel); + fprintf(fp, " Debet units %-8ld Stoplevel %ld\n", nodes.Debet, nodes.StopLevel); + fprintf(fp, " Add promille %ld\n", nodes.AddPerc); + fprintf(fp, "\n File groups:\n "); + groups = nodeshdr.filegrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) % 5) == 0) + fprintf(fp, "\n "); + } + } + if ((i+1) % 5) + fprintf(fp, "\n"); + fprintf(fp, "\n Mail groups:\n "); + groups = nodeshdr.mailgrp / sizeof(group); + for (i = 0; i < groups; i++) { + fread(&group, sizeof(group), 1, no); + if (strlen(group)) { + fprintf(fp, "%-12s ", group); + if (((i+1) % 5) == 0) + fprintf(fp, "\n "); + } + } + fprintf(fp, "\n"); + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_node.h b/mbsetup/m_node.h new file mode 100644 index 00000000..3bca6007 --- /dev/null +++ b/mbsetup/m_node.h @@ -0,0 +1,12 @@ +#ifndef _NODE_H +#define _NODE_H + +int OpenNoderec(void); +void CloseNoderec(int); +int GroupInNode(char *, int); +void EditNodes(void); +int node_doc(FILE *, FILE *, int); +fidoaddr PullUplink(char *); + +#endif + diff --git a/mbsetup/m_ol.c b/mbsetup/m_ol.c new file mode 100644 index 00000000..3537f68b --- /dev/null +++ b/mbsetup/m_ol.c @@ -0,0 +1,534 @@ +/***************************************************************************** + * + * File ..................: setup/m_ol.c + * Purpose ...............: Setup Oneliners. + * Last modification date : 18-Mar-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_ol.h" + + + +int OnelUpdated = 0; + + +/* + * Count nr of oneline records in the database. + * Creates the database if it doesn't exist. + */ +int CountOneline(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + count = 0; + fread(&olhdr, sizeof(olhdr), 1, fil); + + while (fread(&ol, olhdr.recsize, 1, fil) == 1) { + count++; + } + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenOneline(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&olhdr, sizeof(olhdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = olhdr.recsize; + if (oldsize != sizeof(ol)) + OnelUpdated = 1; + else + OnelUpdated = 0; + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ol, 0, sizeof(ol)); + while (fread(&ol, oldsize, 1, fin) == 1) { + fwrite(&ol, sizeof(ol), 1, fout); + memset(&ol, 0, sizeof(ol)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseOneline(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/oneline.temp", getenv("MBSE_ROOT")); + + if (OnelUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"oneline.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendOneline(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ol, 0, sizeof(ol)); + fwrite(&ol, sizeof(ol), 1, fil); + fclose(fil); + OnelUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditOnelRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Oneline"); + + sprintf(mfile, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(olhdr) + ((Area -1) * sizeof(ol)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ol, sizeof(ol), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ol, crc, sizeof(ol)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.8.1 EDIT ONELINER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Text"); + mvprintw( 8, 2, "2. User"); + mvprintw( 9, 2, "3. Date"); + mvprintw(10, 2, "4. Avail"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,12,68, ol.Oneline); + show_str( 8,12,35, ol.UserName); + show_str( 9,12,10, ol.DateOfEntry); + show_bool(10,12, ol.Available); + + j = select_menu(4); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ol, crc1, sizeof(ol)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ol, sizeof(ol), 1, fil); + fclose(fil); + OnelUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,12,68,ol.Oneline, "The ^Oneline^ text to show") + case 2: E_STR( 8,12,30,ol.UserName, "The ^Username^ of the owner of this oneline") + case 3: E_STR( 9,12,10,ol.DateOfEntry,"The ^Date^ this oneliner is added, format: ^DD-MM-YYYY^") + case 4: E_BOOL(10,12, ol.Available, "Is this oneline ^available^") + } + } + + return 0; +} + + + +void EditOneline(void) +{ + int records, i, x, y, o; + char pick[12]; + FILE *fil; + char temp[121]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountOneline(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenOneline() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "8.8.1 ONELINERS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/oneline.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&olhdr, sizeof(olhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(olhdr) + (((o + i) - 1) * olhdr.recsize); + fseek(fil, offset, 0); + fread(&ol, olhdr.recsize, 1, fil); + if (ol.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, ol.Oneline); + temp[38] = '\0'; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records,20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseOneline(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendOneline() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditOnelRec(atoi(pick)); + } +} + + + +void PurgeOneline(void) +{ + FILE *pOneline, *fp; + int recno = 0; + int iCount = 0; + char sFileName[81]; + char temp[81]; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "7.8.2 ONELINERS PURGE"); + set_color(CYAN, BLACK); + working(1, 0, 0); + + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + IsDoing("Purge Oneliners"); + + sprintf(sFileName,"%s/etc/oneline.data", getenv("MBSE_ROOT")); + + if ((pOneline = fopen(sFileName, "r")) == NULL) { + return; + } + + fread(&olhdr, sizeof(olhdr), 1, pOneline); + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + recno++; + if (!ol.Available) + iCount++; + } + working(0, 0, 0); + + sprintf(temp, "%d records, %d records to purge", recno, iCount); + mvprintw(7, 6, temp); + if (iCount == 0) { + mvprintw(9, 6, "Press any key"); + readkey(9, 20, LIGHTGRAY, BLACK); + return; + } + + if (yes_no((char *)"Purge deleted records") == TRUE) { + working(1, 0, 0); + fseek(pOneline, olhdr.hdrsize, 0); + fp = fopen("tmp.1", "a"); + fwrite(&olhdr, sizeof(olhdr), 1, fp); + while (fread(&ol, olhdr.recsize, 1, pOneline) == 1) { + if (ol.Available) + fwrite(&ol, olhdr.recsize, 1, fp); + } + fclose(fp); + fclose(pOneline); + if ((rename("tmp.1", sFileName)) != 0) + working(2, 0, 0); + unlink("tmp.1"); + working(0, 0, 0); + } +} + + + +void ImportOneline(void) +{ + FILE *Imp, *pOneline; + char temp[81]; + int recno = 0; + struct tm *l_date; + char buf[12]; + time_t Time; + + clr_index(); + set_color(WHITE, BLACK); + mvprintw(5, 6, "8.8.3 IMPORT ONELINERS"); + set_color(CYAN, BLACK); + memset(&temp, 0, sizeof(temp)); + strcpy(temp, edit_str(21, 6,64, temp, (char *)"The ^full path and filename^ of the file to import")); + if (strlen(temp) == 0) + return; + + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + if ((Imp = fopen(temp, "r")) == NULL) { + working(2, 0, 0); + working(0, 0, 0); + mvprintw(21, 6, temp); + readkey(22, 6, LIGHTGRAY, BLACK); + return; + } + + sprintf(temp, "%s/etc/oneline.data", getenv("MBSE_ROOT")); + + /* + * Check if database exists, if not create a new one + */ + if ((pOneline = fopen(temp, "r" )) == NULL) { + if ((pOneline = fopen(temp, "w")) != NULL) { + olhdr.hdrsize = sizeof(olhdr); + olhdr.recsize = sizeof(ol); + fwrite(&olhdr, sizeof(olhdr), 1, pOneline); + fclose(pOneline); + } + } else + fclose(pOneline); + + /* + * Open database for appending + */ + if ((pOneline = fopen(temp, "a+")) == NULL) { + working(2, 0, 0); + working(0, 0, 0); + fclose(Imp); + mvprintw(21, 6, temp); + readkey(22, 6, LIGHTGRAY, BLACK); + return; + } + + time(&Time); + l_date = localtime(&Time); + sprintf(buf, "%02d-%02d-%04d", l_date->tm_mday, l_date->tm_mon+1, l_date->tm_year+1900); + + while ((fgets(temp, 80, Imp)) != NULL) { + Striplf(temp); + if ((strlen(temp) > 0) && (strlen(temp) < 78)) { + memset(&ol, 0, sizeof(ol)); + strcpy(ol.Oneline, temp); + strcpy(ol.UserName, CFG.sysop_name); + strcpy(ol.DateOfEntry, buf); + ol.Available = TRUE; + fwrite(&ol, sizeof(ol), 1, pOneline); + recno++; + } + } + + fclose(Imp); + fclose(pOneline); + working(0, 0, 0); + + sprintf(temp, "Imported %d records", recno); + mvprintw(21, 6, temp); + readkey(21, 27, LIGHTGRAY, BLACK); +} + + + +void ol_menu(void) +{ + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.8 ONELINER SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Oneliners"); + mvprintw( 8, 6, "2. Purge Oneliners"); + mvprintw( 9, 6, "3. Import Oneliners"); + + switch(select_menu(3)) { + case 0: + return; + + case 1: + EditOneline(); + break; + + case 2: + PurgeOneline(); + break; + + case 3: + ImportOneline(); + break; + + } + } +} + + diff --git a/mbsetup/m_ol.h b/mbsetup/m_ol.h new file mode 100644 index 00000000..84a2419a --- /dev/null +++ b/mbsetup/m_ol.h @@ -0,0 +1,12 @@ +/* m_ol.h */ + +#ifndef _OL_H +#define _OL_H + + +int CountOneline(void); +void EditOneline(void); +void ol_menu(void); + +#endif + diff --git a/mbsetup/m_protocol.c b/mbsetup/m_protocol.c new file mode 100644 index 00000000..698802b5 --- /dev/null +++ b/mbsetup/m_protocol.c @@ -0,0 +1,538 @@ +/***************************************************************************** + * + * File ..................: mbsetup/m_protocol.c + * Purpose ...............: Setup Protocols. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_protocol.h" + + + +int ProtUpdated = 0; + + +/* + * Count nr of PROT records in the database. + * Creates the database if it doesn't exist. + */ +int CountProtocol(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + PROThdr.hdrsize = sizeof(PROThdr); + PROThdr.recsize = sizeof(PROT); + fwrite(&PROThdr, sizeof(PROThdr), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "1"); + sprintf(PROT.ProtName, "Ymodem"); + sprintf(PROT.ProtUp, "/usr/bin/rb -v"); + sprintf(PROT.ProtDn, "/usr/bin/sb -v -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 92; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "L"); + sprintf(PROT.ProtName, "Local disk"); + sprintf(PROT.ProtUp, "%s/bin/rf", getenv("MBSE_ROOT")); + sprintf(PROT.ProtDn, "%s/bin/sf", getenv("MBSE_ROOT")); + sprintf(PROT.Advice, "It goes before you know"); + PROT.Efficiency = 100; + PROT.Batch = TRUE; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "Y"); + sprintf(PROT.ProtName, "Ymodem 1K"); + sprintf(PROT.ProtUp, "/usr/bin/rb -k -v"); + sprintf(PROT.ProtDn, "/usr/bin/sb -k -v -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 95; + fwrite(&PROT, sizeof(PROT), 1, fil); + + memset(&PROT, 0, sizeof(PROT)); + sprintf(PROT.ProtKey, "Z"); + sprintf(PROT.ProtName, "Zmodem"); + sprintf(PROT.ProtUp, "/usr/bin/rz -p -v"); + sprintf(PROT.ProtDn, "/usr/bin/sz -b -q -r -u"); + sprintf(PROT.Advice, "Press Ctrl-X to abort"); + PROT.Available = TRUE; + PROT.Batch = TRUE; + PROT.Efficiency = 98; + fwrite(&PROT, sizeof(PROT), 1, fil); + + fclose(fil); + return 4; + } else + return -1; + } + + fread(&PROThdr, sizeof(PROThdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - PROThdr.hdrsize) / PROThdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenProtocol(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fin); + /* + * In case we are automaic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = PROThdr.recsize; + if (oldsize != sizeof(PROT)) + ProtUpdated = 1; + else + ProtUpdated = 0; + PROThdr.hdrsize = sizeof(PROThdr); + PROThdr.recsize = sizeof(PROT); + fwrite(&PROThdr, sizeof(PROThdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&PROT, 0, sizeof(PROT)); + while (fread(&PROT, oldsize, 1, fin) == 1) { + fwrite(&PROT, sizeof(PROT), 1, fout); + memset(&PROT, 0, sizeof(PROT)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseProtocol(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *pro = NULL, *tmp; + + sprintf(fin, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/protocol.temp", getenv("MBSE_ROOT")); + + if (ProtUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&PROThdr, PROThdr.hdrsize, 1, fi); + fwrite(&PROThdr, PROThdr.hdrsize, 1, fo); + + while (fread(&PROT, PROThdr.recsize, 1, fi) == 1) + if (!PROT.Deleted) + fill_stlist(&pro, PROT.ProtKey, ftell(fi) - PROThdr.recsize); + sort_stlist(&pro); + + for (tmp = pro; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&PROT, PROThdr.recsize, 1, fi); + fwrite(&PROT, PROThdr.recsize, 1, fo); + } + + fclose(fi); + fclose(fo); + unlink(fout); + tidy_stlist(&pro); + Syslog('+', "Updated \"protocol.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendProtocol(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&PROT, 0, sizeof(PROT)); + fwrite(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + ProtUpdated = 1; + return 0; + } else + return -1; +} + + + +void s_protrec(void); +void s_protrec(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.5 EDIT PROTOCOL"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Select Key"); + mvprintw( 8, 6, "2. Name"); + mvprintw( 9, 6, "3. Upload"); + mvprintw(10, 6, "4. Download"); + mvprintw(11, 6, "5. Available"); + mvprintw(12, 6, "6. Batching"); + mvprintw(13, 6, "7. Bi direct"); + mvprintw(14, 6, "8. Advice"); + mvprintw(15, 6, "9. Efficiency"); + mvprintw(16, 6, "10. Deleted"); + mvprintw(17, 6, "11. Sec. level"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditProtRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Protocol"); + + sprintf(mfile, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(PROThdr) + ((Area -1) * sizeof(PROT)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&PROT, crc, sizeof(PROT)); + working(0, 0, 0); + + s_protrec(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21, 1, PROT.ProtKey); + show_str( 8,21,20, PROT.ProtName); + show_str( 9,21,50, PROT.ProtUp); + show_str( 10,21,50, PROT.ProtDn); + show_bool(11,21, PROT.Available); + show_bool(12,21, PROT.Batch); + show_bool(13,21, PROT.Bidir); + show_str( 14,21,30, PROT.Advice); + show_int( 15,21, PROT.Efficiency); + show_bool(16,21, PROT.Deleted); + show_sec( 17,21, PROT.Level); + + j = select_menu(11); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&PROT, crc1, sizeof(PROT)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&PROT, sizeof(PROT), 1, fil); + fclose(fil); + ProtUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_UPS( 7,21,1, PROT.ProtKey, "The ^Key^ to select this protocol") + case 2: E_STR( 8,21,20,PROT.ProtName, "The ^name^ of this protocol") + case 3: E_STR( 9,21,50,PROT.ProtUp, "The ^Upload^ path, binary and parameters") + case 4: E_STR( 10,21,50,PROT.ProtDn, "The ^Download^ path, binary and parameters") + case 5: E_BOOL(11,21, PROT.Available, "Is this protocol ^available^") + case 6: E_BOOL(12,21, PROT.Batch, "Is this a ^batching^ transfer protocol") + case 7: E_BOOL(13,21, PROT.Bidir, "Is this protocol ^bidirectional^") + case 8: E_STR( 14,21,30,PROT.Advice, "A small ^advice^ to the user, eg \"Press Ctrl-X to abort\"") + case 9: E_INT( 15,21, PROT.Efficiency,"The ^efficiency^ in % of this protocol") + case 10:E_BOOL(16,21, PROT.Deleted, "Is this protocol ^Deleted^") + case 11:E_SEC( 17,21, PROT.Level, "8.5.11 PROTOCOL SECURITY LEVEL", s_protrec) + } + } + + return 0; +} + + + +void EditProtocol(void) +{ + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountProtocol(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenProtocol() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "8.5 PROTOCOL SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/protocol.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fil); + x = 4; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(PROThdr) + ((i - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + if (i == 11) + x = 44; + if (PROT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, PROT.ProtKey, PROT.ProtName); + temp[37] = '\0'; + mvprintw(i + 6, x, temp); + } + fclose(fil); + } + /* Show records here */ + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseProtocol(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendProtocol() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditProtRec(atoi(pick)); + } +} + + + +char *PickProtocol(int nr) +{ + static char Prot[21] = ""; + int records, i, x; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return Prot; + } + + records = CountProtocol(); + if (records == -1) { + working(2, 0, 0); + return Prot; + } + + working(0, 0, 0); + + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%d. PROTOCOL SELECT", nr); + mvprintw( 5, 4, temp); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&PROThdr, sizeof(PROThdr), 1, fil); + x = 2; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(PROThdr) + ((i - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + if (i == 11) + x = 42; + if (PROT.Available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %s %-30s", i, PROT.ProtKey, PROT.ProtName); + temp[37] = '\0'; + mvprintw(i + 6, x, temp); + } + strcpy(pick, select_pick(records, 20)); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + offset = sizeof(PROThdr) + ((atoi(pick) - 1) * PROThdr.recsize); + fseek(fil, offset, 0); + fread(&PROT, PROThdr.recsize, 1, fil); + strcpy(Prot, PROT.ProtName); + } + fclose(fil); + } + } + return Prot; +} + + + +int bbs_prot_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/protocol.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 8, 5, page, (char *)"BBS Transfer protocols"); + j = 0; + fprintf(fp, "\n\n"); + fread(&PROThdr, sizeof(PROThdr), 1, no); + + while ((fread(&PROT, PROThdr.recsize, 1, no)) == 1) { + + if (j == 4) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Selection key %s\n", PROT.ProtKey); + fprintf(fp, " Protocol name %s\n", PROT.ProtName); + fprintf(fp, " Upload command %s\n", PROT.ProtUp); + fprintf(fp, " Download command %s\n", PROT.ProtDn); + fprintf(fp, " Available %s\n", getboolean(PROT.Available)); + fprintf(fp, " Batch protocol %s\n", getboolean(PROT.Batch)); + fprintf(fp, " Bidirectional %s\n", getboolean(PROT.Bidir)); + fprintf(fp, " User advice %s\n", PROT.Advice); + fprintf(fp, " Efficiency %d%%\n", PROT.Efficiency); + fprintf(fp, " Security level %s\n", get_secstr(PROT.Level)); + fprintf(fp, "\n\n"); + + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_protocol.h b/mbsetup/m_protocol.h new file mode 100644 index 00000000..c4f0e668 --- /dev/null +++ b/mbsetup/m_protocol.h @@ -0,0 +1,12 @@ +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + + +int CountProtocol(void); +void EditProtocol(void); +char *PickProtocol(int); +int bbs_prot_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_service.c b/mbsetup/m_service.c new file mode 100644 index 00000000..4f3acbbe --- /dev/null +++ b/mbsetup/m_service.c @@ -0,0 +1,435 @@ +/***************************************************************************** + * + * File ..................: m_service.c + * Purpose ...............: Service Setup + * Last modification date : 30-Apr-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_service.h" + + +int ServiceUpdated; + + +/* + * Count nr of servrec records in the database. + * Creates the database if it doesn't exist. + */ +int CountService(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + servhdr.hdrsize = sizeof(servhdr); + servhdr.recsize = sizeof(servrec); + servhdr.lastupd = time(NULL); + fwrite(&servhdr, sizeof(servhdr), 1, fil); + memset(&servrec, 0, sizeof(servrec)); + sprintf(servrec.Service, "UUCP"); + servrec.Action = EMAIL; + servrec.Active = TRUE; + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "areamgr"); + servrec.Action = AREAMGR; + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "gecho"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "fmail"); + fwrite(&servrec, sizeof(servrec), 1, fil); + servrec.Action = FILEMGR; + sprintf(servrec.Service, "allfix"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "mbtic"); + fwrite(&servrec, sizeof(servrec), 1, fil); + sprintf(servrec.Service, "raid"); + fwrite(&servrec, sizeof(servrec), 1, fil); + fclose(fil); + return 6; + } else + return -1; + } + + fread(&servhdr, sizeof(servhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - servhdr.hdrsize) / servhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenService(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/service.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&servhdr, sizeof(servhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = servhdr.recsize; + if (oldsize != sizeof(servrec)) + ServiceUpdated = 1; + else + ServiceUpdated = 0; + servhdr.hdrsize = sizeof(servhdr); + servhdr.recsize = sizeof(servrec); + fwrite(&servhdr, sizeof(servhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&servrec, 0, sizeof(servrec)); + while (fread(&servrec, oldsize, 1, fin) == 1) { + fwrite(&servrec, sizeof(servrec), 1, fout); + memset(&servrec, 0, sizeof(servrec)); + } + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseService(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *hat = NULL, *tmp; + + sprintf(fin, "%s/etc/service.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/service.temp", getenv("MBSE_ROOT")); + + if (ServiceUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&servhdr, servhdr.hdrsize, 1, fi); + fwrite(&servhdr, servhdr.hdrsize, 1, fo); + + while (fread(&servrec, servhdr.recsize, 1, fi) == 1) + if (!servrec.Deleted) + fill_stlist(&hat, servrec.Service, ftell(fi) - servhdr.recsize); + sort_stlist(&hat); + + for (tmp = hat; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&servrec, servhdr.recsize, 1, fi); + fwrite(&servrec, servhdr.recsize, 1, fo); + } + + tidy_stlist(&hat); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"servrec.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendService(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&servrec, 0, sizeof(servrec)); + /* + * Fill in default values + */ + fwrite(&servrec, sizeof(servrec), 1, fil); + fclose(fil); + ServiceUpdated = 1; + return 0; + } else + return -1; +} + + + +void ServiceScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 2, "16. EDIT SERVICES"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Name"); + mvprintw( 8, 2, "2. Type"); + mvprintw( 9, 2, "3. Active"); + mvprintw(10, 2, "4. Deleted"); +} + + + +/* + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditServiceRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Service"); + + sprintf(mfile, "%s/etc/service.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&servhdr, sizeof(servhdr), 1, fil); + offset = servhdr.hdrsize + ((Area -1) * servhdr.recsize); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&servrec, servhdr.recsize, 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&servrec, crc, servhdr.recsize); + working(0, 0, 0); + + for (;;) { + ServiceScreen(); + set_color(WHITE, BLACK); + show_str( 7,18,15, servrec.Service); + show_service(8, 18, servrec.Action); + show_bool( 9,18, servrec.Active); + show_bool(10,18, servrec.Deleted); + + switch(select_menu(4)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&servrec, crc1, servhdr.recsize); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&servrec, servhdr.recsize, 1, fil); + fclose(fil); + ServiceUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 7,18,15, servrec.Service,"Enter the ^name^ of this ^service^.") + case 2: servrec.Action = edit_service(8,18,servrec.Action); + break; + case 3: E_BOOL( 9,18, servrec.Active, "If this service is ^active^") + case 4: E_BOOL(10,18, servrec.Deleted, "If this record is ^Deleted^") + } + } +} + + + +void EditService(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountService(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenService() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "16. SERVICE MANAGER"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/service.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&servhdr, sizeof(servhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(servhdr) + (((o + i) - 1) * servhdr.recsize); + fseek(fil, offset, 0); + fread(&servrec, servhdr.recsize, 1, fil); + if (servrec.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-15s %s", o+i, servrec.Service, getservice(servrec.Action)); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseService(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendService() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditServiceRec(atoi(pick)); + } +} + + + +int service_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + int j; + + sprintf(temp, "%s/etc/service.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 14, 0, page, (char *)"Service manager"); + j = 0; + + fprintf(fp, "\n"); + fprintf(fp, " Service Action Active\n"); + fprintf(fp, " --------------- -------- ------\n"); + fread(&servhdr, sizeof(servhdr), 1, no); + + while ((fread(&servrec, servhdr.recsize, 1, no)) == 1) { + + if (j == 50) { + page = newpage(fp, page); + fprintf(fp, "\n"); + fprintf(fp, " Service Action Active\n"); + fprintf(fp, " --------------- -------- ------\n"); + j = 0; + } + + fprintf(fp, " %-15s %-8s %s\n", servrec.Service, getservice(servrec.Action), getboolean(servrec.Active)); + j++; + } + + fclose(no); + return page; +} + + diff --git a/mbsetup/m_service.h b/mbsetup/m_service.h new file mode 100644 index 00000000..619303bf --- /dev/null +++ b/mbsetup/m_service.h @@ -0,0 +1,10 @@ +#ifndef _SERVICE_H +#define _SERVICE_H + + +int CountService(void); +void EditService(void); +int service_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_task.c b/mbsetup/m_task.c new file mode 100644 index 00000000..e7be5b7c --- /dev/null +++ b/mbsetup/m_task.c @@ -0,0 +1,243 @@ +/***************************************************************************** + * + * File ..................: setup/m_task.c + * Purpose ...............: Setup TaskManager. + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_task.h" + + + +struct taskrec TCFG; +unsigned long crc1, crc2; + + + +/* + * Open database for editing. + */ +int OpenTask(void); +int OpenTask(void) +{ + FILE *fin; + char fnin[PATH_MAX]; + + sprintf(fnin, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + fread(&TCFG, sizeof(TCFG), 1, fin); + fclose(fin); + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&TCFG, crc1, sizeof(TCFG)); + return 0; + } + return -1; +} + + + +void CloseTask(void); +void CloseTask(void) +{ + char fin[PATH_MAX]; + FILE *fp; + + crc2 = 0xffffffff; + crc2 = upd_crc32((char *)&TCFG, crc2, sizeof(TCFG)); + + if (crc1 != crc2) { + if (yes_no((char *)"Configuration is changed, save changes") == 1) { + working(1, 0, 0); + sprintf(fin, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((fp = fopen(fin, "w+")) != NULL) { + fwrite(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + Syslog('+', "Updated \"task.data\""); + } + } + } + working(1, 0, 0); +} + + + +/* + * Edit task record. + */ +int EditTask(void); +int EditTask() +{ + int j; + char temp[20]; + + clr_index(); + IsDoing("Edit Taskmanager"); + + set_color(WHITE, BLACK); + mvprintw( 4, 1, "18. EDIT TASK MANAGER"); + set_color(CYAN, BLACK); + mvprintw( 6, 1, " 1. Mailout"); + mvprintw( 7, 1, " 2. Mailin"); + mvprintw( 8, 1, " 3. Newnews"); + mvprintw( 9, 1, " 4. Index 1"); + mvprintw(10, 1, " 5. Index 2"); + mvprintw(11, 1, " 6. Index 3"); + mvprintw(12, 1, " 7. Msglink"); + mvprintw(13, 1, " 8. Reqindex"); + mvprintw(14, 1, " 9. ISP conn"); + mvprintw(15, 1, "10. ISP disc"); + mvprintw(16, 1, "11. Ping #1"); + mvprintw(17, 1, "12. Ping #2"); + mvprintw(18, 1, "13. ISP blks"); + mvprintw(19, 1, "14. Max Load"); + + mvprintw(18,29, "15. ZMH start"); + mvprintw(19,29, "16. ZMH end"); + + mvprintw(16,55, "17. Debug"); + mvprintw(17,55, "18. Max POTS"); + mvprintw(18,55, "19. Max ISDN"); + mvprintw(19,55, "20. Max TCP"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6, 15,65, TCFG.cmd_mailout); + show_str( 7, 15,65, TCFG.cmd_mailin); + show_str( 8, 15,65, TCFG.cmd_newnews); + show_str( 9, 15,65, TCFG.cmd_mbindex1); + show_str(10, 15,65, TCFG.cmd_mbindex2); + show_str(11, 15,65, TCFG.cmd_mbindex3); + show_str(12, 15,65, TCFG.cmd_msglink); + show_str(13, 15,65, TCFG.cmd_reqindex); + show_str(14, 15,65, TCFG.isp_connect); + show_str(15, 15,65, TCFG.isp_hangup); + show_str(16, 15,40, TCFG.isp_ping1); + show_str(17, 15,40, TCFG.isp_ping2); + show_bool(18,15, TCFG.ipblocks); + sprintf(temp, "%0.2f", TCFG.maxload); + show_str(19, 15,5, temp); + + show_str( 18,44, 5, TCFG.zmh_start); + show_str( 19,44, 5, TCFG.zmh_end); + + show_bool(16,69, TCFG.debug); + show_int( 17,69, TCFG.max_pots); + show_int( 18,69, TCFG.max_isdn); + show_int( 19,69, TCFG.max_tcp); + + j = select_menu(20); + switch(j) { + case 0: return 0; + case 1: E_STR( 6,15,65,TCFG.cmd_mailout, "The command to execute on semafore ^mailout^") + case 2: E_STR( 7,15,65,TCFG.cmd_mailin, "The command to execute on semafore ^mailin^") + case 3: E_STR( 8,15,65,TCFG.cmd_newnews, "The command to execute on semafore ^newnews^") + case 4: E_STR( 9,15,65,TCFG.cmd_mbindex1, "The compiler 1 command to execute on semafore ^mbindex^") + case 5: E_STR( 10,15,65,TCFG.cmd_mbindex2, "The compiler 2 command to execute on semafore ^mbindex^") + case 6: E_STR( 11,15,65,TCFG.cmd_mbindex3, "The compiler 3 command to execute on semafore ^mbindex^") + case 7: E_STR( 12,15,65,TCFG.cmd_msglink, "The command to execute on semafore ^msglink^") + case 8: E_STR( 13,15,65,TCFG.cmd_reqindex, "The command to execute on semafore ^reqindex^") + case 9: E_STR( 14,15,65,TCFG.isp_connect, "The command to ^connect^ the Internet Connection") + case 10:E_STR( 15,15,65,TCFG.isp_hangup, "The command to ^hangup^ the Internet Connection") + case 11:E_STR( 16,15,40,TCFG.isp_ping1, "The ^IP address^ of host 1 to check the Internet Connection") + case 12:E_STR( 17,15,40,TCFG.isp_ping2, "The ^IP address^ of host 2 to check the Internet Connection") + case 13:E_BOOL(18,15, TCFG.ipblocks, "The ^internet^ connection ^blocks^ dial connections") + case 14:strcpy(temp, edit_str(19,15,5,temp, (char *)"^Maximum system load^ at which processing stops (1.00 .. 3.00)")); + sscanf(temp, "%f", &TCFG.maxload); + break; + case 15:E_STR( 18,44,5, TCFG.zmh_start, "^Start^ of Zone Mail Hour in UTC") + case 16:E_STR( 19,44,5, TCFG.zmh_end, "^End& of Zone Mail Hour in UTC") + case 17:E_BOOL(16,69, TCFG.debug, "Enable ^debug^ logging") + case 18:E_INT( 17,69, TCFG.max_pots, "Maximum simultanous ^POTS^ (analogue) connections") + case 19:E_INT( 18,69, TCFG.max_isdn, "Maximum simultanous ^ISDN^ connections") + case 20:E_INT( 19,69, TCFG.max_tcp, "Maximum simultanous ^TCP/IP^ connections") + } + } + + return 0; +} + + + +void task_menu(void) +{ + OpenTask(); + EditTask(); + CloseTask(); +} + + +int task_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *no; + + sprintf(temp, "%s/etc/task.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + fread(&TCFG, sizeof(TCFG), 1, no); + fclose(no); + + page = newpage(fp, page); + addtoc(fp, toc, 16, 0, page, (char *)"Task manager"); + + fprintf(fp, "\n"); + fprintf(fp, " Command on mailout %s\n", TCFG.cmd_mailout); + fprintf(fp, " Command on mailin %s\n", TCFG.cmd_mailin); + fprintf(fp, " Command on newnews %s\n", TCFG.cmd_newnews); + fprintf(fp, " Command on mbindex 1 %s\n", TCFG.cmd_mbindex1); + fprintf(fp, " Command on mbindex 2 %s\n", TCFG.cmd_mbindex2); + fprintf(fp, " Command on mbindex 3 %s\n", TCFG.cmd_mbindex3); + fprintf(fp, " Command on msglink %s\n", TCFG.cmd_msglink); + fprintf(fp, " Command on reqindex %s\n\n", TCFG.cmd_reqindex); + + fprintf(fp, " Zone Mail Hour start %s\n", TCFG.zmh_start); + fprintf(fp, " Zone Mail Hour end %s\n\n", TCFG.zmh_end); + + fprintf(fp, " ISP connect command %s\n", TCFG.isp_connect); + fprintf(fp, " ISP hangup command %s\n", TCFG.isp_hangup); + fprintf(fp, " ISP ping host 1 %s\n", TCFG.isp_ping1); + fprintf(fp, " ISP ping host 2 %s\n", TCFG.isp_ping2); + fprintf(fp, " Internet blocks dial %s\n\n", getboolean(TCFG.ipblocks)); + + fprintf(fp, " Enable denug logging %s\n", getboolean(TCFG.debug)); + fprintf(fp, " Maximum system load %0.2f\n", TCFG.maxload); + fprintf(fp, " Max POTS connections %d\n", TCFG.max_pots); + fprintf(fp, " Max ISDN connections %d\n", TCFG.max_isdn); + fprintf(fp, " Max TCP/IP connections %d\n", TCFG.max_tcp); + + return page; +} + + diff --git a/mbsetup/m_task.h b/mbsetup/m_task.h new file mode 100644 index 00000000..7e64f419 --- /dev/null +++ b/mbsetup/m_task.h @@ -0,0 +1,10 @@ +#ifndef _TASK_H +#define _TASK_H + + +void task_menu(void); +int task_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_tic.c b/mbsetup/m_tic.c new file mode 100644 index 00000000..13b4346b --- /dev/null +++ b/mbsetup/m_tic.c @@ -0,0 +1,98 @@ +/***************************************************************************** + * + * File ..................: m_tic.c + * Purpose ...............: TIC Setup Program + * Last modification date : 08-Feb-1999 + * + ***************************************************************************** + * Copyright (C) 1997-1999 + * + * Michiel Broek FIDO: 2:2801/16 + * Beekmansbos 10 Internet: mbroek@ux123.pttnwb.nl + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_fgroup.h" +#include "m_ticarea.h" +#include "m_magic.h" +#include "m_hatch.h" +#include "m_tic.h" + + +void tic_menu(void) +{ + for (;;) { + + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10. FILEECHO SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Fileecho Groups"); + mvprintw( 8, 6, "2. Edit Fileecho Areas"); + mvprintw( 9, 6, "3. Edit Hatch Manager"); + mvprintw(10, 6, "4. Edit Magic files"); + + switch(select_menu(4)) { + case 0: + return; + + case 1: + EditFGroup(); + break; + + case 2: + EditTicarea(); + break; + + case 3: + EditHatch(); + break; + + case 4: + EditMagics(); + break; + } + } +} + + + +int tic_doc(FILE *fp, FILE *toc, int page) +{ + int next; + + page = newpage(fp, page); + addtoc(fp, toc, 10, 0, page, (char *)"Files processing"); + + next = tic_group_doc(fp, toc, page); + next = tic_areas_doc(fp, toc, next); + next = tic_hatch_doc(fp, toc, next); + next = tic_magic_doc(fp, toc, next); + + return next; +} + + diff --git a/mbsetup/m_tic.h b/mbsetup/m_tic.h new file mode 100644 index 00000000..896a6fb6 --- /dev/null +++ b/mbsetup/m_tic.h @@ -0,0 +1,4 @@ + +void tic_menu(void); +int tic_doc(FILE *, FILE *, int); + diff --git a/mbsetup/m_ticarea.c b/mbsetup/m_ticarea.c new file mode 100644 index 00000000..3fe88ee5 --- /dev/null +++ b/mbsetup/m_ticarea.c @@ -0,0 +1,1256 @@ +/***************************************************************************** + * + * File ..................: m_ticareas.c + * Purpose ...............: TIC Areas Setup Program + * Last modification date : 29-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "grlist.h" +#include "m_global.h" +#include "m_node.h" +#include "m_fgroup.h" +#include "m_farea.h" +#include "m_archive.h" +#include "m_ticarea.h" + + +int TicUpdated = 0; +unsigned long TicCrc; +FILE *ttfil = NULL; + + + +/* + * Count nr of tic records in the database. + * Creates the database if it doesn't exist. + */ +int CountTicarea(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + Syslog('+', "Created tic.data"); + tichdr.hdrsize = sizeof(tichdr); + tichdr.recsize = sizeof(tic); + tichdr.syssize = CFG.tic_systems * sizeof(sysconnect); + tichdr.lastupd = time(NULL); + fwrite(&tichdr, sizeof(tichdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + fseek(fil, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - tichdr.hdrsize) / (tichdr.recsize + tichdr.syssize); + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenTicarea(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize, oldsys; + struct _sysconnect syscon; + int i, oldsystems; + + sprintf(fnin, "%s/etc/tic.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + Syslog('+', "Opened \"tic.data\""); + TicUpdated = 0; + fread(&tichdr, sizeof(tichdr), 1, fin); + fseek(fin, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, fin); + if (tichdr.hdrsize != sizeof(tichdr)) { + tichdr.hdrsize = sizeof(tichdr); + tichdr.lastupd = time(NULL); + TicUpdated = 1; + } + + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = tichdr.recsize; + oldsys = tichdr.syssize; + oldsystems = oldsys / sizeof(syscon); + if ((oldsize != sizeof(tic)) || (CFG.tic_systems != oldsystems)) { + TicUpdated = 1; + Syslog('+', "\"tic.data\" nr of systems is changed"); + } + tichdr.hdrsize = sizeof(tichdr); + tichdr.recsize = sizeof(tic); + tichdr.syssize = sizeof(syscon) * CFG.tic_systems; + fwrite(&tichdr, sizeof(tichdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&tic, 0, sizeof(tic)); + while (fread(&tic, oldsize, 1, fin) == 1) { + fwrite(&tic, sizeof(tic), 1, fout); + memset(&tic, 0, sizeof(tic)); + /* + * Copy the existing connections + */ + for (i = 1; i <= oldsystems; i++) { + fread(&syscon, sizeof(syscon), 1, fin); + /* + * Write only valid records + */ + if (i <= CFG.tic_systems) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + if (oldsystems < CFG.tic_systems) { + /* + * The size is increased, fill with + * blank records. + */ + memset(&syscon, 0, sizeof(syscon)); + for (i = (oldsystems + 1); i <= CFG.tic_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fout); + } + } + + fclose(fin); + fclose(fout); + Syslog('+', "Opened \"tic.data\""); + if (TicUpdated) + Syslog('+', "Updated \"tic.data\" data format"); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseTicarea(int Force) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *tir = NULL, *tmp; + int i; + struct _sysconnect syscon; + + sprintf(fin, "%s/etc/tic.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/tic.temp", getenv("MBSE_ROOT")); + + if (TicUpdated == 1) { + if (Force || (yes_no((char *)"Tic areas database is changed, save changes")) == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&tichdr, tichdr.hdrsize, 1, fi); + fwrite(&tichdr, tichdr.hdrsize, 1, fo); + + while (fread(&tic, tichdr.recsize, 1, fi) == 1) { + if (!tic.Deleted) + fill_stlist(&tir, tic.Name, ftell(fi) - tichdr.recsize); + fseek(fi, tichdr.syssize, SEEK_CUR); + } + sort_stlist(&tir); + + for (tmp = tir; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fi); + fwrite(&tic, tichdr.recsize, 1, fo); + for (i = 0; i < (tichdr.syssize / sizeof(syscon)); i++) { + fread(&syscon, sizeof(syscon), 1, fi); + fwrite(&syscon, sizeof(syscon), 1, fo); + } + } + + tidy_stlist(&tir); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"tic.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); + Syslog('+', "No update of \"tic.data\""); +} + + + +int AppendTicarea(void); +int AppendTicarea(void) +{ + FILE *fil; + char ffile[81]; + struct _sysconnect syscon; + int i; + + sprintf(ffile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&tic, 0, sizeof(tic)); + /* + * Fill in default values + */ + tic.DupCheck = TRUE; + tic.Secure = TRUE; + tic.VirScan = TRUE; + tic.Announce = TRUE; + tic.UpdMagic = TRUE; + tic.FileId = TRUE; + tic.Active = TRUE; + tic.AreaStart = time(NULL); + fwrite(&tic, sizeof(tic), 1, fil); + memset(&syscon, 0, sizeof(syscon)); + for (i = 1; i <= CFG.tic_systems; i++) + fwrite(&syscon, sizeof(syscon), 1, fil); + fclose(fil); + TicUpdated = 1; + return 0; + } else + return -1; +} + + + +void EditTicSystem(sysconnect *); +void EditTicSystem(sysconnect *Sys) +{ + sysconnect S; + unsigned short zone = 0; + int refresh = TRUE; + + S = (* Sys); + for (;;) { + if (refresh) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5,6, "10.2.25 EDIT CONNECTION"); + set_color(CYAN, BLACK); + mvprintw( 7,6, "1. Aka"); + mvprintw( 8,6, "2. Send to"); + mvprintw( 9,6, "3. Recv from"); + mvprintw(10,6, "4. Pause"); + mvprintw(11,6, "5. Delete"); + refresh = FALSE; + } + + set_color(WHITE, BLACK); + show_str( 7,24,23, aka2str(S.aka)); + show_bool( 8,24, S.sendto); + show_bool( 9,24, S.receivefrom); + show_bool(10,24, S.pause); + zone = S.aka.zone; + + switch(select_menu(5)) { + case 0: (* Sys) = S; + return; + case 1: S.aka = PullUplink((char *)"10.2.25"); + refresh = TRUE; + break; + case 2: E_BOOL( 8,24, S.sendto, "^Send^ files ^to^ this node") + case 3: E_BOOL( 9,24, S.receivefrom, "^Receive^ files ^from^ this node") + case 4: E_BOOL(10,24, S.pause, "Is this node ^paused^") + case 5: if (yes_no((char *)"Delete this entry")) { + memset(&S, 0, sizeof(sysconnect)); + (* Sys) = S; + return; + } + break; + } + + /* + * Set sendto to on when a new + * zone is entered. + */ + if ((S.aka.zone) && (!zone)) { + S.sendto = 1; + } + } +} + + + +int EditTicConnections(FILE *); +int EditTicConnections(FILE *fil) +{ + int systems, o = 0, i, y, x; + long offset; + char pick[12]; + sysconnect System; + char status[4]; + char temp[41]; + + systems = tichdr.syssize / sizeof(sysconnect); + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 5, "10.2.25 TIC AREA CONNECTIONS"); + set_color(CYAN, BLACK); + y = 7; + x = 2; + for (i = 1; i <= 20; i++) { + if ((o+i-1) < systems) { + if (i == 11) { + y = 7; + x = 42; + } + offset = (o+i-1) * sizeof(sysconnect); + if ((fseek(fil, offset, 0)) != 0) { + working(2, 0, 0); + return FALSE; + } + fread(&System, sizeof(sysconnect), 1, fil); + memset(&status, 0, 4); + memset(&status, '-', 3); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + if (System.aka.zone) { + set_color(CYAN,BLACK); + sprintf(temp, "%3d. %s %s", o+i, status, aka2str(System.aka)); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o+i); + } + mvprintw(y, x, temp); + y++; + } + } + strcpy(pick, select_pick(systems, 20)); + + if (strncmp(pick, "-", 1) == 0) { + return FALSE; + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < systems) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if (((atoi(pick) > 0) && (atoi(pick) <= systems))) { + offset = (atoi(pick) -1) * sizeof(sysconnect); + fseek(fil, offset, 0); + fread(&System, sizeof(sysconnect), 1, fil); + EditTicSystem(&System); + fseek(fil, offset, 0); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + } +} + + + +void SetTicScreen(void); +void SetTicScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "10.2 EDIT TIC AREA"); + set_color(CYAN, BLACK); + mvprintw( 6, 2, "1. Comment"); + mvprintw( 7, 2, "2. Area tag"); + mvprintw( 8, 2, "3. BBS area"); + mvprintw( 9, 2, "4. Message"); + mvprintw(10, 2, "5. Group"); + mvprintw(11, 2, "6. Keep #"); + mvprintw(12, 2, "7. Fido aka"); + mvprintw(13, 2, "8. Convert"); + mvprintw(14, 2, "9. Banner"); + mvprintw(15, 2, "10. Replace"); + + mvprintw( 7,37, "11. Dupecheck"); + mvprintw( 8,37, "12. Secure"); + mvprintw( 9,37, "13. No touch"); + mvprintw(10,37, "14. Virus sc."); + mvprintw(11,37, "15. Announce"); + mvprintw(12,37, "16. Upd magic"); + mvprintw(13,37, "17. File_id"); + mvprintw(14,37, "18. Conv.all"); + mvprintw(15,37, "19. Send org."); + + mvprintw( 7,59, "20. Mandatory"); + mvprintw( 8,59, "21. Notified"); + mvprintw( 9,59, "22. Upl discon"); + mvprintw(10,59, "23. Deleted"); + mvprintw(11,59, "24. Active"); + mvprintw(12,59, "25. Systems"); +} + + + +long LoadTicRec(int, int); +long LoadTicRec(int Area, int work) +{ + FILE *fil; + char mfile[81]; + long offset; + sysconnect System; + int i; + + if (work) + working(1, 0, 0); + + sprintf(mfile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + if ((ttfil = tmpfile()) == NULL) { + working(2, 0, 0); + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + offset = tichdr.hdrsize + (((Area -1) * (tichdr.recsize + tichdr.syssize))); + if (fseek(fil, offset, 0) != 0) { + fclose(ttfil); + working(2, 0, 0); + return -1; + } + + fread(&tic, tichdr.recsize, 1, fil); + TicCrc = 0xffffffff; + TicCrc = upd_crc32((char *)&tic, TicCrc, tichdr.recsize); + for (i = 0; i <= (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, fil); + fwrite(&System, sizeof(sysconnect), 1, ttfil); + TicCrc = upd_crc32((char *)&System, TicCrc, sizeof(sysconnect)); + } + fclose(fil); + if (work) + working(0, 0, 0); + return offset; +} + + + +int SaveTicRec(int, int); +int SaveTicRec(int Area, int work) +{ + int i; + FILE *fil; + long offset; + char mfile[81]; + sysconnect System; + + if (work) + working(1, 0, 0); + sprintf(mfile, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r+")) == 0) { + working(2, 0, 0); + return -1; + } + + fread(&tichdr, sizeof(tichdr), 1, fil); + offset = tichdr.hdrsize + (((Area -1) * (tichdr.recsize + tichdr.syssize))); + if (fseek(fil, offset, SEEK_SET)) { + fclose(fil); + working(2, 0, 0); + return -1; + } + + fwrite(&tic, tichdr.recsize, 1, fil); + fseek(ttfil, 0, SEEK_SET); + for (i = 0; i < (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, ttfil); + fwrite(&System, sizeof(sysconnect), 1, fil); + } + fclose(fil); + fclose(ttfil); + ttfil = NULL; + if (work) + working(0, 0, 0); + return 0; +} + + + +void ShowTicStatus(sysconnect); +void ShowTicStatus(sysconnect S) +{ + clr_index(); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "Aka"); + mvprintw( 8, 6, "Send to"); + mvprintw( 9, 6, "Recv from"); + mvprintw(10, 6, "Pause"); + set_color(WHITE, BLACK); + show_str( 7,16,23, aka2str(S.aka)); + show_bool( 8,16, S.sendto); + show_bool( 9,16, S.receivefrom); + show_bool(10,16, S.pause); +} + + + +void TicGlobal(void); +void TicGlobal(void) +{ + gr_list *mgr = NULL, *tmp; + char *p, tfile[128]; + FILE *fil; + fidoaddr a1, a2; + int menu = 0, areanr, Areas, akan = 0, Found; + int Total, Done; + long offset; + sysconnect S, Sc; + + /* + * Build the groups select array + */ + working(1, 0, 0); + sprintf(tfile, "%s/etc/fgroups.data", getenv("MBSE_ROOT")); + if ((fil = fopen(tfile, "r")) != NULL) { + fread(&fgrouphdr, sizeof(fgrouphdr), 1, fil); + + while (fread(&fgroup, fgrouphdr.recsize, 1, fil) == 1) + fill_grlist(&mgr, fgroup.Name); + + fclose(fil); + sort_grlist(&mgr); + } + working(0, 0, 0); + + /* + * Initialize some variables + */ + memset(&S, 0, sizeof(sysconnect)); + S.sendto = TRUE; + S.receivefrom = FALSE; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "10.2 GLOBAL EDIT TIC AREAS"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Delete connection"); + mvprintw( 8, 6, "2. Add new connection"); + mvprintw( 9, 6, "3. Replace connection"); + mvprintw(10, 6, "4. Change connection status"); + mvprintw(11, 6, "5. Change aka to use"); + mvprintw(12, 6, "6. Delete TIC area"); + + memset(&a1, 0, sizeof(fidoaddr)); + memset(&a2, 0, sizeof(fidoaddr)); + + menu = select_menu(6); + switch (menu) { + case 0: return; + case 1: a1 = PullUplink((char *)"AKA TO DELETE"); + break; + case 2: a2 = PullUplink((char *)"AKA TO ADD"); + break; + case 3: a1 = PullUplink((char *)"AKA TO REPLACE"); + a2 = PullUplink((char *)"NEW AKA"); + break; + case 4: S.aka = PullUplink((char *)"AKA TO CHANGE STATUS"); + ShowTicStatus(S); + S.sendto = edit_bool(8,16,S.sendto, (char *)"^Send^ files to this node"); + S.receivefrom = edit_bool(9,16,S.receivefrom, (char *)"^Receive^ files from this node"); + S.pause = edit_bool(10,16,S.pause, (char *)"Is this node ^paused^"); + break; + case 5: akan = PickAka((char *)"10.2.5", TRUE); + break; + } + + E_Group(&mgr, (char *)"SELECT TIC GROUPS TO CHANGE"); + + /* + * Show settings before proceeding + */ + switch (menu) { + case 1: mvprintw(7, 6, "Delete aka %s", aka2str(a1)); + break; + case 2: mvprintw(7, 6, "Add aka %s", aka2str(a2)); + break; + case 3: p = xstrcpy(aka2str(a1)); + mvprintw(7, 6, "Replace aka %s with %s", p, aka2str(a2)); + free(p); + break; + case 4: ShowTicStatus(S); + mvprintw(14, 6, "Change the link status"); + case 5: if (akan != -1) + mvprintw( 7, 6, "Set %s as new aka to use", aka2str(CFG.aka[akan])); + break; + case 6: mvprintw(7, 6, "Delete TIC areas"); + break; + } + + if (yes_no((char *)"Perform changes")) { + working(1, 0, 0); + Areas = CountTicarea(); + Total = Done = 0; + + for (areanr = 1; areanr <= Areas; areanr++) { + offset = LoadTicRec(areanr, FALSE); + if (tic.Active && strlen(tic.Group)) { + for (tmp = mgr; tmp; tmp = tmp->next) { + if (tmp->tagged && (strcmp(tmp->group, tic.Group) == 0)) { + Total++; + switch (menu) { + case 1: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Deleted %s from %s", aka2str(a1), tic.Name); + } + break; + } + } + break; + case 2: fseek(ttfil, 0, SEEK_SET); + Found = FALSE; + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) + if ((Sc.aka.zone == a2.zone) && + (Sc.aka.net == a2.net) && + (Sc.aka.node == a2.node) && + (Sc.aka.point == a2.point)) { + Found = TRUE; + break; + } + if (Found) + break; + fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if (Sc.aka.zone == 0) { + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + memset(&Sc, 0, sizeof(sysconnect)); + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + Sc.sendto = TRUE; + Sc.receivefrom = FALSE; + sprintf(Sc.aka.domain, "%s", a2.domain); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Added %s to area %s", aka2str(a2), tic.Name); + } + break; + } + } + break; + case 3: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == a1.zone) && + (Sc.aka.net == a1.net) && + (Sc.aka.node == a1.node) && + (Sc.aka.point == a1.point)) { + Sc.aka.zone = a2.zone; + Sc.aka.net = a2.net; + Sc.aka.node = a2.node; + Sc.aka.point = a2.point; + sprintf(Sc.aka.domain, "%s", a2.domain); + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + p = xstrcpy(aka2str(a1)); + Syslog('+', "Changed %s into %s in area %s", p, aka2str(a2), tic.Name); + free(p); + } + break; + } + } + break; + case 4: fseek(ttfil, 0, SEEK_SET); + while (fread(&Sc, sizeof(sysconnect), 1, ttfil) == 1) { + if ((Sc.aka.zone == S.aka.zone) && + (Sc.aka.net == S.aka.net) && + (Sc.aka.node == S.aka.node) && + (Sc.aka.point == S.aka.point)) { + Sc.sendto = S.sendto; + Sc.receivefrom = S.receivefrom; + Sc.pause = S.pause; + Sc.cutoff = S.cutoff; + fseek(ttfil, - sizeof(sysconnect), SEEK_CUR); + fwrite(&Sc, sizeof(sysconnect), 1, ttfil); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Changed status of %s in area %s", aka2str(S.aka), tic.Name); + } + break; + } + } + break; + case 5: if (akan != -1) { + if ((tic.Aka.zone != CFG.aka[akan].zone) || + (tic.Aka.net != CFG.aka[akan].net) || + (tic.Aka.node != CFG.aka[akan].node) || + (tic.Aka.point != CFG.aka[akan].point)) { + tic.Aka.zone = CFG.aka[akan].zone; + tic.Aka.net = CFG.aka[akan].net; + tic.Aka.node = CFG.aka[akan].node; + tic.Aka.point = CFG.aka[akan].point; + sprintf(tic.Aka.domain, "%s", CFG.aka[akan].domain); + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Area %s now uses aka %s", tic.Name, aka2str(tic.Aka)); + } + } + } + break; + case 6: if (tic.Active) { + tic.Active = FALSE; + tic.Deleted = TRUE; + if (SaveTicRec(areanr, FALSE) == 0) { + Done++; + Syslog('+', "Deleted TIC area %s", tic.Name); + } + } + break; + } + } + } + } + if (ttfil != NULL) + fclose(ttfil); + } + + working(0, 0, 0); + mvprintw(LINES -3, 6,"Made %d changes in %d possible areas", Done, Total); + (void)readkey(LINES -3, 50, LIGHTGRAY, BLACK); + if (Done) + TicUpdated = TRUE; + } + } + + tidy_grlist(&mgr); +} + + + + +/** + * Edit one record, return -1 if record doesn't exist, 0 if ok. + */ +int EditTicRec(int); +int EditTicRec(int Area) +{ + unsigned long crc1; + int tmp, i, changed = FALSE; + sysconnect System; + + clr_index(); + IsDoing("Edit Tic Area"); + + if (LoadTicRec(Area, TRUE) == -1) + return -1; + + SetTicScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 6,16,55, tic.Comment); + show_str( 7,16,20, tic.Name); + show_int( 8,16, tic.FileArea); + show_str( 9,16,14, tic.Message); + show_str(10,16,12, tic.Group); + show_int(11,16, tic.KeepLatest); + show_str(12,16,20, aka2str(tic.Aka)); + show_str(13,16,5, tic.Convert); + show_str(14,16,14, tic.Banner); + show_bool(15,16, tic.Replace); + + show_bool( 7,51, tic.DupCheck); + show_bool( 8,51, tic.Secure); + show_bool( 9,51, tic.NoTouch); + show_bool(10,51, tic.VirScan); + show_bool(11,51, tic.Announce); + show_bool(12,51, tic.UpdMagic); + show_bool(13,51, tic.FileId); + show_bool(14,51, tic.ConvertAll); + show_bool(15,51, tic.SendOrg); + + show_bool( 7,73, tic.Mandat); + show_bool( 8,73, tic.Notified); + show_bool( 9,73, tic.UplDiscon); + show_bool(10,73, tic.Deleted); + show_bool(11,73, tic.Active); + + switch(select_menu(25)) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&tic, crc1, tichdr.recsize); + fseek(ttfil, 0, 0); + for (i = 0; i <= (tichdr.syssize / sizeof(sysconnect)); i++) { + fread(&System, sizeof(sysconnect), 1, ttfil); + crc1 = upd_crc32((char *)&System, crc1, sizeof(sysconnect)); + } + if ((TicCrc != crc1) || (changed)) { + if (yes_no((char *)"Record is changed, save") == 1) { + if (SaveTicRec(Area, TRUE) == -1) + return -1; + TicUpdated = 1; + Syslog('+', "Saved tic record %d", Area); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 6,16,55, tic.Comment, "The ^description^ for this area."); + case 2: E_STR( 7,16,20, tic.Name, "The ^name^ of this ^TIC^ area."); + case 3: tmp = PickFilearea((char *)"10.2.3"); + if (tmp != 0) + tic.FileArea = tmp; + SetTicScreen(); + break; + case 4: E_STR( 9,16,14, tic.Message, "The ^message^ to include with the .tic files."); + case 5: strcpy(tic.Group, PickFGroup((char *)"10.2.5")); + if (strlen(tic.Group)) { + tic.Aka = fgroup.UseAka; + /* + * If there is an uplink defined in the group, + * and the first connected system is empty, + * copy the uplink as default connection. + */ + if (fgroup.UpLink.zone) { + fseek(ttfil, 0, SEEK_SET); + fread(&System, sizeof(sysconnect), 1, ttfil); + if (!System.aka.zone) { + memset(&System, 0, sizeof(sysconnect)); + System.aka = fgroup.UpLink; + System.receivefrom = TRUE; + fseek(ttfil, 0, SEEK_SET); + fwrite(&System, sizeof(sysconnect), 1, ttfil); + } + } + } + SetTicScreen(); + break; + case 6: E_INT(11,16, tic.KeepLatest, "^Keep^ the ^latest^ number of files."); + case 7: tmp = PickAka((char *)"10.2.7", TRUE); + if (tmp != -1) + tic.Aka = CFG.aka[tmp]; + SetTicScreen(); + break; + case 8: strcpy(tic.Convert, PickArchive((char *)"10.2.8")); + SetTicScreen(); + break; + case 9: E_STR(14,16,14, tic.Banner, "The ^banner^ to put in the file archives"); + case 10:E_BOOL(15,16, tic.Replace, "Allow ^Replace^ files command"); + case 11:E_BOOL( 7,51, tic.DupCheck, "Check for ^duplicates^ in received files"); + case 12:E_BOOL( 8,51, tic.Secure, "Check for ^secure^ systems"); + case 13:E_BOOL( 9,51, tic.NoTouch, "Don't ^touch^ filedate"); + case 14:E_BOOL(10,51, tic.VirScan, "Check received files for ^virusses^"); + case 15:E_BOOL(11,51, tic.Announce, "^Announce^ received files"); + case 16:E_BOOL(12,51, tic.UpdMagic, "Update files ^magic^ names"); + case 17:E_BOOL(13,51, tic.FileId, "Extract ^FILE_ID.DIZ^ from received files"); + case 18:E_BOOL(14,51, tic.ConvertAll, "^Convert^ archive always"); + case 19:E_BOOL(15,51, tic.SendOrg, "^Send original^ file to downlinks"); + case 20:E_BOOL( 7,73, tic.Mandat, "Is this area ^mandatory^"); + case 21:E_BOOL( 8,73, tic.Notified, "Is the sysop ^notified^ if this area is (dis)connected"); + case 22:E_BOOL( 9,73, tic.UplDiscon, "Is the uplink ^disconnected^ from this area"); + case 23:E_BOOL(10,73, tic.Deleted, "Is this area ^deleted^"); + case 24:E_BOOL(11,73, tic.Active, "Is this area ^active^"); + case 25: + if (EditTicConnections(ttfil)) + changed = TRUE; + SetTicScreen(); + break; + + } + } +} + + + +void EditTicarea(void) +{ + int records, i, o, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountTicarea(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenTicarea() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "10.2 TIC AREA SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/tic.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fil); + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = sizeof(tichdr) + (((o + i) - 1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, 0); + fread(&tic, tichdr.recsize, 1, fil); + if (tic.Active) { + set_color(CYAN, BLACK); + sprintf(temp, "%3d. %-20s %-40s", o + i, tic.Name, tic. +Comment); + } else { + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d.", o + i); + } + mvprintw(y, 2, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_area(records, 10)); + + if (strncmp(pick, "-", 1) == 0) { + CloseTicarea(FALSE); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendTicarea() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "G", 1) == 0) { + TicGlobal(); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o = o + 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o = o - 10; + + if (strncmp(pick, "M", 1) == 0) + errmsg((char *)"This has no use here"); + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditTicRec(atoi(pick)); + o = ((atoi(pick) - 1) / 10) * 10; + } + } +} + + + +char *PickTicarea(char *shdr) +{ + int records, i, o = 0, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + static char Buf[81]; + + clr_index(); + working(1, 0, 0); + if (config_read() == -1) { + working(2, 0, 0); + return '\0'; + } + + records = CountTicarea(); + if (records == -1) { + working(2, 0, 0); + return '\0'; + } + + working(0, 0, 0); + + for(;;) { + clr_index(); + set_color(WHITE, BLACK); + sprintf(temp, "%s. TIC AREA SELECT", shdr); + mvprintw(5, 3, temp); + set_color(CYAN, BLACK); + + if (records) { + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&tichdr, sizeof(tichdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 10; i++) { + if ((o + i) <= records) { + offset = tichdr.hdrsize + (((o + i) - 1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fil); + if (tic.Active) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-20s %-40s", o + i, tic.Name, tic.Comment); + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_pick(records, 10)); + + if (strncmp(pick, "-", 1) == 0) + return '\0'; + + if (strncmp(pick, "N", 1) == 0) + if ((o + 10) < records) + o += 10; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 10) >= 0) + o -= 10; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + offset = tichdr.hdrsize + ((atoi(pick) -1) * (tichdr.recsize + tichdr.syssize)); + fseek(fil, offset, SEEK_SET); + fread(&tic, tichdr.recsize, 1, fil); + fclose(fil); + if (tic.Active) { + memset(&Buf, 0, sizeof(Buf)); + sprintf(Buf, "%s", tic.Name); + return Buf; + } + } + } + } +} + + + +int GroupInTic(char *Group) +{ + char temp[81]; + FILE *no; + int systems, Area = 0, RetVal = 0; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + Area++; + + if (!strcmp(tic.Group, Group) && strlen(tic.Group)) { + RetVal++; + Syslog('-', "Group %s in tic area %d: %s", Group, Area, tic.Name); + } + + fseek(no, tichdr.syssize, SEEK_CUR); + } + + fclose(no); + return RetVal; +} + + + +int NodeInTic(fidoaddr A) +{ + int i, Area = 0, RetVal = 0, systems; + FILE *no; + char temp[128]; + sysconnect S; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return 0; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + Area++; + for (i = 0; i < systems; i++) { + fread(&S, sizeof(sysconnect), 1, no); + if (S.aka.zone && (S.aka.zone == A.zone) && (S.aka.net == A.net) && + (S.aka.node == A.node) && (S.aka.point == A.point) && tic.Active) { + RetVal++; + Syslog('-', "Node %s connected to tic area %d: %s", aka2str(A), Area, tic.Name); + } + } + } + + fclose(no); + return RetVal; +} + + + +int tic_areas_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81], status[4]; + FILE *no; + int i, systems, First = TRUE; + sysconnect System; + + sprintf(temp, "%s/etc/tic.data", getenv("MBSE_ROOT")); + if ((no = fopen(temp, "r")) == NULL) + return page; + + fread(&tichdr, sizeof(tichdr), 1, no); + fseek(no, 0, SEEK_SET); + fread(&tichdr, tichdr.hdrsize, 1, no); + systems = tichdr.syssize / sizeof(sysconnect); + + while ((fread(&tic, tichdr.recsize, 1, no)) == 1) { + + page = newpage(fp, page); + + if (First) { + addtoc(fp, toc, 10, 2, page, (char *)"File processing areas"); + First = FALSE; + fprintf(fp, "\n"); + } else + fprintf(fp, "\n\n"); + + fprintf(fp, " Area tag %s\n", tic.Name); + fprintf(fp, " Active %s\n", getboolean(tic.Active)); + fprintf(fp, " Comment %s\n", tic.Comment); + fprintf(fp, " BBS area %ld\n", tic.FileArea); + fprintf(fp, " Message %s\n", tic.Message); + fprintf(fp, " Group %s\n", tic.Group); + fprintf(fp, " Keep Numbe %d\n", tic.KeepLatest); + fprintf(fp, " Fido Aka %s\n", aka2str(tic.Aka)); + fprintf(fp, " Convert to %s\n", tic.Convert); + fprintf(fp, " Convert all %s\n", getboolean(tic.ConvertAll)); + fprintf(fp, " Banner file %s\n", tic.Banner); + fprintf(fp, " Replace ok. %s\n", getboolean(tic.Replace)); + fprintf(fp, " Dupe check %s\n", getboolean(tic.DupCheck)); + fprintf(fp, " Secure %s\n", getboolean(tic.Secure)); + fprintf(fp, " No touch %s\n", getboolean(tic.NoTouch)); + fprintf(fp, " Virus scan %s\n", getboolean(tic.VirScan)); + fprintf(fp, " Announce %s\n", getboolean(tic.Announce)); + fprintf(fp, " Upd. magic %s\n", getboolean(tic.UpdMagic)); + fprintf(fp, " FILE_ID.DIZ %s\n", getboolean(tic.FileId)); + fprintf(fp, " Mandatory %s\n", getboolean(tic.Mandat)); + fprintf(fp, " Upl. discon %s\n", getboolean(tic.UplDiscon)); + fprintf(fp, " Notified %s\n\n", getboolean(tic.Notified)); + + for (i = 0; i < systems; i++) { + fread(&System, sizeof(sysconnect), 1, no); + if (System.aka.zone) { + memset(&status, 0, 4); + memset(&status, '-', 3); + if (System.sendto) + status[0] = 'S'; + if (System.receivefrom) + status[1] = 'R'; + if (System.pause) + status[2] = 'P'; + fprintf(fp, " Link %2d %s %s\n", i+1, status, aka2str(System.aka)); + } + } + } + + fclose(no); + return page; +} + + + diff --git a/mbsetup/m_ticarea.h b/mbsetup/m_ticarea.h new file mode 100644 index 00000000..a8f0fa11 --- /dev/null +++ b/mbsetup/m_ticarea.h @@ -0,0 +1,16 @@ +#ifndef _TICAREA_H +#define _TICAREA_H + + +int OpenTicarea(void); +void CloseTicarea(int); +int NodeInTic(fidoaddr); +int CountTicarea(void); +void EditTicarea(void); +char *PickTicarea(char *); +int GroupInTic(char *); +int tic_areas_doc(FILE *, FILE *, int); + + +#endif + diff --git a/mbsetup/m_tty.c b/mbsetup/m_tty.c new file mode 100644 index 00000000..b73c136c --- /dev/null +++ b/mbsetup/m_tty.c @@ -0,0 +1,518 @@ +/***************************************************************************** + * + * File ..................: setup/m_tty.c + * Purpose ...............: Setup Ttyinfo structure. + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_modem.h" +#include "m_global.h" +#include "m_tty.h" + + + +int TtyUpdated = 0; + + +/* + * Count nr of ttyinfo records in the database. + * Creates the database if it doesn't exist. + */ +int CountTtyinfo(void) +{ + FILE *fil; + char ffile[81]; + int count, i; + + sprintf(ffile, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + ttyinfohdr.hdrsize = sizeof(ttyinfohdr); + ttyinfohdr.recsize = sizeof(ttyinfo); + fwrite(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + + for (i = 0; i < 10; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Network port %d", i+11); + sprintf(ttyinfo.tty, "pts/%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + sprintf(ttyinfo.flags, "IBN,IFC,ITN:60177,XX"); + ttyinfo.type = NETWORK; + ttyinfo.available = TRUE; + sprintf(ttyinfo.name, "Network port #%d", i+11); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 10; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Network port %d", i+1); + sprintf(ttyinfo.tty, "ttyp%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + sprintf(ttyinfo.flags, "IBN,IFC,ITN:60177,XX"); + ttyinfo.type = NETWORK; + ttyinfo.available = TRUE; + sprintf(ttyinfo.name, "Network port #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 6; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Console port %d", i+1); + sprintf(ttyinfo.tty, "tty%d", i); + sprintf(ttyinfo.speed, "10 mbit"); + ttyinfo.type = LOCAL; + ttyinfo.available = TRUE; + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 4; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "ISDN line %d", i+1); + sprintf(ttyinfo.tty, "ttyI%d", i); + sprintf(ttyinfo.speed, "64 kbits"); + sprintf(ttyinfo.flags, "XA,X75,CM"); + ttyinfo.type = ISDN; + ttyinfo.available = FALSE; + ttyinfo.callout = TRUE; + ttyinfo.honor_zmh = TRUE; + sprintf(ttyinfo.name, "ISDN line #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + for (i = 0; i < 4; i++) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + sprintf(ttyinfo.comment, "Modem line %d", i+1); + sprintf(ttyinfo.tty, "ttyS%d", i); + sprintf(ttyinfo.speed, "33.6 kbits"); + sprintf(ttyinfo.flags, "CM,XA,V32B,V42B,V34"); + ttyinfo.type = POTS; + ttyinfo.available = FALSE; + ttyinfo.callout = TRUE; + ttyinfo.honor_zmh = TRUE; + ttyinfo.portspeed = 57600; + sprintf(ttyinfo.name, "Modem line #%d", i+1); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + } + + fclose(fil); + return 34; + } else + return -1; + } + + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - ttyinfohdr.hdrsize) / ttyinfohdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenTtyinfo(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = ttyinfohdr.recsize; + if (oldsize != sizeof(ttyinfo)) + TtyUpdated = 1; + else + TtyUpdated = 0; + ttyinfohdr.hdrsize = sizeof(ttyinfohdr); + ttyinfohdr.recsize = sizeof(ttyinfo); + fwrite(&ttyinfohdr, sizeof(ttyinfohdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&ttyinfo, 0, sizeof(ttyinfo)); + while (fread(&ttyinfo, oldsize, 1, fin) == 1) { + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fout); + memset(&ttyinfo, 0, sizeof(ttyinfo)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseTtyinfo(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *tty = NULL, *tmp; + + sprintf(fin, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + + if (TtyUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&ttyinfohdr, ttyinfohdr.hdrsize, 1, fi); + fwrite(&ttyinfohdr, ttyinfohdr.hdrsize, 1, fo); + + while (fread(&ttyinfo, ttyinfohdr.recsize, 1, fi) == 1) + if (!ttyinfo.deleted) + fill_stlist(&tty, ttyinfo.tty, ftell(fi) - ttyinfohdr.recsize); + sort_stlist(&tty); + + for (tmp = tty; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&ttyinfo, ttyinfohdr.recsize, 1, fi); + fwrite(&ttyinfo, ttyinfohdr.recsize, 1, fo); + } + + tidy_stlist(&tty); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"ttyinfo.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendTtyinfo(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&ttyinfo, 0, sizeof(ttyinfo)); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + TtyUpdated = 1; + return 0; + } else + return -1; +} + + +void TtyScreen(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "6. EDIT TTY LINE"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Comment"); + mvprintw( 8, 6, "2. TTY Device"); + mvprintw( 9, 6, "3. Phone nr."); + mvprintw(10, 6, "4. Line Speed"); + mvprintw(11, 6, "5. Fido Flags"); + mvprintw(12, 6, "6. Line Type"); + mvprintw(13, 6, "7. Available"); + mvprintw(14, 6, "8. Auth. log"); + mvprintw(15, 6, "9. Honor ZMH"); + mvprintw(16, 6, "10. Deleted"); + mvprintw(17, 6, "11. Callout"); + + mvprintw(15,31, "12. Portspeed"); + mvprintw(16,31, "13. Modemtype"); + mvprintw(17,31, "14. EMSI name"); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditTtyRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Ttyinfo"); + + sprintf(mfile, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(ttyinfohdr) + ((Area -1) * sizeof(ttyinfo)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&ttyinfo, crc, sizeof(ttyinfo)); + working(0, 0, 0); + TtyScreen(); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,21,40, ttyinfo.comment); + show_str( 8,21, 6, ttyinfo.tty); + show_str( 9,21,25, ttyinfo.phone); + show_str(10,21,20, ttyinfo.speed); + show_str(11,21,30, ttyinfo.flags); + show_linetype(12,21, ttyinfo.type); + show_bool(13,21, ttyinfo.available); + show_bool(14,21, ttyinfo.authlog); + show_bool(15,21, ttyinfo.honor_zmh); + show_bool(16,21, ttyinfo.deleted); + show_bool(17,21, ttyinfo.callout); + show_int( 15,45, ttyinfo.portspeed); + show_str( 16,45,30,ttyinfo.modem); + show_str( 17,45,35,ttyinfo.name); + + j = select_menu(14); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&ttyinfo, crc1, sizeof(ttyinfo)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&ttyinfo, sizeof(ttyinfo), 1, fil); + fclose(fil); + TtyUpdated = 1; + working(1, 0, 0); + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,21,40,ttyinfo.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,21,7, ttyinfo.tty, "The ^Device name^ of this tty line") + case 3: E_STR( 9,21,25,ttyinfo.phone, "The ^Phone number^ or ^Hostname^ or ^IP address^ of this tty line") + case 4: E_STR( 10,21,20,ttyinfo.speed, "The ^Speed^ of this device") + case 5: E_STR( 11,21,30,ttyinfo.flags, "The ^Fidonet Capability Flags^ for this tty line") + case 6: ttyinfo.type = edit_linetype(12,21, ttyinfo.type); break; + case 7: E_BOOL(13,21, ttyinfo.available,"Switch if this tty line is ^Available^ for use.") + case 8: E_BOOL(14,21, ttyinfo.authlog, "Is mgetty ^Auth^ logging available") + case 9: E_BOOL(15,21, ttyinfo.honor_zmh,"Honor ^Zone Mail Hour^ on this tty line") + case 10:E_BOOL(16,21, ttyinfo.deleted, "Is this tty line ^deleted") + case 11:E_BOOL(17,21, ttyinfo.callout, "Is this line available for ^calling out^") + case 12:E_INT (15,45, ttyinfo.portspeed,"The ^locked speed^ of this tty port (only for modems)") + case 13:strcpy(ttyinfo.modem, PickModem((char *)"6.13")); TtyScreen(); break; + case 14:E_STR( 17,45,30,ttyinfo.name, "The ^EMSI name^ for this tty line") + } + } + + return 0; +} + + + +void EditTtyinfo(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountTtyinfo(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenTtyinfo() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "6. TTY LINES SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/ttyinfo.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20 ; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(ttyinfohdr) + (((o + i) - 1) * ttyinfohdr.recsize); + fseek(fil, offset, 0); + fread(&ttyinfo, ttyinfohdr.recsize, 1, fil); + if (ttyinfo.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-6s %-25s", o+i, ttyinfo.tty, ttyinfo.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseTtyinfo(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendTtyinfo() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) { + EditTtyRec(atoi(pick)); + o = ((atoi(pick) -1) / 20) * 20; + } + } +} + + + +int tty_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *tty; + int j; + + sprintf(temp, "%s/etc/ttyinfo.data", getenv("MBSE_ROOT")); + if ((tty = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 6, 0, page, (char *)"TTY lines information"); + j = 0; + + fprintf(fp, "\n\n"); + fread(&ttyinfohdr, sizeof(ttyinfohdr), 1, tty); + + while ((fread(&ttyinfo, ttyinfohdr.recsize, 1, tty)) == 1) { + if (j == 3) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " TTY name %s\n", ttyinfo.comment); + fprintf(fp, " Device name %s\n", ttyinfo.tty); + fprintf(fp, " Phone or DNS %s\n", ttyinfo.phone); + fprintf(fp, " Line speed %s\n", ttyinfo.speed); + fprintf(fp, " Fido flags %s\n", ttyinfo.flags); + fprintf(fp, " Equipment %s\n", getlinetype(ttyinfo.type)); + fprintf(fp, " Available %s\n", getboolean(ttyinfo.available)); + fprintf(fp, " Auth. log %s\n", getboolean(ttyinfo.authlog)); + fprintf(fp, " Honor ZMH %s\n", getboolean(ttyinfo.honor_zmh)); + fprintf(fp, " Callout %s\n", getboolean(ttyinfo.callout)); + fprintf(fp, " Modem type %s\n", ttyinfo.modem); + fprintf(fp, " Locked speed %ld\n", ttyinfo.portspeed); + fprintf(fp, " EMSI name %s\n", ttyinfo.name); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(tty); + return page; +} + + diff --git a/mbsetup/m_tty.h b/mbsetup/m_tty.h new file mode 100644 index 00000000..e25eac4c --- /dev/null +++ b/mbsetup/m_tty.h @@ -0,0 +1,10 @@ +#ifndef _TTY_H +#define _TTY_H + + +int CountTtyinfo(void); +void EditTtyinfo(void); +int tty_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/m_users.c b/mbsetup/m_users.c new file mode 100644 index 00000000..7f7fba2a --- /dev/null +++ b/mbsetup/m_users.c @@ -0,0 +1,509 @@ +/***************************************************************************** + * + * File ..................: setup/m_users.c + * Purpose ...............: Edit Users + * Last modification date : 29-Jul-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_archive.h" +#include "m_protocol.h" +#include "m_users.h" + + + +int UsrUpdated = 0; + + +/* + * Count nr of usrconfig records in the database. + * Creates the database if it doesn't exist. + */ +int CountUsers(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/users.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + fclose(fil); + return 0; + } else + return -1; + } + + count = 0; + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + + while (fread(&usrconfig, usrconfighdr.recsize, 1, fil) == 1) { + count++; + } + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenUsers(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = usrconfighdr.recsize; + if (oldsize != sizeof(usrconfig)) + UsrUpdated = 1; + else + UsrUpdated = 0; + usrconfighdr.hdrsize = sizeof(usrconfighdr); + usrconfighdr.recsize = sizeof(usrconfig); + fwrite(&usrconfighdr, sizeof(usrconfighdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&usrconfig, 0, sizeof(usrconfig)); + while (fread(&usrconfig, oldsize, 1, fin) == 1) { + fwrite(&usrconfig, sizeof(usrconfig), 1, fout); + memset(&usrconfig, 0, sizeof(usrconfig)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseUsers(void) +{ + char fin[81], fout[81]; + + sprintf(fin, "%s/etc/users.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/users.temp", getenv("MBSE_ROOT")); + + if (UsrUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + if ((rename(fout, fin)) == 0) + unlink(fout); + Syslog('+', "Updated \"users.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendUsers(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&usrconfig, 0, sizeof(usrconfig)); + usrconfig.MailScan = TRUE; + usrconfig.ieFILE = TRUE; + fwrite(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + UsrUpdated = 1; + return 0; + } else + return -1; +} + + + +void Screen1(void) +{ + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 4, 2, "15. EDIT USER"); + set_color(CYAN, BLACK); + mvprintw( 4,21, "First login"); + mvprintw( 5,21, "Last login"); + mvprintw( 6, 2, "1. Full Name"); + mvprintw( 7, 2, "2. Handle"); + mvprintw( 8, 2, "3. Location"); + mvprintw( 9, 2, "4. Address 1"); + mvprintw(10, 2, "5. Address 2"); + mvprintw(11, 2, "6. Address 3"); + mvprintw(12, 2, "7. Voicephone"); + mvprintw(13, 2, "8. Dataphone"); + mvprintw(14, 2, "9. Security"); + mvprintw(15, 2, "10. Birthdate"); + mvprintw(16, 2, "11. Expirydate"); + mvprintw(17, 2, "12. Expiry Sec"); + mvprintw(18, 2, "13. Unix uid"); + mvprintw(19, 2, "14. Comment"); + + mvprintw(12,37, "15. Password"); + mvprintw(13,37, "16. Sex"); + mvprintw(14,37, "17. Credit"); + mvprintw(15,37, "18. Protocol"); + mvprintw(16,37, "19. Archiver"); + mvprintw(17,37, "20. Hidden"); + mvprintw(18,37, "21. Hotkeys"); + + mvprintw( 4,63, "22. Color"); + mvprintw( 5,63, "23. Deleted"); + mvprintw( 6,63, "24. No Kill"); + mvprintw( 7,63, "25. Fs Chat"); + mvprintw( 8,63, "26. Locked"); + mvprintw( 9,63, "27. Silent"); + mvprintw(10,63, "28. CLS"); + mvprintw(11,63, "29. More"); + mvprintw(12,63, "30. Fs Edit"); + mvprintw(13,63, "31. MailScan"); + mvprintw(14,63, "32. Guest"); + mvprintw(15,63, "33. ShowNews"); + mvprintw(16,63, "34. NewFiles"); + mvprintw(17,63, "35. Ext Info"); + mvprintw(18,63, "36. Email"); +} + + + +void Fields1(void) +{ + char Date[30]; + struct tm *ld; + + set_color(WHITE, BLACK); + ld = localtime(&usrconfig.tFirstLoginDate); + sprintf(Date, "%02d-%02d-%04d %02d:%02d:%02d", ld->tm_mday, + ld->tm_mon+1, ld->tm_year + 1900, ld->tm_hour, ld->tm_min, ld->tm_sec); + show_str( 4,33,19, Date); + ld = localtime(&usrconfig.tLastLoginDate); + sprintf(Date, "%02d-%02d-%04d %02d:%02d:%02d", ld->tm_mday, + ld->tm_mon+1, ld->tm_year + 1900, ld->tm_hour, ld->tm_min, ld->tm_sec); + show_str( 5,33,19, Date); + show_str( 6,17,35, usrconfig.sUserName); + show_str( 7,17,35, usrconfig.sHandle); + show_str( 8,17,27, usrconfig.sLocation); + show_str( 9,17,40, usrconfig.address[0]); + show_str(10,17,40, usrconfig.address[1]); + show_str(11,17,40, usrconfig.address[2]); + show_str(12,17,19, usrconfig.sVoicePhone); + show_str(13,17,19, usrconfig.sDataPhone); + show_int(14,17, usrconfig.Security.level); + show_str(15,17,10, usrconfig.sDateOfBirth); + show_str(16,17,10, usrconfig.sExpiryDate); + show_int(17,17, usrconfig.ExpirySec.level); + show_str(18,17, 8, usrconfig.Name); + show_str(19,17,63, usrconfig.sComment); + + if (usrconfig.iPassword == 0) + show_str(12,50,12, (char *)"Invalid"); + else + show_str(12,50,12, (char *)"********"); + show_str( 13,50, 7,usrconfig.sSex); + show_int( 14,50, usrconfig.Credit); + show_str( 15,50,12,usrconfig.sProtocol); + show_str( 16,50, 5,usrconfig.Archiver); + show_bool(17,50, usrconfig.Hidden); + show_bool(18,50, usrconfig.HotKeys); + + show_bool( 4,76, usrconfig.GraphMode); + show_bool( 5,76, usrconfig.Deleted); + show_bool( 6,76, usrconfig.NeverDelete); + show_bool( 7,76, usrconfig.Chat); + show_bool( 8,76, usrconfig.LockedOut); + show_bool( 9,76, usrconfig.DoNotDisturb); + show_bool(10,76, usrconfig.Cls); + show_bool(11,76, usrconfig.More); + show_bool(12,76, usrconfig.FsMsged); + show_bool(13,76, usrconfig.MailScan); + show_bool(14,76, usrconfig.Guest); + show_bool(15,76, usrconfig.ieNEWS); + show_bool(16,76, usrconfig.ieFILE); + show_bool(17,76, usrconfig.OL_ExtInfo); + show_bool(18,76, usrconfig.Email); +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditUsrRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j = 0; + unsigned long crc, crc1; + char temp[81]; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit Users"); + + sprintf(mfile, "%s/etc/users.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(usrconfighdr) + ((Area -1) * sizeof(usrconfig)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&usrconfig, crc, sizeof(usrconfig)); + working(0, 0, 0); + Screen1(); + + for (;;) { + Fields1(); + j = select_menu(36); + switch(j) { + case 0: + crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&usrconfig, crc1, sizeof(usrconfig)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&usrconfig, sizeof(usrconfig), 1, fil); + fclose(fil); + UsrUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + + case 1: E_STR( 6,17,35,usrconfig.sUserName,"The ^First and Last name^ of this user") + case 2: E_STR( 7,17,35,usrconfig.sHandle, "The ^Handle^ of this user") + case 3: E_STR( 8,17,27,usrconfig.sLocation,"The users ^Location^") + case 4: + case 5: + case 6: E_STR(j+5,17,40,usrconfig.address[j-4],"^Address^") + case 7: E_STR(12,17,16, usrconfig.sVoicePhone, "The ^Voice Phone^ number of this user") + case 8: E_STR(13,17,16, usrconfig.sDataPhone, "The ^Data Phone^ number of this user") + case 9: E_USEC(14,17, usrconfig.Security, "15.9 EDIT USER SECURITY", Screen1) + break; + case 10:E_STR(15,17,10, usrconfig.sDateOfBirth,"The ^Date of Birth^ in DD-MM-YYYY format") + case 11:E_STR(16,17,10, usrconfig.sExpiryDate, "The ^Expiry Date^ in DD-MM-YYYY format, 00-00-0000 is no expire") + case 12:E_INT(17,17, usrconfig.ExpirySec.level,"The ^Expiry Level^ for this user") + case 13:E_STR(18,17,8, usrconfig.Name, "The ^Unix username^ for this user") + case 14:E_STR(19,17,62, usrconfig.sComment, "A ^Comment^ for this user") + case 15:strcpy(temp, edit_str(12,50,12, usrconfig.Password, (char *)"Enter the ^password^ for this user")); + if (strlen(temp)) { + memset(&usrconfig.Password, 0, sizeof(usrconfig.Password)); + strcpy(usrconfig.Password, temp); + usrconfig.iPassword = StringCRC32(tu(temp)); + } else { + working(2, 0, 0); + working(0, 0, 0); + } + break; + case 16:strcpy(usrconfig.sSex, tl(edit_str(13,50,7, usrconfig.sSex, (char *)"^Male^ or ^Female^"))); + break; + case 17:E_INT(14,50, usrconfig.Credit, "Users ^Credit^") + case 18:strcpy(temp, PickProtocol(15)); + if (strlen(temp) != 0) + strcpy(usrconfig.sProtocol, temp); + clr_index(); + Screen1(); + Fields1(); + break; + case 19:strcpy(temp, PickArchive((char *)"15")); + if (strlen(temp) != 0) + strcpy(usrconfig.Archiver, temp); + clr_index(); + Screen1(); + Fields1(); + break; + case 20:E_BOOL(17,50,usrconfig.Hidden, "Is user ^hidden^ on the BBS") + case 21:E_BOOL(18,50,usrconfig.HotKeys, "Is user using ^HotKeys^ for menus") + case 22:E_BOOL( 4,76,usrconfig.GraphMode, "Is user using ^ANSI^ colors") + case 23:E_BOOL( 5,76,usrconfig.Deleted, "Is user marked for ^deletion^") + case 24:E_BOOL( 6,76,usrconfig.NeverDelete, "^Never delete^ this user") + case 25:E_BOOL( 7,76,usrconfig.Chat, "User has ^IEMSI Chat^ capability") + case 26:E_BOOL( 8,76,usrconfig.LockedOut, "User is ^Locked Out^ of this BBS") + case 27:E_BOOL( 9,76,usrconfig.DoNotDisturb, "User will not be ^disturbed^") + case 28:E_BOOL(10,76,usrconfig.Cls, "Send ^ClearScreen code^ to users terminal") + case 29:E_BOOL(11,76,usrconfig.More, "User uses the ^More prompt^") + case 30:E_BOOL(12,76,usrconfig.FsMsged, "User uses the ^Fullscreen editor^") + case 31:E_BOOL(13,76,usrconfig.MailScan, "Don't check for ^new mail^") + case 32:E_BOOL(14,76,usrconfig.Guest, "This is a ^Guest^ account") + case 33:E_BOOL(15,76,usrconfig.ieNEWS, "Show ^News Bulletins^ when logging in") + case 34:E_BOOL(16,76,usrconfig.ieFILE, "Show ^New Files^ when logging in") + case 35:E_BOOL(17,76,usrconfig.OL_ExtInfo, "Add ^Extended Message Info^ in OLR download") + case 36:E_BOOL(18,76,usrconfig.Email, "User has a ^private email^ mailbox") + } + } + + return 0; +} + + + +void EditUsers(void) +{ + int records, i, o, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountUsers(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenUsers() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + o = 0; + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 3, "15. USERS EDITOR"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/users.temp", getenv("MBSE_ROOT")); + working(1, 0, 0); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&usrconfighdr, sizeof(usrconfighdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= 20; i++) { + if (i == 11) { + x = 42; + y = 7; + } + if ((o + i) <= records) { + offset = sizeof(usrconfighdr) + (((i + o) - 1) * usrconfighdr.recsize); + fseek(fil, offset, 0); + fread(&usrconfig, usrconfighdr.recsize, 1, fil); + if (!usrconfig.Deleted) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", o + i, usrconfig.sUserName); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + } + fclose(fil); + } + } + working(0, 0, 0); + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseUsers(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendUsers() == 0) { + records++; + working(1, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if (strncmp(pick, "N", 1) == 0) + if ((o + 20) < records) + o = o + 20; + + if (strncmp(pick, "P", 1) == 0) + if ((o - 20) >= 0) + o = o - 20; + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditUsrRec(atoi(pick)); + } +} + + diff --git a/mbsetup/m_users.h b/mbsetup/m_users.h new file mode 100644 index 00000000..4bdd8740 --- /dev/null +++ b/mbsetup/m_users.h @@ -0,0 +1,11 @@ +/* m_users.h */ + +#ifndef _USERS_H +#define _USERS_H + + +int CountUsers(void); +void EditUsers(void); + +#endif + diff --git a/mbsetup/m_virus.c b/mbsetup/m_virus.c new file mode 100644 index 00000000..e232816c --- /dev/null +++ b/mbsetup/m_virus.c @@ -0,0 +1,419 @@ +/***************************************************************************** + * + * File ..................: setup/m_virus.c + * Purpose ...............: Setup Virus structure. + * Last modification date : 22-Jan-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/clcomm.h" +#include "../lib/common.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "stlist.h" +#include "m_global.h" +#include "m_virus.h" + + + +int VirUpdated = 0; + + +/* + * Count nr of virscan records in the database. + * Creates the database if it doesn't exist. + */ +int CountVirus(void) +{ + FILE *fil; + char ffile[81]; + int count; + + sprintf(ffile, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "r")) == NULL) { + if ((fil = fopen(ffile, "a+")) != NULL) { + virscanhdr.hdrsize = sizeof(virscanhdr); + virscanhdr.recsize = sizeof(virscan); + fwrite(&virscanhdr, sizeof(virscanhdr), 1, fil); + + /* + * Create some default records + */ + memset(&virscan, 0, sizeof(virscan)); + sprintf(virscan.comment, "AntiVir/Linux Scanner"); + sprintf(virscan.scanner, "/usr/bin/antivir"); + sprintf(virscan.options, "-allfiles -s -q"); + virscan.available = TRUE; + virscan.error = 0; + fwrite(&virscan, sizeof(virscan), 1, fil); + + memset(&virscan, 0, sizeof(virscan)); + sprintf(virscan.comment, "McAfee VirusScan for Linux"); + sprintf(virscan.scanner, "/usr/local/bin/uvscan"); + sprintf(virscan.options, "--noboot --noexpire -r --secure -"); + virscan.available = TRUE; + virscan.error = 0; + fwrite(&virscan, sizeof(virscan), 1, fil); + + fclose(fil); + return 2; + } else + return -1; + } + + fread(&virscanhdr, sizeof(virscanhdr), 1, fil); + fseek(fil, 0, SEEK_END); + count = (ftell(fil) - virscanhdr.hdrsize) / virscanhdr.recsize; + fclose(fil); + + return count; +} + + + +/* + * Open database for editing. The datafile is copied, if the format + * is changed it will be converted on the fly. All editing must be + * done on the copied file. + */ +int OpenVirus(void) +{ + FILE *fin, *fout; + char fnin[81], fnout[81]; + long oldsize; + + sprintf(fnin, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + sprintf(fnout, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fin = fopen(fnin, "r")) != NULL) { + if ((fout = fopen(fnout, "w")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fin); + /* + * In case we are automatic upgrading the data format + * we save the old format. If it is changed, the + * database must always be updated. + */ + oldsize = virscanhdr.recsize; + if (oldsize != sizeof(virscan)) + VirUpdated = 1; + else + VirUpdated = 0; + virscanhdr.hdrsize = sizeof(virscanhdr); + virscanhdr.recsize = sizeof(virscan); + fwrite(&virscanhdr, sizeof(virscanhdr), 1, fout); + + /* + * The datarecord is filled with zero's before each + * read, so if the format changed, the new fields + * will be empty. + */ + memset(&virscan, 0, sizeof(virscan)); + while (fread(&virscan, oldsize, 1, fin) == 1) { + fwrite(&virscan, sizeof(virscan), 1, fout); + memset(&virscan, 0, sizeof(virscan)); + } + + fclose(fin); + fclose(fout); + return 0; + } else + return -1; + } + return -1; +} + + + +void CloseVirus(void) +{ + char fin[81], fout[81]; + FILE *fi, *fo; + st_list *vir = NULL, *tmp; + + sprintf(fin, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + sprintf(fout,"%s/etc/virscan.temp", getenv("MBSE_ROOT")); + + if (VirUpdated == 1) { + if (yes_no((char *)"Database is changed, save changes") == 1) { + working(1, 0, 0); + fi = fopen(fout, "r"); + fo = fopen(fin, "w"); + fread(&virscanhdr, virscanhdr.hdrsize, 1, fi); + fwrite(&virscanhdr, virscanhdr.hdrsize, 1, fo); + + while (fread(&virscan, virscanhdr.recsize, 1, fi) == 1) + if (!virscan.deleted) + fill_stlist(&vir, virscan.comment, ftell(fi) - virscanhdr.recsize); + sort_stlist(&vir); + + for (tmp = vir; tmp; tmp = tmp->next) { + fseek(fi, tmp->pos, SEEK_SET); + fread(&virscan, virscanhdr.recsize, 1, fi); + fwrite(&virscan, virscanhdr.recsize, 1, fo); + } + + tidy_stlist(&vir); + fclose(fi); + fclose(fo); + unlink(fout); + Syslog('+', "Updated \"virscan.data\""); + return; + } + } + working(1, 0, 0); + unlink(fout); +} + + + +int AppendVirus(void) +{ + FILE *fil; + char ffile[81]; + + sprintf(ffile, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(ffile, "a")) != NULL) { + memset(&virscan, 0, sizeof(virscan)); + fwrite(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + VirUpdated = 1; + return 0; + } else + return -1; +} + + + +/* + * Edit one record, return -1 if there are errors, 0 if ok. + */ +int EditVirRec(int Area) +{ + FILE *fil; + char mfile[81]; + long offset; + int j; + unsigned long crc, crc1; + + clr_index(); + working(1, 0, 0); + IsDoing("Edit VirScan"); + + sprintf(mfile, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(mfile, "r")) == NULL) { + working(2, 0, 0); + return -1; + } + + offset = sizeof(virscanhdr) + ((Area -1) * sizeof(virscan)); + if (fseek(fil, offset, 0) != 0) { + working(2, 0, 0); + return -1; + } + + fread(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + crc = 0xffffffff; + crc = upd_crc32((char *)&virscan, crc, sizeof(virscan)); + working(0, 0, 0); + + set_color(WHITE, BLACK); + mvprintw( 5, 2, "4. EDIT VIRUS SCANNER"); + set_color(CYAN, BLACK); + mvprintw( 7, 2, "1. Comment"); + mvprintw( 8, 2, "2. Command"); + mvprintw( 9, 2, "3. Options"); + mvprintw(10, 2, "4. Available"); + mvprintw(11, 2, "5. Deleted"); + mvprintw(12, 2, "6. Error lvl"); + + for (;;) { + set_color(WHITE, BLACK); + show_str( 7,16,40, virscan.comment); + show_str( 8,16,64, virscan.scanner); + show_str( 9,16,64, virscan.options); + show_bool(10,16, virscan.available); + show_bool(11,16, virscan.deleted); + show_int( 12,16, virscan.error); + + j = select_menu(6); + switch(j) { + case 0: crc1 = 0xffffffff; + crc1 = upd_crc32((char *)&virscan, crc1, sizeof(virscan)); + if (crc != crc1) { + if (yes_no((char *)"Record is changed, save") == 1) { + working(1, 0, 0); + if ((fil = fopen(mfile, "r+")) == NULL) { + working(2, 0, 0); + return -1; + } + fseek(fil, offset, 0); + fwrite(&virscan, sizeof(virscan), 1, fil); + fclose(fil); + VirUpdated = 1; + working(0, 0, 0); + } + } + IsDoing("Browsing Menu"); + return 0; + case 1: E_STR( 7,16,40,virscan.comment, "The ^Comment^ for this record") + case 2: E_STR( 8,16,64,virscan.scanner, "The full ^name and path^ to the binary of this scanner") + case 3: E_STR( 9,16,64,virscan.options, "The ^commandline options^ for this scanner") + case 4: E_BOOL(10,16, virscan.available,"Switch if this virus scanner is ^Available^ for use.") + case 5: E_BOOL(11,16, virscan.deleted, "Is this scanner ^deleted^") + case 6: E_INT( 12,16, virscan.error, "The ^Error Level^ the scanner returns when no virus is found") + } + } + + return 0; +} + + + +void EditVirus(void) +{ + int records, i, x, y; + char pick[12]; + FILE *fil; + char temp[81]; + long offset; + + clr_index(); + working(1, 0, 0); + IsDoing("Browsing Menu"); + if (config_read() == -1) { + working(2, 0, 0); + return; + } + + records = CountVirus(); + if (records == -1) { + working(2, 0, 0); + return; + } + + if (OpenVirus() == -1) { + working(2, 0, 0); + return; + } + working(0, 0, 0); + + for (;;) { + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 4, "4. VIRUS SCANNERS SETUP"); + set_color(CYAN, BLACK); + if (records != 0) { + sprintf(temp, "%s/etc/virscan.temp", getenv("MBSE_ROOT")); + if ((fil = fopen(temp, "r")) != NULL) { + fread(&virscanhdr, sizeof(virscanhdr), 1, fil); + x = 2; + y = 7; + set_color(CYAN, BLACK); + for (i = 1; i <= records; i++) { + offset = sizeof(virscanhdr) + ((i - 1) * virscanhdr.recsize); + fseek(fil, offset, 0); + fread(&virscan, virscanhdr.recsize, 1, fil); + if (i == 11) { + x = 42; + y = 7; + } + if (virscan.available) + set_color(CYAN, BLACK); + else + set_color(LIGHTBLUE, BLACK); + sprintf(temp, "%3d. %-32s", i, virscan.comment); + temp[37] = 0; + mvprintw(y, x, temp); + y++; + } + fclose(fil); + } + } + strcpy(pick, select_record(records, 20)); + + if (strncmp(pick, "-", 1) == 0) { + CloseVirus(); + return; + } + + if (strncmp(pick, "A", 1) == 0) { + working(1, 0, 0); + if (AppendVirus() == 0) { + records++; + working(3, 0, 0); + } else + working(2, 0, 0); + working(0, 0, 0); + } + + if ((atoi(pick) >= 1) && (atoi(pick) <= records)) + EditVirRec(atoi(pick)); + } +} + + +int virus_doc(FILE *fp, FILE *toc, int page) +{ + char temp[81]; + FILE *vir; + int j; + + sprintf(temp, "%s/etc/virscan.data", getenv("MBSE_ROOT")); + if ((vir = fopen(temp, "r")) == NULL) + return page; + + page = newpage(fp, page); + addtoc(fp, toc, 4, 0, page, (char *)"Virus scanners"); + j = 0; + fprintf(fp, "\n\n"); + fread(&virscanhdr, sizeof(virscanhdr), 1, vir); + + while ((fread(&virscan, virscanhdr.recsize, 1, vir)) == 1) { + + if (j == 5) { + page = newpage(fp, page); + fprintf(fp, "\n"); + j = 0; + } + + fprintf(fp, " Scanner name %s\n", virscan.comment); + fprintf(fp, " Command line %s\n", virscan.scanner); + fprintf(fp, " Options %s\n", virscan.options); + fprintf(fp, " Available %s\n", getboolean(virscan.available)); + fprintf(fp, " Errorlevel OK %d\n", virscan.error); + fprintf(fp, "\n\n\n"); + j++; + } + + fclose(vir); + return page; +} + + diff --git a/mbsetup/m_virus.h b/mbsetup/m_virus.h new file mode 100644 index 00000000..791ea11c --- /dev/null +++ b/mbsetup/m_virus.h @@ -0,0 +1,12 @@ +/* m_archive.h */ + +#ifndef _VIRUS_H +#define _VIRUS_H + + +int CountVirus(void); +void EditVirus(void); +int virus_doc(FILE *, FILE *, int); + +#endif + diff --git a/mbsetup/mbsetup.c b/mbsetup/mbsetup.c new file mode 100644 index 00000000..f0c599c6 --- /dev/null +++ b/mbsetup/mbsetup.c @@ -0,0 +1,452 @@ +/***************************************************************************** + * + * File ..................: mbsetup.c + * Purpose ...............: Setup Program + * Last modification date : 24-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2801 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/records.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" +#include "ledit.h" +#include "m_global.h" +#include "m_bbs.h" +#include "m_mail.h" +#include "m_tic.h" +#include "m_fido.h" +#include "m_archive.h" +#include "m_virus.h" +#include "m_tty.h" +#include "m_limits.h" +#include "m_users.h" +#include "m_node.h" +#include "m_fdb.h" +#include "m_new.h" +#include "m_ff.h" +#include "m_modem.h" +#include "m_marea.h" +#include "m_ngroup.h" +#include "m_service.h" +#include "m_domain.h" +#include "m_task.h" + + +mode_t oldmask; /* Old umask value */ +extern int do_quiet; /* Suppress log to screen */ +int exp_golded = FALSE; /* Export GoldED config */ + + +static void die(int onsig) +{ + FILE *fp; + char *temp; + int i; + + signal(onsig, SIG_IGN); + screen_stop(); + + exp_golded = TRUE; + if (exp_golded && (config_read() != -1)) { + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/golded.inc", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "w")) != NULL) { + fprintf(fp, "; GoldED.inc -- Automatic created by mbsetup %s -- Do not edit!\n\n", VERSION); + fprintf(fp, "; Basic information\n;\n"); + fprintf(fp, "USERNAME %s\n\n", CFG.sysop_name); + fprintf(fp, "ADDRESS %s\n", aka2str(CFG.aka[0])); + for (i = 1; i < 40; i++) + if (CFG.akavalid[i]) + fprintf(fp, "AKA %s\n", aka2str(CFG.aka[i])); + fprintf(fp, "\n"); + + gold_akamatch(fp); + + fprintf(fp, "; JAM MessageBase Setup\n;\n"); + fprintf(fp, "JAMPATH %s/tmp/\n", getenv("MBSE_ROOT")); + fprintf(fp, "JAMHARDDELETE NO\n\n"); + + fprintf(fp, "; Semaphore files\n;\n"); + fprintf(fp, "SEMAPHORE NETSCAN %s/sema/mailout\n", getenv("MBSE_ROOT")); + fprintf(fp, "SEMAPHORE ECHOSCAN %s/sema/mailout\n\n", getenv("MBSE_ROOT")); + + gold_areas(fp); + Syslog('+', "Created new %s", temp); + } else { + WriteError("$Could not create %s", temp); + } + + free(temp); + } + + umask(oldmask); + if (onsig && (onsig <= NSIG)) + WriteError("MBSETUP finished on signal %s", SigName[onsig]); + else + Syslog(' ', "MBSETUP finished"); + ExitClient(0); +} + + + +void soft_info(void); +void soft_info(void) +{ + char *temp; + + temp = calloc(81, sizeof(char)); + clr_index(); + set_color(YELLOW, BLACK); + center_addstr( 6, (char *)"MBSE BBS"); + set_color(WHITE, BLACK); + center_addstr( 8, (char *)Copyright); + set_color(YELLOW, BLACK); + center_addstr(10, (char *)"Made in the Netherlands"); + set_color(WHITE, BLACK); +#ifdef __GLIBC__ + sprintf(temp, "Compiled on glibc v%d.%d", __GLIBC__, __GLIBC_MINOR__); +#else +#ifdef __GNU_LIBRARY__ + sprintf(temp, "Compiled on libc v%d", __GNU_LIBRARY__); +#else + sprintf(temp, "Compiled on unknown library"); +#endif +#endif + center_addstr(12, temp); + set_color(LIGHTGREEN, BLACK); + center_addstr(LINES -8, (char *)"This is free software; released under the terms of the GNU General"); + center_addstr(LINES -7, (char *)"Public License as published by the Free Software Foundation."); + set_color(CYAN, BLACK); + free(temp); + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES - 4, COLS / 2 + 8, LIGHTGRAY, BLACK); +} + + + +void site_docs(void); +void site_docs(void) +{ + FILE *fp, *toc; + char temp[81], temp1[81]; + int page = 0, line = 0; + + if (config_read() == -1) + return; + + sprintf(temp, "%s/doc/site.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + clr_index(); + working(1, 0, 0); + IsDoing("Making Sitedocs"); + Syslog('+', "Start creating sitedocs"); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "17. CREATING SITEDOCS"); + set_color(CYAN, BLACK); + mvprintw( 7,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + page = global_doc(fp, toc, page); + page = fido_doc(fp, toc, page); + page = archive_doc(fp, toc, page); + page = virus_doc(fp, toc, page); + page = modem_doc(fp, toc, page); + page = tty_doc(fp, toc, page); + page = node_doc(fp, toc, page); + page = bbs_doc(fp, toc, page); + page = mail_doc(fp, toc, page); + page = tic_doc(fp, toc, page); + page = newf_group_doc(fp, toc, page); + page = new_doc(fp, toc, page); + page = ff_doc(fp, toc, page); + page = service_doc(fp, toc, page); + page = domain_doc(fp, toc, page); + page = task_doc(fp, toc, page); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 17, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Sitedocs created"); + + page = line = 0; + sprintf(temp, "%s/doc/xref.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + Syslog('+', "Start creating crossreference"); + mvprintw( 8,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + page = limit_users_doc(fp, toc, page); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 99, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Crossreference created"); + + page = line = 0; + sprintf(temp, "%s/doc/stat.doc", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "w")) == NULL) + return; + + sprintf(temp1, "%s/tmp/toc.tmp", getenv("MBSE_ROOT")); + if ((toc = fopen(temp1, "w+")) == NULL) { + fclose(fp); + return; + } + + Syslog('+', "Start creating statistics"); + mvprintw( 9,11, (char *)"Create document in file %s", temp); + fflush(stdout); + + /* + * Append table of contents + */ + page = newpage(fp, page); + addtoc(fp, toc, 99, 0, page, (char *)"Table of contents"); + fprintf(fp, "\n\n"); + line = 4; + rewind(toc); + + while (fgets(temp, 256, toc) != NULL) { + fprintf(fp, "%s", temp); + line++; + if (line == 56) { + page = newpage(fp, page); + line = 0; + } + } + + fprintf(fp, "\f"); + fclose(fp); + fclose(toc); + unlink(temp1); + + Syslog('+', "Statistics created"); + + working(0, 0, 0); + + center_addstr(LINES -4, (char *)"Press any key"); + readkey(LINES -4, COLS / 2 + 8, LIGHTGRAY, BLACK); + return; +} + + + +int main(int argc, char *argv[]) +{ + int loop = 1; + struct passwd *pw; + +#ifdef MEMWATCH + mwInit(); +#endif + + /* + * Find out who is on the keyboard or automated the keyboard. + */ + pw = getpwuid(getuid()); + InitClient(pw->pw_name, (char *)"mbsetup", (char *)"nowhere", (char *)"mbsetup.log", 0x1f, (char *)"error.log"); + + /* + * Read the global configuration data + */ + config_check(getenv("MBSE_ROOT")); + + /* + * Setup several signals so when the program terminate's it + * will properly close the curses screens. + */ + signal(SIGINT, (void (*))die); + signal(SIGBUS, (void (*))die); + signal(SIGSEGV,(void (*))die); + signal(SIGTERM,(void (*))die); + signal(SIGKILL,(void (*))die); + + oldmask = umask(002); + + screen_start((char *)"MBsetup"); + do_quiet = TRUE; + Syslog(' ', " "); + Syslog(' ', "MBSETUP v%s started by %s", VERSION, pw->pw_name); + + do { + IsDoing("Browsing Menu"); + clr_index(); + set_color(WHITE, BLACK); + mvprintw( 5, 6, "0. MAIN SETUP"); + set_color(CYAN, BLACK); + mvprintw( 7, 6, "1. Edit Global configuration"); + mvprintw( 8, 6, "2. Edit Fido Networks"); + mvprintw( 9, 6, "3. Edit Archiver Programs"); + mvprintw(10, 6, "4. Edit Virus Scanners"); + mvprintw(11, 6, "5. Edit Modem types"); + mvprintw(12, 6, "6. Edit TTY lines info"); + mvprintw(13, 6, "7. Edit Fidonet Nodes"); + mvprintw(14, 6, "8. Edit BBS Setup"); + mvprintw(15, 6, "9. Edit Mail Setup"); + mvprintw(16, 6, "10. Edit File Echo's setup"); + mvprintw( 7,46, "11. Edit Newfiles Groups"); + mvprintw( 8,46, "12. Edit Newfiles Reports"); + mvprintw( 9,46, "13. Edit FileFind Setup"); + mvprintw(10,46, "14. Edit Files Database"); + mvprintw(11,46, "15. Edit BBS Users"); + mvprintw(12,46, "16. Edit Services"); + mvprintw(13,46, "17. Edit Domains"); + mvprintw(14,46, "18. Edit Task Manager"); + mvprintw(15,46, "19. Show software information"); + mvprintw(16,46, "20. Create site documents"); + + switch(select_menu(20)) { + case 0: + loop = 0; + break; + case 1: + global_menu(); + break; + case 2: + EditFidonet(); + break; + case 3: + EditArchive(); + break; + case 4: + EditVirus(); + break; + case 5: + EditModem(); + break; + case 6: + EditTtyinfo(); + break; + case 7: + EditNodes(); + break; + case 8: + bbs_menu(); + break; + case 9: + mail_menu(); + break; + case 10: + tic_menu(); + break; + case 11: + EditNGroup(); + break; + case 12: + EditNewfiles(); + break; + case 13: + EditFilefind(); + break; + case 14: + EditFDB(); + break; + case 15: + EditUsers(); + break; + case 16: + EditService(); + break; + case 17: + EditDomain(); + break; + case 18: + task_menu(); + break; + case 19: + soft_info(); + break; + case 20: + site_docs(); + break; + } + } while (loop == 1); + + die(0); + return 0; +} + diff --git a/mbsetup/mutil.c b/mbsetup/mutil.c new file mode 100644 index 00000000..893a19dc --- /dev/null +++ b/mbsetup/mutil.c @@ -0,0 +1,140 @@ +/***************************************************************************** + * + * File ..................: mutil.c + * Purpose ...............: Menu Utils + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "screen.h" +#include "mutil.h" + + + +unsigned char readkey(int y, int x, int fg, int bg) +{ + int rc = -1, i; + unsigned char ch = 0; + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + i = 0; + while (rc == -1) { + if ((i % 10) == 0) + show_date(fg, bg, 0, 0); + + locate(y, x); + fflush(stdout); + rc = Waitchar(&ch, 5); + if ((rc == 1) && (ch != KEY_ESCAPE)) + break; + + if ((rc == 1) && (ch == KEY_ESCAPE)) + rc = Escapechar(&ch); + + if (rc == 1) + break; + i++; + Nopper(); + } + + Unsetraw(); + close(ttyfd); + + return ch; +} + + + +unsigned char testkey(int y, int x) +{ + int rc; + unsigned char ch = 0; + + locate(y, x); + fflush(stdout); + + if ((ttyfd = open("/dev/tty", O_RDWR|O_NONBLOCK)) < 0) { + perror("open 9"); + exit(1); + } + Setraw(); + + rc = Waitchar(&ch, 100); + if (rc == 1) { + if (ch == KEY_ESCAPE) + rc = Escapechar(&ch); + } + + Unsetraw(); + close(ttyfd); + + if (rc == 1) + return ch; + else + return '\0'; +} + + + +int newpage(FILE *fp, int page) +{ + page++; + fprintf(fp, "\f MBSE BBS v%-53s page %d\n", VERSION, page); + return page; +} + + + +void addtoc(FILE *fp, FILE *toc, int chapt, int par, int page, char *title) +{ + char temp[81]; + char *tit; + + sprintf(temp, "%s ", title); + tit = xstrcpy(title); + tu(tit); + + if (par) { + fprintf(toc, " %2d.%-3d %s %d\n", chapt, par, padleft(temp, 50, '.'), page); + fprintf(fp, "\n\n %d.%d. %s\n\n", chapt, par, tit); + } else { + fprintf(toc, " %2d %s %d\n", chapt, padleft(temp, 52, '.'), page); + fprintf(fp, "\n\n %d. %s\n", chapt, tit); + } + free(tit); +} + + + diff --git a/mbsetup/mutil.h b/mbsetup/mutil.h new file mode 100644 index 00000000..ea78cecb --- /dev/null +++ b/mbsetup/mutil.h @@ -0,0 +1,10 @@ +#ifndef _MUTIL_H +#define _MUTIL_H + +unsigned char readkey(int, int, int, int); +unsigned char testkey(int, int); +int newpage(FILE *, int); +void addtoc(FILE *, FILE *, int, int, int, char *); + +#endif + diff --git a/mbsetup/screen.c b/mbsetup/screen.c new file mode 100644 index 00000000..2f8f6b18 --- /dev/null +++ b/mbsetup/screen.c @@ -0,0 +1,271 @@ +/***************************************************************************** + * + * File ..................: screen.c + * Purpose ...............: Screen functions for setup. + * Last modification date : 08-Oct-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/ansi.h" +#include "../lib/common.h" +#include "screen.h" + + + +/************************************************************************* + * + * Global section + */ + + +void clrtoeol() +{ + int i; + + printf("\r"); + for (i = 0; i < COLS; i++) + putchar(' '); + printf("\r"); + fflush(stdout); +} + + + +void hor_lin(int y, int x, int len) +{ + int i; + + locate(y, x); + for (i = 0; i < len; i++) + putchar('-'); + fflush(stdout); +} + + + +static int old_f = -1; +static int old_b = -1; + +void set_color(int f, int b) +{ + if ((f != old_f) || (b != old_b)) { + old_f = f; + old_b = b; + colour(f, b); + fflush(stdout); + } +} + + + +static time_t lasttime; + +/* + * Show the current date & time in the second status row + */ +void show_date(int fg, int bg, int y, int x) +{ + time_t now; + char *p; + + time(&now); + if (now != lasttime) { + lasttime = now; + set_color(LIGHTGREEN, BLUE); + p = ctime(&now); + Striplf(p); + mvprintw(1, 44, (char *)"%s TZUTC %s", p, gmtoffset(now)); + p = asctime(gmtime(&now)); + Striplf(p); + mvprintw(2, 44, (char *)"%s UTC", p); + if (y && x) + locate(y, x); + set_color(fg, bg); + } +} + + + +void center_addstr(int y, char *s) +{ + mvprintw(y, (COLS / 2) - (strlen(s) / 2), s); +} + + + +/* + * Curses and screen initialisation. + */ +void screen_start(char *name) +{ + int i; + + TermInit(1); + /* + * Overwrite screen the first time, if user had it black on white + * it will change to white on black. clear() won't do the trick. + */ + set_color(LIGHTGRAY, BLUE); + locate(1, 1); + for (i = 0; i < LINES; i++) { + if (i == 3) + colour(LIGHTGRAY, BLACK); + clrtoeol(); + if (i < LINES) + printf("\n"); + } + fflush(stdout); + + set_color(WHITE, BLUE); + locate(1, 1); + printf((char *)"%s for MBSE BBS version %s", name, VERSION); + set_color(YELLOW, BLUE); + locate(2, 1); + printf((char *)ShortRight); + set_color(LIGHTGRAY, BLACK); + show_date(LIGHTGRAY, BLACK, 0, 0); + fflush(stdout); +} + + + +/* + * Screen deinit + */ +void screen_stop() +{ + set_color(LIGHTGRAY, BLACK); + clear(); + fflush(stdout); +} + + + +/* + * Message at the upperright window about actions + */ +void working(int txno, int y, int x) +{ + int i; + + /* + * If txno not 0 there will be something written. The + * reversed attributes for mono, or white on red for + * color screens is set. The cursor is turned off and + * original cursor position is saved. + */ + show_date(LIGHTGRAY, BLACK, 0, 0); + + if (txno != 0) + set_color(YELLOW, RED); + else + set_color(LIGHTGRAY, BLACK); + + switch (txno) { + case 0: mvprintw(4, 66, (char *)" "); + break; + case 1: mvprintw(4, 66, (char *)"Working . . ."); + break; + case 2: mvprintw(4, 66, (char *)">>> ERROR <<<"); + for (i = 1; i <= 5; i++) { + putchar(7); + fflush(stdout); + usleep(150000); + } + usleep(550000); + break; + case 3: mvprintw(4, 66, (char *)"Form inserted"); + putchar(7); + fflush(stdout); + sleep(1); + break; + case 4: mvprintw(4, 66, (char *)"Form deleted "); + putchar(7); + fflush(stdout); + sleep(1); + break; + } + + show_date(LIGHTGRAY, BLACK, 0, 0); + set_color(LIGHTGRAY, BLACK); + if (y && x) + locate(y, x); + fflush(stdout); +} + + + +/* + * Clear the middle window + */ +void clr_index() +{ + int i; + + set_color(LIGHTGRAY, BLACK); + for (i = 3; i <= (LINES - 1); i++) { + locate(i, 1); + clrtoeol(); + } +} + + + +/* + * Show help at the bottom of the screen. + */ +void showhelp(char *T) +{ + int f, i, x, forlim; + + f = FALSE; + locate(LINES-1, 1); + set_color(WHITE, RED); + clrtoeol(); + x = 0; + forlim = strlen(T); + + for (i = 0; i < forlim; i++) { + if (T[i] == '^') { + if (f == FALSE) { + f = TRUE; + set_color(YELLOW, RED); + } else { + f = FALSE; + set_color(WHITE, RED); + } + } else { + putchar(T[i]); + x++; + } + } + set_color(LIGHTGRAY, BLACK); + fflush(stdout); +} + + diff --git a/mbsetup/screen.h b/mbsetup/screen.h new file mode 100644 index 00000000..01f9809f --- /dev/null +++ b/mbsetup/screen.h @@ -0,0 +1,19 @@ +#ifndef _SCREEN_H +#define _SCREEN_H + + +void clrtoeol(void); +void hor_lin(int y, int x, int len); +void set_color(int f, int b); +void show_date(int f, int b, int y, int x); +void center_addstr(int y, char *s); +void screen_start(char *); +void screen_stop(void); +void working(int txno, int y, int x); +void clr_index(void); +void showhelp(char *T); + +// int menu_prompt(void); + +#endif + diff --git a/mbsetup/stlist.c b/mbsetup/stlist.c new file mode 100644 index 00000000..4d4c1d3e --- /dev/null +++ b/mbsetup/stlist.c @@ -0,0 +1,117 @@ +/***************************************************************************** + * + * File ..................: stlist.c + * Purpose ...............: String sorting for databases. + * Last modification date : 27-Nov-2000 + * + ***************************************************************************** + * Copyright (C) 1997-2000 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "../lib/libs.h" +#include "../lib/structs.h" +#include "../lib/common.h" +#include "../lib/clcomm.h" +#include "stlist.h" + + +/* + * Tidy the strings array + */ +void tidy_stlist(st_list ** fdp) +{ + st_list *tmp, *old; + + for (tmp = *fdp; tmp; tmp = old) { + old = tmp->next; + free(tmp); + } + + *fdp = NULL; +} + + + +/* + * Add a string to the array + */ +void fill_stlist(st_list **fdp, char *stringname, long pos) +{ + st_list *tmp; + + tmp = (st_list *)malloc(sizeof(st_list)); + tmp->next = *fdp; + sprintf(tmp->string, "%s", stringname); + tmp->pos = pos; + *fdp = tmp; +} + + + +int compstring(st_list **, st_list **); + +/* + * Sort the array of strings + */ +void sort_stlist(st_list **fdp) +{ + st_list *ta, **vector; + size_t n = 0, i; + + if (*fdp == NULL) + return; + + for (ta = *fdp; ta; ta = ta->next) + n++; + + vector = (st_list **)malloc(n * sizeof(st_list *)); + + i = 0; + for (ta = *fdp; ta; ta = ta->next) + vector[i++] = ta; + + qsort(vector, n, sizeof(st_list*), (int(*)(const void*, const void*))compstring); + + (*fdp) = vector[0]; + i = 1; + + for (ta = *fdp; ta; ta = ta->next) { + + if (i < n) + ta->next = vector[i++]; + else + ta->next = NULL; + } + + free(vector); + return; +} + + + +int compstring(st_list **fdp1, st_list **fdp2) +{ + return strcmp((*fdp1)->string, (*fdp2)->string); +} + diff --git a/mbsetup/stlist.h b/mbsetup/stlist.h new file mode 100644 index 00000000..4e08f459 --- /dev/null +++ b/mbsetup/stlist.h @@ -0,0 +1,17 @@ +#ifndef _STLIST_H +#define _STLIST_H + +typedef struct _st_list { + struct _st_list *next; + char string[81]; + long pos; +} st_list; + + +void tidy_stlist(st_list **); +void fill_stlist(st_list **, char *, long); +void sort_stlist(st_list **); + + +#endif + diff --git a/mbtask/Makefile.am b/mbtask/Makefile.am new file mode 100644 index 00000000..c81fd24e --- /dev/null +++ b/mbtask/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +EXTRA_DIST = issue + +noinst_PROGRAMS = mbtask + +mbtask_SOURCES = mbtask.c mbtask.h signame.c signame.h taskutil.c taskutil.h \ +taskcomm.c taskcomm.h taskstat.c taskstat.h taskdisk.c taskdisk.h \ +taskregs.c taskregs.h taskinfo.c taskinfo.h outstat.c outstat.h \ +scanout.c scanout.h nodelist.c nodelist.h callstat.c callstat.h libs.h + +LDADD = ../lib/libmemwatch.a + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o root -g root -m 6711 mbtask $(bindir) + @if [ -f $(sysconfdir)/mbsed.conf ]; then \ + rm $(sysconfdir)/mbsed.conf ; \ + fi + @if [ -f $(sysconfdir)/client.conf ]; then \ + rm $(sysconfdir)/client.conf ; \ + fi + @if [ -f $(bindir)/mbsed ]; then \ + rm $(bindir)/mbsed ; \ + fi + @if [ ! -f $(sysconfdir)/issue ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir)"; \ + fi + diff --git a/mbtask/Makefile.in b/mbtask/Makefile.in new file mode 100644 index 00000000..af3981fa --- /dev/null +++ b/mbtask/Makefile.in @@ -0,0 +1,396 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = issue + +noinst_PROGRAMS = mbtask + +mbtask_SOURCES = mbtask.c mbtask.h signame.c signame.h taskutil.c taskutil.h taskcomm.c taskcomm.h taskstat.c taskstat.h taskdisk.c taskdisk.h taskregs.c taskregs.h taskinfo.c taskinfo.h outstat.c outstat.h scanout.c scanout.h nodelist.c nodelist.h callstat.c callstat.h libs.h + + +LDADD = ../lib/libmemwatch.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(noinst_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +mbtask_OBJECTS = mbtask.o signame.o taskutil.o taskcomm.o taskstat.o \ +taskdisk.o taskregs.o taskinfo.o outstat.o scanout.o nodelist.o \ +callstat.o +mbtask_LDADD = $(LDADD) +mbtask_DEPENDENCIES = ../lib/libmemwatch.a +mbtask_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(mbtask_SOURCES) +OBJECTS = $(mbtask_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps mbtask/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstPROGRAMS: + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) + +distclean-noinstPROGRAMS: + +maintainer-clean-noinstPROGRAMS: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +mbtask: $(mbtask_OBJECTS) $(mbtask_DEPENDENCIES) + @rm -f mbtask + $(LINK) $(mbtask_LDFLAGS) $(mbtask_OBJECTS) $(mbtask_LDADD) $(LIBS) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = mbtask + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +callstat.o: callstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h callstat.h +mbtask.o: mbtask.c libs.h ../config.h ../lib/memwatch.h ../lib/structs.h \ + signame.h taskstat.h taskutil.h taskregs.h taskcomm.h outstat.h \ + nodelist.h mbtask.h +nodelist.o: nodelist.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h nodelist.h +outstat.o: outstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h scanout.h nodelist.h callstat.h \ + outstat.h +scanout.o: scanout.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskutil.h scanout.h +signame.o: signame.c signame.h +taskcomm.o: taskcomm.c libs.h ../config.h ../lib/memwatch.h taskstat.h \ + taskregs.h taskdisk.h taskinfo.h taskutil.h taskcomm.h +taskdisk.o: taskdisk.c libs.h ../config.h ../lib/memwatch.h taskdisk.h \ + taskutil.h +taskinfo.o: taskinfo.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskinfo.h +taskregs.o: taskregs.c libs.h ../config.h ../lib/memwatch.h taskstat.h \ + taskregs.h taskutil.h +taskstat.o: taskstat.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h taskstat.h outstat.h taskutil.h +taskutil.o: taskutil.c libs.h ../config.h ../lib/memwatch.h \ + ../lib/structs.h signame.h scanout.h taskutil.h + +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile $(PROGRAMS) +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-noinstPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-noinstPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-noinstPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: mostlyclean-noinstPROGRAMS distclean-noinstPROGRAMS \ +clean-noinstPROGRAMS maintainer-clean-noinstPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-data-recursive \ +uninstall-data-recursive install-exec-recursive \ +uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \ +all-recursive check-recursive installcheck-recursive info-recursive \ +dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + $(INSTALL) -s -o root -g root -m 6711 mbtask $(bindir) + @if [ -f $(sysconfdir)/mbsed.conf ]; then \ + rm $(sysconfdir)/mbsed.conf ; \ + fi + @if [ -f $(sysconfdir)/client.conf ]; then \ + rm $(sysconfdir)/client.conf ; \ + fi + @if [ -f $(bindir)/mbsed ]; then \ + rm $(bindir)/mbsed ; \ + fi + @if [ ! -f $(sysconfdir)/issue ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0644 issue $(sysconfdir)"; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/mbtask/callstat.c b/mbtask/callstat.c new file mode 100644 index 00000000..d49cf0e6 --- /dev/null +++ b/mbtask/callstat.c @@ -0,0 +1,135 @@ +/***************************************************************************** + * + * File ..................: mbtask/callstat.c + * Purpose ...............: Read mailer last call status + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "callstat.h" + + +extern struct sysconfig CFG; + + +char *stsname(faddr *); +char *stsname(faddr *addr) +{ + static char buf[PATH_MAX]; + char *p, *domain=NULL; + char zpref[8]; + int i; + + sprintf(buf, "%s", CFG.outbound); + + if (CFG.addr4d) { + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * If we got a 5d address we use the given domain, if + * we got a 4d address, we look for a matching domain name. + */ + if (addr->domain) + domain = xstrcpy(addr->domain); + else + for (i = 0; i < 40; i++) + if (CFG.aka[i].zone == addr->zone) { + domain = xstrcpy(CFG.aka[i].domain); + break; + } + + if ((domain != NULL) && (strlen(CFG.aka[0].domain) != 0) && + (strcasecmp(domain,CFG.aka[0].domain) != 0)) { + if ((p = strrchr(buf,'/'))) + p++; + else + p = buf; + strcpy(p, domain); + for (; *p; p++) + *p = tolower(*p); + for (i = 0; i < 40; i++) + if ((strlen(CFG.aka[i].domain)) && + (strcasecmp(CFG.aka[i].domain, domain) == 0)) + break; + + /* + * The default zone must be the first one in the + * setup, other zones get the hexadecimal zone + * number appended. + */ + if (CFG.aka[i].zone == addr->zone) + zpref[0] = '\0'; + else + sprintf(zpref, ".%03x", addr->zone); + } else { + /* + * this is our primary domain + */ + if ((addr->zone == 0) || (addr->zone == CFG.aka[0].zone)) + zpref[0]='\0'; + else + sprintf(zpref,".%03x",addr->zone); + } + } + + p = buf + strlen(buf); + + if (addr->point) + sprintf(p,"%s/%04x%04x.pnt/%08x.sts", zpref,addr->net,addr->node,addr->point); + else + sprintf(p,"%s/%04x%04x.sts",zpref,addr->net,addr->node); + + if (domain) + free(domain); + return buf; +} + + + +callstat *getstatus(faddr *addr) +{ + static callstat cst; + FILE *fp; + + cst.trytime = 0L; + cst.tryno = 0; + cst.trystat = 0; + + if ((fp = fopen(stsname(addr), "r"))) { + fread(&cst, sizeof(callstat), 1, fp); + fclose(fp); + } + + return &cst; +} + + diff --git a/mbtask/callstat.h b/mbtask/callstat.h new file mode 100644 index 00000000..dbe5bdbc --- /dev/null +++ b/mbtask/callstat.h @@ -0,0 +1,26 @@ +#ifndef CALLSTAT_H +#define CALLSTAT_H + + +#define ST_PORTERR 1 +#define ST_NOCONN 2 +#define ST_MDMERR 3 +#define ST_LOCKED 4 +#define ST_LOOKUP 6 +#define ST_NOCALL7 7 +#define ST_NOCALL8 8 +#define ST_NOPORT 9 +#define ST_NOTZMH 10 +#define ST_SESSION 30 + + +typedef struct _callstat { + time_t trytime; + int tryno; + int trystat; +} callstat; + + +callstat *getstatus(faddr*); + +#endif diff --git a/mbtask/issue b/mbtask/issue new file mode 100644 index 00000000..5011e912 --- /dev/null +++ b/mbtask/issue @@ -0,0 +1,12 @@ + + .--. Welcome at MBSE BBS Professional + |o_o | -------------------------------- + |:_/ | + // \\ \\ Abandon all hope ye who have entered cyberspace. + (| | ) + /'\\_ _/\`\\ + \\___)=(___/ +Powered by Linux. + +To start the bbs login with "bbs" without quotes. + diff --git a/mbtask/libs.h b/mbtask/libs.h new file mode 100644 index 00000000..d7698ea9 --- /dev/null +++ b/mbtask/libs.h @@ -0,0 +1,166 @@ +/***************************************************************************** + * + * File ..................: libs.h + * Purpose ...............: Libraries include list + * Last modification date : 05-jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbse@user.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#ifndef _LIBS_H +#define _LIBS_H + +#define TRUE 1 +#define FALSE 0 +#define SS_BUFSIZE 1024 /* Streams socket buffersize */ + + +#include "../config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../lib/memwatch.h" + + +/* + * Some older systems don;t have this + */ +#ifndef ICMP_FILTER +#define ICMP_FILTER 1 + +struct icmp_filter { + u_int32_t data; +}; + +#endif + + +/* some older glibc versions seem to lack this. */ +# ifndef IP_PKTINFO +# define IP_PKTINFO 8 +# endif +# ifndef CMSG_LEN +/* ---- from glibc 2.1.2 */ + + +/* Ancillary data object manipulation macros. */ +# if !defined __STRICT_ANSI__ && defined __GNUC__ && __GNUC__ >= 2 +# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data) +# else +# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1)) +# endif +# define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg) +# define CMSG_FIRSTHDR(mhdr) \ + ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr) \ + ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) NULL) +# define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \ + & ~(sizeof (size_t) - 1)) +# define CMSG_SPACE(len) (CMSG_ALIGN (len) \ + + CMSG_ALIGN (sizeof (struct cmsghdr))) +# define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +extern struct cmsghdr *__cmsg_nxthdr __P ((struct msghdr *__mhdr, + struct cmsghdr *__cmsg)); +# ifdef __USE_EXTERN_INLINES +# ifndef _EXTERN_INLINE +# define _EXTERN_INLINE extern __inline +# endif +_EXTERN_INLINE struct cmsghdr * +__cmsg_nxthdr (struct msghdr *__mhdr, struct cmsghdr *__cmsg) __THROW +{ + if ((size_t) __cmsg->cmsg_len < sizeof (struct cmsghdr)) + /* The kernel header does this so there may be a reason. */ + return 0; + + __cmsg = (struct cmsghdr *) ((unsigned char *) __cmsg + + CMSG_ALIGN (__cmsg->cmsg_len)); + if ((unsigned char *) (__cmsg + 1) >= ((unsigned char *) __mhdr->msg_control + + __mhdr->msg_controllen) + || ((unsigned char *) __cmsg + CMSG_ALIGN (__cmsg->cmsg_len) + >= ((unsigned char *) __mhdr->msg_control + __mhdr->msg_controllen))) + /* No more entries. */ + return 0; + return __cmsg; +} +# endif /* Use `extern inline'. */ +# endif + + +/* A macro to extract the pointer to the address of a struct sockaddr (_in or _in6) */ +#define SOCKA_A4(a) ((void *)&((struct sockaddr_in *)(a))->sin_addr) + + +/* Some old libs don't have socklen_t */ +#ifndef socklen_t +#define socklen_t unsigned int +#endif + + +#pragma pack(1) + +#define MAXNAME 35 +#define MAXUFLAGS 16 + +typedef struct _faddr { + char *name; + unsigned int point; + unsigned int node; + unsigned int net; + unsigned int zone; + char *domain; +} faddr; + + + + +#endif + diff --git a/mbtask/mbtask.c b/mbtask/mbtask.c new file mode 100644 index 00000000..ae0e13d4 --- /dev/null +++ b/mbtask/mbtask.c @@ -0,0 +1,1440 @@ +/***************************************************************************** + * + * File ..................: mbtask/mbtask.c + * Purpose ...............: MBSE BBS Task Manager + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "signame.h" +#include "taskstat.h" +#include "taskutil.h" +#include "taskregs.h" +#include "taskcomm.h" +#include "outstat.h" +#include "nodelist.h" +#include "mbtask.h" + + + +/* + * Defines. + * SLOWRUN is number of seconds for mailer calls. Use between 5 and 30. + */ +#define MAXTASKS 10 +#define SLOWRUN 20 +#define TMPNAME "TMP." +#define LCKNAME "LOCKTASK" +#define ICMP_BASEHDR_LEN 8 +#define ICMP_MAX_ERRS 5 +#define SET_SOCKA_LEN4(socka) +#define Copyright "Copyright (C) 1997-2001 Michiel Broek, All Rights Reserved" + + +typedef enum {P_INIT, P_SENT, P_FAIL, P_OK, P_ERROR, P_NONE} PINGSTATE; + + + +/* + * Global variables + */ +static onetask task[MAXTASKS]; /* Array with tasks */ +reg_info reginfo[MAXCLIENT]; /* Array with clients */ +static pid_t pgrp; /* Pids group */ +static char lockfile[PATH_MAX]; /* Lockfile */ +int sock = -1; /* Datagram socket */ +struct sockaddr_un servaddr; /* Server address */ +struct sockaddr_un from; /* From address */ +int fromlen; +static char spath[PATH_MAX]; /* Socket path */ +int logtrans = 0; /* Log transactions */ +struct taskrec TCFG; /* Task config record */ +struct sysconfig CFG; /* System config */ +struct _nodeshdr nodeshdr; /* Nodes header record */ +struct _nodes nodes; /* Nodes data record */ +struct _fidonethdr fidonethdr; /* Fidonet header rec. */ +struct _fidonet fidonet; /* Fidonet data record */ +time_t tcfg_time; /* Config record time */ +time_t cfg_time; /* Config record time */ +char tcfgfn[PATH_MAX]; /* Config file name */ +char cfgfn[PATH_MAX]; /* Config file name */ +int ping_isocket; /* Ping socket */ +int icmp_errs = 0; /* ICMP error counter */ +int internet = FALSE; /* Internet is down */ +float Load; /* System Load */ +int Processing; /* Is system running */ +int ZMH = FALSE; /* Zone Mail Hour */ +int UPSalarm = FALSE; /* UPS alarm status */ +extern int s_bbsopen; /* BBS open semafore */ +extern int s_scanout; /* Scan outbound sema */ +extern int s_mailout; /* Mail out semafore */ +extern int s_mailin; /* Mail in semafore */ +extern int s_index; /* Compile nl semafore */ +extern int s_newnews; /* New news semafore */ +extern int s_reqindex; /* Create req index sem */ +extern int s_msglink; /* Messages link sem */ +int pingstate = P_INIT; /* Ping state */ +int pingnr = 1; /* Ping #, 1 or 2 */ +int pingresult[2]; /* Ping results */ +char pingaddress[41]; /* Ping current address */ + + + +/* + * Load main configuration, if it doesn't exist, create it. + * This is the case the very first time when you start MBSE BBS. + */ +void load_maincfg(void) +{ + FILE *fp; + struct utsname un; + int i; + + if ((fp = fopen(cfgfn, "r")) == NULL) { + memset(&CFG, 0, sizeof(CFG)); + + /* + * Fill Registration defaults + */ + sprintf(CFG.bbs_name, "MBSE BBS"); + uname((struct utsname *)&un); +#ifdef __USE_GNU + sprintf(CFG.sysdomain, "%s.%s", un.nodename, un.domainname); +#else + sprintf(CFG.sysdomain, "%s.%s", un.nodename, un.__domainname); +#endif + sprintf(CFG.comment, "MBSE Linux BBS development"); + sprintf(CFG.origin, "MBSE Linux BBS. Made in the Netherlands"); + sprintf(CFG.location, "Earth"); + + /* + * Fill Filenames defaults + */ + sprintf(CFG.logfile, "system.log"); + sprintf(CFG.error_log, "error.log"); + sprintf(CFG.default_menu, "main.mnu"); + sprintf(CFG.current_language, "english.lang"); + sprintf(CFG.chat_log, "chat.log"); + sprintf(CFG.welcome_logo, "logo.asc"); + + /* + * Fill Global defaults + */ + sprintf(CFG.bbs_menus, "%s/english/menus", getenv("MBSE_ROOT")); + sprintf(CFG.bbs_txtfiles, "%s/english/txtfiles", getenv("MBSE_ROOT")); + sprintf(CFG.bbs_usersdir, "%s/home", getenv("MBSE_ROOT")); + sprintf(CFG.nodelists, "/var/spool/mbse/nodelist"); + sprintf(CFG.inbound, "/var/spool/mbse/unknown"); + sprintf(CFG.pinbound, "/var/spool/mbse/inbound"); + sprintf(CFG.outbound, "/var/spool/mbse/outbound"); + sprintf(CFG.dospath, "a:"); /* The biggest floppy on earth, JvdW. */ + sprintf(CFG.uxpath, "/var/spool/mbse"); + sprintf(CFG.badtic, "/var/spool/mbse/badtic"); + sprintf(CFG.ticout, "/var/spool/mbse/ticqueue"); + sprintf(CFG.req_magic, "%s/magic", getenv("MBSE_ROOT")); + + /* + * Newfiles reports + */ + sprintf(CFG.ftp_base, "/var/spool/mbse/ftp"); + CFG.newdays = 30; + CFG.security.level = 20; + CFG.new_split = 27; + CFG.new_force = 30; + + /* + * BBS Globals + */ + CFG.CityLen = 6; + CFG.max_login = 5; + CFG.elite_mode = FALSE; + CFG.exclude_sysop = TRUE; + CFG.iConnectString = FALSE; + CFG.iAskFileProtocols = FALSE; + CFG.sysop_access = 32000; + CFG.password_length = 4; + CFG.iPasswd_Char = '.'; + CFG.idleout = 3; + CFG.iQuota = 10; + CFG.iCRLoginCount = 10; + CFG.bbs_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + CFG.util_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + CFG.OLR_NewFileLimit = 30; + CFG.OLR_MaxReq = 25; + CFG.slow_util = TRUE; + CFG.iCrashLevel = 100; + CFG.iAttachLevel = 100; + CFG.new_groups = 25; + + CFG.slow_util = TRUE; + CFG.iCrashLevel = 100; + CFG.iAttachLevel = 100; + CFG.new_groups = 25; + sprintf(CFG.startname, "bbs"); + CFG.freespace = 10; + + /* + * New Users + */ + CFG.newuser_access.level = 5; + CFG.iCapUserName = TRUE; + CFG.iAnsi = TRUE; + CFG.iDataPhone = TRUE; + CFG.iVoicePhone = TRUE; + CFG.iDOB = TRUE; + CFG.iTelephoneScan = TRUE; + CFG.iLocation = TRUE; + CFG.iHotkeys = TRUE; + CFG.iCapLocation = FALSE; + CFG.AskAddress = FALSE; + CFG.GiveEmail = TRUE; + + /* + * Colors + */ + CFG.TextColourF = 3; + CFG.TextColourB = 0; + CFG.UnderlineColourF = 14; + CFG.UnderlineColourB = 0; + CFG.InputColourF = 11; + CFG.InputColourB = 0; + CFG.CRColourF = 15; + CFG.CRColourB = 0; + CFG.MoreF = 13; + CFG.MoreB = 0; + CFG.HiliteF = 15; + CFG.HiliteB = 0; + CFG.FilenameF = 14; + CFG.FilenameB = 0; + CFG.FilesizeF = 13; + CFG.FilesizeB = 0; + CFG.FiledateF = 10; + CFG.FiledateB = 0; + CFG.FiledescF = 3; + CFG.FiledescB = 0; + CFG.MsgInputColourF = 3; + CFG.MsgInputColourB = 0; + + /* + * NextUser Door + */ + sprintf(CFG.sNuScreen, "welcome"); + sprintf(CFG.sNuQuote, "Please press [ENTER] to continue: "); + + /* + * Safe Door + */ + CFG.iSafeFirstDigit = 1; + CFG.iSafeSecondDigit = 2; + CFG.iSafeThirdDigit = 3; + CFG.iSafeMaxTrys = 4; + CFG.iSafeMaxNumber = 20; + CFG.iSafeNumGen = FALSE; + strcpy(CFG.sSafePrize, "Free access for a year!"); + sprintf(CFG.sSafeWelcome, "safewel"); + sprintf(CFG.sSafeOpened, "safeopen"); + + /* + * Paging + */ + CFG.iPageLength = 30; + CFG.iMaxPageTimes = 5; + CFG.iAskReason = TRUE; + CFG.iSysopArea = 1; + CFG.iExternalChat = FALSE; + strcpy(CFG.sExternalChat, "/usr/local/bin/chat"); + CFG.iAutoLog = TRUE; + strcpy(CFG.sChatDevice, "/dev/tty01"); + CFG.iChatPromptChk = TRUE; + CFG.iStopChatTime = TRUE; + for (i = 0; i < 7; i++) { + sprintf(CFG.cStartTime[i], "18:00"); + sprintf(CFG.cStopTime[i], "23:59"); + } + + /* + * Time Bank + */ + CFG.iMaxTimeBalance = 200; + CFG.iMaxTimeWithdraw = 100; + CFG.iMaxTimeDeposit = 60; + CFG.iMaxByteBalance = 500; + CFG.iMaxByteWithdraw = 300; + CFG.iMaxByteDeposit = 150; + strcpy(CFG.sTimeRatio, "3:1"); + strcpy(CFG.sByteRatio, "3:1"); + + /* + * Fill ticconf defaults + */ + CFG.ct_ResFuture = TRUE; + CFG.ct_ReplExt = TRUE; + CFG.ct_PlusAll = TRUE; + CFG.ct_Notify = TRUE; + CFG.ct_Message = TRUE; + CFG.ct_TIC = TRUE; + CFG.tic_days = 30; + sprintf(CFG.hatchpasswd, "DizIzMyBIGseeKret"); + CFG.drspace = 2048; + CFG.tic_systems = 10; + CFG.tic_groups = 25; + CFG.tic_dupes = 16000; + + /* + * Fill Mail defaults + */ + CFG.maxpktsize = 150; + CFG.maxarcsize = 300; + sprintf(CFG.badboard, "/var/spool/mbse/mail/badmail"); + sprintf(CFG.dupboard, "/var/spool/mbse/mail/dupmail"); + sprintf(CFG.popnode, "localhost"); + sprintf(CFG.smtpnode, "localhost"); + sprintf(CFG.nntpnode, "localhost"); + CFG.toss_days = 30; + CFG.toss_dupes = 16000; + CFG.toss_old = 60; + CFG.defmsgs = 500; + CFG.defdays = 90; + CFG.toss_systems = 10; + CFG.toss_groups = 25; + CFG.UUCPgate.zone = 2; + CFG.UUCPgate.net = 292; + CFG.UUCPgate.node = 875; + sprintf(CFG.UUCPgate.domain, "fidonet"); + CFG.nntpdupes = 16000; + + for (i = 0; i < 32; i++) + sprintf(CFG.fname[i], "Flag %d", i+1); + + + /* + * Fido mailer defaults + */ + CFG.timeoutreset = 3L; + CFG.timeoutconnect = 60L; + sprintf(CFG.phonetrans[0].match, "31-255"); + sprintf(CFG.phonetrans[1].match, "31-"); + sprintf(CFG.phonetrans[1].repl, "0"); + sprintf(CFG.phonetrans[2].repl, "00"); + CFG.Speed = 9600; + CFG.dialdelay = 60; + sprintf(CFG.Flags, "CM,XX,IBN,IFC,ITN"); + CFG.cico_loglevel = DLOG_ALLWAYS | DLOG_ERROR | DLOG_ATTENT | DLOG_NORMAL | DLOG_VERBOSE; + + /* + * FTP Server + */ + CFG.ftp_limit = 20; + CFG.ftp_loginfails = 2; + CFG.ftp_compress = TRUE; + CFG.ftp_tar = TRUE; + CFG.ftp_log_cmds = TRUE; + CFG.ftp_anonymousok = TRUE; + CFG.ftp_mbseok = FALSE; + sprintf(CFG.ftp_readme_login, "README*"); + sprintf(CFG.ftp_readme_cwd, "README*"); + sprintf(CFG.ftp_msg_login, "/welcome.msg"); + sprintf(CFG.ftp_msg_cwd, ".message"); + sprintf(CFG.ftp_msg_shutmsg, "/etc/nologin"); + sprintf(CFG.ftp_upl_path, "%s/incoming", CFG.ftp_base); + sprintf(CFG.ftp_banner, "%s/etc/ftpbanner", getenv("MBSE_ROOT")); + sprintf(CFG.ftp_email, "sysop@%s", CFG.sysdomain); + sprintf(CFG.ftp_pth_filter, "^[-A-Za-z0-9_\\.]*$ ^\\. ^-"); + sprintf(CFG.ftp_pth_message, "%s/etc/pathmsg", getenv("MBSE_ROOT")); + + /* + * WWW defaults + */ + sprintf(CFG.www_root, "/var/lib/apache/htdocs"); + sprintf(CFG.www_link2ftp, "files"); + sprintf(CFG.www_url, "http://%s", CFG.sysdomain); + sprintf(CFG.www_charset, "ISO 8859-1"); + sprintf(CFG.www_tbgcolor, "Silver"); + sprintf(CFG.www_hbgcolor, "Aqua"); + sprintf(CFG.www_author, "Your Name"); + sprintf(CFG.www_convert,"/usr/X11R6/bin/convert -geometry x100"); + sprintf(CFG.www_icon_home, "up.gif"); + sprintf(CFG.www_name_home, "Home"); + sprintf(CFG.www_icon_back, "back.gif"); + sprintf(CFG.www_name_back, "Back"); + sprintf(CFG.www_icon_prev, "left.gif"); + sprintf(CFG.www_name_prev, "Previous page"); + sprintf(CFG.www_icon_next, "right.gif"); + sprintf(CFG.www_name_next, "Next page"); + CFG.www_files_page = 10; + + if ((fp = fopen(cfgfn, "a+")) == NULL) { + perror(""); + fprintf(stderr, "Can't create %s\n", cfgfn); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(2); + } + fwrite(&CFG, sizeof(CFG), 1, fp); + fclose(fp); + } else { + fread(&CFG, sizeof(CFG), 1, fp); + fclose(fp); + } + + cfg_time = file_time(cfgfn); +} + + + +/* + * Load task configuration data. + */ +void load_taskcfg(void) +{ + FILE *fp; + + if ((fp = fopen(tcfgfn, "r")) == NULL) { + memset(&TCFG, 0, sizeof(TCFG)); + TCFG.maxload = 1.50; + sprintf(TCFG.zmh_start, "02:30"); + sprintf(TCFG.zmh_end, "03:30"); + sprintf(TCFG.cmd_mailout, "%s/bin/mbfido scan web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mailin, "%s/bin/mbfido tic toss web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_newnews, "%s/bin/mbfido news web -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mbindex1, "%s/bin/mbindex -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_mbindex2, "%s/bin/goldnode -f -q", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_msglink, "%s/bin/mbmsg link -quiet", getenv("MBSE_ROOT")); + sprintf(TCFG.cmd_reqindex, "%s/bin/mbfile index -quiet", getenv("MBSE_ROOT")); + TCFG.ipblocks = TRUE; + TCFG.max_pots = 1; + TCFG.max_isdn = 0; + TCFG.max_tcp = 0; + if ((fp = fopen(tcfgfn, "a+")) == NULL) { + tasklog('?', "$Can't create %s", tcfgfn); + die(2); + } + fwrite(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + tasklog('+', "Created new %s", tcfgfn); + } else { + fread(&TCFG, sizeof(TCFG), 1, fp); + fclose(fp); + } + + tcfg_time = file_time(tcfgfn); +} + + + +/* + * Launch an external program in the background. + * On success add it to the tasklist and return + * the pid. + */ +pid_t launch(char *cmd, char *opts, char *name, int tasktype) +{ + char buf[PATH_MAX]; + char *vector[16]; + int i, rc = 0; + pid_t pid = 0; + + if (checktasks(0) >= MAXTASKS) { + tasklog('?', "Launch: can't execute %s, maximum tasks reached", cmd); + return 0; + } + + if (opts == NULL) + sprintf(buf, "%s", cmd); + else + sprintf(buf, "%s %s", cmd, opts); + + i = 0; + vector[i++] = strtok(buf," \t\n\0"); + while ((vector[i++] = strtok(NULL," \t\n")) && (i<16)); + vector[15] = NULL; + + if (file_exist(vector[0], X_OK)) { + tasklog('?', "Launch: can't execute %s, command not found", vector[0]); + return 0; + } + + pid = fork(); + switch (pid) { + case -1: + tasklog('?', "$Launch: error, can't fork grandchild"); + return 0; + case 0: + /* From Paul Vixies cron: */ + (void)setsid(); /* It doesn't seem to help */ + close(0); + if (open("/dev/null", O_RDONLY) != 0) { + tasklog('?', "$Launch: \"%s\": reopen of stdin to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + close(1); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 1) { + tasklog('?', "$Launch: \"%s\": reopen of stdout to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + close(2); + if (open("/dev/null", O_WRONLY | O_APPEND | O_CREAT,0600) != 2) { + tasklog('?', "$Launch: \"%s\": reopen of stderr to /dev/null failed", buf); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + } + errno = 0; + rc = execv(vector[0],vector); + tasklog('?', "$Launch: execv \"%s\" failed, returned %d", cmd, rc); +#ifdef MEMWATCH + mwTerm(); +#endif + _exit(-1); + default: + /* grandchild's daddy's process */ + break; + } + + /* + * Add it to the tasklist. + */ + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name) == 0) { + strcpy(task[i].name, name); + strcpy(task[i].cmd, cmd); + if (opts) + strcpy(task[i].opts, opts); + task[i].pid = pid; + task[i].status = 0; + task[i].running = TRUE; + task[i].rc = 0; + task[i].tasktype = tasktype; + break; + } + } + + if (opts) + tasklog('+', "Launch: task %d \"%s %s\" success, pid=%d", i, cmd, opts, pid); + else + tasklog('+', "Launch: task %d \"%s\" success, pid=%d", i, cmd, pid); + return pid; +} + + + +/* + * Count specific running tasks + */ +int runtasktype(int tasktype) +{ + int i, count = 0; + + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name) && task[i].running && (task[i].tasktype == tasktype)) + count++; + } + return count; +} + + + +/* + * Check all running tasks registered in the tasklist. + * Report programs that are stopped. If signal is set + * then send that signal. + */ +int checktasks(int onsig) +{ + int i, j, rc, count = 0, first = TRUE, status, do_outstat = FALSE; + + for (i = 0; i < MAXTASKS; i++) { + if (strlen(task[i].name)) { + + if (onsig) { + if (kill(task[i].pid, onsig) == 0) + tasklog('+', "%s to %s (pid %d) succeeded", SigName[onsig], task[i].name, task[i].pid); + else + tasklog('+', "%s to %s (pid %d) failed", SigName[onsig], task[i].name, task[i].pid); + } + + task[i].rc = wait4(task[i].pid, &status, WNOHANG | WUNTRACED, NULL); + if (task[i].rc) { + task[i].running = FALSE; + if (task[i].tasktype == CALL_POTS || task[i].tasktype == CALL_ISDN || task[i].tasktype == CALL_IP) + do_outstat = TRUE; + } + + if (first && task[i].rc) { + first = FALSE; + tasklog('t', "Task T pid stat status rc status"); + tasklog('t', "---------------- - ----- ---- ----------- ----- --------"); + for (j = 0; j < MAXTASKS; j++) + if (strlen(task[j].name)) + tasklog('t', "%-16s %d %5d %s %-11d %5d %08x", task[j].name, + task[j].tasktype, task[j].pid, task[j].running?"runs":"stop", + task[j].status, task[j].rc, task[j].status); + } + + switch (task[i].rc) { + case -1: + if (errno == ECHILD) + tasklog('+', "Task %d \"%s\" is ready", i, task[i].name); + else + tasklog('+', "Task %d \"%s\" is ready, error: %s", i, task[i].name, strerror(errno)); + break; + case 0: + /* + * Update last known status when running. + */ + task[i].status = status; + count++; + break; + default: + tasklog('+', "errno=%d %s", errno, strerror(errno)); + if (WIFEXITED(task[i].status)) { + rc = WEXITSTATUS(task[i].status); + if (rc) + tasklog('+', "Task %s is ready, error=%d", task[i].name, rc); + else + tasklog('+', "Task %s is ready", task[i].name); + } else if (WIFSIGNALED(task[i].status)) { + rc = WTERMSIG(task[i].status); + if (rc <= 31) + tasklog('+', "Task %s terminated on signal %s (%d)", task[i].name, SigName[rc], rc); + else + tasklog('+', "Task %s terminated with error nr %d", task[i].name, rc); + } else if (WIFSTOPPED(task[i].status)) { + rc = WSTOPSIG(task[i].status); + tasklog('+', "Task %s stopped on signal %s (%d)", task[i].name, SigName[rc], rc); + } else { + tasklog('+', "FIXME: 1"); + } + break; + } + + if (!task[i].running) + memset(&task[i], 0, sizeof(onetask)); + } + } + + if (do_outstat) + outstat(); + + return count; +} + + + +void die(int onsig) +{ + int i, count; + + signal(onsig, SIG_IGN); + tasklog('+', "Shutting down on signal %s", SigName[onsig]); + + /* + * First check if there are tasks running, if so try to stop them + */ + if ((count = checktasks(0))) { + tasklog('+', "There are %d tasks running, sending SIGTERM", count); + checktasks(SIGTERM); + for (i = 0; i < 15; i++) { + sleep(1); + count = checktasks(0); + if (count == 0) + break; + } + if (count) { + /* + * There are some diehards running... + */ + tasklog('+', "There are %d tasks running, sending SIGKILL", count); + count = checktasks(SIGKILL); + } + if (count) { + sleep(1); + count = checktasks(0); + if (count) + tasklog('?', "Still %d tasks running, giving up", count); + } + } + + ulocktask(); + if (sock != -1) + close(sock); + if (ping_isocket != -1) + close(ping_isocket); + if (!file_exist(spath, R_OK)) { + unlink(spath); + } + tasklog(' ', "MBTASK finished"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(onsig); +} + + + +/* + * Put a lock on this program. + */ +int locktask(char *root) +{ + char Tmpfile[81]; + FILE *fp; + pid_t oldpid; + + sprintf(Tmpfile, "%s/var/", root); + strcpy(lockfile, Tmpfile); + sprintf(Tmpfile + strlen(Tmpfile), "%s%u", TMPNAME, getpid()); + sprintf(lockfile + strlen(lockfile), "%s", LCKNAME); + + if ((fp = fopen(Tmpfile, "w")) == NULL) { + perror("mbtask"); + printf("Can't create lockfile \"%s\"\n", Tmpfile); + return 1; + } + fprintf(fp, "%10u\n", getpid()); + fclose(fp); + + while (TRUE) { + if (link(Tmpfile, lockfile) == 0) { + unlink(Tmpfile); + return 0; + } + if ((fp = fopen(lockfile, "r")) == NULL) { + perror("mbtask"); + printf("Can't open lockfile \"%s\"\n", Tmpfile); + unlink(Tmpfile); + return 1; + } + if (fscanf(fp, "%u", &oldpid) != 1) { + perror("mbtask"); + printf("Can't read old pid from \"%s\"\n", Tmpfile); + fclose(fp); + unlink(Tmpfile); + return 1; + } + fclose(fp); + if (kill(oldpid,0) == -1) { + if (errno == ESRCH) { + printf("Stale lock found for pid %u\n", oldpid); + unlink(lockfile); + /* no return, try lock again */ + } else { + perror("mbtask"); + printf("Kill for %u failed\n",oldpid); + unlink(Tmpfile); + return 1; + } + } else { + printf("Another mbtask is already running, pid=%u\n", oldpid); + unlink(Tmpfile); + return 1; + } + } +} + + + +void ulocktask(void) +{ + if (lockfile) + (void)unlink(lockfile); +} + + + +/* + * Takes a packet as send out and a recieved ICMP packet and looks whether the ICMP packet is + * an error reply on the sent-out one. packet is only the packet (without IP header). + * errmsg includes an IP header. + * to is the destination address of the original packet (the only thing that is actually + * compared of the IP header). The RFC sais that we get at least 8 bytes of the offending packet. + * We do not compare more, as this is all we need. + */ +static int icmp4_errcmp(char *packet, int plen, struct in_addr *to, char *errmsg, int elen, int errtype) +{ + struct iphdr iph; + struct icmphdr icmph; + struct iphdr eiph; + char *data; + + /* XXX: lots of memcpy to avoid unaligned accesses on alpha */ + if (elen < sizeof(struct iphdr)) + return 0; + memcpy(&iph, errmsg, sizeof(iph)); + if (iph.protocol != IPPROTO_ICMP || elen < iph.ihl * 4 + ICMP_BASEHDR_LEN + sizeof(eiph)) + return 0; + memcpy(&icmph, errmsg + iph.ihl * 4, ICMP_BASEHDR_LEN); + memcpy(&eiph, errmsg + iph.ihl * 4 + ICMP_BASEHDR_LEN, sizeof(eiph)); + if (elen < iph.ihl * 4 + ICMP_BASEHDR_LEN + eiph.ihl * 4 + 8) + return 0; + data = errmsg + iph.ihl * 4 + ICMP_BASEHDR_LEN + eiph.ihl * 4; + return icmph.type == errtype && memcmp(&to->s_addr, &eiph.daddr, sizeof(to->s_addr)) == 0 && + memcmp(data, packet, plen < 8 ?plen:8) == 0; +} + + + +unsigned short get_rand16(void) +{ + return random()&0xffff; +} + + +short p_sequence = 0; +unsigned short id; +struct icmphdr icmpd; +struct sockaddr_in to; + +/* + * IPv4/ICMPv4 ping. Called from ping (see below) + */ +int ping_send(struct in_addr addr) +{ + int len; + int isock; + struct icmp_filter f; + unsigned long sum; + unsigned short *ptr; + + isock = ping_isocket; + p_sequence = 1; + id = (unsigned short)get_rand16(); /* randomize a ping id */ + + /* Fancy ICMP filering -- only on Linux (as far is I know) */ + + /* In fact, there should be macros for treating icmp_filter, but I haven't found them in Linux 2.2.15. + * So, set it manually and unportable ;-) */ + /* This filter lets ECHO_REPLY (0), DEST_UNREACH(3) and TIME_EXCEEDED(11) pass. */ + /* !(0000 1000 0000 1001) = 0xff ff f7 f6 */ + f.data=0xfffff7f6; + if (setsockopt(isock, SOL_RAW, ICMP_FILTER, &f, sizeof(f)) == -1) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$icmp ping: setsockopt() failed %d", isock); + return -1; + } + + icmpd.type = ICMP_ECHO; + icmpd.code = 0; + icmpd.checksum = 0; + icmpd.un.echo.id = htons((short)id); + icmpd.un.echo.sequence = htons(p_sequence); + + /* Checksumming - Algorithm taken from nmap. Thanks... */ + + ptr = (unsigned short *)&icmpd; + sum = 0; + + for (len = 0; len < 4; len++) { + sum += *ptr++; + } + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + icmpd.checksum = ~sum; + + memset(&to, 0, sizeof(to)); + to.sin_family = AF_INET; + to.sin_port = 0; + to.sin_addr = addr; + SET_SOCKA_LEN4(to); + if (sendto(isock, &icmpd, ICMP_BASEHDR_LEN, 0, (struct sockaddr *)&to, sizeof(to)) == -1) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$icmp ping: sendto()"); + return -2; + } + return 0; +} + + + +int ping_receive(struct in_addr addr) +{ + char buf[1024]; + int isock; + int len; + struct sockaddr_in ffrom; + struct icmphdr icmpp; + struct iphdr iph; + socklen_t sl; + struct pollfd pfd; + + isock = ping_isocket; + + pfd.fd = isock; + pfd.events = POLLIN; + /* + * 10 mSec is enough, this function is called at regular intervals. + */ + if (poll(&pfd, 1, 10) < 0) { + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('?', "$poll/select failed"); + return -3; + } + + if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) { + sl = sizeof(ffrom); + if ((len = recvfrom(isock, &buf, sizeof(buf), 0,(struct sockaddr *)&ffrom, &sl)) != -1) { + if (len > sizeof(struct iphdr)) { + memcpy(&iph, buf, sizeof(iph)); + if (len - iph.ihl * 4 >= ICMP_BASEHDR_LEN) { + memcpy(&icmpp, ((unsigned long int *)buf)+iph.ihl, sizeof(icmpp)); + if (iph.saddr == addr.s_addr && + icmpp.type == ICMP_ECHOREPLY && + ntohs(icmpp.un.echo.id) == id && + ntohs(icmpp.un.echo.sequence) <= p_sequence) { + return 0; + } else { + /* No regular echo reply. Maybe an error? */ + if (icmp4_errcmp((char *)&icmpd, ICMP_BASEHDR_LEN, + &to.sin_addr, buf, len, ICMP_DEST_UNREACH) || + icmp4_errcmp((char *)&icmpd, ICMP_BASEHDR_LEN, + &to.sin_addr, buf, len, ICMP_TIME_EXCEEDED)) { + return -4; + } + } + } + } + } else { + return -5; /* error */ + } + } + return -6; /* no answer */ +} + + + +/* + * Check semafore's, system status flags etc. This is called + * each second to test for condition changes. + */ +void check_sema(void); +void check_sema(void) +{ + /* + * Check UPS status. + */ + if (IsSema((char *)"upsalarm")) { + if (!UPSalarm) + tasklog('!', "UPS: power failure"); + UPSalarm = TRUE; + } else { + if (UPSalarm) + tasklog('!', "UPS: the power is back"); + UPSalarm = FALSE; + } + if (IsSema((char *)"upsdown")) { + tasklog('!', "UPS: power failure, starting shutdown"); + /* + * Since the upsdown semafore is permanent, the system WILL go down + * there is no point for this program to stay. Signal all tasks and stop. + */ + die(SIGTERM); + } + + /* + * Check Zone Mail Hour + */ + get_zmh(); + + /* + * Newnews semafore can also be set in the semafore directory. + */ + if (IsSema((char *)"newnews")) { + RemoveSema((char *)"newnews"); + s_newnews = TRUE; + } +} + + + +void scheduler(void) +{ + struct passwd *pw; + int running = 0, rc, rlen; + int LOADhi = FALSE, oldmin = 70, olddo = 70; + char *cmd = NULL, doing[32], buf[2048]; + time_t now; + struct tm *tm; + FILE *fp; + float lavg1, lavg2, lavg3; + struct pollfd pfd; + struct in_addr paddr; + + InitFidonet(); + + /* + * Registrate this server for mbmon in slot 0. + */ + reginfo[0].pid = getpid(); + sprintf(reginfo[0].tty, "-"); + sprintf(reginfo[0].uname, "mbse"); + sprintf(reginfo[0].prg, "mbtask"); + sprintf(reginfo[0].city, "localhost"); + sprintf(reginfo[0].doing, "Start"); + reginfo[0].started = time(NULL); + + Processing = TRUE; + TouchSema((char *)"mbtask.last"); + pw = getpwuid(getuid()); + + /* + * Setup UNIX Datagram socket + */ + if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { + tasklog('?', "$Can't create socket"); + die(1); + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + strcpy(servaddr.sun_path, spath); + + if (bind(sock, &servaddr, sizeof(servaddr)) < 0) { + close(sock); + sock = -1; + tasklog('?', "$Can't bind socket %s", spath); + die(1); + } + + pingresult[1] = TRUE; + pingresult[2] = TRUE; + initnl(); + sem_set((char *)"scanout", TRUE); + + do { + /* + * Poll UNIX Datagram socket until the defined timeout. + */ + pfd.fd = sock; + pfd.events = POLLIN | POLLPRI; + pfd.revents = 0; + rc = poll(&pfd, 1, 1000); + if (rc == -1) { + /* + * Poll can be interrupted by a finished child so that's not a real error. + */ + if (errno != EINTR) { + tasklog('?', "$poll() rc=%d sock=%d, events=%04x", rc, sock, pfd.revents); + } + } else if (rc) { + if (pfd.revents & POLLIN) { + memset(&buf, 0, sizeof(buf)); + fromlen = sizeof(from); + rlen = recvfrom(sock, buf, sizeof(buf) -1, 0, &from, &fromlen); + do_cmd(buf); + } else { + tasklog('-', "Return poll rc=%d, events=%04x", rc, pfd.revents); + } + } + + /* + * Check all registered connections and semafore's + */ + reg_check(); + check_sema(); + + /* + * Check the systems load average. + */ + if ((fp = fopen((char *)"/proc/loadavg", "r"))) { + if (fscanf(fp, "%f %f %f", &lavg1, &lavg2, &lavg3) == 3) { + Load = lavg1; + if (lavg1 >= TCFG.maxload) { + if (!LOADhi) { + tasklog('!', "System load too high: %2.2f (%2.2f)", lavg1, TCFG.maxload); + LOADhi = TRUE; + } + } else { + if (LOADhi) { + tasklog('!', "System load normal: %2.2f (%2.2f)", lavg1, TCFG.maxload); + LOADhi = FALSE; + } + } + } + fclose(fp); + } + + /* + * Report to the system monitor. + */ + memset(&doing, 0, sizeof(doing)); + if ((running = checktasks(0))) + sprintf(doing, "Run %d tasks", running); + else if (UPSalarm) + sprintf(doing, "UPS alarm"); + else if (!s_bbsopen) + sprintf(doing, "BBS is closed"); + else if (Processing) + sprintf(doing, "Waiting (%d)", oldmin); + else + sprintf(doing, "Overload %2.2f", lavg1); + + sprintf(reginfo[0].doing, "%s", doing); + reginfo[0].lastcon = time(NULL); + + /* + * Touch the mbtask.last semafore to prove this daemon + * is actually running. + * Reload configuration data if the file is changed. + */ + now = time(NULL); + tm = localtime(&now); + if (tm->tm_min != olddo) { + olddo = tm->tm_min; + TouchSema((char *)"mbtask.last"); + if (file_time(tcfgfn) != tcfg_time) { + tasklog('+', "Task configuration changed, reloading"); + load_taskcfg(); + } + if (file_time(cfgfn) != cfg_time) { + tasklog('+', "Main configuration changed, reloading"); + load_maincfg(); + } + } + + if (s_bbsopen && !UPSalarm && !LOADhi) { + + if (!Processing) { + tasklog('+', "Resuming normal operations"); + Processing = TRUE; + } + + /* + * Here we run all normal operations. + */ + if (s_mailout && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_mailout, NULL, (char *)"mailout", MBFIDO); + running = checktasks(0); + s_mailout = FALSE; + } + + if (s_mailin && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_mailin, NULL, (char *)"mailin", MBFIDO); + running = checktasks(0); + s_mailin = FALSE; + } + + if (s_newnews && (!runtasktype(MBFIDO))) { + launch(TCFG.cmd_newnews, NULL, (char *)"newnews", MBFIDO); + running = checktasks(0); + s_newnews = FALSE; + } + + /* + * Only run the nodelist compiler if nothing else + * is running. There's no hurry to compile the + * new lists. If more then one compiler is defined, + * start them in parallel. + */ + if (s_index && (!running)) { + if (strlen(TCFG.cmd_mbindex1)) + launch(TCFG.cmd_mbindex1, NULL, (char *)"compiler 1", MBINDEX); + if (strlen(TCFG.cmd_mbindex2)) + launch(TCFG.cmd_mbindex2, NULL, (char *)"compiler 2", MBINDEX); + if (strlen(TCFG.cmd_mbindex3)) + launch(TCFG.cmd_mbindex3, NULL, (char *)"compiler 3", MBINDEX); + running = checktasks(0); + s_index = FALSE; + } + + /* + * Linking messages is also only done when there is + * nothing else to do. + */ + if (s_msglink && (!running)) { + launch(TCFG.cmd_msglink, NULL, (char *)"msglink", MBFIDO); + running = checktasks(0); + s_msglink = FALSE; + } + + /* + * Creating filerequest indexes. + */ + if (s_reqindex && (!running)) { + launch(TCFG.cmd_reqindex, NULL, (char *)"reqindex", MBFILE); + running = checktasks(0); + s_reqindex = FALSE; + } + + if ((tm->tm_sec / SLOWRUN) != oldmin) { + + /* + * These tasks run once per 20 seconds. + */ + oldmin = tm->tm_sec / SLOWRUN; + + /* + * If the previous pingstat is still P_SENT, the we now consider it a timeout. + */ + if (pingstate == P_SENT) { + pingresult[pingnr] = FALSE; + icmp_errs++; + if (icmp_errs < ICMP_MAX_ERRS) + tasklog('p', "ping %s seq=%d timeout", pingaddress, p_sequence); + } + + /* + * Check internet connection with ICMP ping + */ + rc = 0; + if (pingnr == 1) { + pingnr = 2; + if (strlen(TCFG.isp_ping2)) { + sprintf(pingaddress, "%s", TCFG.isp_ping2); + } else { + pingstate = P_NONE; + } + } else { + pingnr = 1; + if (strlen(TCFG.isp_ping1)) { + sprintf(pingaddress, "%s", TCFG.isp_ping1); + } else { + pingstate = P_NONE; + } + } + + if (inet_aton(pingaddress, &paddr)) { + rc = ping_send(paddr); + if (internet) + tasklog('p', "ping send %s id=%d rc=%d", pingaddress, id, rc); + if (rc) { + if (icmp_errs++ < ICMP_MAX_ERRS) + tasklog('?', "ping send %s rc=%d", pingaddress, rc); + pingstate = P_FAIL; + pingresult[pingnr] = FALSE; + } else { + pingstate = P_SENT; + } + } else { + if (icmp_errs++ < ICMP_MAX_ERRS) + tasklog('?', "Ping address %d is invalid \"%s\"", pingnr, pingaddress); + pingstate = P_NONE; + } + + if (pingresult[1] == FALSE && pingresult[2] == FALSE) { + icmp_errs++; + if (internet) { + tasklog('!', "Internet connection is down"); + internet = FALSE; + } + } else { + if (!internet) { + tasklog('!', "Internet connection is up"); + internet = TRUE; + } + icmp_errs = 0; + } + + /* + * Run the mailer if something to do. For now we run just + * one task and lock it with CALL_POTS. + * Later tasks for different calltypes should run parallel. + */ + if (s_scanout && !runtasktype(CALL_POTS)) { + cmd = xstrcpy(pw->pw_dir); + cmd = xstrcat(cmd, (char *)"/bin/mbcico"); + launch(cmd, (char *)"-r1", (char *)"mbcico", CALL_POTS); + running = checktasks(0); + free(cmd); + cmd = NULL; + } + } + + switch (pingstate) { + case P_NONE: pingresult[pingnr] = TRUE; + break; + case P_SENT: rc = ping_receive(paddr); + if (!rc) { + pingstate = P_OK; + pingresult[pingnr] = TRUE; + if (internet) + tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc); + } else { + if (rc != -6) + tasklog('p', "ping recv %s id=%d rc=%d", pingaddress, id, rc); + } + break; + } + + } else { + if (Processing) { + tasklog('+', "Suspending operations"); + Processing = FALSE; + } + } + } while (TRUE); +} + + + +int main(int argc, char **argv) +{ + struct passwd *pw; + int i; + pid_t frk; + FILE *fp; + +#ifdef MEMWATCH + mwInit(); +#endif + /* + * Print copyright notices and setup logging. + */ + printf("MBTASK: MBSE BBS v%s Task Manager Daemon\n", VERSION); + printf(" %s\n\n", Copyright); + + /* + * Catch all the signals we can, and ignore the rest. Note that SIGKILL can't be ignored + * but that's live. This daemon should only be stopped by SIGTERM. + */ + for(i = 0; i < NSIG; i++) { + if ((i == SIGHUP) || (i == SIGINT) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV) || (i == SIGTERM)) + signal(i, (void (*))die); + else + signal(i, SIG_IGN); + } + + /* + * Create the ping socket while we are still root. + */ + if ((ping_isocket = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) { + perror(""); + printf("socket init failed, is mbtask not installed setuid root?\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + /* + * mbtask is setuid root, drop privileges to user mbse. + * This will stay forever like this, no need to become + * root again. The child can't even become root anymore. + */ + pw = getpwnam((char *)"mbse"); + if (setuid(pw->pw_uid)) { + perror(""); + printf("can't setuid to mbse\n"); + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + if (setgid(pw->pw_gid)) { + perror(""); + printf("can't setgid to bbs\n"); + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + umask(007); + if (locktask(pw->pw_dir)) { + close(ping_isocket); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + + sprintf(cfgfn, "%s/etc/config.data", getenv("MBSE_ROOT")); + load_maincfg(); + + tasklog(' ', " "); + tasklog(' ', "MBTASK v%s", VERSION); + sprintf(tcfgfn, "%s/etc/task.data", getenv("MBSE_ROOT")); + load_taskcfg(); + status_init(); + + memset(&task, 0, sizeof(task)); + memset(®info, 0, sizeof(reginfo)); + sprintf(spath, "%s/tmp/mbtask", getenv("MBSE_ROOT")); + + /* + * Server initialization is complete. Now we can fork the + * daemon and return to the user. We need to do a setpgrp + * so that the daemon will no longer be assosiated with the + * users control terminal. This is done before the fork, so + * that the child will not be a process group leader. Otherwise, + * if the child were to open a terminal, it would become + * associated with that terminal as its control terminal. + */ + if ((pgrp = setpgrp()) == -1) { + tasklog('?', "$setpgrp failed"); + die(0); + } + + frk = fork(); + switch (frk) { + case -1: + tasklog('?', "$Unable to fork daemon"); + die(0); + case 0: + /* + * Starting the deamon child process here. + */ + fclose(stdin); + fclose(stdout); + fclose(stderr); + scheduler(); + /* Not reached */ + default: + /* + * Here we detach this process and let the child + * run the deamon process. Put the child's pid + * in the lockfile before leaving. + */ + if ((fp = fopen(lockfile, "w"))) { + fprintf(fp, "%10u\n", frk); + fclose(fp); + } + tasklog('+', "Starting daemon with pid %d", frk); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(0); + } + + /* + * Not reached + */ + return 0; +} + + + diff --git a/mbtask/mbtask.h b/mbtask/mbtask.h new file mode 100644 index 00000000..6584d67b --- /dev/null +++ b/mbtask/mbtask.h @@ -0,0 +1,52 @@ +#ifndef _MBTASK_H +#define _MBTASK_H + + +typedef enum {CALL_POTS, CALL_ISDN, CALL_IP, MBFIDO, MBINDEX, MBFILE} TASKTYPE; + + +/* + * Running tasks information + */ +typedef struct _onetask { + char name[16]; /* Name of the task */ + char cmd[PATH_MAX]; /* Command to binary */ + char opts[128]; /* Commandline opts */ + int tasktype; /* Type of task */ + pid_t pid; /* Pid of task */ + int running; /* Running or not */ + int status; /* Waitpid status */ + int rc; /* Exit code */ +} onetask; + + + +/* + * Logging flagbits, ' ' ? ! + - + */ +#define DLOG_ALLWAYS 0x00000001 +#define DLOG_ERROR 0x00000002 +#define DLOG_ATTENT 0x00000004 +#define DLOG_NORMAL 0x00000008 +#define DLOG_VERBOSE 0x00000010 + + + +time_t file_time(char *); +void load_maincfg(void); +void load_taskcfg(void); +pid_t launch(char *, char *, char *, int); +int runtasktype(int); +int checktasks(int); +void die(int); +static int icmp4_errcmp(char *, int, struct in_addr *, char *, int, int); +unsigned short get_rand16(void); +int ping_send(struct in_addr); +int ping_receive(struct in_addr); +void scheduler(void); +int locktask(char *); +void ulocktask(void); + + +#endif + diff --git a/mbtask/nodelist.c b/mbtask/nodelist.c new file mode 100644 index 00000000..1de7dcb6 --- /dev/null +++ b/mbtask/nodelist.c @@ -0,0 +1,572 @@ +/***************************************************************************** + * + * File ..................: nodelist.c + * Purpose ...............: Read nodelists information + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "nodelist.h" + + +#define NULLDOMAIN "nulldomain" + + +struct _pkey pkey[] = { + {(char *)"Down", NL_NODE, NL_DOWN}, + {(char *)"Hold", NL_NODE, NL_HOLD}, + {(char *)"Region", NL_REGION, NL_REGION}, + {(char *)"Host", NL_HOST, NL_HOST}, + {(char *)"Hub", NL_HUB, NL_HUB}, + {(char *)"Point", NL_POINT, NL_POINT}, + {(char *)"Pvt", NL_NODE, NL_NODE}, + {NULL, 0, 0} +}; + + + +struct _okey okey[] = { + {(char *)"CM", OL_CM}, + {(char *)"MO", OL_MO}, + {(char *)"LO", OL_LO}, + {(char *)"MN", OL_MN}, + {NULL, 0} +}; + +struct _fkey fkey[] = { + {(char *)"V22", NL_V22}, + {(char *)"V29", NL_V29}, + {(char *)"V32", NL_V32}, + {(char *)"V32B",NL_V32B | NL_V32}, + {(char *)"V34", NL_V34}, + {(char *)"V42", NL_V42 | NL_MNP}, + {(char *)"V42B",NL_V42B | NL_V42 | NL_MNP}, + {(char *)"MNP", NL_MNP}, + {(char *)"H96", NL_H96}, + {(char *)"HST", NL_HST | NL_MNP}, + {(char *)"H14", NL_H14 | NL_HST | NL_MNP}, + {(char *)"H16", NL_H16 | NL_H14 | NL_HST | NL_MNP | NL_V42 | NL_V42B}, + {(char *)"MAX", NL_MAX}, + {(char *)"PEP", NL_PEP}, + {(char *)"CSP", NL_CSP}, + {(char *)"V32T",NL_V32T | NL_V32B | NL_V32}, + {(char *)"VFC", NL_VFC}, + {(char *)"ZYX", NL_ZYX | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP}, + {(char *)"X2C", NL_X2C | NL_X2S | NL_V34}, + {(char *)"X2S", NL_X2S | NL_V34}, + {(char *)"V90C",NL_V90C | NL_V90S | NL_V34}, + {(char *)"V90S",NL_V90S | NL_V34}, + {(char *)"Z19", NL_Z19 | NL_V32B | NL_V32 | NL_V42B | NL_V42 | NL_MNP | NL_ZYX}, + {NULL, 0} +}; + +struct _xkey xkey [] = { + {(char *)"XA", RQ_XA}, + {(char *)"XB", RQ_XB}, + {(char *)"XC", RQ_XC}, + {(char *)"XP", RQ_XP}, + {(char *)"XR", RQ_XR}, + {(char *)"XW", RQ_XW}, + {(char *)"XX", RQ_XX}, + {NULL, 0} +}; + +struct _dkey dkey [] = { + {(char *)"V110L", ND_V110L}, + {(char *)"V110H", ND_V110H}, + {(char *)"V120L", ND_V120L}, + {(char *)"V120H", ND_V120H}, + {(char *)"X75", ND_X75}, + {NULL, 0} +}; + +struct _ikey ikey [] = { + {(char *)"IBN", IP_IBN}, + {(char *)"IFC", IP_IFC}, + {(char *)"ITN", IP_ITN}, + {(char *)"IVM", IP_IVM}, + {(char *)"IP", IP_IP}, + {(char *)"IFT", IP_IFT}, + {NULL, 0} +}; + +extern struct sysconfig CFG; + + +int initnl(void) +{ + int rc = 0; + FILE *dbf, *fp; + char *filexnm, *path; + struct _nlfil fdx; + + filexnm = xstrcpy(CFG.nodelists); + filexnm = xstrcat(filexnm,(char *)"/node.files"); + + if ((dbf = fopen(filexnm, "r")) == NULL) { + tasklog('?', "$Can't open %s", filexnm); + rc = 101; + } else { + path = calloc(PATH_MAX, sizeof(char)); + + while (fread(&fdx, sizeof(fdx), 1, dbf) == 1) { + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + rc = 101; + } else { + fclose(fp); + } + } + + fclose(dbf); + free(path); + } + + free(filexnm); + return rc; +} + + + +int comp_node(struct _nlidx, struct _ixentry); +int comp_node(struct _nlidx fap1, struct _ixentry fap2) +{ + if (fap1.zone != fap2.zone) + return (fap1.zone - fap2.zone); + else if (fap1.net != fap2.net) + return (fap1.net - fap2.net); + else if (fap1.node != fap2.node) + return (fap1.node - fap2.node); + else + return (fap1.point - fap2.point); +} + + + +node *getnlent(faddr *addr) +{ + FILE *fp; + static node nodebuf; + static char buf[256], *p, *q; + struct _ixentry xaddr; + int i, j, Found = FALSE; + int ixflag, stdflag; + char *mydomain, *path; + struct _nlfil fdx; + struct _nlidx ndx; + long lowest, highest, current; + + tasklog('s', "getnlent: %s", ascfnode(addr,0xff)); + + mydomain = xstrcpy(CFG.aka[0].domain); + if (mydomain == NULL) + mydomain = (char *)NULLDOMAIN; + + nodebuf.addr.domain = NULL; + nodebuf.addr.zone = 0; + nodebuf.addr.net = 0; + nodebuf.addr.node = 0; + nodebuf.addr.point = 0; + nodebuf.addr.name = NULL; + nodebuf.upnet = 0; + nodebuf.upnode = 0; + nodebuf.region = 0; + nodebuf.type = 0; + nodebuf.pflag = 0; + nodebuf.name = NULL; + nodebuf.location = NULL; + nodebuf.sysop = NULL; + nodebuf.phone = NULL; + nodebuf.speed = 0; + nodebuf.mflags = 0L; + nodebuf.oflags = 0L; + nodebuf.xflags = 0L; + nodebuf.iflags = 0L; + nodebuf.dflags = 0L; + nodebuf.uflags[0] = NULL; + + if (addr == NULL) + goto retdummy; + + if (addr->zone == 0) + addr->zone = CFG.aka[0].zone; + xaddr.zone = addr->zone; + nodebuf.addr.zone = addr->zone; + xaddr.net = addr->net; + nodebuf.addr.net = addr->net; + xaddr.node = addr->node; + nodebuf.addr.node = addr->node; + xaddr.point = addr->point; + nodebuf.addr.point = addr->point; + + if (initnl()) + goto retdummy; + + /* + * First, lookup node in index. NOTE -- NOT 5D YET + */ + path = calloc(128, sizeof(char)); + sprintf(path, "%s/%s", CFG.nodelists, "node.index"); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + + fseek(fp, 0, SEEK_END); + highest = ftell(fp) / sizeof(ndx); + lowest = 0; + + while (TRUE) { + current = ((highest - lowest) / 2) + lowest; + fseek(fp, current * sizeof(ndx), SEEK_SET); + if (fread(&ndx, sizeof(ndx), 1, fp) != 1) + break; + + if (comp_node(ndx, xaddr) == 0) { + Found = TRUE; + break; + } + if (comp_node(ndx, xaddr) < 0) + lowest = current; + else + highest = current; + if ((highest - lowest) <= 1) + break; + } + + fclose(fp); + + if (!Found) { + free(path); + goto retdummy; + } + + sprintf(path, "%s/%s", CFG.nodelists, "node.files"); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + + /* + * Get filename from node.files + */ + for (i = 0; i < (ndx.fileno +1); i++) + fread(&fdx, sizeof(fdx), 1, fp); + fclose(fp); + + /* CHECK DOMAIN HERE */ + + /* + * Open and read in real nodelist + */ + sprintf(path, "%s/%s", CFG.nodelists, fdx.filename); + if ((fp = fopen(path, "r")) == NULL) { + tasklog('?', "$Can't open %s", path); + free(path); + goto retdummy; + } + free(path); + + if (fseek(fp, ndx.offset, SEEK_SET) != 0) { + tasklog('?', "$Seek failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + + if (fgets(buf, sizeof(buf)-1, fp) == NULL) { + tasklog('?', "$fgets failed for nodelist entry"); + fclose(fp); + goto retdummy; + } + fclose(fp); + + nodebuf.type = ndx.type; + nodebuf.pflag = ndx.pflag; + + if (*(p = buf + strlen(buf) -1) == '\n') + *p = '\0'; + if (*(p = buf + strlen(buf) -1) == '\r') + *p = '\0'; + for (p = buf; *p; p++) + if (*p == '_') + *p = ' '; + + p = buf; + + if ((q = strchr(p,','))) + *q++ = '\0'; + + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.name = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.location = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.sysop = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + if (strcasecmp(p, "-Unpublished-") == 0) + nodebuf.phone = NULL; + else + nodebuf.phone = p; + p = q; + if (p == NULL) + goto badsyntax; + + if ((q=strchr(p,','))) + *q++ = '\0'; + nodebuf.speed = atoi(p); + + /* + * Process the nodelist flags. + */ + ixflag = 0; + stdflag = TRUE; + for (p = q; p; p = q) { + if ((q = strchr(p, ','))) + *q++ = '\0'; + if ((strncasecmp(p, "U", 1) == 0) && (strlen(p) == 1)) { + stdflag = FALSE; + } else { + /* + * Experimental: process authorized flags and + * User flags both as authorized. + */ + for (j = 0; fkey[j].key; j++) + if (strcasecmp(p, fkey[j].key) == 0) + nodebuf.mflags |= fkey[j].flag; + for (j = 0; okey[j].key; j++) + if (strcasecmp(p, okey[j].key) == 0) + nodebuf.oflags |= okey[j].flag; + for (j = 0; dkey[j].key; j++) + if (strcasecmp(p, dkey[j].key) == 0) + nodebuf.dflags |= dkey[j].flag; + for (j = 0; ikey[j].key; j++) + if (strncasecmp(p, ikey[j].key, strlen(ikey[j].key)) == 0) + nodebuf.iflags |= ikey[j].flag; + for (j = 0; xkey[j].key; j++) + if (strcasecmp(p, xkey[j].key) == 0) + nodebuf.xflags |= xkey[j].flag; + if (!stdflag) { + if (ixflag < MAXUFLAGS) { + nodebuf.uflags[ixflag++] = p; + if (ixflag < MAXUFLAGS) + nodebuf.uflags[ixflag] = NULL; + } + } + } + } + + nodebuf.addr.name = nodebuf.sysop; + nodebuf.addr.domain = xstrcpy(fdx.domain); + nodebuf.upnet = ndx.upnet; + nodebuf.upnode = ndx.upnode; + nodebuf.region = ndx.region; + if (addr->domain == NULL) + addr->domain = xstrcpy(nodebuf.addr.domain); + + moflags(nodebuf.mflags); + diflags(nodebuf.dflags); + ipflags(nodebuf.iflags); + olflags(nodebuf.oflags); + free(mydomain); + + return &nodebuf; + +badsyntax: + tasklog('?', "nodelist %d offset +%lu: bad syntax in line \"%s\"", + ndx.fileno, (unsigned long)ndx.offset, buf); + /* fallthrough */ + +retdummy: + memset(&nodebuf, 0, sizeof(nodebuf)); + nodebuf.pflag = NL_DUMMY; + nodebuf.name = (char *)"Unknown"; + nodebuf.location = (char *)"Nowhere"; + nodebuf.sysop = (char *)"Sysop"; + nodebuf.phone = NULL; + nodebuf.speed = 2400; + free(mydomain); + + return &nodebuf; +} + + + +void olflags(unsigned long flags) +{ + char *t; + + t = xstrcpy((char *)"Mailer flags :"); + if (flags & OL_CM) + t = xstrcat(t, (char *)" CM"); + if (flags & OL_MO) + t = xstrcat(t, (char *)" MO"); + if (flags & OL_LO) + t = xstrcat(t, (char *)" LO"); + if (flags & OL_MN) + t = xstrcat(t, (char *)" MN"); + tasklog('s', "%s", t); + free(t); +} + + + +void moflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + t = xstrcpy((char *)"Modem flags :"); + if (flags & NL_V22) + t = xstrcat(t, (char *)" V22"); + if (flags & NL_V29) + t = xstrcat(t, (char *)" V29"); + if (flags & NL_V32) + t = xstrcat(t, (char *)" V32"); + if (flags & NL_V32B) + t = xstrcat(t, (char *)" V32B"); + if (flags & NL_V34) + t = xstrcat(t, (char *)" V34"); + if (flags & NL_V42) + t = xstrcat(t, (char *)" V42"); + if (flags & NL_V42B) + t = xstrcat(t, (char *)" V42B"); + if (flags & NL_MNP) + t = xstrcat(t, (char *)" MNP"); + if (flags & NL_H96) + t = xstrcat(t, (char *)" H96"); + if (flags & NL_HST) + t = xstrcat(t, (char *)" HST"); + if (flags & NL_H14) + t = xstrcat(t, (char *)" H14"); + if (flags & NL_H16) + t = xstrcat(t, (char *)" H16"); + if (flags & NL_MAX) + t = xstrcat(t, (char *)" MAX"); + if (flags & NL_PEP) + t = xstrcat(t, (char *)" PEP"); + if (flags & NL_CSP) + t = xstrcat(t, (char *)" CSP"); + if (flags & NL_V32T) + t = xstrcat(t, (char *)" V32T"); + if (flags & NL_VFC) + t = xstrcat(t, (char *)" VFC"); + if (flags & NL_ZYX) + t = xstrcat(t, (char *)" ZYX"); + if (flags & NL_X2C) + t = xstrcat(t, (char *)" X2C"); + if (flags & NL_X2S) + t = xstrcat(t, (char *)" X2S"); + if (flags & NL_V90C) + t = xstrcat(t, (char *)" V90C"); + if (flags & NL_V90S) + t = xstrcat(t, (char *)" V90S"); + tasklog('s', "%s", t); + free(t); +} + + + +void diflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"ISDN flags :"); + if (flags & ND_V110L) + t = xstrcat(t, (char *)" V110L"); + if (flags & ND_V110H) + t = xstrcat(t, (char *)" V110H"); + if (flags & ND_V120L) + t = xstrcat(t, (char *)" V120L"); + if (flags & ND_V120H) + t = xstrcat(t, (char *)" V120H"); + if (flags & ND_X75) + t = xstrcat(t, (char *)" X75"); + tasklog('s', "%s", t); + free(t); +} + + + +void ipflags(unsigned long flags) +{ + char *t; + + if (!flags) + return; + + t = xstrcpy((char *)"TCP/IP flags :"); + if (flags & IP_IBN) + t = xstrcat(t, (char *)" IBN"); + if (flags & IP_IFC) + t = xstrcat(t, (char *)" IFC"); + if (flags & IP_ITN) + t = xstrcat(t, (char *)" ITN"); + if (flags & IP_IVM) + t = xstrcat(t, (char *)" IVM"); + if (flags & IP_IP) + t = xstrcat(t, (char *)" IP"); + tasklog('s', "%s", t); + free(t); +} + + + diff --git a/mbtask/nodelist.h b/mbtask/nodelist.h new file mode 100644 index 00000000..6668c904 --- /dev/null +++ b/mbtask/nodelist.h @@ -0,0 +1,189 @@ +#ifndef _NODELIST_H +#define _NODELIST_H + +/* +#include "../config.h" + +#pragma pack(1) +*/ + +#define MAXNAME 35 +#define MAXUFLAGS 16 + + +/* + * Analogue Modem flag values, order is important, first the + * compresion capabilities, then the linespeeds. This is late + * tested by portsel to find the fastest common connection + * speed for a given line if you have multiple dialout modems. + */ +#define NL_MNP 0x00000001L +#define NL_V42 0x00000002L +#define NL_V42B 0x00000004L +#define NL_V22 0x00000008L +#define NL_V29 0x00000010L +#define NL_V32 0x00000020L +#define NL_H96 0x00000040L +#define NL_HST 0x00000080L +#define NL_MAX 0x00000100L +#define NL_PEP 0x00000200L +#define NL_CSP 0x00000400L +#define NL_V32B 0x00000800L +#define NL_H14 0x00001000L +#define NL_V32T 0x00002000L +#define NL_H16 0x00004000L +#define NL_ZYX 0x00008000L +#define NL_Z19 0x00010000L +#define NL_VFC 0x00020000L +#define NL_V34 0x00040000L +#define NL_X2C 0x00080000L +#define NL_X2S 0x00100000L +#define NL_V90C 0x00200000L +#define NL_V90S 0x00400000L + + + +/* + * ISDN Flags + */ +#define ND_V110L 0x00000001L +#define ND_V110H 0x00000002L +#define ND_V120L 0x00000004L +#define ND_V120H 0x00000008L +#define ND_X75 0x00000010L + + + +/* + * TCP/IP flags + */ +#define IP_IBN 0x00000001L +#define IP_IFC 0x00000002L +#define IP_ITN 0x00000004L +#define IP_IVM 0x00000008L +#define IP_IP 0x00000010L +#define IP_IFT 0x00000020L + + + +/* + * Online special flags + */ +#define OL_CM 0x00000001L +#define OL_MO 0x00000002L +#define OL_LO 0x00000004L +#define OL_MN 0x00000008L + + + +/* + * Request flags + */ +#define RQ_RQMODE 0x0000000fL +#define RQ_RQ_BR 0x00000001L +#define RQ_RQ_BU 0x00000002L +#define RQ_RQ_WR 0x00000004L +#define RQ_RQ_WU 0x00000008L +#define RQ_XA (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XB (RQ_RQ_BR | RQ_RQ_BU | RQ_RQ_WR ) +#define RQ_XC (RQ_RQ_BR | RQ_RQ_WR | RQ_RQ_WU) +#define RQ_XP (RQ_RQ_BR | RQ_RQ_BU ) +#define RQ_XR (RQ_RQ_BR | RQ_RQ_WR ) +#define RQ_XW ( RQ_RQ_WR ) +#define RQ_XX ( RQ_RQ_WR | RQ_RQ_WU) + + + +/* + * Nodelist entry + */ +typedef struct _node { + faddr addr; /* Node address */ + unsigned short upnet; /* Uplink netnumber */ + unsigned short upnode; /* Uplink nodenumber */ + unsigned short region; /* Region belongin to */ + unsigned char type; + unsigned char pflag; + char *name; /* System name */ + char *location; /* System location */ + char *sysop; /* Sysop name */ + char *phone; /* Phone number */ + unsigned speed; /* Baudrate */ + unsigned long mflags; /* Modem flags */ + unsigned long dflags; /* ISDN flags */ + unsigned long iflags; /* TCP-IP flags */ + unsigned long oflags; /* Online flags */ + unsigned long xflags; /* Request flags */ + char *uflags[MAXUFLAGS]; /* User flags */ +} node; + + + +extern struct _fkey { + char *key; + unsigned long flag; +} fkey[]; + + + +extern struct _dkey { + char *key; + unsigned long flag; +} dkey[]; + + + +extern struct _ikey { + char *key; + unsigned long flag; +} ikey[]; + + + +extern struct _okey { + char *key; + unsigned long flag; +} okey[]; + + + +extern struct _xkey { + char *key; + unsigned long flag; +} xkey[]; + + + +extern struct _nodelist { + char *domain; + FILE *fp; +} *nodevector; + + + +struct _ixentry { + unsigned short zone; + unsigned short net; + unsigned short node; + unsigned short point; +}; + + + +extern struct _pkey { + char *key; + unsigned char type; + unsigned char pflag; +} pkey[]; + + +int initnl(void); +node *getnlent(faddr *); +void olflags(unsigned long); +void moflags(unsigned long); +void diflags(unsigned long); +void ipflags(unsigned long); + + +#endif + diff --git a/mbtask/outstat.c b/mbtask/outstat.c new file mode 100644 index 00000000..efc8c583 --- /dev/null +++ b/mbtask/outstat.c @@ -0,0 +1,249 @@ +/***************************************************************************** + * + * File ..................: mbtask/outstat.c + * Purpose ...............: Scan mail outbound status + * Last modification date : 08-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "scanout.h" +#include "nodelist.h" +#include "callstat.h" +#include "outstat.h" + + +extern int do_quiet; +extern struct sysconfig CFG; + + + +static struct _alist +{ + struct _alist *next; /* Next entry */ + faddr addr; /* Node address */ + int flavors; /* ORed flavors of mail/files */ + time_t time; /* Date/time of mail/files */ + off_t size; /* Total size of mail/files */ + callstat cst; /* Last call status */ + unsigned long olflags; /* Nodelist online flags */ + unsigned long moflags; /* Nodelist modem flags */ + unsigned long diflags; /* Nodelist ISDN flags */ + unsigned long ipflags; /* Nodelist TCP/IP flags */ +} *alist = NULL; + + +#define F_NORMAL 1 +#define F_CRASH 2 +#define F_IMM 4 +#define F_HOLD 8 +#define F_FREQ 16 +#define F_POLL 32 + + + +int outstat() +{ + int rc, first = TRUE; + struct _alist *tmp, *old; + char flstr[6]; + char temp[81]; + + tasklog('+', "Scanning outbound"); + /* + * Clear current table + */ + for (tmp = alist; tmp; tmp = old) { + old = tmp->next; + free(tmp->addr.domain); + free(tmp); + } + alist = NULL; + + if ((rc = scanout(each))) { + tasklog('?', "Error scanning outbound, aborting"); + return rc; + } + + for (tmp = alist; tmp; tmp = tmp->next) { + if (first) { + tasklog('+', "Flavor Size Online Modem ISDN TCP/IP Calls Status Address"); + first = FALSE; + } + strcpy(flstr,"......"); + if ((tmp->flavors) & F_IMM ) flstr[0]='I'; + if ((tmp->flavors) & F_CRASH ) flstr[1]='C'; + if ((tmp->flavors) & F_NORMAL) flstr[2]='N'; + if ((tmp->flavors) & F_HOLD ) flstr[3]='H'; + if ((tmp->flavors) & F_FREQ ) flstr[4]='R'; + if ((tmp->flavors) & F_POLL ) flstr[5]='P'; + + sprintf(temp, "%s %8lu %08x %08x %08x %08x %5d %6d %s", flstr, (long)tmp->size, + (unsigned int)tmp->olflags, (unsigned int)tmp->moflags, + (unsigned int)tmp->diflags, (unsigned int)tmp->ipflags, + tmp->cst.tryno, tmp->cst.trystat, ascfnode(&(tmp->addr), 0x1f)); + tasklog('+', "%s", temp); + } + + return 0; +} + + + +int each(faddr *addr, char flavor, int isflo, char *fname) +{ + struct _alist **tmp; + struct stat st; + FILE *fp; + char buf[256], *p; + node *nlent; + callstat *cst; + + if ((isflo != OUT_PKT) && (isflo != OUT_FLO) && (isflo != OUT_REQ) && (isflo != OUT_POL)) + return 0; + + for (tmp = &alist; *tmp; tmp = &((*tmp)->next)) + if (((*tmp)->addr.zone == addr->zone) && ((*tmp)->addr.net == addr->net) && + ((*tmp)->addr.node == addr->node) && ((*tmp)->addr.point == addr->point) && + (((*tmp)->addr.domain == NULL) || (addr->domain == NULL) || + (strcasecmp((*tmp)->addr.domain,addr->domain) == 0))) + break; + if (*tmp == NULL) { + nlent = getnlent(addr); + *tmp = (struct _alist *)malloc(sizeof(struct _alist)); + (*tmp)->next = NULL; + (*tmp)->addr.name = NULL; + (*tmp)->addr.zone = addr->zone; + (*tmp)->addr.net = addr->net; + (*tmp)->addr.node = addr->node; + (*tmp)->addr.point = addr->point; + (*tmp)->addr.domain = xstrcpy(addr->domain); + if (nlent->addr.domain) + free(nlent->addr.domain); + (*tmp)->flavors = 0; + if (nlent->pflag != NL_DUMMY) { + (*tmp)->olflags = nlent->oflags; + (*tmp)->moflags = nlent->mflags; + (*tmp)->diflags = nlent->dflags; + (*tmp)->ipflags = nlent->iflags; + } else { + (*tmp)->olflags = 0L; + (*tmp)->moflags = 0L; + (*tmp)->diflags = 0L; + (*tmp)->ipflags = 0L; + } + time(&((*tmp)->time)); + (*tmp)->size = 0L; + } + + cst = getstatus(addr); + (*tmp)->cst.trytime = cst->trytime; + (*tmp)->cst.tryno = cst->tryno; + (*tmp)->cst.trystat = cst->trystat; + + if ((isflo == OUT_FLO) || (isflo == OUT_PKT)) + switch (flavor) { + case '?': break; + case 'i': (*tmp)->flavors |= F_IMM; break; + case 'o': (*tmp)->flavors |= F_NORMAL; break; + case 'c': (*tmp)->flavors |= F_CRASH; break; + case 'h': (*tmp)->flavors |= F_HOLD; break; + default: tasklog('?', "Unknown flavor: '%c'\n",flavor); break; + } + + if (stat(fname,&st) != 0) { + tasklog('?', "$Can't stat %s", fname); + st.st_size = 0L; + (void)time(&st.st_mtime); + } + + /* + * Find the oldest time + */ + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + + if (isflo == OUT_FLO) { + if ((fp = fopen(fname,"r"))) { + while (fgets(buf, sizeof(buf) - 1, fp)) { + if (*(p = buf + strlen(buf) - 1) == '\n') + *p-- = '\0'; + while (isspace(*p)) + *p-- = '\0'; + for (p = buf; *p; p++) + if (*p == '\\') + *p='/'; + for (p = buf; *p && isspace(*p); p++); + if (*p == '~') continue; + if ((*p == '#') || (*p == '-') || (*p == '^') || (*p == '@')) + p++; + if (stat(p, &st) != 0) { + if (strlen(CFG.dospath)) { + if (stat(Dos2Unix(p), &st) != 0) { + /* + * Fileattach dissapeared, maybe + * the node doesn't poll enough and + * is losing mail or files. + */ + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } else { + if (stat(p, &st) != 0) { + st.st_size = 0L; + (void)time(&st.st_mtime); + } + } + } + + if ((p = strrchr(fname,'/'))) + p++; + else + p = fname; + if ((strlen(p) == 12) && (strspn(p,"0123456789abcdefABCDEF") == 8) && (p[8] == '.')) { + if (st.st_mtime < (*tmp)->time) + (*tmp)->time = st.st_mtime; + } + (*tmp)->size += st.st_size; + } + fclose(fp); + } else + tasklog('?', "Can't open %s", fname); + + } else if (isflo == OUT_PKT) { + (*tmp)->size += st.st_size; + } else if (isflo == OUT_REQ) { + (*tmp)->flavors |= F_FREQ; + } else if (isflo == OUT_POL) { + (*tmp)->flavors |= F_POLL; + } + + return 0; +} + + diff --git a/mbtask/outstat.h b/mbtask/outstat.h new file mode 100644 index 00000000..e1aadd6b --- /dev/null +++ b/mbtask/outstat.h @@ -0,0 +1,10 @@ +#ifndef _OUTSTAT_H +#define _OUTSTAT_H + + +int each(faddr *, char, int, char *); +int outstat(void); + + +#endif + diff --git a/mbtask/scanout.c b/mbtask/scanout.c new file mode 100644 index 00000000..f745a26d --- /dev/null +++ b/mbtask/scanout.c @@ -0,0 +1,242 @@ +/***************************************************************************** + * + * File ..................: mbtask/scanout.c + * Purpose ...............: Outbound scanning + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskutil.h" +#include "scanout.h" + + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + + +static faddr addr = { + NULL, + 0,0,0,0, + NULL +}; + + +extern struct sysconfig CFG; +extern struct _fidonet fidonet; + + + +static int scan_dir(int (*)(faddr*,char,int,char*),char*,int); +static int scan_dir(int (*fn)(faddr *, char, int, char *), char *dname, int ispoint) +{ + char fname[PATH_MAX]; + char flavor = '?'; + DIR *dp = NULL; + struct dirent *de; + int rc = 0, isflo, fage; + time_t t_start; + + t_start = time(NULL); +// tasklog('o' ,"scan_dir \"%s\" (%s)",MBSE_SS(dname),ispoint?"point":"node"); + + if ((dp = opendir(dname)) == NULL) { + tasklog('-', "Creating directory %s", dname); + /* + * Create a fake filename, mkdirs() likes that. + */ + sprintf(fname, "%s/foo", dname); + (void)mkdirs(fname); + if ((dp = opendir(dname)) == NULL) { + tasklog('o' ,"\"%s\" cannot be opened, proceed",MBSE_SS(dname)); + return 0; + } + } + + while ((de=readdir(dp))) + if ((strlen(de->d_name) == 12) && (de->d_name[8] == '.') && + (strspn(de->d_name,"0123456789abcdefABCDEF") == 8)) { +// tasklog('o' ,"checking: \"%s\"",de->d_name); + addr.point= 0; + strncpy(fname,dname,PATH_MAX-2); + strcat(fname,"/"); + strncat(fname,de->d_name,PATH_MAX-strlen(fname)-2); + + if ((strcasecmp(de->d_name+9,"pnt") == 0) && !ispoint) { + sscanf(de->d_name,"%04x%04x",&addr.net,&addr.node); + if ((rc = scan_dir(fn, fname, 1))) + goto exout; + } else if ((strcasecmp(de->d_name+8,".out") == 0) || + (strcasecmp(de->d_name+8,".cut") == 0) || + (strcasecmp(de->d_name+8,".hut") == 0) || + (strcasecmp(de->d_name+8,".iut") == 0) || + (strcasecmp(de->d_name+8,".opk") == 0) || + (strcasecmp(de->d_name+8,".cpk") == 0) || + (strcasecmp(de->d_name+8,".hpk") == 0) || + (strcasecmp(de->d_name+8,".ipk") == 0) || + (strcasecmp(de->d_name+8,".flo") == 0) || + (strcasecmp(de->d_name+8,".clo") == 0) || + (strcasecmp(de->d_name+8,".hlo") == 0) || + (strcasecmp(de->d_name+8,".ilo") == 0) || + (strcasecmp(de->d_name+8,".req") == 0) || + (strcasecmp(de->d_name+8,".pol") == 0)) { + if (ispoint) + sscanf(de->d_name,"%08x", &addr.point); + else + sscanf(de->d_name,"%04x%04x", &addr.net,&addr.node); + flavor = tolower(de->d_name[9]); + if (flavor == 'f') + flavor='o'; + if (strcasecmp(de->d_name+10,"ut") == 0) + isflo=OUT_PKT; + else if (strcasecmp(de->d_name+10,"pk") == 0) + isflo=OUT_DIR; + else if (strcasecmp(de->d_name+10,"lo") == 0) + isflo=OUT_FLO; + else if (strcasecmp(de->d_name+9,"req") == 0) + isflo=OUT_REQ; + else if (strcasecmp(de->d_name+9,"pol") == 0) + isflo=OUT_POL; + else + isflo=-1; +// tasklog('o' ,"%s \"%s\"", (isflo == OUT_FLO) ? "flo file" : "packet", de->d_name); + if ((rc=fn(&addr,flavor,isflo,fname))) + goto exout; + } else if ((strncasecmp(de->d_name+9,"su",2) == 0) || + (strncasecmp(de->d_name+9,"mo",2) == 0) || + (strncasecmp(de->d_name+9,"tu",2) == 0) || + (strncasecmp(de->d_name+9,"we",2) == 0) || + (strncasecmp(de->d_name+9,"th",2) == 0) || + (strncasecmp(de->d_name+9,"fr",2) == 0) || + (strncasecmp(de->d_name+9,"sa",2) == 0)) { + isflo = OUT_ARC; + if ((rc = fn(&addr, flavor, isflo, fname))) + goto exout; + +// tasklog('o' ,"arcmail file \"%s\"",de->d_name); + sprintf(fname, "%s/%s", dname, de->d_name); + fage = (int)((t_start - file_time(fname)) / 86400); + + if (file_size(fname) == 0) { +// tasklog('o', "Age %d days", fage); + /* + * Remove truncated ARCmail that has a day extension + * other then the current day or if the file is older + * then 6 days. + */ + if ((strncasecmp(de->d_name+9, dayname(), 2)) || (fage > 6)) { + if (unlink(fname) == 0) + tasklog('-', "Removed truncated ARCmail file %s", fname); + } + } + + if (CFG.toss_days && (fage > CFG.toss_days)) { + /* + * Remove ARCmail that is on hold too long. + */ + if (unlink(fname) == 0) + tasklog('+', "Removed ARCmail %s, %d days", fname, fage); + } + } else { +// tasklog('o' ,"skipping \"%s\"",de->d_name); + } + } + +exout: + closedir(dp); + return rc; +} + + + +int scanout(int (*fn)(faddr *, char, int, char *)) +{ + int i, j, rc = 0; + unsigned short zone = 0; + char fext[5]; + char *p = NULL, *q = NULL; + DIR *dp; + + if ((dp = opendir(CFG.outbound)) == NULL) { + tasklog('?', "$Can't open outbound directory \"%s\" for reading", MBSE_SS(CFG.outbound)); + return 1; + } + closedir(dp); + + /* + * Build outbound directory names with zone numbers. + */ + for (i = 0; i < 40; i++) { + if ((CFG.aka[i].zone) && (CFG.aka[i].zone != zone)) { + zone = CFG.aka[i].zone; + if (SearchFidonet(zone)) { + for (j = 0; j < 6; j++) { + /* + * Create outbound directory name for + * the primary aka of that zone. + */ + p = xstrcpy(CFG.outbound); + if (zone != CFG.aka[0].zone) { + if ((q = strrchr(p, '/'))) + *q = '\0'; + p = xstrcat(p, (char *)"/"); + p = xstrcat(p, fidonet.domain); + } + + /* + * Not primary zones in the domain get + * a directory extension. + */ + if (fidonet.zone[j]) { + if (j) { + sprintf(fext, ".%03x", fidonet.zone[j]); + p = xstrcat(p, fext); + } +// tasklog('o', "Zone %d Dir %s", fidonet.zone[j], p); + addr.zone = fidonet.zone[j]; + addr.domain = fidonet.domain; + + if ((rc = scan_dir(fn, p, 0))) { + if (p) + free(p); + p = NULL; + return rc; + } + } + + if (p) + free(p); + p = NULL; + } + } + } + } + return rc; +} + + diff --git a/mbtask/scanout.h b/mbtask/scanout.h new file mode 100644 index 00000000..b5dcdfc2 --- /dev/null +++ b/mbtask/scanout.h @@ -0,0 +1,13 @@ +#ifndef SCANOUT_H +#define SCANOUT_H + +#define OUT_PKT 0 +#define OUT_DIR 1 +#define OUT_FLO 2 +#define OUT_ARC 3 +#define OUT_REQ 4 +#define OUT_POL 5 + +extern int scanout(int (*)(faddr*,char,int,char*)); + +#endif diff --git a/mbtask/signame.c b/mbtask/signame.c new file mode 100644 index 00000000..1ccff62f --- /dev/null +++ b/mbtask/signame.c @@ -0,0 +1,94 @@ +/***************************************************************************** + * + * File ..................: signame.c + * Purpose ...............: Signal names + * Last modification date : 24-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "signame.h" + + +/* + * Signal handler signal names. + */ + +#ifdef __i386__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __PPC__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGBUS", "SIGFPE", + "SIGKILL", "SIGUSR1", "SIGSEGV", "SIGUSR2", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGSTKFLT", + "SIGCHLD", "SIGCONT", "SIGSTOP", "SIGTSTP", + "SIGTTIN", "SIGTTOU", "SIGURG", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGIO", "SIGPWR", "SIGUNUSED"}; + +#endif + +#ifdef __sparc__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGIOT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGLOST", "SIGUSR1", "SIGUSR2"}; +#endif + +#ifdef __alpha__ + +char SigName[32][16] = { "NOSIGNAL", + "SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", + "SIGTRAP", "SIGABRT", "SIGEMT", "SIGFPE", + "SIGKILL", "SIGBUS", "SIGSEGV", "SIGSYS", + "SIGPIPE", "SIGALRM", "SIGTERM", "SIGURG", + "SIGSTOP", "SIGTSTP", "SIGCONT", "SIGCHLD", + "SIGTTIN", "SIGTTOU", "SIGIO", "SIGXCPU", + "SIGXFSZ", "SIGVTALRM", "SIGPROF", "SIGWINCH", + "SIGINFO", "SIGUSR1", "SIGUSR2"}; + + +#endif + diff --git a/mbtask/signame.h b/mbtask/signame.h new file mode 100644 index 00000000..cfeb4e4b --- /dev/null +++ b/mbtask/signame.h @@ -0,0 +1,9 @@ +#ifndef _SIGNAME_H +#define _SIGNAME_H + + +char SigName[32][16]; + + +#endif + diff --git a/mbtask/taskcomm.c b/mbtask/taskcomm.c new file mode 100644 index 00000000..04a1771c --- /dev/null +++ b/mbtask/taskcomm.c @@ -0,0 +1,466 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskcomm.c + * Purpose ...............: MBSE BBS Daemon + * Last modification date : 05-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + ***************************************************************************** + * + * This program uses the BSD IPC stream sockets mechanism. This is the + * server program. You need an entry in /etc/services for tcp service + * "mbse" on port 60180. Yes, this is 1 higher as for ifcico. You don't + * need an entry in inetd.conf, because this program is written as a + * daemon for fast access. + * + *****************************************************************************/ + +#include "libs.h" +#include "taskstat.h" +#include "taskregs.h" +#include "taskdisk.h" +#include "taskinfo.h" +#include "taskutil.h" +#include "taskcomm.h" + + +extern int oserr; /* Copy of Unix error */ +extern int sock; /* Server socket */ +extern struct sockaddr_un from; /* From socket address */ +extern int fromlen; /* From address length */ +extern int logtrans; /* Log transactions */ + + +/************************************************************************ + * + * Logging procedures. + */ + +int userlog(char *); +int userlog(char *param) +{ + char *prname, *prpid, *grade, *msg; + static char lfn[64], token[14]; + + lfn[0] = '\0'; + strcpy(token, strtok(param, ",")); + strcpy(token, strtok(NULL, ",")); + sprintf(lfn, "%s/log/%s", getenv("MBSE_ROOT"), token); + prname = strtok(NULL, ","); + prpid = strtok(NULL, ","); + grade = strtok(NULL, ","); + msg = strtok(NULL, "\0"); + msg[strlen(msg) -1] = '\0'; + return ulog(lfn, grade, prname, prpid, msg); +} + + + +/* + * Process command received from the client. + */ +char *exe_cmd(char *); +char *exe_cmd(char *in) +{ + static char obuf[SS_BUFSIZE]; + static char ibuf[SS_BUFSIZE]; + static char cmd[4]; + static char token[SS_BUFSIZE]; + static char ebuf[19]; + static char *cnt, var1[16]; + int result; + + strcpy(ibuf, in); + strncpy(cmd, ibuf, 4); + token[0] = '\0'; + strcpy(ebuf, "200:1,Syntax error;"); + + /* + * Split the commandline after the colon so we can give the + * options directly to the actual functions. Also set a default + * and most used answer. + */ + strcpy(token, &ibuf[5]); + strcpy(obuf, "100:0;"); + + + /* + * The A(counting) commands. + * + * AINI:5,pid,tty,user,program,city; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "AINI", 4) == 0) { + if (reg_newcon(token) != -1) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ACLO:1,pid; + * 107:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd ,"ACLO", 4) == 0) { + if (reg_closecon(token) == 0) { + strcpy(obuf, "107:0;"); + return obuf; + } else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADOI:2,pid,doing; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ADOI", 4) == 0) { + if (reg_doing(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ATTY:2,pid,tty; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ATTY", 4) == 0) { + if (reg_tty(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ALOG:5,file,program,pid,grade,text; + * 100:0; + * 201:1,errno; + */ + if (strncmp(cmd, "ALOG", 4) == 0) { + if (userlog(token) != 0) + sprintf(obuf, "201:1,%d;", oserr); + return obuf; + } + + /* + * AUSR:3,pid,user,city; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "AUSR", 4) == 0) { + if (reg_user(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADIS:2,pid,flag; (set Do Not Disturb). + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ADIS", 4) == 0) { + if (reg_silent(token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ATIM:2,pid,seconds; + * 100:0; + * 200:1,Syntax Error; + */ + if (strncmp(cmd, "ATIM", 4) == 0) { + if (reg_timer(TRUE, token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * ADEF:1,pid; + * 100:0; + */ + if (strncmp(cmd, "ADEF", 4) == 0) { + if (reg_timer(FALSE, token) == 0) + return obuf; + else { + stat_inc_serr(); + return ebuf; + } + } + + /* + * The chat commands + * + * CIPM:1,pid; (Is personal message present) + * 100:2,fromname,message; + * 100:0; + */ + if (strncmp(cmd, "CIPM", 4) == 0) { + return reg_ipm(token); + } + + /* + * CSPM:3,fromuser,touser,text; (Send personal message). + * 100:1,n; n: 0=oke, 1=donotdisturb 2=buffer full 3=error + * 100:0; + */ + if (strncmp(cmd, "CSPM", 4) == 0) { + if ((result = reg_spm(token))) { + sprintf(obuf, "100:1,%d;", result); + return obuf; + } else + return obuf; + } + + /* + * The G(lobal) commands. + * + * GNOP:1,pid; + * 100:0; + */ + if (strncmp(cmd ,"GNOP", 4) == 0) { + reg_nop(token); + return obuf; + } + + /* + * GPNG:n,data; + * 100:n,data; + */ + if (strncmp(cmd, "GPNG", 4) == 0) { + sprintf(obuf, "100:%s", token); + return obuf; + } + + /* + * GVER:0; + * 100:1,Version ...; + */ + if (strncmp(cmd, "GVER", 4) == 0) { + sprintf(obuf, "100:1,Version %s;", VERSION); + return obuf; + } + + /* + * GSTA:0; + * 100:19,start,laststart,daily,startups,clients,tot_clients,tot_peak,tot_syntax,tot_comerr, + * today_clients,today_peak,today_syntax,today_comerr,!BBSopen,ZMH,internet,Processing,Load,sequence; + * 201:1,16; + */ + if (strncmp(cmd, "GSTA", 4) == 0) { + return stat_status(); + } + + /* + * GMON:1,n; n=1 First time + * 100:7,pid,tty,user,program,city,isdoing,starttime; + * 100:0; + */ + if (strncmp(cmd, "GMON", 4) == 0) { + cnt = strtok(token, ","); + strcpy(var1, strtok(NULL, ";")); + return get_reginfo(atoi(var1)); + } + + /* + * GDST:0; + * 100:n,data1,..,data10; + */ + if (strncmp(cmd, "GDST", 4) == 0) { + return get_diskstat(); + } + + /* + * GSYS:0; + * 100:7,calls,pots_calls,isdn_calls,network_calls,local_calls,startdate,last_caller; + * 201:1,16; + */ + if (strncmp(cmd, "GSYS", 4) == 0) { + return get_sysinfo(); + } + + /* + * GLCC:0; + * 100:1,n; + */ + if (strncmp(cmd, "GLCC", 4) == 0) { + return get_lastcallercount(); + } + + /* + * GLCR:1,recno; + * 100:9,user,location,level,device,time,mins,calls,speed,actions; + * 201:1,16; + */ + if (strncmp(cmd, "GLCR", 4) == 0) { + cnt = strtok(token, ","); + strcpy(var1, strtok(NULL, ";")); + return get_lastcallerrec(atoi(var1)); + } + + + /* + * The (S)tatus commands. + * + * SBBS:0; + * 100:2,n,status message; + */ + if (strncmp(cmd, "SBBS", 4) == 0) { + switch(stat_bbs_stat()) { + case 0: + sprintf(obuf, "100:2,0,The system is open for use;"); + break; + case 1: + sprintf(obuf, "100:2,1,The system is closed right now!;"); + break; + case 2: + sprintf(obuf, "100:2,2,The system is closed for Zone Mail Hour!;"); + break; + } + return obuf; + } + + /* + * SOPE:0; + * 100:0; + */ + if (strncmp(cmd, "SOPE", 4) == 0) { + stat_set_open(1); + return obuf; + } + + /* + * SCLO:1,message; + * 100:0; + */ + if (strncmp(cmd, "SCLO", 4) == 0) { + stat_set_open(0); + return obuf; + } + + /* + * SFRE:0; + * 100:1,Running utilities: n Active users: n; + * 100:0; + * 201:1,16; + */ + if (strncmp(cmd, "SFRE", 4) == 0) { + return reg_fre(); + } + + /* + * SSEQ:0; + * 100:1,number; + * 200:1,16; + */ + if (strncmp(cmd, "SSEQ", 4) == 0) { + return getseq(); + } + + /* + * SEST:1,semafore; Get status of semafore + * 100:1,n; 1 = set, 0 = not set + * 200:1,16; + */ + if (strncmp(cmd, "SEST", 4) == 0) { + return sem_status(token); + } + + /* + * SECR:1,semafore; Set semafore + * 100:0; + * 200:1,16; + */ + if (strncmp(cmd, "SECR", 4) == 0) { + return sem_create(token); + } + + /* + * SERM:1,semafore; Remove semafore + * 100:0; + * 200:1,16; + */ + if (strncmp(cmd, "SERM", 4) == 0) { + return sem_remove(token); + } + + + /* + * If we got this far, there must be an error. + */ + stat_inc_serr(); + return ebuf; +} + + + +void do_cmd(char *cmd) +{ + char buf[SS_BUFSIZE]; + int slen, tries = 0; + + sprintf(buf, "%s", exe_cmd(cmd)); + if (logtrans) { + tasklog('-', "< %s", cmd); + tasklog('-', "> %s", buf); + } + + for (;;) { + slen = sendto(sock, buf, strlen(buf), 0, &from, fromlen); + if (slen == -1) + tasklog('?', "$do_cmd(): sendto error %d %s", tries, from.sun_path); + else if (slen != strlen(buf)) + tasklog('?', "do_cmd(): send %d of %d bytes, try=%d", slen, strlen(buf), tries); + else + return; + tries++; + if (tries == 3) + return; + sleep(1); + } +} + + diff --git a/mbtask/taskcomm.h b/mbtask/taskcomm.h new file mode 100644 index 00000000..50c17b34 --- /dev/null +++ b/mbtask/taskcomm.h @@ -0,0 +1,7 @@ +#ifndef _TASKCOMM_H +#define _TASKCOMM_H + +void do_cmd(char *); + +#endif + diff --git a/mbtask/taskdisk.c b/mbtask/taskdisk.c new file mode 100644 index 00000000..a3019138 --- /dev/null +++ b/mbtask/taskdisk.c @@ -0,0 +1,93 @@ +/***************************************************************************** + * + * File ..................: mbtask/statdisk.c + * Purpose ...............: Give status of all filesystems + * Last modification date : 23-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 Internet: mbse@user.sourceforge.net + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "taskdisk.h" +#include "taskutil.h" + + + +/* + * This function returns the information of all mounted filesystems, + * but no more then 10 filesystems. + */ +char *get_diskstat() +{ + char *mtab, *dev, *fs, *type, *tmp = NULL; + FILE *fp; + int i = 0; + static char buf[SS_BUFSIZE]; + struct statfs sfs; + char tt[80]; + unsigned long temp; + + buf[0] = '\0'; + mtab = calloc(256, sizeof(char)); + if ((fp = fopen((char *)"/etc/mtab", "r")) == 0) { + sprintf(buf, "100:0;"); + return buf; + } + + while (fgets(mtab, 255, fp)) { + dev = strtok(mtab, " "); + fs = strtok(NULL, " "); + type = strtok(NULL, " "); + if (strncmp((char *)"/dev/", dev, 5) == 0) { + if (statfs(fs, &sfs) == 0) { + i++; + if (tmp == NULL) + tmp = xstrcpy((char *)","); + else + tmp = xstrcat(tmp, (char *)","); + tt[0] = '\0'; + temp = (unsigned long)(sfs.f_bsize / 512L); + sprintf(tt, "%lu %lu %s %s", + (unsigned long)(sfs.f_blocks * temp) / 2048L, + (unsigned long)(sfs.f_bavail * temp) / 2048L, + fs, type); + tmp = xstrcat(tmp, tt); + } + if (i == 10) /* No more then 10 filesystems */ + break; + } + } + fclose(fp); + + if (strlen(tmp) > (SS_BUFSIZE - 8)) + sprintf(buf, "100:0;"); + else + sprintf(buf, "100:%d%s;", i, tmp); + + return buf; +} + + + diff --git a/mbtask/taskdisk.h b/mbtask/taskdisk.h new file mode 100644 index 00000000..64617450 --- /dev/null +++ b/mbtask/taskdisk.h @@ -0,0 +1,8 @@ +#ifndef _TASKDISK_H +#define _TASKDISK_H + +char *get_diskstat(void); /* Get disk status */ + + +#endif + diff --git a/mbtask/taskinfo.c b/mbtask/taskinfo.c new file mode 100644 index 00000000..10c9d454 --- /dev/null +++ b/mbtask/taskinfo.c @@ -0,0 +1,138 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskinfo.c + * Purpose ...............: Give system information + * Last modification date : 24-May-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskinfo.h" + + + +/* + * Get BBS System info. + */ +char *get_sysinfo(void) +{ + FILE *fp; + static char buf[SS_BUFSIZE]; + char *temp; + struct sysrec SYSINFO; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/sysinfo.data", getenv("MBSE_ROOT")); + + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + free(temp); + + if (fread(&SYSINFO, sizeof(SYSINFO), 1, fp) == 1) + sprintf(buf, "100:7,%ld,%ld,%ld,%ld,%ld,%s,%s;", SYSINFO.SystemCalls, + SYSINFO.Pots, SYSINFO.ISDN, SYSINFO.Network, SYSINFO.Local, + ctime(&SYSINFO.StartDate), SYSINFO.LastCaller); + fclose(fp); + + return buf; +} + + + +char *get_lastcallercount(void) +{ + static char buf[SS_BUFSIZE]; + char *temp; + FILE *fp; + struct lastcallershdr LCALLhdr; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + fread(&LCALLhdr, sizeof(LCALLhdr), 1, fp); + fseek(fp, 0, SEEK_END); + sprintf(buf, "100:1,%ld;", ((ftell(fp) - LCALLhdr.hdrsize) / LCALLhdr.recsize)); + fclose(fp); + return buf; +} + + + +char *get_lastcallerrec(int Rec) +{ + static char buf[SS_BUFSIZE]; + char *temp, action[8]; + FILE *fp; + struct lastcallershdr LCALLhdr; + struct lastcallers LCALL; + + sprintf(buf, "201:1,16;"); + temp = calloc(128, sizeof(char)); + sprintf(temp, "%s/etc/lastcall.data", getenv("MBSE_ROOT")); + if ((fp = fopen(temp, "r")) == NULL) { + free(temp); + return buf; + } + fread(&LCALLhdr, sizeof(LCALLhdr), 1, fp); + fseek(fp, ((Rec -1) * LCALLhdr.recsize) + LCALLhdr.hdrsize, SEEK_SET); + + if (fread(&LCALL, LCALLhdr.recsize, 1, fp) == 1) { + LCALL.UserName[15] = '\0'; + LCALL.Location[12] = '\0'; + strcpy(action, "-------"); + if (LCALL.Hidden) + action[0] = 'H'; + if (LCALL.Download) + action[1] = 'D'; + if (LCALL.Upload) + action[2] = 'U'; + if (LCALL.Read) + action[3] = 'R'; + if (LCALL.Wrote) + action[4] = 'W'; + if (LCALL.Chat) + action[5] = 'C'; + if (LCALL.Olr) + action[6] = 'O'; + action[7] = '\0'; + sprintf(buf, "100:9,%s,%s,%d,%s,%s,%d,%d,%s,%s;", LCALL.UserName, LCALL.Location, + LCALL.SecLevel, LCALL.Device, LCALL.TimeOn, + LCALL.CallTime, LCALL.Calls, LCALL.Speed, action); + } + + fclose(fp); + return buf; +} + + diff --git a/mbtask/taskinfo.h b/mbtask/taskinfo.h new file mode 100644 index 00000000..a366cf06 --- /dev/null +++ b/mbtask/taskinfo.h @@ -0,0 +1,10 @@ +#ifndef _TASKINFO_H +#define _TASKINFO_H + +char *get_sysinfo(void); /* Get System Info */ +char *get_lastcallercount(void); /* Get Lastcallers count */ +char *get_lastcallerrec(int); /* Get Lastcaller record */ + + +#endif + diff --git a/mbtask/taskregs.c b/mbtask/taskregs.c new file mode 100644 index 00000000..804d4bf3 --- /dev/null +++ b/mbtask/taskregs.c @@ -0,0 +1,478 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskregs.c + * Purpose ...............: Buffers for registration information. + * Last modification date : 07-Jun-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "taskstat.h" +#include "taskregs.h" +#include "taskutil.h" + +extern reg_info reginfo[MAXCLIENT]; /* Array with clients */ +static int entrypos = 0; /* Status pointer */ + + +/*********************************************************************** + * + * Search for a pid. + */ +int reg_find(char *); +int reg_find(char *pids) +{ + int i; + + for (i = 0; i < MAXCLIENT; i++) { + if ((int)reginfo[i].pid == atoi(pids)) + return i; + } + + tasklog('?', "Panic, pid %s not found", pids); + return -1; +} + + + +/*********************************************************************** + * + * Registrate a new connection and fill the data. + */ + +int reg_newcon(char *data) +{ + char *cnt, *pid, *tty, *uid, *prg, *city; + int retval; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + tty = strtok(NULL, ","); + uid = strtok(NULL, ","); + prg = strtok(NULL, ","); + city = strtok(NULL, ";"); + + /* + * Abort if no empty record is found + */ + if ((retval = reg_find((char *)"0")) == -1) { + tasklog('?', "Maximum clients (%d) reached", MAXCLIENT); + return -1; + } + + memset((char *)®info[retval], 0, sizeof(reg_info)); + reginfo[retval].pid = atoi(pid); + strncpy((char *)®info[retval].tty, tty, 6); + strncpy((char *)®info[retval].uname, uid, 35); + strncpy((char *)®info[retval].prg, prg, 14); + strncpy((char *)®info[retval].city, city, 35); + strcpy((char *)®info[retval].doing, "-"); + reginfo[retval].started = time(NULL); + reginfo[retval].lastcon = time(NULL); + reginfo[retval].altime = 600; + + /* + * Everyone says do not disturb, unless the flag + * is cleared by the owner of this process. + */ + reginfo[retval].silent = 1; + + tasklog('-', "Registered client pgm \"%s\", pid %s, slot %d", prg, pid, retval); + stat_inc_clients(); + return retval; +} + + + +int reg_closecon(char *data) +{ + char *cnt, *pid; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + if ((rec = reg_find(pid)) == -1) + return -1; + + tasklog('-', "Unregistered client pgm \"%s\", pid %s, slot %d", reginfo[rec].prg, pid, rec); + memset(®info[rec], 0, sizeof(reg_info)); + stat_dec_clients(); + return 0; +} + + + +/* + * Check all registred connections. + */ +void reg_check(void) +{ + int i; + time_t Now; + + Now = time(NULL); + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid) { + if (kill(reginfo[i].pid, 0) == -1) { + if (errno == ESRCH) { + tasklog('?', "Stale registration found for pid %d (%s)", reginfo[i].pid, reginfo[i].prg); + memset(®info[i], 0, sizeof(reg_info)); + stat_dec_clients(); + } + } else { + /* + * Check timeout + */ + if ((Now - reginfo[i].lastcon) >= reginfo[i].altime) { + if (reginfo[i].altime < 600) { + kill(reginfo[i].pid, SIGKILL); + tasklog('+', "Send SIGKILL to pid %d", reginfo[i].pid); + } else { + kill(reginfo[i].pid, SIGTERM); + tasklog('+', "Send SIGTERM to pid %d", reginfo[i].pid); + } + /* + * 10 seconds to the next kill + */ + reginfo[i].altime = 10; + reginfo[i].lastcon = time(NULL); + } + } + } + } +} + + + +/* + * Update doing information for this process. + */ +int reg_doing(char *data) +{ + char *cnt, *pid, *line; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + line = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy(reginfo[rec].doing, line, 35); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update timer using NOP + */ +int reg_nop(char *data) +{ + char *cnt, *pid; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Set new timer value + */ +int reg_timer(int Set, char *data) +{ + char *pid; + int cnt, rec, val; + + cnt = atoi(strtok(data, ",")); + if (Set) { + if (cnt != 2) + return -1; + pid = strtok(NULL, ","); + val = atoi(strtok(NULL, ";")); + if (val < 600) + val = 600; + } else { + if (cnt != 1) + return -1; + pid = strtok(NULL, ";"); + val = 600; + } + + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].altime = val; + reginfo[rec].lastcon = time(NULL); + tasklog('r', "Set timeout value for %d to %d", reginfo[rec].pid, val); + return 0; +} + + + +/* + * Update tty information for this process. + */ +int reg_tty(char *data) +{ + char *cnt, *pid, *tty; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + tty = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy((char *)®info[rec].tty, tty, 6); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update the "do not disturb" flag. + */ +int reg_silent(char *data) +{ + char *cnt, *pid, *line; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + line = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + reginfo[rec].silent = atoi(line); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Update username and city for this process. + */ +int reg_user(char *data) +{ + char *cnt, *pid, *user, *city; + int rec; + + cnt = strtok(data, ","); + pid = strtok(NULL, ","); + user = strtok(NULL, ","); + city = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return -1; + + strncpy((char *)®info[rec].uname, user, 35); + strncpy((char *)®info[rec].city, city, 35); + reginfo[rec].lastcon = time(NULL); + return 0; +} + + + +/* + * Check for personal message + */ +char *reg_ipm(char *data) +{ + char *cnt, *pid; + static char buf[128]; + int rec; + + buf[0] = '\0'; + + sprintf(buf, "100:0;"); + cnt = strtok(data, ","); + pid = strtok(NULL, ";"); + + if ((rec = reg_find(pid)) == -1) + return buf; + + reginfo[rec].lastcon = time(NULL); + if (!reginfo[rec].ismsg) + return buf; + + buf[0] = '\0'; + sprintf(buf, "100:2,%s,%s;", reginfo[rec].fname[reginfo[rec].ptr_out], reginfo[rec].msg[reginfo[rec].ptr_out]); + if (reginfo[rec].ptr_out < RB) + reginfo[rec].ptr_out++; + else + reginfo[rec].ptr_out = 0; + if (reginfo[rec].ptr_out == reginfo[rec].ptr_in) + reginfo[rec].ismsg = FALSE; + tasklog('+', "reg_ipm: in=%d out=%d ismsg=%d", reginfo[rec].ptr_in, reginfo[rec].ptr_out, reginfo[rec].ismsg); + + return buf; +} + + + +/* + * Send personal message + */ +int reg_spm(char *data) +{ + char *cnt, *from, *too, *txt; + int i; + + cnt = strtok(data, ","); + from = strtok(NULL, ","); + too = strtok(NULL, ","); + txt = strtok(NULL, ";"); + + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid && (strcasecmp(reginfo[i].uname, too) == 0)) { + /* + * If the in and out pointers are the same and the + * message present flag is still set, then this user + * can't get anymore new messages. + */ + if (reginfo[i].ismsg && (reginfo[i].ptr_in == reginfo[i].ptr_out)) { + return 2; + } + + /* + * If user has the "do not distrurb" flag set. + */ + if (reginfo[i].silent) { + return 1; + } + + /* + * If all is well, insert the new message. + */ + strncpy((char *)®info[i].fname[reginfo[i].ptr_in], from, 35); + strncpy((char *)®info[i].msg[reginfo[i].ptr_in], txt, 80); + if (reginfo[i].ptr_in < RB) + reginfo[i].ptr_in++; + else + reginfo[i].ptr_in = 0; + reginfo[i].ismsg = TRUE; + tasklog('+', "reg_spm: in=%d out=%d ismsg=%d", reginfo[i].ptr_in, reginfo[i].ptr_out, reginfo[i].ismsg); + return 0; + } + } + + /* + * User not found + */ + return 3; +} + + + +char *reg_fre(void) +{ + static char buf[80]; + int i, users = 0, utils = 0; + + buf[0] = '\0'; + + for (i = 1; i < MAXCLIENT; i++) { + if (reginfo[i].pid) { + if ((!strncmp(reginfo[i].prg, "mbsebbs", 7)) || + (!strncmp(reginfo[i].prg, "mbftpd", 6))) + users++; + + if ((!strncmp(reginfo[i].prg, "mbfido", 6)) || + (!strncmp(reginfo[i].prg, "mbmail", 6)) || + (!strncmp(reginfo[i].prg, "mball", 5)) || + (!strncmp(reginfo[i].prg, "mbaff", 5)) || + (!strncmp(reginfo[i].prg, "mbcico", 6)) || + (!strncmp(reginfo[i].prg, "mbfile", 6)) || + (!strncmp(reginfo[i].prg, "mbmsg", 5)) || + (!strncmp(reginfo[i].prg, "mbindex", 7)) || + (!strncmp(reginfo[i].prg, "mbdiff", 6)) || + (!strncmp(reginfo[i].prg, "mbuser", 6))) + utils++; + } + } + + if (users || utils) + sprintf(buf, "100:1,Running utilities: %02d Active users: %02d;", utils, users); + else + sprintf(buf, "100:0;"); + return buf; +} + + + +/* + * Get registration information. The first time the parameter + * must be 1, for the next searches 0. Returns 100:0; if there + * is an error or the end of file is reached. + */ +char *get_reginfo(int first) +{ + static char buf[256]; + + memset(&buf, 0, sizeof(buf)); + sprintf(buf, "100:0;"); + + /* + * Loop forever until an error occours, eof is reached or + * the data is valid. Only in the last case valid data is + * returned to the caller. + */ + for (;;) { + if (first == 1) + entrypos = 0; + else + entrypos++; + + if (entrypos == MAXCLIENT) + return buf; + + if ((int)reginfo[entrypos].pid != 0) { + sprintf(buf, "100:7,%d,%s,%s,%s,%s,%s,%d;", + reginfo[entrypos].pid, reginfo[entrypos].tty, + reginfo[entrypos].uname, reginfo[entrypos].prg, + reginfo[entrypos].city, reginfo[entrypos].doing, + (int)reginfo[entrypos].started); + return buf; + } + } + /* never reached */ +} + + diff --git a/mbtask/taskregs.h b/mbtask/taskregs.h new file mode 100644 index 00000000..b70c1f6d --- /dev/null +++ b/mbtask/taskregs.h @@ -0,0 +1,49 @@ +#ifndef _TASKREGS_H +#define _TASKREGS_H + +#define MAXCLIENT 100 + + +/* + * Connected clients information + */ +#define RB 5 + +typedef struct _reg_info { + pid_t pid; /* Pid or zero if free */ + char tty[7]; /* Connected tty */ + char uname[36]; /* User name */ + char prg[15]; /* Program name */ + char city[36]; /* Users city */ + char doing[36]; /* What is going on */ + time_t started; /* Startime connection */ + time_t lastcon; /* Last connection */ + int altime; /* Alarm time */ + unsigned silent : 1; /* Do not disturb */ + unsigned chatting : 1; /* User is chatting */ + unsigned ismsg : 1; /* Message waiting */ + int channel; /* Chat channel */ + int ptr_in; /* Input buffer pointer */ + int ptr_out; /* Output buffer ptr */ + char fname[RB][36]; /* Message from user */ + char msg[RB][81]; /* The message itself */ +} reg_info; + + +void reg_init(void); +int reg_newcon(char *); +int reg_closecon(char *); +void reg_check(void); +int reg_doing(char *); +int reg_nop(char *); +int reg_timer(int, char *); +int reg_tty(char *); +int reg_user(char *); +int reg_silent(char *); +char *reg_ipm(char *); +int reg_spm(char *); +char *reg_fre(void); +char *get_reginfo(int); + +#endif + diff --git a/mbtask/taskstat.c b/mbtask/taskstat.c new file mode 100644 index 00000000..e9df9e2d --- /dev/null +++ b/mbtask/taskstat.c @@ -0,0 +1,438 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskstat.c + * Purpose ...............: Keep track of server status + * Last modification date : 09-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MB BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MB BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "taskstat.h" +#include "outstat.h" +#include "taskutil.h" + + + +/* + * Semafores + */ +int s_scanout = FALSE; +int s_mailout = FALSE; +int s_mailin = FALSE; +int s_reqindex = FALSE; +int s_index = FALSE; +int s_msglink = FALSE; +int s_newnews = FALSE; +int s_bbsopen = FALSE; +extern int UPSalarm; + + + +extern struct taskrec TCFG; +extern int internet; +extern int ZMH; + + +typedef struct { + long tot_clt; /* Total client connects */ + long peak_clt; /* Peak simultaneous tot_cltes */ + long s_error; /* Syntax errors from clients */ + long c_error; /* Comms errors from clients */ +} cl_stat; + + +typedef struct { + time_t start; /* Start date/time */ + time_t laststart; /* Last start date/time */ + time_t daily; /* Last daily update */ + long startups; /* Total starts */ + long clients; /* Connected clients */ + cl_stat total; /* Total statistics */ + cl_stat today; /* Todays statistics */ + unsigned open : 1; /* Is BBS open */ + unsigned long sequence; /* Sequencer counter */ +} status_r; + + +static char stat_fn[PATH_MAX]; /* Statusfile name */ +static status_r status; /* Status data */ +extern float Load; /* System Load */ +extern int Processing; /* Is system running */ + + +/************************************************************************ + * + * Initialize the statusfile, create it if necesary. + */ +void status_init() +{ + size_t cnt; + int stat_fd; + + sprintf(stat_fn, "%s/var/status.mbsed", getenv("MBSE_ROOT")); + + /* + * First check if this is the very first time we start the show. + * If so, we generate an empty status file with only the start + * date in it. + */ + stat_fd = open(stat_fn, O_RDWR); + if (stat_fd == -1) { + memset((char *)&status, 0, sizeof(status_r)); + status.start = time(NULL); + status.daily = time(NULL); + status.sequence = (unsigned long)time(NULL); + stat_fd = open(stat_fn, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + cnt = write(stat_fd, &status, sizeof(status_r)); + tasklog('+', "New statusfile created"); + lseek(stat_fd, 0, SEEK_SET); + } + + cnt = read(stat_fd, &status, sizeof(status_r)); + if (cnt != sizeof(status_r)) { + printf("Error reading status file\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + status.startups++; + status.laststart = time(NULL); + status.clients = 1; /* We are a client ourself */ + s_bbsopen = status.open; + lseek(stat_fd, 0, SEEK_SET); + cnt = write(stat_fd, &status, sizeof(status_r)); + if (cnt != sizeof(status_r)) { + tasklog('?', "$Error rewrite status file\n"); +#ifdef MEMWATCH + mwTerm(); +#endif + exit(1); + } + close(stat_fd); +} + + + +/* + * Writeback the updated status record. + */ +void status_write(void); +void status_write(void) +{ + int d, stat_fd; + struct tm ttm, ytm; + time_t temp; + + temp = time(NULL); + ttm = *localtime(&temp); + ytm = *localtime(&status.daily); + + /* + * If we passed to the next day, zero the today counters + */ + if (ttm.tm_yday != ytm.tm_yday) { + tasklog('+', "Last days statistics:"); + tasklog('+', "Total clients : %lu", status.today.tot_clt); + tasklog('+', "Peak clients : %lu", status.today.peak_clt); + tasklog('+', "Syntax errors : %lu", status.today.s_error); + tasklog('+', "Comms errors : %lu", status.today.c_error); + + memset((char *)&status.today, 0, sizeof(cl_stat)); + status.daily = time(NULL); + tasklog('+', "Zeroed todays status counters"); + } + + stat_fd = open(stat_fn, O_RDWR); + d = lseek(stat_fd, 0, SEEK_SET); + d = write(stat_fd, &status, sizeof(status_r)); + if (d != sizeof(status_r)) + tasklog('?', "Error writing statusfile, only %d bytes", d); + + /* + * CLose the statusfile + */ + if (close(stat_fd) != 0) + tasklog('?', "$Error closing statusfile"); +} + + + +/************************************************************************* + * + * Various actions on the statusfile. + */ + + +/* + * Check for Zone Mail Hour, return TRUE if it is. + */ +int get_zmh() +{ + struct tm *l_date; + char sstime[6]; + time_t Now; + + Now = time(NULL); + l_date = gmtime(&Now); + sprintf(sstime, "%02d:%02d", l_date->tm_hour, l_date->tm_min); + + if ((strncmp(sstime, TCFG.zmh_start, 5) >= 0) && (strncmp(sstime, TCFG.zmh_end, 5) < 0)) { + if (!ZMH) { + CreateSema((char *)"zmh"); + sem_set((char *)"scanout", TRUE); + tasklog('!', "Start of Zone Mail Hour"); + ZMH = TRUE; + } + } else { + if (ZMH) { + RemoveSema((char *)"zmh"); + sem_set((char *)"scanout", TRUE); + tasklog('!', "End of Zone Mail Hour"); + ZMH = FALSE; + } + } + return ZMH; +} + + + +void stat_inc_clients() +{ + status.clients++; + status.total.tot_clt++; + status.today.tot_clt++; + if (status.clients >= status.total.peak_clt) + status.total.peak_clt = status.clients; + if (status.clients >= status.today.peak_clt) + status.today.peak_clt = status.clients; + + status_write(); +} + + + +void stat_dec_clients() +{ + status.clients--; + status_write(); +} + + + +void stat_set_open(int op) +{ + if (op) { + if (!s_bbsopen) { + tasklog('!', "The bbs is open"); + sem_set((char *)"scanout", TRUE); + } + } else { + if (s_bbsopen) { + tasklog('!', "The bbs is closed"); + } + } + s_bbsopen = status.open = op; + status_write(); +} + + + +void stat_inc_serr() +{ + status.total.s_error++; + status.today.s_error++; + status_write(); +} + + + +void stat_inc_cerr() +{ + status.total.c_error++; + status.today.c_error++; + status_write(); +} + + + +char *stat_status() +{ + static char buf[160]; + + buf[0] = '\0'; + sprintf(buf, "100:19,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%ld,%d,%d,%d,%d,%2.2f,%lu;", + status.start, status.laststart, status.daily, + status.startups, status.clients, + status.total.tot_clt, status.total.peak_clt, + status.total.s_error, status.total.c_error, + status.today.tot_clt, status.today.peak_clt, + status.today.s_error, status.today.c_error, + status.open, get_zmh(), internet, Processing, Load, status.sequence); + return buf; +} + + + +/* + * Return open status: + * 0 = open. + * 1 = closed. + * 2 = Zone Mail Hour. + */ +int stat_bbs_stat() +{ + if (!status.open) + return 1; + if (get_zmh()) + return 2; + return 0; +} + + + +/* + * Get next sequence number + */ +char *getseq(void) +{ + static char buf[80]; + + buf[0] = '\0'; + status.sequence++; + status_write(); + sprintf(buf, "100:1,%lu;", status.sequence); + return buf; +} + + + +int sem_set(char *sem, int value) +{ + int rc = TRUE; + + tasklog('s', "sem_set(%s, %s)", sem, value?"TRUE":"FALSE"); + + if (!strcmp(sem, "scanout")) { + if (value && !s_scanout) { + outstat(); + } + s_scanout = value; + } else if (!strcmp(sem, "mailout")) { + s_mailout = value; + } else if (!strcmp(sem, "mailin")) { + s_mailin = value; + } else if (!strcmp(sem, "mbindex")) { + s_index = value; + } else if (!strcmp(sem, "newnews")) { + s_newnews = value; + } else if (!strcmp(sem, "msglink")) { + s_msglink = value; + } else if (!strcmp(sem, "reqindex")) { + s_reqindex = value; + } else { + rc = FALSE; + } + return rc; +} + + + +char *sem_status(char *data) +{ + char *cnt, *sem; + static char buf[40]; + int value; + + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + + if (!strcmp(sem, "scanout")) { + value = s_scanout; + } else if (!strcmp(sem, "mailout")) { + value = s_mailout; + } else if (!strcmp(sem, "mailin")) { + value = s_mailin; + } else if (!strcmp(sem, "mbindex")) { + value = s_index; + } else if (!strcmp(sem, "newnews")) { + value = s_newnews; + } else if (!strcmp(sem, "msglink")) { + value = s_msglink; + } else if (!strcmp(sem, "reqindex")) { + value = s_reqindex; + } else if (!strcmp(sem, "upsalarm")) { + value = UPSalarm; + } else { + tasklog('s', "sem_status(%s) buf=%s", sem, buf); + return buf; + } + + sprintf(buf, "100:1,%s;", value ? "1":"0"); + tasklog('s', "sem_status(%s) = %d buf=%s", sem, value, buf); + return buf; +} + + + +char *sem_create(char *data) +{ + static char buf[40]; + char *cnt, *sem; + + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + + if (sem_set(sem, TRUE)) + sprintf(buf, "100:0;"); + + return buf; +} + + + +char *sem_remove(char *data) +{ + static char buf[40]; + char *cnt, *sem; + + cnt = strtok(data, ","); + sem = strtok(NULL, ";"); + buf[0] = '\0'; + sprintf(buf, "200:1,16;"); + + if (sem_set(sem, FALSE)) + sprintf(buf, "100:0;"); + + return buf; +} + + diff --git a/mbtask/taskstat.h b/mbtask/taskstat.h new file mode 100644 index 00000000..bc2e84e8 --- /dev/null +++ b/mbtask/taskstat.h @@ -0,0 +1,20 @@ +#ifndef _TASKSTAT_H +#define _TASKSTAT_H + +void status_init(void); /* Initialize status module */ +void stat_inc_clients(void); /* Increase connected clients */ +void stat_dec_clients(void); /* Decrease connected clients */ +void stat_set_open(int); /* Set BBS open status */ +void stat_inc_serr(void); /* Increase syntax error */ +void stat_inc_cerr(void); /* Increase comms error */ +char *stat_status(void); /* Return status record */ +int stat_bbs_stat(void); /* Get BBS open status */ +char *getseq(void); /* Get next sequence number */ +int get_zmh(void); /* Check Zone Mail Hour */ +int sem_set(char *, int); /* Set/Reset semafore */ +char *sem_status(char *); /* Get semafore status */ +char *sem_create(char *); /* Create semafore */ +char *sem_remove(char *); /* Remove semafore */ + +#endif + diff --git a/mbtask/taskutil.c b/mbtask/taskutil.c new file mode 100644 index 00000000..1b3d8725 --- /dev/null +++ b/mbtask/taskutil.c @@ -0,0 +1,439 @@ +/***************************************************************************** + * + * File ..................: mbtask/taskutil.c + * Purpose ...............: MBSE BBS Task Manager, utilities + * Last modification date : 06-Jul-2001 + * + ***************************************************************************** + * Copyright (C) 1997-2001 + * + * Michiel Broek FIDO: 2:280/2802 + * Beekmansbos 10 + * 1971 BV IJmuiden + * the Netherlands + * + * This file is part of MBSE BBS. + * + * This BBS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * MBSE BBS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MBSE BBS; see the file COPYING. If not, write to the Free + * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + *****************************************************************************/ + +#include "libs.h" +#include "../lib/structs.h" +#include "signame.h" +#include "scanout.h" +#include "taskutil.h" + + + +pid_t mypid; /* Original parent pid if child */ +int oserr; /* Last OS error number */ +extern struct sysconfig CFG; +extern struct _fidonethdr fidonethdr; +extern struct _fidonet fidonet; +extern struct taskrec TCFG; + + + +static char *mon[] = { + (char *)"Jan",(char *)"Feb",(char *)"Mar", + (char *)"Apr",(char *)"May",(char *)"Jun", + (char *)"Jul",(char *)"Aug",(char *)"Sep", + (char *)"Oct",(char *)"Nov",(char *)"Dec" +}; + + + +/************************************************************************ + * + * Loging procedures. + */ + + +char *date(void); +char *date(void) +{ + struct tm ptm; + time_t now; + static char buf[20]; + + now = time(NULL); + ptm = *localtime(&now); + sprintf(buf,"%02d-%s-%04d %02d:%02d:%02d", ptm.tm_mday, mon[ptm.tm_mon], ptm.tm_year+1900, + ptm.tm_hour, ptm.tm_min, ptm.tm_sec); + return(buf); +} + + + +/* + * general log for this server + */ +void tasklog(int grade, const char *format, ...) +{ + va_list va_ptr; + char outstr[1024]; + int oldmask; + FILE *logfile; + char *logname; + + if (grade == '+' || grade == '-' || grade == '!' || grade == '?' || grade == ' ' || TCFG.debug) { + va_start(va_ptr, format); + vsprintf(outstr, format, va_ptr); + va_end(va_ptr); + + logname = calloc(PATH_MAX, sizeof(char)); + oldmask=umask(066); + sprintf(logname, "%s/log/mbtask.log", getenv("MBSE_ROOT")); + logfile = fopen(logname, "a"); + umask(oldmask); + if (logfile == NULL) { + printf("Cannot open logfile \"%s\"\n", logname); + free(logname); + return; + } + + fprintf(logfile, "%c %s mbtask[%d] ", grade, date(), getpid()); + fprintf(logfile, *outstr == '$' ? outstr+1 : outstr); + if (*outstr == '$') + fprintf(logfile, ": %s\n", strerror(errno)); + else + fprintf(logfile, "\n"); + + fflush(logfile); + if (fclose(logfile) != 0) + printf("Cannot close logfile \"%s\"\n", logname); + + free(logname); + } + return; +} + + + +/* + * user log process + */ +int ulog(char *fn, char *grade, char *prname, char *prpid, char *format) +{ + int oldmask; + FILE *log; + + oldmask = umask(066); + log = fopen(fn, "a"); + umask(oldmask); + if (log == NULL) { + oserr = errno; + tasklog('!', "$Cannot open user logfile %s", fn); + return -1; + } + + fprintf(log, "%s %s %s[%s] ", grade, date(), prname, prpid); + fwrite(format, strlen(format), 1, log); + fprintf(log, "\n"); + + fflush(log); + if (fclose(log) != 0) { + oserr = errno; + tasklog('!', "$Cannot close user logfile %s", fn); + return -1; + } + return 0; +} + + + +char *xstrcpy(char *src) +{ + char *tmp; + + if (src == NULL) + return(NULL); + tmp = malloc(strlen(src)+1); + strcpy(tmp, src); + return tmp; +} + + + +char *xstrcat(char *src, char *add) +{ + char *tmp; + size_t size = 0; + + if ((add == NULL) || (strlen(add) == 0)) + return src; + if (src) + size = strlen(src); + size += strlen(add); + tmp = malloc(size + 1); + *tmp = '\0'; + if (src) { + strcpy(tmp, src); + free(src); + } + strcat(tmp, add); + return tmp; +} + + + +void CreateSema(char *sem) +{ + char temp[PATH_MAX]; + int fd; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if (access(temp, F_OK) == 0) + return; + if ((fd = open(temp, O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) >= 0) + close(fd); + else + tasklog('?', "Can't create semafore %s", temp); +} + + + +void TouchSema(char *sem) +{ + char temp[PATH_MAX]; + int fd; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if ((fd = open(temp, O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) >= 0) { + close(fd); + } else + tasklog('?', "Can't touch semafore %s", temp); +} + + + +void RemoveSema(char *sem) +{ + char temp[PATH_MAX]; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + if (access(temp, F_OK)) + return; + if (unlink(temp) == -1) + tasklog('?', "Can't remove semafore %s", temp); +} + + + +int IsSema(char *sem) +{ + char temp[PATH_MAX]; + + sprintf(temp, "%s/sema/%s", getenv("MBSE_ROOT"), sem); + return (access(temp, F_OK) == 0); +} + + + +/* + * Test if the given file exists. The second option is: + * R_OK - test for Read rights + * W_OK - test for Write rights + * X_OK - test for eXecute rights + * F_OK - test file presence only + */ +int file_exist(char *path, int mode) +{ + if (access(path, mode) != 0) + return errno; + + return 0; +} + + +/* + * Make directory tree, the name must end with a / + */ +int mkdirs(char *name) +{ + char buf[PATH_MAX], *p, *q; + int rc, last = 0, oldmask; + + memset(&buf, 0, sizeof(buf)); + strncpy(buf, name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + + p = buf+1; + + oldmask = umask(000); + while ((q = strchr(p, '/'))) { + *q = '\0'; + rc = mkdir(buf, 0775); + last = errno; + *q = '/'; + p = q+1; + } + + umask(oldmask); + + if ((last == 0) || (last == EEXIST)) { + return TRUE; + } else { + tasklog('?', "$mkdirs(%s)", name); + return FALSE; + } +} + + + +/* + * Return size of file, or -1 if file doesn't exist + */ +long file_size(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_size; +} + + + +/* + * Return time of file, or -1 if file doen't exist, which is + * the same as 1 second before 1 jan 1970. You may test the + * result on -1 since time_t is actualy a long integer. + */ +time_t file_time(char *path) +{ + static struct stat sb; + + if (stat(path, &sb) == -1) + return -1; + + return sb.st_mtime; +} + + +/* + * Return ASCII string for node, the bits in 'fl' set the + * output format. + */ +char *ascfnode(faddr *a, int fl) +{ + static char buf[128]; + + if (a == NULL) { + strcpy(buf, ""); + return buf; + } + + buf[0] = '\0'; + if ((fl & 0x40) && (a->name)) + sprintf(buf+strlen(buf),"%s of ",a->name); + if ((fl & 0x08) && (a->zone)) + sprintf(buf+strlen(buf),"%u:",a->zone); + if (fl & 0x04) + sprintf(buf+strlen(buf),"%u/",a->net); + if (fl & 0x02) + sprintf(buf+strlen(buf),"%u",a->node); + if ((fl & 0x01) && (a->point)) + sprintf(buf+strlen(buf),".%u",a->point); + if ((fl & 0x10) && (a->domain)) + sprintf(buf+strlen(buf),"@%s",a->domain); + return buf; +} + + + +char *Dos2Unix(char *dosname) +{ + char buf[PATH_MAX]; + static char buf2[PATH_MAX]; + char *p, *q; + + memset(&buf, 0, sizeof(buf)); + memset(&buf2, 0, sizeof(buf2)); + sprintf(buf, "%s", dosname); + p = buf; + + if (strlen(CFG.dospath)) { + if (strncasecmp(p, CFG.dospath, strlen(CFG.dospath)) == 0) { + strcpy((char *)buf2, CFG.uxpath); + for (p+=strlen(CFG.dospath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } else { + if (strncasecmp(p, CFG.uxpath, strlen(CFG.uxpath)) == 0) { + for (p+=strlen(CFG.uxpath), q = buf2 + strlen(buf2); *p; p++, q++) + *q = ((*p) == '\\')?'/':tolower(*p); + *q = '\0'; + p = buf2; + } + } + } + return buf2; +} + + + +static char *dow[] = {(char *)"su", (char *)"mo", (char *)"tu", (char *)"we", + (char *)"th", (char *)"fr", (char *)"sa"}; + +char *dayname(void) +{ + time_t tt; + struct tm *ptm; + static char buf[3]; + + (void)time(&tt); + ptm = localtime(&tt); + sprintf(buf, "%s", dow[ptm->tm_wday]); + + return buf; +} + + + +void InitFidonet(void) +{ + memset(&fidonet, 0, sizeof(fidonet)); +} + + + +int SearchFidonet(unsigned short zone) +{ + FILE *fil; + char fidonet_fil[PATH_MAX]; + int i; + + sprintf(fidonet_fil, "%s/etc/fidonet.data", getenv("MBSE_ROOT")); + if ((fil = fopen(fidonet_fil, "r")) == NULL) { + return FALSE; + } + fread(&fidonethdr, sizeof(fidonethdr), 1, fil); + + while (fread(&fidonet, fidonethdr.recsize, 1, fil) == 1) { + for (i = 0; i < 6; i++) { + if (zone == fidonet.zone[i]) { + fclose(fil); + return TRUE; + } + } + } + fclose(fil); + return FALSE; +} + + diff --git a/mbtask/taskutil.h b/mbtask/taskutil.h new file mode 100644 index 00000000..d79d2e5a --- /dev/null +++ b/mbtask/taskutil.h @@ -0,0 +1,42 @@ +#ifndef _TASKUTIL_H +#define _TASKUTIL_H + + +#define TRUE 1 +#define FALSE 0 +#define SS_BUFSIZE 1024 /* Socket buffersize */ +#define MBSE_SS(x) (x)?(x):"(null)" + + +typedef struct _srv_auth { + struct _srv_auth *next; + char *hostname; + char *authcode; +} srv_auth; + + + +/* + * Function prototypes + */ +void tasklog(int, const char *, ...); +int ulog(char *, char *, char *, char *, char*); +char *xstrcpy(char *); +char *xstrcat(char *, char *); +void CreateSema(char *); +void TouchSema(char *); +void RemoveSema(char *); +int IsSema(char *); +int file_exist(char *, int); +int mkdirs(char *); +long file_size(char *); +time_t file_time(char *); +char *ascfnode(faddr *, int); +char *Dos2Unix(char *); +char *dayname(void); +void InitFidonet(void); +int SearchFidonet(unsigned short); + + +#endif + diff --git a/missing b/missing new file mode 100755 index 00000000..7789652e --- /dev/null +++ b/missing @@ -0,0 +1,190 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' configure.in` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 00000000..6b3b5fc5 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id$ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/script/Makefile.am b/script/Makefile.am new file mode 100644 index 00000000..1be3c7f6 --- /dev/null +++ b/script/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = . + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + @if [ ! -x $(sysconfdir)/maint ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/midnight ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/weekly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/monthly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir)" ; \ + fi + @./installinit + +EXTRA_DIST = README maint midnight weekly monthly installinit rc rc.shutdown mbse.start mbse.stop + + diff --git a/script/Makefile.in b/script/Makefile.in new file mode 100644 index 00000000..1d668e34 --- /dev/null +++ b/script/Makefile.in @@ -0,0 +1,306 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +AWK = @AWK@ +CC = @CC@ +COMPRESS = @COMPRESS@ +GROUP = @GROUP@ +GZIP = @GZIP@ +LEX = @LEX@ +LOG_COMPRESS = @LOG_COMPRESS@ +LOG_COMPRESSEXT = @LOG_COMPRESSEXT@ +MAKEINFO = @MAKEINFO@ +OWNER = @OWNER@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +SUBDIRS = . + +EXTRA_DIST = README maint midnight weekly monthly installinit rc rc.shutdown mbse.start mbse.stop +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +DIST_COMMON = README Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +all: all-redirect +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps script/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. + +@SET_MAKE@ + +all-recursive install-data-recursive install-exec-recursive \ +installdirs-recursive install-recursive uninstall-recursive \ +check-recursive installcheck-recursive info-recursive dvi-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $(MAKEFLAGS); amf=$$2; \ + dot_seen=no; \ + rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \ + rev="$$subdir $$rev"; \ + test "$$subdir" = "." && dot_seen=yes; \ + done; \ + test "$$dot_seen" = "no" && rev=". $$rev"; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = script + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + for subdir in $(SUBDIRS); do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + chmod 777 $(distdir)/$$subdir; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir=../$(top_distdir) distdir=../$(distdir)/$$subdir distdir) \ + || exit 1; \ + fi; \ + done +info-am: +info: info-recursive +dvi-am: +dvi: dvi-recursive +check-am: all-am +check: check-recursive +installcheck-am: +installcheck: installcheck-recursive +install-exec-am: install-exec-local +install-exec: install-exec-recursive + +install-data-am: +install-data: install-data-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-recursive +uninstall-am: +uninstall: uninstall-recursive +all-am: Makefile +all-redirect: all-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: installdirs-recursive +installdirs-am: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-tags mostlyclean-generic + +mostlyclean: mostlyclean-recursive + +clean-am: clean-tags clean-generic mostlyclean-am + +clean: clean-recursive + +distclean-am: distclean-tags distclean-generic clean-am + +distclean: distclean-recursive + +maintainer-clean-am: maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-recursive + +.PHONY: install-data-recursive uninstall-data-recursive \ +install-exec-recursive uninstall-exec-recursive installdirs-recursive \ +uninstalldirs-recursive all-recursive check-recursive \ +installcheck-recursive info-recursive dvi-recursive \ +mostlyclean-recursive distclean-recursive clean-recursive \ +maintainer-clean-recursive tags tags-recursive mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck \ +install-exec-local install-exec-am install-exec install-data-am \ +install-data install-am install uninstall-am uninstall all-redirect \ +all-am all installdirs-am installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-exec-local: + @if [ "$(shell whoami)" != "root" ] ; then \ + echo; echo " Must be root to install!"; echo; exit 3; \ + fi + @if [ ! -x $(sysconfdir)/maint ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 maint $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/midnight ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 midnight $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/weekly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 weekly $(sysconfdir)" ; \ + fi + @if [ ! -x $(sysconfdir)/monthly ]; then \ + $(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir) ; \ + echo "$(INSTALL) -o @OWNER@ -g @GROUP@ -m 0711 monthly $(sysconfdir)" ; \ + fi + @./installinit + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/script/README b/script/README new file mode 100644 index 00000000..c34b6ca6 --- /dev/null +++ b/script/README @@ -0,0 +1,7 @@ + MBSE BBS Script files. + +If you want to make any changes to the scripts, do it here and not in the +~/etc and ~/bin directories. After making the changes do a 'make install' +as root and the scripts are in place with the right permissions and owners. + + Michiel diff --git a/script/installinit b/script/installinit new file mode 100755 index 00000000..f2e2cc6d --- /dev/null +++ b/script/installinit @@ -0,0 +1,556 @@ +#!/bin/sh +# +# Installation script to install bootscripts. +# +# (C) Michiel Broek, v0.21 27-May-2001 +# +PATH=/bin:/sbin:/usr/bin:/usr/sbin:$MBSE_ROOT/bin +DISTNAME= +DISTVERS= +DISTINIT= +SU="su" + +#------------------------------------------------------------------------ +# +# Logging procedure, needs two parameters. +# +log() { + /bin/echo `date +%d-%b-%y\ %X ` $1 $2 >> installinit.log +} + + + +# Check one subdirectory +# +checkdir() { + if [ ! -d $1 ]; then + mkdir $1 + log "+" "[$?] created directory $1" + fi +} + + + +# Check /etc/rc.d subdirs +# +checkrcdir() { + checkdir "/etc/rc.d/init.d" + checkdir "/etc/rc.d/rc0.d" + checkdir "/etc/rc.d/rc1.d" + checkdir "/etc/rc.d/rc2.d" + checkdir "/etc/rc.d/rc3.d" + checkdir "/etc/rc.d/rc4.d" + checkdir "/etc/rc.d/rc5.d" + checkdir "/etc/rc.d/rc6.d" +} + + +#------------------------------------------------------------------------ +# + +log "+" "installinit started" + +# Basic checks. +if [ `whoami` != "root" ]; then +cat << EOF +*** Run $0 as root only! *** + + Because some of the system files must be changed, you must be root + to use this script. + +*** SETUP aborted *** +EOF + log "!" "Aborted, not root" + exit 2 +fi + +if [ "$MBSE_ROOT" = "" ]; then + echo "*** The MBSE_ROOT doesn't exist ***" + log "!" "Aborted, MBSE_ROOT variable doesn't exist" + exit 2 +fi + + +# First do various tests to see which Linux distribution this is. +# +if [ -f /etc/slackware-version ]; then + # Slackware 7.0 and later + DISTNAME="Slackware" + DISTVERS=`cat /etc/slackware-version` +else + if [ -f /etc/debian_version ]; then + # Debian, at least since version 2.2 + DISTNAME="Debian" + DISTVERS=`cat /etc/debian_version` + else + if [ -f /etc/SuSE-release ]; then + DISTNAME="SuSE" + DISTVERS=`cat /etc/SuSE-release | grep VERSION | awk '{ print $3 }'` + else + if [ -f /etc/redhat-release ]; then + DISTNAME="RedHat" + DISTVERS=`cat /etc/redhat-release | awk '{ print $5 }'` + else + if [ -f /etc/mandrake-release ]; then + DISTNAME="Mandrake" + # Format: Linux Mandrake release 8.0 (Cooker) for i586 + DISTVERS=`cat /etc/mandrake-release | awk '{ print $4 }'` + else + if [ -f /etc/rc.d/rc.0 ] && [ -f /etc/rc.d/rc.local ]; then + # If Slackware wasn't detected yet it is version 4.0 or older. + DISTNAME="Slackware" + DISTVERS="Old" + else + DISTNAME="Unknown" + log "!" "unknown distribution, collecting data" + log "-" "`uname -a`" + log "-" "`ls -la /etc`" + echo "Failed to install bootscripts, unknown Linux distribution." + echo "Please mail the file `pwd`/script/installinit.log to mbroek@users.sourceforge.net" + echo "or send it as file attach to Michiel Broek at 2:280/2802@Fidonet." + echo "Add information about the distribution you use in the message." + exit 1; + fi + fi + fi + fi + fi +fi + + +log "+" "Distribution $DISTNAME $DISTVERS" + + +#-------------------------------------------------------------------------- +# +# Adding scripts for SuSE +# +if [ "$DISTNAME" = "SuSE" ]; then + DISTINIT="/sbin/init.d/mbsed" + echo "Installing SystemV init scripts for SuSE" + log "+" "Installing SystemV init scripts for SuSE" + echo "Adding $DISTINIT" + +cat << EOF >$DISTINIT +#!/bin/bash +# Copyright (c) 2001 Michiel Broek +# +# Author: Michiel Broek , 23-May-2001 +# +# $DISTINIT for SuSE +# + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +case "\$1" in + start|reload) + echo -n "MBSE BBS starting:" + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n " mbtask" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo " and opened the bbs." + else + echo "" + fi + ;; + stop) + echo -n "MBSE BBS shutdown:" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n " logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done," + fi + echo -n " stopping mbtask " + killproc \$MBSE_ROOT/bin/mbtask -15 + echo "done." + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + status) + echo -n "MBSE BBS status: " + if [ "\`/sbin/pidof mbtask\`" = "" ]; then + echo "mbtask is NOT running" + else + echo "mbtask Ok" + fi + ;; + *) + echo "Usage: \$0 {start|stop|status|reload|restart}" + exit 1 +esac +exit 0 +EOF + + chmod 755 /etc/rc.d/init.d/mbsed + echo "Making links for start/stop in runlevel 2" + ln -s ../mbsed /sbin/init.d/rc2.d/K05mbsed + ln -s ../mbsed /sbin/init.d/rc2.d/S99mbsed + echo "Making links for start/stop in runlevel 3" + ln -s ../mbsed /sbin/init.d/rc3.d/K05mbsed + ln -s ../mbsed /sbin/init.d/rc3.d/S99mbsed + echo "SuSE SystemV init configured" + log "+" "SuSE SystemV init configured" +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for Slackware +# +if [ "$DISTNAME" = "Slackware" ]; then + if [ "$DISTVERS" = "Old" ] || [ "$DISTVERS" = "7.0.0" ]; then + # + # Slackware before version 7.1 + # + DISTINIT="$MBSE_ROOT/etc/rc" + echo "Adding old style Slackware MBSE BBS start/stop scripts" + log "+" "Adding old style Slackware MBSE BBS start/stop scripts" + if [ "`grep MBSE /etc/rc.d/rc.local`" = "" ]; then + log "+" "Adding $MBSE_ROOT/etc/rc to /etc/rc.d/rc.local" + mv /etc/rc.d/rc.local /etc/rc.d/rc.local.mbse + cat /etc/rc.d/rc.local.mbse >/etc/rc.d/rc.local + echo "# Start MBSE BBS" >>/etc/rc.d/rc.local + echo "$MBSE_ROOT/etc/rc" >>/etc/rc.d/rc.local + chmod 755 /etc/rc.d/rc.local + echo " Added $MBSE_ROOT/etc/rc to /etc/rc.d/rc.local" + echo " /etc/rc.d/rc.local.mbse is a backup file." + echo "" + echo " You must manualy insert the lines '$MBSE_ROOT/etc/rc.shutdown'" + echo " into /etc/rc.d/rc.0 and /etc/rc.d/rc.K If you don't do it" + echo " everything will work also, but MBSE BBS isn't proper closed" + echo " if you halt or reboot your system." + fi + cp mbse.start $MBSE_ROOT/bin + cp mbse.stop $MBSE_ROOT/bin + cp rc $MBSE_ROOT/etc + cp rc.shutdown $MBSE_ROOT/etc + chown mbse.bbs $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop + chmod 755 $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop + chown root.root $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + chmod 744 $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + else + DISTINIT="/etc/rc.d/init.d/mbsed" + echo "Adding SystemV Slackware MBSE BBS start/stop scripts" + log "+" "Adding SystemV Slackware MBSE BBS start/stop scripts" + checkrcdir + +cat << EOF >$DISTINIT +#!/bin/sh +# +# Author: Michiel Broek , 23-May-2001 +# +# $DISTINIT for Slackware +# + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "MBSE BBS starting:" + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n " mbtask" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo " and opened the bbs." + fi + ;; + stop) + echo -n "MBSE BBS shutdown:" + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n " logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done," + fi + echo -n " stopping mbtask " + kill -15 \`pidof \$MBSE_ROOT/bin/mbtask\` + echo "done." + ;; + status) + echo -n "MBSE BBS status: " + if [ "\`/sbin/pidof mbtask\`" = "" ]; then + echo "mbtask is NOT running" + else + echo "mbtask Ok" + fi + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + *) + echo "Usage: mbsed {start|stop|restart|status}" + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + if [ -f $MBSE_ROOT/bin/mbse.start ]; then + echo "Removing old startup scripts" + rm $MBSE_ROOT/bin/mbse.start $MBSE_ROOT/bin/mbse.stop $MBSE_ROOT/etc/rc $MBSE_ROOT/etc/rc.shutdown + fi + echo "Making links for start/stop in runlevel 3" + if [ -f /etc/rc.d/rc3.d/K05mbsed ]; then + rm /etc/rc.d/rc3.d/K05mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc3.d/K05mbsed + if [ -f /etc/rc.d/rc3.d/S95mbsed ]; then + rm /etc/rc.d/rc3.d/S95mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc3.d/S95mbsed + echo "Making links for start/stop in runlevel 4" + if [ -f /etc/rc.d/rc4.d/K05mbsed ]; then + rm /etc/rc.d/rc4.d/K05mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc4.d/K05mbsed + if [ -f /etc/rc.d/rc4.d/S95mbsed ]; then + rm /etc/rc.d/rc4.d/S95mbsed + fi + ln -s ../init.d/mbsed /etc/rc.d/rc4.d/S95mbsed + echo "Slackware SystemV init configured" + log "+" "Slackware SystemV init configured" + fi +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for RedHat and Mandrake +# FIXME: some details unknown about Mandrake +# +if [ "$DISTNAME" = "RedHat" ] || [ "$DISTNAME" = "Mandrake" ]; then + + log "+" "Adding RedHat/Mandrake SystemV init scripts" + DISTINIT="/etc/rc.d/init.d/mbsed" + SU="su" + # + # From RedHat version 6.1 and up the behaviour of "su" has changed. + # For Mandrake we follow the same behaviour. + # + if [ -f /etc/redhat-release ]; then + RHR=`cat /etc/redhat-release | awk '{ print $5 }' | tr -d .` + if [ $RHR -gt 60 ]; then + echo "You are running RedHat v6.1 or newer" + SU="su -" + else + echo "You are running RedHat v6.0 or older" + fi + else + if [ -f /etc/mandrake-release ]; then + RHR=`cat /etc/mandrake-release | awk '{ print $4 }' | tr -d .` + if [ $RHR -gt 60 ]; then + echo "You are running Mandrake v6.1 or newer" + SU="su -" + else + echo "You are running Mandrake v6.0 or older" + fi + else + echo "You are in big trouble." + fi + fi + echo "Adding startup file $DISTINIT" + +cat << EOF >$DISTINIT +#!/bin/sh +# +# chkconfig: 345 99 05 +# description: Starts and stops MBSE BBS. +# +# For RedHat and Mandrake SYSV init style. +# 23-May-2001 M. Broek +# +# Source function library. +. /etc/rc.d/init.d/functions + +# Source networking configuration. +. /etc/sysconfig/network + +# Check that networking is up. +[ \${NETWORKING} = "no" ] && exit 1 + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ] +then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ] +then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "Starting MBSE BBS: " + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + $SU mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n "mbtask " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + $SU mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo "opened" + fi + touch /var/lock/subsys/mbsed + ;; + stop) + echo -n "Shutting down MBSE BBS: " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n "logoff users " + $SU mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + echo -n "done, " + fi + echo -n "stop mbtask: " + killproc mbtask -15 + rm -f /var/lock/subsys/mbsed + echo "done." + ;; + status) + status mbsed + ;; + restart) + echo "Restarting MBSE BBS: just kidding!" + ;; + *) + echo "Usage: mbsed {start|stop|restart|status}" + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + echo "With the runlevel editor, 'tksysv' if you are running X," + echo "or 'ntsysv' if you are running virtual consoles, you must" + echo "now add 'mbsed' start to the default runlevel, and 'mbsed'" + echo "stop to runlevels 0 and 6" +fi + + + +#-------------------------------------------------------------------------- +# +# Adding scripts for Debian +# +# +if [ "$DISTNAME" = "Debian" ]; then + echo "You are running Debian Linux $DISTVERS" + log "+" "Adding Debian SystemV init script" + DISTINIT="/etc/init.d/mbsebbs" + +cat << EOF >$DISTINIT +#!/bin/sh +# +# Note: this is not 100% Debian style, at least it works for now. +# 23-May-2001 Michiel Broek. +# +# description: Starts and stops the MBSE BBS. + +# For Debian SYSV init style. + +# Find the MBSE_ROOT from the /etc/passwd file. +MBSE_ROOT=\`cat /etc/passwd | grep mbse: | awk -F ':' '{ print \$6}'\` + +if [ "\$MBSE_ROOT" = "" ]; then + echo "MBSE BBS: No 'mbse' user in the password file." + exit 1 +fi + +if [ ! -d \$MBSE_ROOT ]; then + echo "MBSE BBS: Home directory '\$MBSE_ROOT' not found." + exit 1 +fi + +PATH=/sbin:/bin:/usr/sbin:/usr/bin:\$MBSE_ROOT/bin +DAEMON=\$MBSE_ROOT/bin/mbtask +NAME=mbsebbs +DESC="MBSE BBS" + +export MBSE_ROOT + +# See how we were called. +case "\$1" in + start) + echo -n "Starting \$DESC: " + rm -f \$MBSE_ROOT/sema/* + rm -f \$MBSE_ROOT/var/*.LCK + su mbse -c '\$MBSE_ROOT/bin/mbtask' >/dev/null + echo -n "mbtask " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + su mbse -c '\$MBSE_ROOT/bin/mbstat open -quiet' + echo -n "opened " + fi + echo "done." + ;; + stop) + echo -n "Stopping \$DESC: " + if [ -f \$MBSE_ROOT/etc/config.data ]; then + echo -n "logoff users " + su mbse -c '\$MBSE_ROOT/bin/mbstat close wait -quiet' >/dev/null + fi + start-stop-daemon --stop --signal 15 --user mbtask + echo "\$NAME done." + ;; + force-reload|restart) + echo "Restarting \$DESC: is not possible, done." + ;; + *) + N=/etc/init.d/\$NAME + echo "Usage: \$N {start|stop|restart|force-reload}" >&2 + exit 1 +esac + +exit 0 +EOF + chmod 755 $DISTINIT + update-rc.d mbsebbs defaults + echo "Debian install ready." + log "+" "Debian SystemV init script installed" +fi + +echo +echo "Please note, your MBSE BBS startup file is \"$DISTINIT\"" +echo diff --git a/script/maint b/script/maint new file mode 100644 index 00000000..aa75a31b --- /dev/null +++ b/script/maint @@ -0,0 +1,26 @@ +#!/bin/sh +# +# MBSE BBS Maintenance - Should be run from cron. +# +# 18-Mar-2000 MB. + +if [ -z "$MBSE_ROOT" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# Don't do maintenance if running on UPS battery power. +# +if [ -f $MBSE_ROOT/sema/upsalarm ]; then + exit 0 +fi + +$MBSE_ROOT/bin/mbuser pack kill 180 50 -quiet +$MBSE_ROOT/bin/mbmsg kill pack link -quiet +$MBSE_ROOT/bin/mbfile kill check pack index -quiet +# $MBSE_ROOT/bin/mbfile kill check pack index web -quiet +$MBSE_ROOT/bin/mbtoberep >$MBSE_ROOT/doc/toberep.doc +$MBSE_ROOT/bin/mbaff announce filefind -quiet + +cd $MBSE_ROOT/tmp +$MBSE_ROOT/bin/mball list index -zip -quiet + diff --git a/script/mbse.start b/script/mbse.start new file mode 100644 index 00000000..0c2f01bd --- /dev/null +++ b/script/mbse.start @@ -0,0 +1,32 @@ +# +# ~/bin/mbse.start +# BBS Startup script, should be run as BBS owner. +# Note: This is only used on Slackware systems until 7.0.0 +# +# 27-May-2001 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +# If installed, start the BBS. +# +if [ -f $MBSE_ROOT/bin/mbtask ]; then + echo -n "Starting MBSE BBS: " + rm -f $MBSE_ROOT/sema/* + rm -f $MBSE_ROOT/var/*.LCK + rm -f $MBSE_ROOT/tmp/mb* + cd $MBSE_ROOT + $MBSE_ROOT/bin/mbtask >/dev/null + echo -n "mbtask " + if [ -f $MBSE_ROOT/etc/config.data ]; then + $MBSE_ROOT/bin/mbstat open -quiet + echo -n "opened " + fi + echo "done" +else + echo "mbtask not available!" + exit 1 +fi + diff --git a/script/mbse.stop b/script/mbse.stop new file mode 100644 index 00000000..67f03a82 --- /dev/null +++ b/script/mbse.stop @@ -0,0 +1,38 @@ +# +# ~/bin/mbse.start +# BBS Shutdown script, should be run as BBS owner. +# Note: this is only used on Slackware systems. +# +# 27-May-2001 MB. + +export PATH="/sbin:/usr/sbin:/bin:/usr/bin:$MBSE_ROOT/bin:" + + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +if [ -f $MBSE_ROOT/bin/mbtask ]; then + echo -n "Shutdown MBSE BBS: " + if [ -f $MBSE_ROOT/etc/config.data ]; then + echo -n "closing the bbs " + cd $MBSE_ROOT + $MBSE_ROOT/bin/mbstat close wait -quiet + echo -n "done, " + fi + # Now kill the daemons + echo -n "kill " + base=`basename mbtask` + pid=`pidof $base` + echo -n "mbtask " + if ps h $pid >/dev/null 2>&1; then + kill $pid + RC=$? + [ $RC -eq 0 ] && echo -n "ok " || echo -n "failed " + fi + echo "" +else + echo "mbtask not available!" +fi +# diff --git a/script/midnight b/script/midnight new file mode 100644 index 00000000..494c7632 --- /dev/null +++ b/script/midnight @@ -0,0 +1,28 @@ +#!/bin/sh +# +# MBSE BBS Midnight - Should be run from cron at 00:00 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done + +# Rollover statistic counters. +# +$MBSE_ROOT/bin/mbfido roll -quiet + +# Log "What's on Hold" +# +$MBSE_ROOT/bin/mbout stat -quiet + +# Export messages "missed" by the fast mailscan +# +$MBSE_ROOT/bin/mbfido scan -full -quiet + diff --git a/script/monthly b/script/monthly new file mode 100644 index 00000000..7eeaddcc --- /dev/null +++ b/script/monthly @@ -0,0 +1,15 @@ +#!/bin/sh +# +# MBSE BBS Monthly - Should be run at the first of the month at 00:10 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done diff --git a/script/rc b/script/rc new file mode 100644 index 00000000..22bf17af --- /dev/null +++ b/script/rc @@ -0,0 +1,15 @@ +#!/bin/sh +# +# $MBSE_ROOT/etc/rc: BBS Startup script for Slackware. +# +# 08-Jul-1999 + +# Remove stale tempfiles from cron. +rm -f /tmp/cron.mbse.* + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +su - mbse -c $MBSE_ROOT/bin/mbse.start + diff --git a/script/rc.shutdown b/script/rc.shutdown new file mode 100644 index 00000000..77dbe0c7 --- /dev/null +++ b/script/rc.shutdown @@ -0,0 +1,14 @@ +#!/bin/sh +# +# /mnt/prod/mbse/etc/rc.shutdown: BBS Shutdown script for Slackware +# +# 08-Jul-1998 + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + + +su mbse -c $MBSE_ROOT/bin/mbse.stop +sleep 2 +# diff --git a/script/weekly b/script/weekly new file mode 100644 index 00000000..41004a96 --- /dev/null +++ b/script/weekly @@ -0,0 +1,18 @@ +#!/bin/sh +# +# MBSE BBS Weekly - Should be run every week at sunday from cron at 00:05 +# +# 26-Aug-1999 MB. + +if [ "$MBSE_ROOT" = "" ]; then + export MBSE_ROOT=`cat /etc/passwd | grep mbse: | awk -F ':' '{ print $6}'` +fi + +# While the system is on UPS battery power, don't start maintenance +# +while [ -f $MBSE_ROOT/sema/upsalarm ]; do + sleep 60 +done + +$MBSE_ROOT/bin/mbfido notify -quiet + diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 00000000..9788f702 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp