summaryrefslogblamecommitdiffstats
path: root/mbbsd/menu.c
blob: bd598cea8d3ba289d69f5d42dca01be00ebcef23 (plain) (tree)
1
2
3
4
5
6
7
8
9
          

                

                                             

                              
                                                                      
                                   
 
                             

                               
                                  
 

                                        
           
           











                                         
    
                                             
 




                                                
                                   
                
                  
                                          
                                 

                 
 
                     
            



                                                       

     
                              
                                   
                                    
                                             
                                 
                                                

                      

                                                         

                                        
         
     
      
















                                                              
                                              

                         
                                   
 
                            
            



                           



                       
                   

                
                      
 

                                     
                                            

                            
                                     



                                          

                                 





                                          
                                

                              
     
 

 

                    









                                             





              






                                                  
                                              
                                                                              




                                      
                                   























                                                                               


                            














                                               

                  
                                    
                                       




                 
                         


                                                                      

                               




                                                            
                                                           

                                                                    


                                         
 
 
  
                           

                                                                        

                                       
   
                                                             
    
                  
 

          






                                                                              





                                                               
 





                                                                             








                                                                       
     


                                                
                            
                                                                          


                                                          
                     



                                            

 
                




                                                               
          
                                              


                          
 
                     
 


                                                                                   
                                   
                                   
       
 
                      
                             
                                        
                                                                                               
                        

            



                 
 
      
                                                                  
                                                               







                                                
                                                                               
 
                                          
                                     
                        
 
                        
                             
                                
 



                                 
                                           
 
                  


                         

                      

                                                     
                            

                           





















                                         
                                                        









                              
                                                        




                                 
                                              
                                                       
                                                              



                                             
                                                                             





                                 
                                   

                      
                                                       


















                                                                       

                                         
                                   


                                               
 
                                                    
                                                  
                                                         




                                      


                                         

         







                               
                                                           



                                         
                                           
                          




                                                  
                                                 


                                                 
                                                     




                 
                                                                              
                                                                  
 
                                   
                                       













                                                                              



                   
                                      
                                                                
                                                                  
                                                           
                                                           
                               
                                                                    
         

                                                             
                                                                         

                                                               




                                                                   
                                      
                                                             
                                                       



                                                       
                                                                          
                                                         
                                                

                                                       
                 


                                                           
      
                                                             













                                
                                      


                                                             
                                                             



                                                             















                                                                 
                           


             




                
 
               
                                      




                                                                                    
                  
                                                             
     
                                                             
      
                                                                         
             
                                                                   
                                                               
                


                   


























                                

                            







                                                          




                                                

      






                                                              
                                                            





                                                            

                                                            


















                                                            
                   
                                     

                                                          

                                              
                    
                                                     

                
                                                              
      
                                                      
                                                          
                                                        


                                                                


               
                               
                                                          

                                                          

                
                                                        



                    
                                       










                                                                   












                                                                                             
                                                                  









                                                                  
                     
                                                                             


             
                      
                                                        


             
                        
                       

                   
                                      
                                                              








                                                                      


                   
                                       








                                                                                                         



                        
                                                    


             
                                   
 
                                                                          



                                                                 


                   



                                                                             
                                                  


             

               

           
 
                                                


             

          
 
                                              


             

          
 
                                               


             

          
 
                                               


             

         
 
                                              


             

               
 
                                                 


             

               
 
                                               

             
 
/* $Id$ */
#include "bbs.h"

// UNREGONLY 改為由 BASIC 來判斷是否為 guest.

#define CheckMenuPerm(x) \
    ( (x == MENU_UNREGONLY)? \
      ((!HasUserPerm(PERM_BASIC) || HasUserPerm(PERM_LOGINOK))?0:1) :\
    ((x) ? HasUserPerm(x) : 1))

/* help & menu processring */
static int      refscreen = NA;
extern char    *boardprefix;
extern struct utmpfile_t *utmpshm;

static const char *title_tail_msgs[] = {
    "看板",
    "系列",
    "文摘",
};
static const char *title_tail_attrs[] = {
    ANSI_COLOR(37),
    ANSI_COLOR(32),
    ANSI_COLOR(36),
};
enum {
    TITLE_TAIL_BOARD = 0,
    TITLE_TAIL_SELECT,
    TITLE_TAIL_DIGEST,
};

