home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / odoors34.arj / RAVOTE.C < prev    next >
C/C++ Source or Header  |  1992-05-07  |  24KB  |  500 lines

  1. /*          ╔════════════════════════════════════════════════════╗
  2.  *          ║   ┌─────┐                                          ║
  3.  *          ║   │     │┌────┐┌───┐┌──┐                           ║
  4.  *          ║   │     ││    │├───┘│  │                           ║
  5.  *          ║   └─────┘├────┘└─── │  ├────┐                      ║
  6.  *          ║          │             │    │┌───┐┌───┐┌─── ┌──    ║
  7.  *          ║                        │    ││   ││   ││    └──┐   ║
  8.  *          ║                        └────┘└───┘└───┘│     ──┘   ║
  9.  *          ║                    ────────────                    ║
  10.  *          ║                    Version 3.40         DEMO DOOR  ║
  11.  *          ╚════════════════════════════════════════════════════╝
  12.  *           (C) Copyright 1992, Brian Pirie. All Rights Reserved.
  13.  *
  14.  * ┌──────────┐
  15.  * │ RAVOTE.C │
  16.  * └──────────┘
  17.  *      RAVote is a sample door written in OpenDoors. This is arelatively
  18.  *  simple door that allows BBS users to vote anonymously on various topics,
  19.  *  entered by other users. Users are able to view the results of any of the
  20.  *  topics, only if they have already voted, and may only vote on each topic
  21.  *  once. The door automatically uses ANSI graphics if available, and should
  22.  *  work with any BBS system that produces a DORINFO1.DEF file. On the command-
  23.  *  line you can specify a path to this file if it is not in the current
  24.  *  directory. The Sysop (automatically detected by comparing user name to sysop
  25.  *  name) also has the option of deleting existing questions.
  26.  *
  27.  *      RAVote, of course, also provides all the features available in
  28.  *  any OpenDoors door (whithout any extra effort on the part of the
  29.  *  programmer), such as sysop chatting & paging, full status line, shell to
  30.  *  dos, time adjusting, hangup & lockout, and other function keys. It does,
  31.  *  of course, properly monitor carrier detect & user inactivity and user time
  32.  *  left. Ravote also runs very quickly and reliably & uses BIOS screen
  33.  *  updating for maximum compatibility with DesqView & other such environments.
  34.  *  RAVote will also function perfectly normally in local mode, except that
  35.  *  if you wish to use Hangup features, you must check the errorlevel returned
  36.  *  by the door. Hangup still functions normally in remote mode.
  37.  *
  38.  *      RaVote will exit with one of the following errorlevels:
  39.  *                        0 - Critical Door error (no fossil, etc.)
  40.  *                        1 - Carrier lost, user off-line
  41.  *                        2 - Sysop terminated call, user off-line
  42.  *                        3 - User time used up, user STILL ON-LINE
  43.  *                        4 - Keyboard inactivity timeout, user off-line
  44.  *                        5 - Sysop dropped user back to BBS, user ON-LINE
  45.  *                       10 - User chose to return to BBS
  46.  *                       11 - User chose to logoff, user off-line
  47.  *                       12 - Critical RAVote error
  48.  *
  49.  *      RaVote may be recompiled or changed as you wish, under the conditions
  50.  *  of the OpenDoors licence (ie, if you haven't registered, you can not
  51.  *  distribute any doors compiled in OpenDoors, and may only use OpenDoors for
  52.  *  a three-week period). If you wish to compile RaVote, as with any OpenDoors
  53.  *  door, all you have to do is make sure OPENDOOR.H is present in the default
  54.  *  directory, and that Turbo C is configured to compile in the OpenDoors
  55.  *  library file. For more information, please see the accompanying
  56.  *  documentation.
  57.  */
  58.  
  59.  
  60. #include <conio.h>
  61. #include <io.h>
  62. #include <fcntl.h>
  63. #include <sys\stat.h>
  64.  
  65. #include"opendoor.h"                   /* Must be included in all doors */
  66.  
  67.  
  68. #define MENU_COLOR 0x0b                /* Definitions for ANSI colors, if used */
  69. #define INPUT_COLOR 0x0e
  70. #define TITLE_COLOR 0x0c
  71. #define LIST_COLOR 0x0a
  72.  
  73.  
  74. int    main(int argc,char *argv[]);    /* Function prototype declarations */
  75. void   choose_topic(int mode);         /* Allows user to choose a question */
  76. void   display_results(void);          /* Displays the results of a question */
  77. void   vote(void);                     /* Places the user's vote */
  78. int    add_answer(void);               /* Adds a new answer to the question */
  79. void   save_file(void);                /* Saves the RAVOTE.BBS file */
  80. void   delete_question(void);          /* Removes a question from the file */
  81. void   main_menu(void);                /* Displays the RAVote main menu */
  82.  
  83.  
  84. struct                                 /* RAVOTE.BBS file format */
  85.    {
  86.    int    num_questions;               /* Number of questions in the file */
  87.    char   quest_title[20][60],         /* The "Title" of each question */
  88.           quest_by[20][36],            /* Who wrote each question */
  89.           quest_text[20][60];          /* The actual question itself */
  90.    int    quest_num_ans[20];           /* The number of answers to each quest. */
  91.    char   quest_answers[20][20][60];   /* The possible answers for each quest. */
  92.    int    total_votes[20],             /* # of times quest. has been voted on */
  93.           votes[20][20],               /* # of votes each chioce has recieved */
  94.           num_users;                   /* Number of users who have used door */
  95.    char   user[200][36],               /* Each user's name */
  96.           voted[200][20];              /* Has the user voted on each question? */
  97.    } file;
  98.  
  99.                                        /* Variables used by the door */
  100. int handle, counter, usernum, topic, choice, key, sysop;
  101. char string[80];
  102.  
  103.  
  104. int main(int argc,char *argv[])
  105.     {
  106.                                        /* Tell OpenDoors your name, */
  107.                                        /* registration key & your door's */
  108.                                        /* name at the beginning of any */
  109.                                        /* program */
  110.     strcpy(od_registered_to,"[Unregistered]");
  111.     od_registration_key=000000000000;
  112.     strcpy(od_program_name,"RAVote 3.40");
  113.  
  114.  
  115.                                        /* get path to door files from command */
  116.                                        /* line, if any */
  117.     if(argc>1) strncpy(od_control.info_path,argv[1],59);
  118.  
  119.                                        /* display copyright notice */
  120.                                        /* note that since this is the first */
  121.                                        /* call to any OpenDoors function, the */
  122.                                        /* initialization is also done at this */
  123.                                        /* time (such as reading door files, */
  124.                                        /* opening fossil, seting up od_control, */
  125.                                        /* and so on). If you wish to have */
  126.                                        /* access to or to change any of these */
  127.                                        /* values, make sure that you call */
  128.                                        /* od_init() before you do anything */
  129.                                        /* else in your program */
  130.     od_disp_str("[RAVote 3.40 - (C) Copyright 1992, Brian Pirie - All rights Reserved]\n\r");
  131.  
  132.  
  133.                                        /* Cause OpenDoors to call the */
  134.                                        /* save_file() function before exiting, */
  135.                                        /* under any circumstances. This way, */
  136.                                        /* the data file will be saved, even */
  137.                                        /* if the user looses connection. */
  138.     od_control.od_before_exit=save_file;
  139.  
  140.                                        /* Open the RAVOTE.BBS data file */
  141.     if((handle=open("ravote.bbs",O_RDONLY|O_BINARY))==-1)
  142.        {                               /* Create the file if it does not exist */
  143.        handle=open("ravote.bbs",O_RDWR|O_BINARY|O_CREAT,S_IWRITE|S_IREAD);
  144.        file.num_questions=0;           /* Blank file to zero questions, and */
  145.        file.num_users=0;               /* Zero users */
  146.        write(handle,&file,sizeof(file));
  147.        }
  148.     else
  149.        read(handle,&file,sizeof(file));/* Read data from file if it exists */
  150.     close(handle);                     /* Close the file again */
  151.  
  152.                                        /* Search for user in RAVOTE.BBS */
  153.     for(usernum=0;usernum<file.num_users;++usernum)
  154.        if(strcmp(file.user[usernum],od_control.user_name)==0) break;
  155.  
  156.     if(usernum==file.num_users)        /* If user hasn't used RAVote before */
  157.        {                               /* Add him to the file */
  158.        if(++file.num_users>200) od_exit(12,FALSE);
  159.        strcpy(file.user[usernum],od_control.user_name);
  160.        for(counter=0;counter<20;++counter)
  161.           file.voted[usernum][counter]=FALSE;
  162.        }
  163.                                        /* Check if the user is the sysop */
  164.     sysop=strcmp(od_control.user_name,od_control.sysop_name)==0;
  165.  
  166.     do
  167.        {
  168.        main_menu();                    /* Display the main menu */
  169.  
  170.        od_set_attrib(INPUT_COLOR);     /* Display prompt with time left to user */
  171.        od_printf("Select Command (%d mins)\n\r",od_control.caller_timelimit);
  172.        od_set_attrib(MENU_COLOR);
  173.  
  174.        switch(key=od_get_key(TRUE))    /* Get user's choice */
  175.           {
  176.           case 'v': case 'V':          /* If user hit V key (upper or lower */
  177.              do                        /*                    case) */
  178.                 {
  179.                 choose_topic(FALSE);   /* Allow user to choose question from */
  180.                                        /* those he hasn't voted on yet */
  181.  
  182.                                        /* If valid topic # entered */
  183.                 if(topic>=0 && topic<=19)
  184.                    {                   /* Display the question to the user */
  185.                    od_set_attrib(TITLE_COLOR);
  186.                    od_disp_str("\n\r\n\r");od_clr_scr();
  187.                    od_disp_str(file.quest_text[topic]);
  188.                    od_disp_str("\n\r");
  189.                    od_set_attrib(LIST_COLOR);
  190.  
  191.                                        /* Display possible answers to user */
  192.                    for(counter=0;counter<file.quest_num_ans[topic];++counter)
  193.                       {
  194.                       od_printf("    %2d.) %s\n\r",counter+1,file.quest_answers[topic][counter]);
  195.                       }
  196.                                        /* Get user's choice */
  197.                    od_set_attrib(MENU_COLOR);
  198.                    od_disp_str("\n\rSelect answer, [O] for other, or [Enter] to pass: ");
  199.  
  200.                                        /* Allow user to input choice of up to */
  201.                                        /* two characters */
  202.                    od_set_attrib(INPUT_COLOR);
  203.                    od_input_str(string,2,32,127);
  204.                    od_set_attrib(MENU_COLOR);
  205.                    choice=atoi(string)-1;
  206.  
  207.                                        /* If user chose "Other" option */
  208.                    if(string[0]=='o' || string[0]=='O')
  209.                       {                /* If room to add another answer */
  210.                       if(file.quest_num_ans[topic]<20)
  211.                          {             /* Allow user to add his answer to quest */
  212.                          od_disp_str("\n\r\n\rWhat is your \"Other\" answer?\n\r");
  213.                          if(add_answer())
  214.                             {          /* If user actually added answer */
  215.                             choice=file.quest_num_ans[topic]-1;
  216.                             vote();    /* record his vote */
  217.                             }
  218.                          }
  219.                       else             /* If there is no room for more answers */
  220.                          {             /* Let the user know */
  221.                          od_disp_str("\n\r\n\rThis question already has 20 answers!\n\r");
  222.                          od_disp_str("Press any key to continue...\n\r");
  223.                          od_get_key(TRUE);
  224.                          }
  225.                       }
  226.  
  227.                    else                /* If user voted for an existing */
  228.                       {                /* choice */
  229.                       if(choice>=0 && choice<=file.quest_num_ans[topic])
  230.                          {
  231.                          vote();       /* record their vote */
  232.                          }
  233.                       }
  234.                    }
  235.  
  236.                 } while(topic!=-1);    /* Loop until user is finished voting */
  237.              break;
  238.  
  239.  
  240.           case 'r': case 'R':          /* If user wants to display results */
  241.              for(;;)
  242.                 {
  243.                 choose_topic(TRUE);    /* Allow user to choose a topic */
  244.                 if(topic==-1) break;   /* Exit loop if abort result display */
  245.                 display_results();     /* Display results of question */
  246.                 }
  247.              break;
  248.  
  249.  
  250.           case 'a': case 'A':          /* If adding a new question */
  251.              od_clr_scr();             /* Clear the screen (if mode turned on) */
  252.              if(file.num_questions<20) /* If there is room for another quest. */
  253.                 {                      /* Store user's name as author of quest. */
  254.                 strcpy(file.quest_by[file.num_questions],od_control.user_name);
  255.                 file.total_votes[file.num_questions]=0;
  256.                                        /* Get question title from user */
  257.                 od_disp_str("\n\r\n\rWhat is the title of your question?\n\r > ");
  258.                 od_set_attrib(INPUT_COLOR);
  259.                 od_input_str(string,59,32,127);
  260.                 od_set_attrib(MENU_COLOR);
  261.                 strcpy(file.quest_title[file.num_questions],string);
  262.  
  263.                 if(strlen(string)!=0)  /* If user didn't abort */
  264.                    {                   /* Get the question itself from user */
  265.                    od_disp_str("\n\rWhat is your question?\n\r > ");
  266.                    od_set_attrib(INPUT_COLOR);
  267.                    od_input_str(string,59,32,127);
  268.                    od_set_attrib(MENU_COLOR);
  269.                    strcpy(file.quest_text[file.num_questions],string);
  270.                                        /* If user didn't abort */
  271.                    if(strlen(string)!=0)
  272.                       {                /* Get the user's answers */
  273.                       od_disp_str("\n\rNow, enter the possible answers to your question:\n\r");
  274.                       topic=file.num_questions;
  275.                       file.quest_num_ans[topic]=0;
  276.                       while(add_answer());
  277.  
  278.                                        /* confirm question creation */
  279.                       od_set_attrib(MENU_COLOR);
  280.                       od_disp_str("Do you wish to save this question? (Y/N) ");
  281.  
  282.                                        /* get yes or no from user */
  283.                       do choice=od_get_key(TRUE); while(choice!='Y' && choice!='N' && choice!='y' && choice!='n');
  284.  
  285.                       if(choice=='y' || choice=='Y')
  286.                          file.num_questions++;
  287.                       }
  288.                    }
  289.                 }
  290.              else                      /* If no room for a new question, */
  291.                 {                      /*  let the user know */
  292.                 od_disp_str("Sorry, RAVote has a limit of 20 questions.\n\r");
  293.                 od_disp_str("Press any key to continue...\n\r\n\r");
  294.                 od_get_key(TRUE);
  295.                 }
  296.  
  297.              break;
  298.  
  299.  
  300.           case 'p': case 'P':          /* If user wants to page the sysop */
  301.              od_page();                /* OpenDoors takes care of the rest */
  302.              break;
  303.  
  304.           case 'd': case 'D':          /* If user chose delete key */
  305.              if(sysop)                 /* If it is the sysop */
  306.                 {
  307.                 od_clr_scr();          /* Clear the screen */
  308.                                        /* ask which question to delete */
  309.                 od_disp_str("Please enter question number to delete: ");
  310.                 od_set_attrib(INPUT_COLOR);
  311.                 od_input_str(string,2,'0','9');
  312.                 topic=atoi(string)-1;
  313.                 od_set_attrib(MENU_COLOR);
  314.                                        /* If valid choice */
  315.                 if(topic>=0 && topic<file.num_questions)
  316.                    {                   /* Confirm question deletion */
  317.                    od_printf("\n\r\n\r Delete: %s\n\r\n\r",file.quest_title[topic]);
  318.                    od_set_attrib(TITLE_COLOR);
  319.                    od_disp_str("Are You Sure? (Y/N)\n\r");
  320.                    od_set_attrib(MENU_COLOR);
  321.  
  322.                    do choice=od_get_key(TRUE); while(choice!='Y' && choice!='N' && choice!='y' && choice!='n');
  323.  
  324.                    if(choice=='y' || choice=='Y')
  325.                       {                /* If sysop agrees, it's gone! */
  326.                       delete_question();
  327.                       }
  328.                    }
  329.                 }
  330.           }                            /* Loop until quit to BBS or logoff */
  331.        } while(key!='Q' && key!='q' && key!='G' && key!='g');
  332.  
  333.     if(key=='G' || key=='g')           /* If user wishsed to log off */
  334.        {                               /* Say goodbye */
  335.        od_printf("\n\rGoodbye from %s...\n\r",od_control.system_name);
  336.        od_exit(11,TRUE);               /* Let OpenDoors take care of the rest */
  337.        }
  338.     else
  339.        {                               /* Acknoledge return to BBS */
  340.        od_printf("\n\rReturning you to %s...\n\r",od_control.system_name);
  341.        od_exit(10,FALSE);              /* Again OpenDoors does the rest */
  342.        }
  343.  
  344.     return(0);
  345.     }
  346.  
  347.  
  348. void save_file(void)                   /* Function to save RAVOTE.BBS file */
  349.    {                                   /* (called before door termination) */
  350.    handle=open("ravote.bbs",O_WRONLY|O_BINARY);
  351.    write(handle,&file,sizeof(file));
  352.    close(handle);
  353.    }
  354.  
  355.  
  356. int add_answer(void)                   /* Function to add answer to file */
  357.    {                                   /* Check for room to add answer */
  358.    if(file.quest_num_ans[topic]>=20) return(FALSE);
  359.  
  360.    od_set_attrib(MENU_COLOR);          /* Get user's answer */
  361.    od_printf(" %2d> ",file.quest_num_ans[topic]+1);
  362.    od_set_attrib(INPUT_COLOR);
  363.    od_input_str(string,59,32,127);
  364.    if(strlen(string)==0) return(FALSE);
  365.                                        /* If no abort, add to question */
  366.    file.votes[topic][file.quest_num_ans[topic]]=0;
  367.    strcpy(file.quest_answers[topic][file.quest_num_ans[topic]++],string);
  368.    return(TRUE);
  369.    }
  370.  
  371.  
  372.  
  373. void choose_topic(int mode)            /* function to let user to choose quest */
  374.    {
  375.    register char displayed=FALSE;
  376.  
  377.    for(;;)
  378.       {
  379.       od_set_attrib(TITLE_COLOR);
  380.       od_clr_scr();                    /* Clear the screen */
  381.       od_disp_str("Choose A Topic:\n\r");
  382.       od_set_attrib(LIST_COLOR);
  383.                                        /* display questions */
  384.       for(counter=0;counter<file.num_questions;++counter)
  385.          {                             /* if question should be displayed */
  386.          if(file.voted[usernum][counter]==mode)
  387.             {
  388.             displayed=TRUE;            /* spit 'er out! */
  389.             od_printf("    %d.) %s\n\r",counter+1,file.quest_title[counter]);
  390.             }
  391.          }
  392.                                        /* if no topics were displayed... */
  393.       if(!displayed) od_disp_str("\n\r    No Topics to choose from.\n\r\n\r");
  394.  
  395.       od_set_attrib(MENU_COLOR);
  396.  
  397.       od_disp_str("Select topic, or [Enter] to return to main menu: ");
  398.  
  399.       od_set_attrib(INPUT_COLOR);
  400.  
  401.       od_input_str(string,2,'0','9');  /* Get user's choice */
  402.  
  403.       topic=atoi(string)-1;            /* Convert string to number */
  404.  
  405.       if(topic==-1) return;            /* If user aborted, exit */
  406.                                        /* if valid question, exit */
  407.       if(topic<file.num_questions && topic>=0 && file.voted[usernum][topic]==mode) return;
  408.       }
  409.    }
  410.  
  411.  
  412.  
  413. void display_results(void)             /* function to display results of quest */
  414.    {
  415.    od_set_attrib(TITLE_COLOR);         /* display the header */
  416.    od_clr_scr();
  417.    od_printf("%s\n\r(Created by: %s)\n\r",file.quest_title[topic],file.quest_by[topic]);
  418.  
  419.    od_set_attrib(LIST_COLOR);
  420.                                        /* loop through each answer */
  421.    for(counter=0;counter<file.quest_num_ans[topic];++counter)
  422.                                        /* display answer with # & % of votes */
  423.    od_printf("  %-3d  %3d%%   %s\n\r",file.votes[topic][counter],(file.votes[topic][counter]*100)/file.total_votes[topic],file.quest_answers[topic][counter]);
  424.  
  425.    od_set_attrib(MENU_COLOR);
  426.                                        /* Wait for user to hit a key */
  427.    od_disp_str("\n\rPress any key to continue...");
  428.    od_get_key(TRUE);
  429.    od_disp_str("\n\r\n\r");
  430.    }
  431.  
  432.  
  433. void vote(void)                        /* function to record user's vote */
  434.    {
  435.    file.voted[usernum][topic]=TRUE;    /* stop him from voting on it again */
  436.    ++file.total_votes[topic];          /* increase total number of votes */
  437.    ++file.votes[topic][choice];        /* add user's vote */
  438.    display_results();                  /* show user results of question to date */
  439.    }
  440.  
  441.  
  442. void delete_question(void)             /* function to delete a question */
  443.    {                                   /* decrement total # of questions */
  444.    if(topic==--file.num_questions) return;
  445.                                        /* shuffle all other questions up one */
  446.    memcpy(file.quest_title[topic],file.quest_title[topic+1],60*(19-topic));
  447.    memcpy(file.quest_by[topic],file.quest_by[topic+1],36*(19-topic));
  448.    memcpy(file.quest_text[topic],file.quest_text[topic+1],60*(19-topic));
  449.    memcpy(&file.quest_num_ans[topic],&file.quest_num_ans[topic+1],2*(19-topic));
  450.    memcpy(file.quest_answers[topic],file.quest_answers[topic+1],1200*(19-topic));
  451.    memcpy(&file.total_votes[topic],&file.total_votes[topic+1],2*(19-topic));
  452.    memcpy(file.votes[topic],file.votes[topic+1],40*(19-topic));
  453.    for(counter=0;counter<file.num_users;++counter)
  454.       memcpy(&file.voted[counter][topic],&file.voted[counter][topic+1],19-topic);
  455.    }
  456.  
  457.  
  458.  
  459. void main_menu(void)
  460.    {
  461.    od_clear_keybuffer();               /* Clear any pending keys in buffer */
  462.    od_clr_scr();                       /* Clear screen */
  463.  
  464.    if(od_send_file("RAVOTE"))
  465.       {
  466.       return;
  467.       }
  468.  
  469.    else if(od_control.caller_ansi)     /* Display ANSI title if ANSI mode is on */
  470.       {
  471.       od_set_attrib(TITLE_COLOR);
  472.       od_disp_str("\n\r┌───────────────────────────────────┐\n\r│ ");
  473.       od_set_attrib(LIST_COLOR);
  474.       od_disp_str("RAVote ■ OpenDoors 3.40 Demo Door ");
  475.       od_set_attrib(TITLE_COLOR);
  476.       od_disp_str("│\n\r└───────────────────────────────────┘\n\r");
  477.       od_disp_str("     Copyright 1992, Brian Pirie\n\r");
  478.       }
  479.    else                                /* Display ASCII title if ANSI is off */
  480.       {
  481.       od_disp_str("\n\r+-----------------------------------+\n\r");
  482.       od_disp_str("| RAVote - OpenDoors 3.40 Demo Door |\n\r");
  483.       od_disp_str("+-----------------------------------+\n\r");
  484.       od_disp_str("     Copyright 1992, Brian Pirie\n\r");
  485.       }
  486.  
  487.    od_set_attrib(MENU_COLOR);
  488.                                        /* Display main menu (note that the */
  489.                                        /* delete booth option is only displayed */
  490.                                        /* to the sysop) */
  491.    od_disp_str("\n\r       [V] Vote on a Topic\n\r");
  492.    od_disp_str("       [R] View results\n\r");
  493.    od_disp_str("       [A] Add a new question\n\r");
  494.    od_disp_str("       [P] Page Sysop\n\r");
  495.    if(sysop) od_disp_str("       [D] Delete Booth\n\r");
  496.    od_disp_str("       [G] Goodbye (Logoff)\n\r");
  497.    od_disp_str("       [Q] Return to BBS\n\r\n\r");
  498.  
  499.    }
  500.