home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume36 / ldb / part06 < prev    next >
Encoding:
Text File  |  1993-04-10  |  37.5 KB  |  911 lines

  1. Newsgroups: comp.sources.misc
  2. From: ross@teserv.den.mmc.com (Perry R. Ross)
  3. Subject: v36i103:  ldb - Play backgammon by e-mail, v1.3, Part06/12
  4. Message-ID: <1993Apr11.233041.18281@sparky.imd.sterling.com>
  5. X-Md4-Signature: 930de1f65eeb0ed01c04599b5836edf9
  6. Date: Sun, 11 Apr 1993 23:30:41 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: ross@teserv.den.mmc.com (Perry R. Ross)
  10. Posting-number: Volume 36, Issue 103
  11. Archive-name: ldb/part06
  12. Environment: UNIX, C, VMS, VAXC, CURSES, 32BIT
  13. Supersedes: ldb: Volume 28, Issue 93-97
  14.  
  15. #! /bin/sh
  16. # This is a shell archive.  Remove anything before this line, then unpack
  17. # it by saving it into a file and typing "sh file".  To overwrite existing
  18. # files, type "sh file -c".  You can also feed this as standard input via
  19. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  20. # will see the following message at the end:
  21. #        "End of archive 6 (of 12)."
  22. # Contents:  main.c
  23. # Wrapped by ross@teserv.den.mmc.com on Tue Apr  6 14:52:21 1993
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'main.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'main.c'\"
  27. else
  28. echo shar: Extracting \"'main.c'\" \(35683 characters\)
  29. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  30. X/*    main.c        8/3/91
  31. X *
  32. X * Copyright 1991  Perry R. Ross
  33. X *
  34. X * Permission to use, copy, modify, and distribute this software and its
  35. X * documentation without fee is hereby granted, subject to the restrictions
  36. X * detailed in the README file, which is included here by reference.
  37. X * Any other use requires written permission from the author.  This software
  38. X * is distributed "as is" without any warranty, including any implied
  39. X * warranties of merchantability or fitness for a particular purpose.
  40. X * The author shall not be liable for any damages resulting from the
  41. X * use of this software.  By using this software, the user agrees
  42. X * to these terms.
  43. X */
  44. X
  45. X#include "ldb.h"
  46. X
  47. X/*============================================================================
  48. X *    ldb --    Long Distance Backgammon
  49. X *
  50. X * The following arguments are recognized:
  51. X *    -read        Mail is read, and the games are updated and saved.
  52. X *            The user is not prompted for his moves.
  53. X *    -play        Any games that are waiting for local input are
  54. X *            displayed for the user to process.  No mail is read.
  55. X *    -color xy    The colors for any games started are set to x and y.
  56. X *            The first color is played by the local user, and the
  57. X *            other is played by the opponent.  Legal color
  58. X *            characters are upper and lower case letters.
  59. X *            The default is "-color rw".
  60. X *    -direction up/down
  61. X *            The direction of play for the local user is set
  62. X *            to the specified value.  The default is
  63. X *            "-direction up".
  64. X *    -myaddr addr    Override the "myaddr" field of .ldbrc for any
  65. X *            games started by this invocation of ldb.
  66. X *    -newaddr    This argument tells ldb to notify all opponents that
  67. X *            your e-mail address has changed.  The new address is
  68. X *            obtained from .ldbrc and stored in the people file.
  69. X *            Each packet you send after using -newaddr will include
  70. X *            a field telling your opponent(s) of your new address;
  71. X *            when a packet is received from an opponent, that
  72. X *            opponent is considered notified and the newaddr is
  73. X *            cancelled.  This is done for all opponents until all
  74. X *            have been notified.  Opponents using pre-1.3 versions
  75. X *            of ldb are not notified, and a warning message is
  76. X *            printed locally.  These users must change your
  77. X *            address manually with a text editor.  If the address
  78. X *            in .ldbrc is not correct for some of your opponents,
  79. X *            you must:
  80. X *                1. Put the most common address in .ldbrc
  81. X *                2. run: ldb -read -newaddr
  82. X *                3. edit .ldbpeople and change the myaddr=
  83. X *                   fields for those opponents
  84. X *                   that need different addresses.  Do the
  85. X *                   same with .ldbdata.
  86. X *                4. Resume using ldb normally.
  87. X *                5. Oh well, sorry.
  88. X *    -start user    A game is started with the specified user.  User may
  89. X *            be either an e-mail address or an alias for an
  90. X *            opponent that has been played previously.
  91. X *    -remotestart user1 user2
  92. X *            A game is started between user1 and user2.  The local
  93. X *            host sends a remote start message to user1 instructing
  94. X *            it to start a game with user2.  The local host
  95. X *            does not participate thereafter in the game.
  96. X *            For the purposes of the -color and -direction options,
  97. X *            user1 is considered the local user.
  98. X *    -broadcast file
  99. X *            A file is mailed to all opponents.  This is useful
  100. X *            for announcing vacation absences, etc.
  101. X *    -help        A summary of available options is printed.  This
  102. X *            list may be more up to date than these comments.
  103. X *    -jacoby        Enables the jacoby rule for any games subsequently
  104. X *            started.  This rule states that gammons or backgammons
  105. X *            only count as 1 when neither player doubled during
  106. X *            the game.
  107. X *    -crawford    Enables the crawford rule for any games subsequently
  108. X *            started.  This rule prevents doubling when either
  109. X *            player is within 1 point of winning the match.
  110. X *    -european    Enables european scoring for any subsequently
  111. X *            created games.  This rule makes backgammons count
  112. X *            as double games, rather than triple.
  113. X *    -permanent    Marks any subsequently created games as permanent.
  114. X *            Permanent games will be restarted whenever they
  115. X *            end.  This is for people you play all the time.
  116. X *            Permanent games must be deleted via -control.
  117. X *    -match points    Marks any subsequently created games as matches
  118. X *            that play to the specified number of points.
  119. X *            Games will be restarted until one player wins
  120. X *            this number of points.
  121. X *    -control    Enters control mode.  No games may be started
  122. X *            or played.  Each game is displayed, along with
  123. X *            a menu that allows various administrative
  124. X *            functions to be performed.
  125. X *    -reconstruct file
  126. X *            This option allows you to recover your .ldbdata
  127. X *            file even if you lose all copies.  Simply have
  128. X *            all your opponents send you their .ldbdata files
  129. X *            and, one by one, feed them into ldb with the
  130. X *            -reconstruct option.  Ldb will scan the file,
  131. X *            find any games that have your name as the
  132. X *            opponent, and rebuild your game data using the
  133. X *            data in that game.
  134. X *    -score        Print the cumulative score for all your opponents.
  135. X *
  136. X * If neither -read or -play is given, the default is to do both; incoming mail
  137. X * is read, then any games requiring the user's attention are displayed.
  138. X *
  139. X *----------------------------------------------------------------------------
  140. X *                REVISION HISTORY
  141. X *** Version 01   Rev 0   Patch 0
  142. X * 1.    Initial release.  Countless helpful suggestions from Karen Ward.
  143. X *
  144. X *** Version 01   Rev 1   Patch 0
  145. X * 1.    The personal name and e-mail address printed on the top line
  146. X *    were switched.  It makes more sense to be playing a person rather
  147. X *    than an address.  If the e-mail address is too long to fit on
  148. X *    the top line, it is truncated and an ellipsis is added.
  149. X * 2.    Pressing ESC while entering a comment now returns you to the
  150. X *    previous menu and discards the comment.  This allows you to
  151. X *    change your mind after hitting "Send", for example.  Suggested
  152. X *    by Franc,ois Pinard.
  153. X * 3.    The checkpoint code was moved to sendpkt(), where the games
  154. X *    are saved before the packet is sent.  This removes a window
  155. X *    where a packet could be sent but ldb could croak before saving
  156. X *    the game.  Suggested by Earle Ake.
  157. X * 4.    Ldb will not ask for the second digit of a point number when:
  158. X *        The first digit is 3 - 9,
  159. X *        The first digit is 1 and there is no point in 10 - 19
  160. X *            that could use the selected roll, or
  161. X *        The first digit is 2 and there is no point in 20 - 24
  162. X *            that could use the selected roll.
  163. X *    Suggested by Earle Ake and Franc,ois Pinard.
  164. X * 5.    When a roll is selected and a piece is on the bar, no point is
  165. X *    prompted for, since moving off the bar is the only legal move.
  166. X *    Suggested by Franc,ois Pinard.
  167. X * 6.    The Makefile now used $(CC) instead of cc.  Suggested by
  168. X *    Franc,ois Pinard.
  169. X * 7.    A number of patches to make ldb run under SCO Xenix (and probably
  170. X *    SCO UNIX as well) were sent by Dinesh Vichare.
  171. X * 8.    A bare bones rename function is included for those systems that
  172. X *    don't have one.  Suggested by Franc,ois Pinard.
  173. X * 9.    Comments are now rot13'd before they are sent.  This keeps
  174. X *    them from being read while mail is extracted.  They are
  175. X *    rotated back when ldb displays them.  This is disabled if the
  176. X *    opponent is using the old (1.0) ldb version, so 1.1 and 1.0
  177. X *    ldb's will still work together.  The only catch is when you switch
  178. X *    from 1.0 to 1.1 with games in progress, your opponents won't know
  179. X *    you've switched until you send them a move.  As a result, the
  180. X *    comment from their next message will be garbled.  To avoid this,
  181. X *    do "ldb -read" under 1.0, then switch to 1.1 to play.  This is
  182. X *    only necessary once, after that your opponent's will know you
  183. X *    are using 1.1 and the messages will work normally.
  184. X *    Suggested by Franc,ois Pinard.
  185. X * 10.    Ldb now clears the screen before exiting.  Keeps wandering
  186. X *    manager types from seeing the remnants of a game.
  187. X * 11.    The sequence number warning was removed for leftover messages
  188. X *    from dead games.
  189. X * 12.    There is now a "Press <return> to continue" before the screen
  190. X *    is drawn if any messages were printed.  This lets you read
  191. X *    the messages before the screen is cleared.  Suggested by
  192. X *    practically everybody.
  193. X * 13.    Default file names for vms are now ldb.rc, ldb.data,  and ldb.olddata.
  194. X *    This keeps the ldb files together and out of the way, since vms
  195. X *    doesn't treat filenames with a leading '.' like UNIX does.
  196. X *    Suggested by Earle Ake.
  197. X * 14.    There is now a debug setting in .ldbrc.  It is a mask, with each
  198. X *    bit enabling debug info from a different piece of code.  The
  199. X *    bits are defined as DB_* in ldb.h Suggested by Earle Ake.
  200. X * 15.    A sum of all rolls is kept in the "rolls" and "doubles" fields
  201. X *    of the game structure.  This counts the number of each type of
  202. X *    roll you get, and the number of doubles of each type.
  203. X *    The same is true for your opponent's rolls and doubles in
  204. X *    the oprolls and opdoubles fields.  Suggested by Earle Ake.
  205. X * 16.    The crawford and jacoby rules are now supported.  They are activated
  206. X *    by the -crawford and -jacoby command line options, and can only
  207. X *    be enabled by whoever starts the game.  If they are used to start
  208. X *    a game with a version of ldb that does not support them, a message
  209. X *    is printed and they are disabled.
  210. X * 17.    Ldb now allows a game to be declared "permanent", meaning that
  211. X *    it is automatically restarted when it is over.  This is activated
  212. X *    the the -permanent command line option, and can only be enabled
  213. X *    by whoever starts the game.
  214. X * 18.    Ldb now supports match play.  This is activated by the -match
  215. X *    command line options, which takes a numeric argument specifying
  216. X *    how many points the match plays to.  When a game that is part of
  217. X *    a match ends, and the specified number of points has not been reached,
  218. X *    the game is restarted.
  219. X * 19.    The "buttons" in the menu in fe_curses now light up to show the
  220. X *    item that was chosen.
  221. X * 20.    Ldb now supports the "european rule", which states that backgammons
  222. X *    only count double, not triple, the game value.
  223. X * 21.    Ldb now creates a lock file when it starts in such a way as to
  224. X *    prevent multiple ldb processes from running in the same account at the
  225. X *    same time.  The lock code does not depend on any operating system
  226. X *    locking features, other than O_EXCL, and so should be fairly portable.
  227. X * 22.    There is now an option in .ldbrc to automatically delete mail
  228. X *    files after they have been read.  It will refuse to delete
  229. X *    files that begin with '/' (on UNIX only) to help prevent
  230. X *    catastrophic mistakes.  This option is off by default,
  231. X *    and should only be used with great care.
  232. X *    You should also read the disclaimer at the top of this (and all
  233. X *    other) files, where it says I'm not responsible.  Caveat User.
  234. X * 23.    A "timeout" setting has been added to .ldbrc.  Games that have
  235. X *    not been accessed for more than "timeout" days (default 7),
  236. X *    and are waiting on remote input, have the last packet automatically
  237. X *    resent.  If timeout is set to 0, automatic resends are disabled.
  238. X * 24.    A "keepold" setting has been added to .ldbrc.  Games that are over
  239. X *    are retained in .ldbdata for "keepold" days (default 7), allowing
  240. X *    time for the last move to be resent if necessary.  If "keepold" is
  241. X *    set to 0, games are deleted as soon as they are over.
  242. X * 25.    Old start packets are now rejected.  To do this, a new file
  243. X *    called the "people" file is maintained.  This file is organised
  244. X *    by opponent address, and stores the start time of the newest completed
  245. X *    game, called the "fence".  Any start packets not newer than the
  246. X *    fence are discarded.  The only way a legitimate start packet would be
  247. X *    rejected is if it were not fed to ldb until after another game with
  248. X *    the same opponent had been started and finished.  This should never
  249. X *    happen, but if it did, all that would be required to fix it would
  250. X *    be to have the opponent resend the start packet via -control.
  251. X * 26.    The people file also stores the opponent's name and
  252. X *    an alias, or nickname, for the opponent.  The alias is initialized
  253. X *    to the first word of the opponent's name with all capitals changed
  254. X *    to lower case.  To change an opponent's alias, a text editor may
  255. X *    be used on the people file.  The -start command will take an
  256. X *    alias in place of an e-mail address.  There is no check for
  257. X *    duplicate aliases, and if one is used in a -start command, the
  258. X *    game will be started with the first record found in the people
  259. X *    file with that alias.
  260. X * 27.    The people file also stores a record of all games won/lost to
  261. X *    that opponent.  The data stored includes games won/lost, points
  262. X *    won/lost, gammons won/lost, backgammons won/lost, and matches won/lost.
  263. X *    There is currently no utility to print these out, but they can
  264. X *    be extracted from the people file manually.  See the definitions
  265. X *    for SC_* in ldb.h to see which number is which.
  266. X * 28.    There is now a way to reconstruct the .ldbdata file from your
  267. X *    opponents' .ldbdata files.  Just have them mail their ldbdata
  268. X *    files to you, remove the mail header, and run:
  269. X *        ldb -reconstruct file
  270. X *    where file is the file containing the opponent's ldbdata file.
  271. X *    Each game in that file showing you as the opponent is extracted
  272. X *    and inserted into your game list.  You will be prompted for the
  273. X *    address of your opponent (and name, if they are not in the
  274. X *    people file) for each game found.
  275. X * 29.    The people file has a method for handling people with multiple
  276. X *    e-mail addresses.  When a new opponent is found with the
  277. X *    same name as an existing one, but a different address, the
  278. X *    user is asked if these addresses refer to the same person.
  279. X *    If they do, an "equiv" record is added to the people file,
  280. X *    which merely records that the second address refers to the
  281. X *    same person as the first.  If they don't (e.g. John Smith),
  282. X *    two separate people records are created for the different people.
  283. X * 30.    There is now a way to request a resend from your opponent under
  284. X *    -control.  The menu item is "Get Resend", since "Request Resend"
  285. X *    would have used the same first letter as "Resend". (oh well)
  286. X *    A special packet is sent to your opponent; when his ldb receives it,
  287. X *    it will perform a resend automatically.  This feature is disabled
  288. X *    if the opversion field of the game structure indicates your
  289. X *    opponent is using a pre-1.1 version of ldb.  Sending the resend
  290. X *    packet to an ldb older than 1.1 would cause it to abort.  Oops.
  291. X * 31.    Any upper or lower case letters may now be used to draw the
  292. X *    pieces on the board.  Previously only r, w, and b were used.
  293. X *    As r, w, and b stood for red, white, and black, the option
  294. X *    to set them was called -color.  While the letters no longer
  295. X *    (necessarily) represent colors, the option is still -color.
  296. X * 32.    A screen dump of a game may be obtained via the -control menu.
  297. X *    The dump goes to ldb_screen.dmp.
  298. X *
  299. X * ---  The following modifications made by Earle Ake.
  300. X *
  301. X * 1.    A context-sensitive help function was added that is activated by
  302. X *    pressing 'h' or '?' at any time other than while composing a message.
  303. X * 2.    The redraw key now works under VMS.  Clearok() needed to be called
  304. X *    to force a redraw.
  305. X * 3.    The superkey function now works under VMS.  It was rewritten to
  306. X *    spawn a subprocess and execute the supercmd if specified.
  307. X *    The user must logout of the subprocess to resume the game.
  308. X * 4.    The .ldbrc file now contains reasonable defaults for VMS when
  309. X *    the VMS-compiled ldb creates it.  The sendcmd setting calls
  310. X *    the IN% mailer by default.
  311. X * 5.    Old versions of .oldldbdata are now purged.
  312. X * 6.    setattr() and clrattr() are used instead of standout() and
  313. X *    standend() to get reverse video on VMS.  standout() on VMS
  314. X *    used bold instead of reverse video, which made the cube
  315. X *    look non-cubical.
  316. X * 7.    The current pip count for you and your opponent are displayed
  317. X *    above the board.  These change depending on which board is
  318. X *    displayed, and are updated as you move.
  319. X * 8.    An extensive display of statistics regarding the number and
  320. X *    frequency of rolls and doubles for both users can be displayed
  321. X *    by pressing the % or # keys.  This data can also be displayed
  322. X *    as a histogram.
  323. X *
  324. X *** Version 01   Rev 2   Patch 0
  325. X *** Note Rev 2 was never officially released.  A number of beta versions
  326. X *** of 1.2 were distributed, and this led to so much confusion that the
  327. X *** official release was called 1.3.
  328. X * 1.    The "Get Resend" option in -control is disabled for games
  329. X *    that are over.  Patch by Earle Ake.
  330. X * 2.    All occurrences of "gets" have been replaced by "fgets" to
  331. X *    avoid buffer overrun problems.
  332. X * 3.    Ldb now detects games where no further contact is possible and
  333. X *    changes the "BAR" indicator to "---".
  334. X * 4.    The "Resend" option in -control is disabled for games that are in
  335. X *    a "local" state (i.e. it is the local player's turn).
  336. X * 5.    The cumulative score from the people file can now be displayed
  337. X *    via the -score command line argument.  This is similar to a
  338. X *    system implemented by Doug Parisek, but uses the info from the
  339. X *    people file rather than from a separate standings file.
  340. X * 6.    An option has been added to make ldb notify the game starter
  341. X *    when a game started by -remotestart has ended.  If a
  342. X *    -notify <addr> option is on the command line before the
  343. X *    -remotestart, the ldb from both players will send a message
  344. X *    to <addr> when the game ends.  This message will look like
  345. X *    a normal ldb packet, but the opcode will be NOTIFY, and
  346. X *    the comment field will contain three numbers; these are
  347. X *    the termination code (T_* in ldb.h), the game value, and
  348. X *    the backgammon flag (1 = gammon, 2 = backgammon, 0 = neither).
  349. X *    Note that the integer values of the termination codes changed
  350. X *    between rev 1.0 and rev 1.1 -- the one in the comment field
  351. X *    corresponds to the new codes (the ones found in ldb.h from
  352. X *    rev 1.1 or higher).  The comment2 field contains the address
  353. X *    of the opponent played.  Ldb itself has no provisions to read
  354. X *    notify packets, and would not be able to do anything useful
  355. X *    with them if it could.  They are purely for the use of a
  356. X *    game starter, if anyone feels like writing one.
  357. X * 7.    Remote start packets left in the mail file no longer start
  358. X *    a new game every time ldb is run.  This is done by scanning
  359. X *    the game list for a game where both opaddr and starttime match
  360. X *    those shown in the remotestart packet, and discarding it if
  361. X *    one is found.  If it is not found, the address is looked up in
  362. X *    the people list and the fence time, if any, is checked.
  363. X *    This catches the case where the game started by that remotestart
  364. X *    packet has already finished.  Bug found by Mark Rubin.
  365. X * 8.    The -remotestart option now supports the crawford, jacoby, europe,
  366. X *    and permanent options, as well as match play.
  367. X * 9.    The crawford rule code has been rewritten.  It now (correctly)
  368. X *    only disallows doubling for the first game after either player
  369. X *    reaches match score - 1.  Subsequent games allow doubling.
  370. X *    During the crawford rule game, the C indicator above the board
  371. X *    is drawn in reverse video.
  372. X * 10.    Concede now scores a gammon if the loser has not borne off any
  373. X *    pieces, and a backgammon if the loser has any pieces in the winners
  374. X *    inner table.  This fixes a bug where Concede could be used to
  375. X *    avoid a gammon/backgammon.
  376. X * 11.    Ldb now scans the mail file(s) before checking for access timeouts.
  377. X *    Previously, it would perform automatic resends for games when
  378. X *    a message for that game was waiting in the mail, resulting in an
  379. X *    unnecessary resend.  This was common when returning from vacation,
  380. X *    for example, when all games would time out.
  381. X * 12.    The error messages displayed when a move is rejected have been
  382. X *    made more understandable.  Previously the same set of messages
  383. X *    were used for the local player and for received moves, and the
  384. X *    wording was somewhat awkward to allow this double usage.  Local
  385. X *    errors now use the messages in rejlcl[], while received moves still
  386. X *    use the messages in rejmsg[].
  387. X * 13.    A serious bug was fixed in rcvop.c.  restart() and mstart() did not
  388. X *    call legalmoves() to regenerate the maxused and hiused fields of
  389. X *    the game structure.  The consequence of this for restart() is that
  390. X *    move checking will not work for the first move of any game that had
  391. X *    a tie on an opening roll.  For mstart(), which starts the next
  392. X *    game of a match, maxused and hiused will still be whatever they
  393. X *    were for the last move of the previous game, which could result in
  394. X *    either allowing an illegal move or disallowing a legal one.
  395. X *    Bug found by Earle Ake.
  396. X * 14.    Cbreak is now turned off during the supercmd.
  397. X * 15.    Any printing character (other than space) is allowed to be used
  398. X *    to draw game pieces.  These can be upper or lower case letters,
  399. X *    numbers, or punctuation.  The only restriction is that the characters
  400. X *    used may not be the same for both players.  This includes using
  401. X *    the upper and lower case of the same letter.
  402. X * 16.    Command line options may now be abbreviated by the shortest
  403. X *    unique string.
  404. X * 17.    If the -broadcast option is given without a file argument, it
  405. X *    reads from stdin.  -broadcast also reads the people file instead
  406. X *    of the game file, so duplicate messages are not sent to opponents
  407. X *    with more than one game in progress.
  408. X * 18.    The -start and -remotestart options are deferred until after all
  409. X *    options have been scanned.  This removes order dependencies in
  410. X *    command line options, so that:
  411. X *        ldb -match 7 -start joe
  412. X *    and    ldb -start joe -match 7
  413. X *    have identical effect.  Because of this change, only one -start and
  414. X *    one -remotestart may be used per run of ldb.  Suggested by Earle Ake.
  415. X * 19.    findppl now detects infinite loops in equiv records.  Should never
  416. X *    happen, but ...
  417. X *** Version 01   Rev 2   Patch 0
  418. X * 1.    A warning is printed if the crawford rule is used with a pre-1.3
  419. X *    version of ldb.  The Crawford rule was fixed during 1.2, but many
  420. X *    beta versions were distributed before this fix was included.
  421. X * 2.    The -newaddr option was added.  I was going to wait on this, but
  422. X *    my employment situation is such that I may need to use it soon. :-(
  423. X *============================================================================
  424. X */
  425. X
  426. Xmain(argc,argv)
  427. Xint argc;
  428. Xchar *argv[];
  429. X{
  430. Xstruct game *g;
  431. Xstruct people *p;
  432. XFILE *fp;
  433. Xchar subj[128];
  434. Xchar *bcfile;
  435. Xint i, j, Newaddr;
  436. Xchar c, c2;
  437. Xint done;
  438. Xint ldbsignal();
  439. Xint flags, match;
  440. Xchar *start_addr;
  441. Xchar *rst1, *rst2;
  442. X
  443. Xghead = NULL;            /* init game list to empty */
  444. Xgtail = NULL;
  445. Xsignal(SIGINT,ldbsignal);    /* set up interrupt trap to save games */
  446. XRflag = 1;        /* should we try to extract incoming mail? */
  447. XPflag = 1;        /* should we process waiting games? */
  448. XNewaddr = 0;
  449. XRandomInit(time((long *)0));    /* seed the random number generator */
  450. X
  451. Xreadldbrc();        /* read startup file */
  452. X
  453. Xget_lock(rc.lockfile);    /* is another ldb already running? */
  454. X
  455. Xcr_mycolor = rc.defclrs[0];    /* default color when creating games */
  456. Xcr_opcolor = rc.defclrs[1];
  457. Xcr_mydir = (*rc.defdir == 'u') ? 1 : -1;    /* default direction */
  458. X
  459. Xreadgames();        /* load games in progress */
  460. X
  461. Xmatch = 0;        /* default to no match play */
  462. Xflags = 0;        /* default to no special rules or perm games */
  463. Xnotify = NULL;        /* default to no notify address */
  464. Xstart_addr = NULL;    /* default to no game started */
  465. Xrst1 = NULL;        /* default to no remote start game */
  466. Xrst2 = NULL;
  467. Xfor (i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
  468. X    j = optlookup(&argv[i][1]);
  469. X    if (j == -2) {
  470. X        printf("%s:\tambiguous option: %s\n\n",*argv,argv[i]);
  471. X        usage(0);        /* print short help */
  472. X        ldbexit(STAT_ABORT);
  473. X        }
  474. X    if (j < 0) {
  475. X        printf("%s:\tunrecognized option: %s\n\n",*argv,argv[i]);
  476. X        usage(0);        /* print short help */
  477. X        ldbexit(STAT_ABORT);
  478. X        }
  479. X    switch (options[j].index) {
  480. X    case OPT_START:            /* start a game */
  481. X        i++;
  482. X        if (argv[i] == NULL) {
  483. X            printf("%s: -start needs argument\n",*argv);
  484. X            usage(0);
  485. X            ldbexit(STAT_ABORT);
  486. X            }
  487. X        if (start_addr != NULL) {
  488. X            printf("%s: only one -start allowed.\n",*argv);
  489. X            usage(0);
  490. X            ldbexit(STAT_ABORT);
  491. X            }
  492. X        start_addr = argv[i];
  493. X        break;
  494. X    case OPT_RSTART:        /* remote start */
  495. X        i++;
  496. X        if ( (argv[i] == NULL) || (argv[i+1] == NULL) ) {
  497. X            printf("%s: -remotestart needs two arguments\n",*argv);
  498. X            usage(0);
  499. X            ldbexit(STAT_ABORT);
  500. X            }
  501. X        if (rst1 != NULL) {
  502. X            printf("%s: only one -remotestart allowed.\n",*argv);
  503. X            usage(0);
  504. X            ldbexit(STAT_ABORT);
  505. X            }
  506. X        rst1 = argv[i];
  507. X        rst2 = argv[i+1];
  508. X        i++;
  509. X        break;
  510. X    case OPT_READ:
  511. X        Pflag = 0;        /* just read, no processing */
  512. X        break;
  513. X    case OPT_PLAY:
  514. X        Rflag = 0;        /* just process, no read */
  515. X        break;
  516. X    case OPT_MYADDR:        /* set my e-mail address */
  517. X        i++;
  518. X        if (argv[i] == NULL) {
  519. X            printf("%s: -myaddr needs argument\n",*argv);
  520. X            usage(0);
  521. X            ldbexit(STAT_ABORT);
  522. X            }
  523. X        strcpy(rc.myaddr,argv[i]);    /* copy in new address */
  524. X        break;
  525. X    case OPT_NEWADDR:        /* send new address to all opponents */
  526. X        Newaddr++;        /* process this opt after mail read */
  527. X        break;
  528. X    case OPT_HELP:            /* print long help */
  529. X        usage(1);
  530. X        ldbexit(STAT_NORM);
  531. X    case OPT_NOTIFY:
  532. X        i++;
  533. X        if (argv[i] == NULL) {
  534. X            printf("%s: -notify needs argument\n",*argv);
  535. X            usage(0);
  536. X            ldbexit(STAT_ABORT);
  537. X            }
  538. X        notify = argv[i];
  539. X        break;
  540. X    case OPT_COLOR:            /* set colors */
  541. X        if (argv[++i] == NULL) {
  542. X            printf("%s: -color option needs argument\n",*argv);
  543. X            usage(0);
  544. X            ldbexit(STAT_ABORT);
  545. X            }
  546. X        cr_mycolor = argv[i][0];    /* first char is my color */
  547. X        cr_opcolor = argv[i][1]; /* second char is opponent's color */
  548. X        if ( (! isprint(cr_mycolor)) || (cr_mycolor == ' ') ) {
  549. X            printf("%s: invalid color: %d\n",*argv,cr_mycolor);
  550. X            usage(0);
  551. X            ldbexit(STAT_ABORT);
  552. X            }
  553. X        if ( (! isprint(cr_opcolor)) || (cr_opcolor == ' ') ) {
  554. X            printf("%s: invalid color: %d\n",*argv,cr_opcolor);
  555. X            usage(0);
  556. X            ldbexit(STAT_ABORT);
  557. X            }
  558. X        c = cr_mycolor;
  559. X        if (isupper(c))
  560. X            c = tolower(c);
  561. X        c2 = cr_opcolor;
  562. X        if (isupper(c2))
  563. X            c2 = tolower(c2);
  564. X        if (c == c2) {
  565. X            printf("%s: duplicate color: %c\n",*argv,cr_mycolor);
  566. X            usage(0);
  567. X            ldbexit(STAT_ABORT);
  568. X            }
  569. X        break;
  570. X    case OPT_DIRECTION:        /* set direction */
  571. X        if (argv[++i] == NULL) {
  572. X            printf("%s: -direction option needs argument\n",*argv);
  573. X            usage(0);
  574. X            ldbexit(STAT_ABORT);
  575. X            }
  576. X        c = argv[i][0];
  577. X        if (isupper(c))
  578. X            c = tolower(c);
  579. X        if (c == 'u')
  580. X            cr_mydir = 1;        /* I play up */
  581. X        else if (c == 'd')
  582. X            cr_mydir = -1;        /* I play down */
  583. X        else {
  584. X            printf("%s: invalid direction: %s\n",*argv,argv[i]);
  585. X            usage(0);
  586. X            ldbexit(STAT_ABORT);
  587. X            }
  588. X        break;
  589. X    case OPT_JACOBY:
  590. X        flags |= F_JACOBY;
  591. X        break;
  592. X    case OPT_CRAWFORD:
  593. X        flags |= F_CRAWFORD;
  594. X        break;
  595. X    case OPT_EUROPE:
  596. X        flags |= F_EUROPE;
  597. X        break;
  598. X    case OPT_PERM:
  599. X        flags |= F_PERM;
  600. X        break;
  601. X    case OPT_MATCH:
  602. X        if (argv[++i] == NULL) {
  603. X            printf("%s: -match option needs argument\n",*argv);
  604. X            usage(0);
  605. X            ldbexit(STAT_ABORT);
  606. X            }
  607. X        if (! isdigit(*argv[i])) {
  608. X            printf("%s: -match needs numeric argument\n",*argv);
  609. X            usage(0);
  610. X            ldbexit(STAT_ABORT);
  611. X            }
  612. X        match = atoi(argv[i]);
  613. X        break;
  614. X    case OPT_SCORE:
  615. X        if (start_addr != NULL)
  616. X            printf("warning: -start not processed.\n");
  617. X        if (rst1 != NULL)
  618. X            printf("warning: -remotestart not processed.\n");
  619. X        printscore();
  620. X        ldbexit(STAT_NORM);
  621. X    case OPT_BCAST:                /* broadcast a message */
  622. X        if (argv[++i] == NULL) {    /* no arg, read stdin */
  623. X            if ( (fp = fopen(rc.tempfile,"w")) == NULL) {
  624. X                printf("%s: can't write temp file %s\n",
  625. X                    *argv,rc.tempfile);
  626. X                ldbexit(STAT_ABORT);
  627. X                }
  628. X            while (fgets(subj,sizeof(subj),stdin) != NULL)
  629. X                fputs(subj,fp);
  630. X            fclose(fp);
  631. X            bcfile = rc.tempfile;
  632. X            }
  633. X        else
  634. X            bcfile = argv[i];    /* just read named file */
  635. X        sprintf(subj,"LDB Broadcast Message from %s",rc.myname);
  636. X        for (p = phead; p != NULL; p = p->next)    { /* for all people */
  637. X            if (p->equiv != NULL)    /* it's an equiv record */
  638. X                continue;    /* skip it */
  639. X            for (g = ghead; g != NULL; g = g->next)    /* cur opp? */
  640. X                if (strcmp(g->opaddr,p->addr) == 0)
  641. X                    break;
  642. X            if (g == NULL)    /* not a current opponent */
  643. X                continue;    /* skip it */
  644. X            TSendFile(p->addr,bcfile,subj); /* send msg */
  645. X            }
  646. X        break;
  647. X    case OPT_CONTROL:            /* control my games */
  648. X        control();
  649. X        if (start_addr != NULL)
  650. X            printf("warning: -start not processed.\n");
  651. X        if (rst1 != NULL)
  652. X            printf("warning: -remotestart not processed.\n");
  653. X        ldbexit(STAT_NORM);
  654. X    case OPT_RECONS:            /* reconstruct a game */
  655. X        if (argv[++i] == NULL) {
  656. X            printf("%s: -reconstruct option needs argument\n",
  657. X                *argv);
  658. X            usage(0);
  659. X            ldbexit(STAT_ABORT);
  660. X            }
  661. X        recons(argv[i]);
  662. X        if (start_addr != NULL)
  663. X            printf("warning: -start not processed.\n");
  664. X        if (rst1 != NULL)
  665. X            printf("warning: -remotestart not processed.\n");
  666. X        ldbexit(STAT_NORM);
  667. X    default:
  668. X        fprintf(stderr,
  669. X           "Sorry, the %s option is not implemented yet.\n",
  670. X            options[j].name);
  671. X        ldbexit(STAT_ABORT);
  672. X        }
  673. X    }
  674. X
  675. Xif (start_addr != NULL)
  676. X    startgame(start_addr,cr_mydir,cr_mycolor,cr_opcolor,flags,match,0);
  677. Xif (rst1 != NULL)
  678. X    remotestart(rst1,rst2,flags,match);
  679. X
  680. Xif ( (Pflag == 0) && (Rflag == 0) ) {    /* user gave both -play and -read */
  681. X    Pflag = 1;            /* turn both back on */
  682. X    Rflag = 1;
  683. X    }
  684. Xwhile (i < argc)        /* if files given on command line, read them */
  685. X    readmail(argv[i++]);
  686. Xif (Rflag)            /* if we are supposed to read default file */
  687. X    readmail(rc.mfile);    /* do that too */
  688. X
  689. X    /* process the newaddr option, if necessary */
  690. Xif (Newaddr) {
  691. X    for (g = ghead; g != NULL; g = g->next)        /* for all games */
  692. X        if (strcmp(g->myaddr,rc.myaddr) != 0) {    /* if addr different */
  693. X            free(g->myaddr);        /* change it */
  694. X            g->myaddr = save(rc.myaddr);
  695. X            }
  696. X    i = 0;
  697. X    for (p = phead; p != NULL; p = p->next) {    /* for all op's */
  698. X        if (p->equiv != NULL)        /* ignore equiv records */
  699. X            continue;
  700. X        if (strcmp(rc.myaddr,p->myaddr) == 0)    /* addr unchanged */
  701. X            continue;
  702. X        free(p->myaddr);    /* free old string */
  703. X        p->myaddr = save(rc.myaddr);    /* save new addr */
  704. X        if (p->opver < 130)    /* old ldb can't newaddr */
  705. X            message(
  706. X            "%s uses old ldb -- must change addr manually.\n",
  707. X            p->addr);
  708. X        else {
  709. X            p->newaddr = NA_PEND;    /* newaddr is pending*/
  710. X            i++;            /* keep count */
  711. X            }
  712. X        }
  713. X    message("newaddr: %d opponents to notify.\n",i);
  714. X    }
  715. X
  716. Xi = 0;
  717. Xfor (g = ghead; g != NULL; g = g->next)    { /* does any game need our input? */
  718. X    check_timeout(g);    /* check for access timeouts */
  719. X    if ( (g->state >= OPSTATES) &&
  720. X         ! ( (g->state == ST_GAMEOVER) && (g->flags & F_DISPLAYED) ) )
  721. X        i++;
  722. X    }
  723. Xif ( (i == 0) || (Pflag == 0) ) {        /* if not, exit */
  724. X    writegames(rc.gfile,rc.gbackup,rc.pfile);    /* save games */
  725. X    ldbexit(STAT_NORM);
  726. X    }
  727. XTInitialize();                    /* fire up the transport */
  728. XFeInitialize();                    /* fire up the front end */
  729. XFeDrawScreen();                /* draw the screen outline */
  730. Xfor (g = ghead, done = 0; (g != NULL) && (done >= 0); g = g->next)
  731. X    while ( (done = process(g)) > 0);    /* process game til done */
  732. XFeFinishSession();                /* close down the front end */
  733. XTFinishSession();                /* close down the transport */
  734. Xwritegames(rc.gfile,rc.gbackup,rc.pfile);    /* save the games in a file */
  735. Xldbexit(STAT_NORM);
  736. X}
  737. X
  738. X
  739. X/*----------------------------------------------------------------------
  740. X *    ldbsignal -- signal handler
  741. X *
  742. X * This function is called when the user hits the interrupt character.
  743. X * It is currently a very simple function; it saves the games in the
  744. X * INTGFILE file, closes down the front end and the transport, and exits.
  745. X *----------------------------------------------------------------------
  746. X */
  747. X
  748. Xldbsignal()
  749. X{
  750. X
  751. Xwritegames(INTGFILE,NULL,INTPFILE);
  752. XFeFinishSession();    /* let front-end close down gracefully */
  753. XTFinishSession();    /* let transport close down gracefully */
  754. Xfprintf(stderr,"WARNING: games saved in %s and %s\n",INTGFILE,INTPFILE);
  755. Xldbexit(STAT_ABORT);
  756. X}
  757. X
  758. X
  759. X/*----------------------------------------------------------------------
  760. X *    usage -- print command line options.
  761. X *
  762. X * This function prints a help message.  This can be either in the
  763. X * short or long format.  The short format merely lists all options
  764. X * in a very dense format.  The long format prints each option on
  765. X * a separate line, along with a short explanation of its purpose.
  766. X *----------------------------------------------------------------------
  767. X */
  768. X
  769. Xusage(help)
  770. Xint help;        /* 0 = short message, 1 = long message */
  771. X{
  772. Xstruct opt *o;
  773. Xint l;
  774. X
  775. Xprintf("options:\n");
  776. Xif (help) {        /* print out the whole shootin' match */
  777. X    for (o = options; o->name != NULL; o++)
  778. X        printf("\t-%s%s%s\n",o->name,o->args,o->help);
  779. X#if PATCHLEVEL == 0
  780. X    printf("\nLdb version %d.%d by Perry R. Ross.  Mail comments\n",
  781. X        VERSION,REVISION);
  782. X#else
  783. X    printf(
  784. X    "\nLdb version %d.%d (patch %d) by Perry R. Ross.  Mail\ncomments",
  785. X    VERSION,REVISION,PATCHLEVEL);
  786. X#endif
  787. X    printf("or suggestions to \"%s\".\n",AUTHOR_EMAIL);
  788. X    }
  789. Xelse {
  790. X    l = 0;
  791. X    printf("\t");
  792. X    for (o = options; o->name != NULL; o++) {
  793. X        if ( (l += (strlen(o->name)+strlen(o->args)+3)) > 55) {
  794. X            printf("\n\t");
  795. X            l = 0;
  796. X            }
  797. X        printf("[-%s%s] ",o->name,o->args);
  798. X        }
  799. X    printf("\n\n");
  800. X    }
  801. X}
  802. X
  803. X
  804. X/*----------------------------------------------------------------------
  805. X *    remotestart -- start a game between two other people
  806. X *
  807. X * This function tells a user to start a game with another user.
  808. X * Neither user needs to be the one running remotestart; although
  809. X * this would work, -start is a more efficient way to do that.
  810. X * Remotestart could be used to start games between opponents in
  811. X * a tournament, or to set up a pickup game facility, where people
  812. X * wanting to play would mail to a central machine, which would
  813. X * pair players by some criteria (such as ability) and start a
  814. X * game between them.
  815. X *----------------------------------------------------------------------
  816. X */
  817. X
  818. Xremotestart(u1,u2,flags,match)
  819. Xchar *u1, *u2;
  820. Xint flags;
  821. Xint match;
  822. X{
  823. Xstruct packet p;
  824. Xchar colors[4];
  825. Xchar mbuf[8];
  826. X
  827. Xp.version = LDB_VER;        /* fill in a packet */
  828. Xp.timestamp = time( (long *)0);    /* give it a timestamp */
  829. Xp.gameid = "REMOTESTART";    /* give it a phony gameid */
  830. Xp.opcode = RSTART;        /* remote start opcode */
  831. Xp.name = NULL;            /* we don't need to send a name */
  832. Xp.addr = u2;            /* put opponent's address in packet */
  833. Xp.comment = NULL;        /* don't have a comment */
  834. Xp.comment2 = NULL;
  835. Xp.seq = 1;            /* start with sequence number 1 */
  836. Xp.notify = notify;        /* send notify address if any */
  837. Xclearmvs(p.mvs);        /* no moves to send */
  838. Xsprintf(colors,"%c%c",cr_mycolor,cr_opcolor);
  839. Xp.colors = colors;
  840. Xp.dir = (cr_mydir > 0) ? "up" : "down";
  841. Xp.autodbl = NULL;
  842. Xp.jacoby = (flags & F_JACOBY) ? "yes" : NULL;        /* jacoby rule? */
  843. Xp.crawford = (flags & F_CRAWFORD) ? "yes" : NULL;    /* crawford rule? */
  844. Xp.european = (flags & F_EUROPE) ? "yes" : NULL;        /* european scoring? */
  845. Xp.perm = (flags & F_PERM) ? "yes" : NULL;        /* perm game? */
  846. Xif (match > 0) {        /* match play */
  847. X    sprintf(mbuf,"%d",match);    /* make it a string */
  848. X    p.match = mbuf;            /* and put it in the packet */
  849. X    }
  850. Xelse
  851. X    p.match = NULL;            /* not a match, omit this field */
  852. Xp.gameptr = NULL;        /* just in case */
  853. XTSendPacket(&p,u1);        /* send the remote start command to u1 */
  854. X}
  855. X
  856. X
  857. X/*----------------------------------------------------------------------
  858. X *    optlookup -- find command line option in options table
  859. X *
  860. X * This function looks up a command line switch in the options table,
  861. X * returning the index into options[].  It returns -1 if the option
  862. X * was not found, and -2 if the option was ambiguous.  Options may be
  863. X * abbreviated to the shortest unique substring of the option.
  864. X *----------------------------------------------------------------------
  865. X */
  866. X
  867. Xoptlookup(optstr)
  868. Xchar *optstr;
  869. X{
  870. Xint i, j, l, n;
  871. X
  872. Xn = 0;
  873. Xif ( (l = strlen(optstr)) == 0)            /* empty option string */
  874. X    return(-1);                /* that's no good */
  875. Xfor (i = 0; options[i].name != NULL; i++)    /* look for arg */
  876. X    if (strncmp(options[i].name,optstr,l) == 0) {    /* found it */
  877. X        j = i;                /* remember index */
  878. X        n++;                /* count how many */
  879. X        }
  880. Xif (n == 0)                    /* didn't find it */
  881. X    return(-1);                /* return error */
  882. Xif (n > 1)                    /* found more than 1 match */
  883. X    return(-2);                /* return error */
  884. Xreturn(j);                    /* return the index */
  885. X}
  886. END_OF_FILE
  887. if test 35683 -ne `wc -c <'main.c'`; then
  888.     echo shar: \"'main.c'\" unpacked with wrong size!
  889. fi
  890. # end of 'main.c'
  891. fi
  892. echo shar: End of archive 6 \(of 12\).
  893. cp /dev/null ark6isdone
  894. MISSING=""
  895. for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
  896.     if test ! -f ark${I}isdone ; then
  897.     MISSING="${MISSING} ${I}"
  898.     fi
  899. done
  900. if test "${MISSING}" = "" ; then
  901.     echo You have unpacked all 12 archives.
  902.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  903. else
  904.     echo You still need to unpack the following archives:
  905.     echo "        " ${MISSING}
  906. fi
  907. ##  End of shell archive.
  908. exit 0
  909.  
  910. exit 0 # Just in case...
  911.