void
showtitle(const char *title, const char *mid)
{
    /* we have to...
     * - display title in left, cannot truncate.
     * - display mid message, cannot truncate
     * - display tail (board info), if possible.
     */
    int llen, rlen, mlen, mpos = 0;
    int pos = 0;
    int tail_type;
    const char *mid_attr = ANSI_COLOR(33);
    int is_currboard_special = 0;
    char buf[64];


    /* prepare mid */
#ifdef DEBUG
    {
    sprintf(buf, "  current pid: %6d  ", getpid());
    mid = buf; 
    mid_attr = ANSI_COLOR(41;5);
    }
#else
    if (ISNEWMAIL(currutmp)) {
    mid = "    你有新信件    ";
    mid_attr = ANSI_COLOR(41;5);
    } else if ( HasUserPerm(PERM_ACCTREG) ) {
    // TODO cache this value?
    int nreg = regform_estimate_queuesize();
    if(nreg > 100)
    {
        nreg -= (nreg % 10);
        sprintf(buf, "  超過 %03d 篇未審核  ", nreg);
        mid_attr = ANSI_COLOR(41;5);
        mid = buf;
    }
    }
#endif

    /* prepare tail */
    if (currmode & MODE_SELECT)
    tail_type = TITLE_TAIL_SELECT;
    else if (currmode & MODE_DIGEST)
    tail_type = TITLE_TAIL_DIGEST;
    else
    tail_type = TITLE_TAIL_BOARD;

    if(currbid > 0)
    {
    assert(0<=currbid-1 && currbid-1<MAX_BOARD);
    is_currboard_special = (
        (getbcache(currbid)->brdattr & BRD_HIDE) &&
        (getbcache(currbid)->brdattr & BRD_POSTMASK));
    }

    /* now, calculate real positioning info */
    llen = strlen(title);
    mlen = strlen(mid);
    mpos = (t_columns -1 - mlen)/2;

    /* first, print left. */
    clear();
    outs(TITLE_COLOR "【");
    outs(title);
    outs("】");
    pos = llen + 4;

    /* print mid */
    while(pos++ < mpos)
    outc(' ');
    outs(mid_attr);
    outs(mid);
    pos += mlen;
    outs(TITLE_COLOR);

    /* try to locate right */
    rlen = strlen(currboard) + 4 + 4;
    if(currboard[0] && pos+rlen < t_columns)
    {
    // print right stuff
    while(pos++ < t_columns-rlen)
        outc(' ');
    outs(title_tail_attrs[tail_type]);
    outs(title_tail_msgs[tail_type]);
    outs("《");

    if (is_currboard_special)
        outs(ANSI_COLOR(32));
    outs(currboard);
    outs(title_tail_attrs[tail_type]);
    outs("》" ANSI_RESET "\n");
    } else {
    // just pad it.
    while(pos++ < t_columns)
        outc(' ');
    outs(ANSI_RESET "\n");
    }

}

int TopBoards(void);

/* Ctrl-Z Anywhere Fast Switch, not ZG. */
static char zacmd = 0;

// ZA is waiting, hurry to the meeting stone!
int 
ZA_Waiting(void)
{
    return (zacmd != 0);
}

void
ZA_Drop(void)
{
    zacmd = 0;
}

// Promp user our ZA bar and return for selection.
int
ZA_Select(void)
{
    int k;

    // TODO refresh status bar?
    vs_footer(VCLR_ZA_CAPTION " ★快速切換: ",
        " (b)文章列表 (c)分類 (t)熱門 (f)我的最愛 (m)信箱 (u)使用者名單");
    k = vkey();

    if (k < ' ' || k >= 'z') return 0;
    k = tolower(k);

    if(strchr("bcfmut", k) == NULL)
    return 0;

    zacmd = k;
    return 1;
}

// The ZA processor, only invoked in menu.
void 
ZA_Enter(void)
{
    char cmd = zacmd;
    while (zacmd)
    {
    cmd = zacmd;
    zacmd = 0;

    // All ZA applets must check ZA_Waiting() at every stack of event loop.
    switch(cmd) {
        case 'b':
        Read();
        break;
        case 'c':
        Class();
        break;
        case 't':
        TopBoards();
        break;
        case 'f':
        Favorite();
        break;
        case 'm':
        m_read();
        break;
        case 'u':
        t_users();
        break;
    }
    // if user exit with new ZA assignment,
    // direct enter in next loop.
    }
}

/* 動畫處理 */
#define FILMROW 11
static unsigned short menu_row = 12;
static unsigned short menu_column = 20;

static void
show_status(void)
{
    int i;
    struct tm      ptime;
    char           *myweek = "天一二三四五六";
    const char     *msgs[] = {"關閉", "打開", "拔掉", "防水", "好友"};

    localtime4_r(&now, &ptime);
    i = ptime.tm_wday << 1;
    move(b_lines, 0);
    vbarf(ANSI_COLOR(34;46) "[%d/%d 星期%c%c %d:%02d]" 
      ANSI_COLOR(1;33;45) "%-14s"
      ANSI_COLOR(30;47) " 線上" ANSI_COLOR(31) 
      "%d" ANSI_COLOR(30) "人, 我是" ANSI_COLOR(31) "%s"
      ANSI_COLOR(30) "\t[呼叫器]" ANSI_COLOR(31) "%s ",
      ptime.tm_mon + 1, ptime.tm_mday, myweek[i], myweek[i + 1],
      ptime.tm_hour, ptime.tm_min, currutmp->birth ?
      "生日要請客唷" : SHM->today_is,
      SHM->UTMPnumber, cuser.userid,
      msgs[currutmp->pager]);
}

/*
 * current caller of movie:
 *   board.c: movie(0);    // called when IN_CLASSROOT()
 *                         // with currstat = CLASS -> don't show movies
 *   xyz.c:   movie(999999);  // logout
 *   menu.c:  movie(cmdmode); // ...
 */
#define N_SYSMOVIE (sizeof(movie_map) / sizeof(movie_map[0]))
void
movie(int cmdmode)
{
    int i;

    // movie 前幾筆是 Note 板精華區「<系統> 動態看板」(SYS) 目錄下的文章
    // movie_map 是用來依 cmdmode 挑出特定的動態看板,index 跟 mode_map 一樣。
    const int movie_map[] = {
    2, 10, 11, -1, 3, -1, 12,
    7, 9, 8, 4, 5, 6,
    };

    // don't show if stat in class or user wants to skip movies
    if (currstat == CLASS || !(cuser.uflag & MOVIE_FLAG))
    return;
    // also prevent SHM busy status
    if (SHM->Pbusystate || SHM->last_film <= 0)
    return;

    if (cmdmode < N_SYSMOVIE &&
        0 < movie_map[cmdmode] && movie_map[cmdmode] <= SHM->last_film) {
    i = movie_map[cmdmode];
    } else if (cmdmode == 999999) { /* Goodbye my friend */
    i = 0;
    } else {
    // do not use random. we work in slide show mode. 
    // since menu is updated per hour, the total presentation time 
    // should be less than one hour. 3600/MAX_MOVIE(500)=7.
    // syncnow();
    if (SHM->last_film > N_SYSMOVIE)
        i = N_SYSMOVIE + (now / (3600 / MAX_MOVIE) ) % 
        (SHM->last_film+1-N_SYSMOVIE);
    else
        i = 0; // SHM->last_film;
    }

    move(1, 0);
    clrtoln(1 + FILMROW);   /* 清掉上次的 */
#ifdef LARGETERM_CENTER_MENU
    out_lines(SHM->notes[i], 11, (t_columns - 80)/2);   /* 只印11行就好 */
#else
    out_lines(SHM->notes[i], 11, 0);    /* 只印11行就好 */
#endif
    outs(ANSI_RESET);
#ifdef DEBUG
    // XXX piaip test
    move(FILMROW, 0); prints(" [ %d ] ", i);
#endif
}

typedef struct {
    int     (*cmdfunc)();
    int     level;
    char    *desc;                   /* next/key/description */
} commands_t;

static int
show_menu(int moviemode, const commands_t * p)
{
    register int    n = 0;
    register char  *s;

    movie(moviemode);

    // seems not everyone likes the menu in center.
#ifdef LARGETERM_CENTER_MENU
    // update menu column [fixed const because most items are designed in this way)
    menu_column = (t_columns-40)/2;
    menu_row = 12 + (t_lines-24)/2;
#endif 

    move(menu_row, 0);
    while ((s = p[n].desc)) {
    if (CheckMenuPerm(p[n].level)) {
        prints("%*s  (" ANSI_COLOR(1;36) "%c" ANSI_COLOR(0) ")%s\n", menu_column, "", s[1],
           s+2);
    }
    n++;
    }
    return n - 1;
}


enum {
    M_ADMIN = 0, M_AMUSE, M_CHC, M_JCEE, M_MAIL, M_MMENU, M_NMENU,
    M_PMENU, M_PSALE, M_SREG, M_TMENU, M_UMENU, M_XMENU, M_XMAX
};

static const int mode_map[] = {
    ADMIN, AMUSE, CHC, JCEE, MAIL, MMENU, NMENU,
    PMENU, PSALE, SREG, TMENU, UMENU, XMENU,
};

static void
domenu(int cmdmode, const char *cmdtitle, int cmd, const commands_t cmdtable[])
{
    int             lastcmdptr, moviemode;
    int             n, pos, total, i;
    int             err;

    moviemode = cmdmode;
    assert(cmdmode < M_XMAX);
    cmdmode = mode_map[cmdmode];

    setutmpmode(cmdmode);

    showtitle(cmdtitle, BBSName);

    total = show_menu(moviemode, cmdtable);

    show_status();
    lastcmdptr = pos = 0;

    do {
    i = -1;
    switch (cmd) {
    case Ctrl('Z'):
        ZA_Select(); // we'll have za loop later.
        refscreen = YEA;
        i = lastcmdptr;
        break;
    case Ctrl('I'):
        t_idle();
        refscreen = YEA;
        i = lastcmdptr;
        break;
    case Ctrl('N'):
        New();
        refscreen = YEA;
        i = lastcmdptr;
        break;
    case Ctrl('A'):
        if (mail_man() == FULLUPDATE)
        refscreen = YEA;
        i = lastcmdptr;
        break;
    case KEY_DOWN:
        i = lastcmdptr;
    case KEY_HOME:
    case KEY_PGUP:
        do {
        if (++i > total)
            i = 0;
        } while (!CheckMenuPerm(cmdtable[i].level));
        break;
    case KEY_END:
    case KEY_PGDN:
        i = total;
        break;
    case KEY_UP:
        i = lastcmdptr;
        do {
        if (--i < 0)
            i = total;
        } while (!CheckMenuPerm(cmdtable[i].level));
        break;
    case KEY_LEFT:
    case 'e':
    case 'E':
        if (cmdmode == MMENU)
        cmd = 'G';      // to exit
        else if ((cmdmode == MAIL) && chkmailbox())
        cmd = 'R';      // force keep reading mail
        else
        return;
    default:
        if ((cmd == 's' || cmd == 'r') &&
        (cmdmode == MMENU || cmdmode == TMENU || cmdmode == XMENU)) {
        if (cmd == 's')
            ReadSelect();
        else
            Read();
        refscreen = YEA;
        i = lastcmdptr;
        currstat = cmdmode;
        break;
        }
        if (cmd == KEY_ENTER || cmd == KEY_RIGHT) {
        move(b_lines, 0);
        clrtoeol();

        currstat = XMODE;

        if ((err = (*cmdtable[lastcmdptr].cmdfunc) ()) == QUIT)
            return;
        currutmp->mode = currstat = cmdmode;

        if (err == XEASY) {
            refresh();
            safe_sleep(1);
        } else if (err != XEASY + 1 || err == FULLUPDATE)
            refscreen = YEA;

        if (err != -1)
            cmd = cmdtable[lastcmdptr].desc[0];
        else
            cmd = cmdtable[lastcmdptr].desc[1];
        }
        if (cmd >= 'a' && cmd <= 'z')
        cmd = toupper(cmd);
        while (++i <= total)
        if (cmdtable[i].desc[1] == cmd)
            break;

        if (!CheckMenuPerm(cmdtable[i].level)) {
        for (i = 0; cmdtable[i].desc; i++)
            if (CheckMenuPerm(cmdtable[i].level))
            break;
        if (!cmdtable[i].desc)
            return;
        }

        if (cmd == 'H' && i > total){
        /* TODO: Add menu help */
        }
    }

    // end of all commands
    if (ZA_Waiting())
    {
        ZA_Enter();
        refscreen = 1;
        currstat = cmdmode;
    }

    if (i > total || !CheckMenuPerm(cmdtable[i].level))
        continue;

    if (refscreen) {
        showtitle(cmdtitle, BBSName);
        show_menu(moviemode, cmdtable);
        show_status();
        refscreen = NA;
    }
    cursor_clear(menu_row + pos, menu_column);
    n = pos = -1;
    while (++n <= (lastcmdptr = i))
        if (CheckMenuPerm(cmdtable[n].level))
        pos++;

    cursor_show(menu_row + pos, menu_column);
    } while (((cmd = igetch()) != EOF) || refscreen);

    abort_bbs(0);
}
/* INDENT OFF */

// ----------------------------------------------------------- MENU DEFINITION
// 注意每個 menu 最多不能同時顯示超過 11 項 (80x24 標準大小的限制)

/* administrator's maintain menu */
static const commands_t adminlist[] = {
    {m_user, PERM_SYSOP,        "UUser          使用者資料"},
    {search_user_bypwd, 
    PERM_ACCOUNTS|PERM_POLICE_MAN,  "SSearch User   特殊搜尋使用者"},
    {search_user_bybakpwd,
    PERM_ACCOUNTS,          "OOld User data 查閱\備份使用者資料"},
    {m_board, PERM_SYSOP|PERM_BOARD,    "BBoard         設定看板"},
    {m_register, 
    PERM_ACCOUNTS|PERM_ACCTREG, "RRegister      審核註冊表單"},
    {x_file, 
    PERM_SYSOP|PERM_VIEWSYSOP,  "XXfile         編輯系統檔案"},
    {give_money, 
    PERM_SYSOP|PERM_VIEWSYSOP,  "GGivemoney     紅包雞"},
    {u_list, PERM_SYSOP,        "UUsers         列出註冊名單"},
    {m_loginmsg, PERM_SYSOP,        "MMessage Login 進站水球"},
    {NULL, 0, NULL}
};

/* mail menu */
static const commands_t maillist[] = {
    {m_new,  PERM_READMAIL,     "RNew           閱\讀新進郵件"},
    {m_read, PERM_READMAIL,     "RRead          多功\能讀信選單"},
    {m_send, PERM_LOGINOK,      "RSend          站內寄信"},
    {mail_list, PERM_LOGINOK,   "RMail List     群組寄信"},
// #ifdef USE_MAIL_AUTO_FORWARD
    {setforward, PERM_LOGINOK,  "FForward       設定信箱自動轉寄" },
// #endif
    {m_sysop, 0,                "YYes, sir!     寫信給站長"},
    {m_internet, PERM_INTERNET, "RInternet      寄信到站外"},
    {mail_mbox, PERM_INTERNET,  "RZip UserHome  把所有私人資料打包回去"},
    {built_mail_index, 
    PERM_LOGINOK,       "SSavemail      重建信箱索引"},
    {mail_all, PERM_SYSOP,      "RAll           寄信給所有使用者"},
    {NULL, 0, NULL}
};

/* Talk menu */
static const commands_t talklist[] = {
    {t_users, 0,            "UUsers         線上使用者列表"},
    {t_query, 0,            "QQuery         查詢網友"},
    // PERM_PAGE - 水球都要 PERM_LOGIN 了
    // 沒道理可以 talk 不能水球。
    {t_talk, PERM_LOGINOK,  "TTalk          找人聊聊"},
    // PERM_CHAT 非 login 也有,會有人用此吵別人。
    {t_chat, PERM_LOGINOK,  "CChat          【" BBSMNAME2 "多人聊天室】"},
    {t_pager, PERM_BASIC,   "PPager         切換呼叫器"},
    // XXX 發呆有太多其它方法可以進去了... drop?
    {t_idle, 0,             "IIdle          發呆"},
    {t_qchicken, 0,         "WWatch Pet     查詢寵物"},
#ifdef PLAY_ANGEL
    {t_changeangel, 
    PERM_LOGINOK,       "UAChange Angel 更換小天使"},
    {t_angelmsg, PERM_ANGEL,"LLeave message 留言給小主人"},
#endif
    {t_display, 0,          "DDisplay       顯示上幾次熱訊"},
    {NULL, 0, NULL}
};

/* name menu */
static int t_aloha() {
    friend_edit(FRIEND_ALOHA);
    return 0;
}

static int t_special() {
    friend_edit(FRIEND_SPECIAL);
    return 0;
}

static const commands_t namelist[] = {
    {t_override, PERM_LOGINOK,"OOverRide      好友名單"},
    {t_reject, PERM_LOGINOK,  "BBlack         壞人名單"},
    {t_aloha,PERM_LOGINOK,    "AALOHA         上站通知名單"},
    {t_fix_aloha,PERM_LOGINOK,"XXFixALOHA     修正上站通知"},
    {t_special,PERM_LOGINOK,  "SSpecial       其他特別名單"},
    {NULL, 0, NULL}
};


static const commands_t myfilelist[] = {
    {u_editplan,    PERM_LOGINOK,   "QQueryEdit     編輯名片檔"},
    {u_editsig,     PERM_LOGINOK,   "SSignature     編輯簽名檔"},
    {NULL, 0, NULL}
};

static int
u_myfiles()
{
    domenu(M_UMENU, "個人檔案", 'Q', myfilelist);
    return 0;
}


int u_fixgoodpost(void); // assess.c
void Customize(); // user.c

static int 
u_customize()
{
    Customize();
    return 0;
}


/* User menu */
static const commands_t userlist[] = {
    {u_customize,   PERM_BASIC,     "UUCustomize    個人化設定"},
    {u_info,        PERM_LOGINOK,   "IInfo          設定個人資料與密碼"},
    {calendar,      PERM_LOGINOK,   "CCalendar      行事曆"},
    {u_loginview,   PERM_BASIC,     "LLogin View    選擇進站畫面"},
    {u_myfiles,     PERM_LOGINOK,   "MMy Files      【個人檔案】 (名片,簽名檔...)"},
#if HAVE_FREECLOAK
    {u_cloak,       PERM_LOGINOK,   "KKCloak        隱身術"},
#else
    {u_cloak,       PERM_CLOAK,     "KKCloak        隱身術"},
#endif
    {u_register,    MENU_UNREGONLY, "RRegister      填寫《註冊申請單》"},
#ifdef ASSESS
    {u_cancelbadpost,PERM_LOGINOK,  "BBye BadPost   申請刪除劣文"},
    {u_fixgoodpost, PERM_LOGINOK,   "FFix GoodPost  修復優文"},
#endif // ASSESS
    {NULL, 0, NULL}
};

#ifdef HAVE_INFO
static int
x_program(void)
{
    more("etc/version", YEA);
    return 0;
}
#endif

#ifdef HAVE_LICENSE
static int
x_gpl(void)
{
    more("etc/GPL", YEA);
    return 0;
}
#endif

#ifdef HAVE_SYSUPDATES
static int
x_sys_updates(void)
{
    more("etc/sysupdates", YEA);
    return 0;
}
#endif

#ifdef DEBUG
int _debug_check_keyinput();
int _debug_reportstruct()
{
    clear();
    prints("boardheader_t:\t%d\n", sizeof(boardheader_t));
    prints("fileheader_t:\t%d\n", sizeof(fileheader_t));
    prints("userinfo_t:\t%d\n", sizeof(userinfo_t));
    prints("screenline_t:\t%d\n", sizeof(screenline_t));
    prints("SHM_t:\t%d\n", sizeof(SHM_t));
    prints("userec_t:\t%d\n", sizeof(userec_t));
    pressanykey();
    return 0;
}

#endif

/* XYZ tool sub menu */
static const commands_t m_xyz_hot[] = {
    {x_week, 0,      "WWeek          《本週五十大熱門話題》"},
    {x_issue, 0,     "IIssue         《今日十大熱門話題》"},
#ifdef HAVE_X_BOARDS
    {x_boards,0,     "HHot Boards    《看板人氣排行榜》"},
#endif
    {x_boardman,0,   "MMan Boards    《看板精華區排行榜》"},
    {NULL, 0, NULL}
};

/* XYZ tool sub menu */
static const commands_t m_xyz_user[] = {
    {x_user100 ,0,   "UUsers         《使用者百大排行榜》"},
    {topsong,PERM_LOGINOK,   
                 "GGTop Songs    《使用者點歌排行榜》"},
    {x_today, 0,     "TToday         《今日上線人次統計》"},
    {x_yesterday, 0, "YYesterday     《昨日上線人次統計》"},
    {NULL, 0, NULL}
};

static int
x_hot(void)
{
    domenu(M_XMENU, "熱門話題與看板", 'W', m_xyz_hot);
    return 0;
}

static int
x_users(void)
{
    domenu(M_XMENU, "使用者統計資訊", 'U', m_xyz_user);
    return 0;
}

/* XYZ tool menu */
static const commands_t xyzlist[] = {
    {x_hot,  0,      "TTHot Topics   《熱門話題與看板》"},
    {x_users,0,      "UUsers         《使用者相關統計》"},
#ifndef DEBUG
    /* All these are useless in debug mode. */
#ifdef  HAVE_LICENSE
    {x_gpl, 0,       "IILicense       GNU 使用執照"},
#endif
#ifdef HAVE_INFO
    {x_program, 0,   "PProgram       本程式之版本與版權宣告"},
#endif
    {x_history, 0,   "HHistory       《我們的成長》"},
    {x_note, 0,      "NNote          《酸甜苦辣流言板》"},
    {x_login,0,      "SSystem        《系統重要公告》"},
#ifdef HAVE_SYSUPDATES
    {x_sys_updates,0,"LLUpdates      《本站系統程式更新紀錄》"},
#endif

#else // !DEBUG

    {_debug_check_keyinput, 0, 
                 "MMKeycode      檢查按鍵控制碼工具"},
    {_debug_reportstruct, 0, 
                 "RReportStruct  報告各種結構的大小"},
#endif // !DEBUG

    {p_sysinfo, 0,   "XXinfo         《查看系統資訊》"},
    {NULL, 0, NULL}
};

/* Ptt money menu */
static const commands_t moneylist[] = {
    {p_give, 0,         "00Give        給其他人錢"},
    {save_violatelaw, 0,"11ViolateLaw  繳罰單"},
#if !HAVE_FREECLOAK
    {p_cloak, 0,        "22Cloak       切換 隱身/現身   $19  /次"},
#endif
    {p_from, 0,         "33From        暫時修改故鄉     $49  /次"},
    {ordersong,0,       "44OSong       歐桑動態點歌機   $200 /次"},
    {p_exmail, 0,       "55Exmail      購買信箱         $1000/封"},
    {NULL, 0, NULL}
};

static const commands_t      cmdlist[] = {
    {admin, PERM_SYSOP|PERM_ACCOUNTS|PERM_BOARD|PERM_VIEWSYSOP|PERM_ACCTREG|PERM_POLICE_MAN, 
                "00Admin       【 系統維護區 】"},
    {Announce,  0,      "AAnnounce     【 精華公佈欄 】"},
#ifdef DEBUG
    {Favorite,  0,      "FFavorite     【 我的最不愛 】"},
#else
    {Favorite,  0,      "FFavorite     【 我 的 最愛 】"},
#endif
    {Class, 0,      "CClass        【 分組討論區 】"},
    {Mail,  PERM_BASIC, "MMail         【 私人信件區 】"},
    {Talk,  0,      "TTalk         【 休閒聊天區 】"},
    {User,  PERM_BASIC, "UUser         【 個人設定區 】"},
    {Xyz,   0,      "XXyz          【 系統資訊區 】"},
    {Play_Play, PERM_LOGINOK,   "PPlay         【 娛樂與休閒 】"},
    {Name_Menu, PERM_LOGINOK,   "NNamelist     【 編特別名單 】"},
#ifdef DEBUG
    {Goodbye,   0,      "GGoodbye      再見再見再見再見"},
#else
    {Goodbye,   0,      "GGoodbye         離開,再見… "},
#endif
    {NULL,  0,      NULL}
};

int main_menu(void) {
    domenu(M_MMENU, "主功\能表", (ISNEWMAIL(currutmp) ? 'M' : 'C'), cmdlist);
    return 0;
}

static int p_money() {
    domenu(M_PSALE, BBSMNAME2 "量販店", '0', moneylist);
    return 0;
};

static int playground();
static int chessroom();

/* Ptt Play menu */
static const commands_t playlist[] = {
    {note, PERM_LOGINOK,     "NNote        【 刻刻流言板 】"},
    {p_money,PERM_LOGINOK,   "PPay         【" ANSI_COLOR(1;31) 
                 " " BBSMNAME2 "量販店 " ANSI_RESET "】"},
    {chicken_main,PERM_LOGINOK, 
                 "CChicken     【" ANSI_COLOR(1;34) 
                 " " BBSMNAME2 "養雞場 " ANSI_RESET "】"},
    {playground,PERM_LOGINOK,"AAmusement   【" ANSI_COLOR(1;33) 
                 " " BBSMNAME2 "遊樂場 " ANSI_RESET "】"},
    {chessroom, PERM_LOGINOK,"BBChess      【" ANSI_COLOR(1;34) 
                 " " BBSMNAME2 "棋院   " ANSI_RESET "】"},
    {NULL, 0, NULL}
};

static const commands_t chesslist[] = {
    {chc_main,         PERM_LOGINOK, "11CChessFight   【" ANSI_COLOR(1;33) " 象棋邀局 " ANSI_RESET "】"},
    {chc_personal,     PERM_LOGINOK, "22CChessSelf    【" ANSI_COLOR(1;34) " 象棋打譜 " ANSI_RESET "】"},
    {chc_watch,        PERM_LOGINOK, "33CChessWatch   【" ANSI_COLOR(1;35) " 象棋觀棋 " ANSI_RESET "】"},
    {gomoku_main,      PERM_LOGINOK, "44GomokuFight   【" ANSI_COLOR(1;33) "五子棋邀局" ANSI_RESET "】"},
    {gomoku_personal,  PERM_LOGINOK, "55GomokuSelf    【" ANSI_COLOR(1;34) "五子棋打譜" ANSI_RESET "】"},
    {gomoku_watch,     PERM_LOGINOK, "66GomokuWatch   【" ANSI_COLOR(1;35) "五子棋觀棋" ANSI_RESET "】"},
    {gochess_main,     PERM_LOGINOK, "77GoChessFight  【" ANSI_COLOR(1;33) " 圍棋邀局 " ANSI_RESET "】"},
    {gochess_personal, PERM_LOGINOK, "88GoChessSelf   【" ANSI_COLOR(1;34) " 圍棋打譜 " ANSI_RESET "】"},
    {gochess_watch,    PERM_LOGINOK, "99GoChessWatch  【" ANSI_COLOR(1;35) " 圍棋觀棋 " ANSI_RESET "】"},
    {NULL, 0, NULL}
};

static int chessroom() {
    domenu(M_CHC, BBSMNAME2 "棋院", '1', chesslist);
    return 0;
}

static const commands_t plist[] = {

    {ticket_main, PERM_LOGINOK,  "11Gamble      【 " BBSMNAME2 "賭場 】"},
    {vice_main, PERM_LOGINOK,    "22Vice        【 發票對獎 】"},
    {g_card_jack, PERM_LOGINOK,  "33Jack        【  黑傑克  】"},
    {g_ten_helf, PERM_LOGINOK,   "44Tenhalf     【  十點半  】"},
    {card_99, PERM_LOGINOK,      "55Nine        【  九十九  】"},
    {NULL, 0, NULL}
};

// ---------------------------------------------------------------- SUB MENUS

static int 
playground() {
    domenu(M_AMUSE, BBSMNAME2 "遊樂場",'1',plist);
    return 0;
}

/* main menu */

int
admin(void)
{
    domenu(M_ADMIN, "系統維護", 'X', adminlist);
    return 0;
}

int
Mail(void)
{
    domenu(M_MAIL, "電子郵件", 'R', maillist);
    return 0;
}

int
Talk(void)
{
    domenu(M_TMENU, "聊天說話", 'U', talklist);
    return 0;
}

int
User(void)
{
    domenu(M_UMENU, "個人設定", 'U', userlist);
    return 0;
}

int
Xyz(void)
{
    domenu(M_XMENU, "工具程式", 'T', xyzlist);
    return 0;
}

int
Play_Play(void)
{
    domenu(M_PMENU, "網路遊樂場", 'A', playlist);
    return 0;
}

int
Name_Menu(void)
{
    domenu(M_NMENU, "名單編輯", 'O', namelist);
    return 0;
}