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


                    

                             
                     
           
                              
 
                      
                                            
               
                                      

                   

                                           



               

             


                                   
           
                       
 
                                                          








                          
           
                                
 





                         
          
                                  


                                
 
                                                        


                                             




                  
          
                                                                                       
 

                           
 

                                                            
                  
                      
 
                   
                   
                               
                                                             

                  

                              
                     
                                 

                      
                                                       



                                     
                                                   



                           
                                                                                                       
                                           







                                
                

                                                               
          
                         


             
          
                                      



                              
 

                 
                                 
                                    


                 
                                                                                    

                 


                                                                  
                

                                            
                     






                             
           
                                           


                                
                                                         


                       
           


                             




















                                                           




                                                                 
           
                       

                                
 

                                                        


                          
           
                        

                                
 




                                                 
                                                          
                                                                          


                          
           



                         
                          
 

                           
                                                                           


                                       
                                                                           
                                              
                                                  
                           
 

                                                               

                                                                 
 
                                                 
                                     
                     

                                                                    








                                   
           
                        
 



                                                 
                                        




                                  
                                                             
                                                                         
                               
 
                                             




                          


                
          
                                                
 
                                               
                                      



                     
          


                           
 
                      

                 

                                                          






                                        
                    
                                
 
   
            
 
                                                 
                                                                              
                           

                                    

                                   

                           





                                               
                                         
 
                                                                  
                                
                  


                              
                                                 

                                                 

                                                                   
                                                                



                             
     

               

                                                                       
                                                          
                         
          
                                               
           
                                                     
                                                    
                              

                                          
                     
         
                                          
                  
                                                   
                                         
                                                    
                                     
                                                  
                                              
 




                             
 
                   
 
                 
                
                                        
 

                            
                                                                
 

                 
 
                       
                        

                             


                         
                                    
 

                                       
 
                      
                                                 
                      
 
                     




                                     
                                                           





                                          
                         
             
                           
                

                                        
                                                                                        


                                

                       
                                
             
                           
                

                                        
                                                                                        


                               
                     

                         

         
                                  

                                                  
                                              
                                                                      


                                                
                                  






                                                                
                                                
                                            




                                                         
                                              
                         
                                                
                                  
                                                     
                                             
                          

                                                               


                                                                          
 





                                          
                                                     
                           
                
                                 
                                     
                                                                                          


                                     
                                 

                                                                      



                                                         
                                                        



                                          
                                     

                                 
                                     
                                                   
                
                                 
                                                          
                                                                                          

                                 
                                 

                                                                      



                                                         
                                     


                                                     
                                     
                         
                                     
                                     
                                     
                                       
 
                                       

                         
                                        
                           
                                     





                                          
 


                                                



                               


                                                                  
                                          
                          

                                       
                                        
 
                                              
                                       
                                         
                                                                      
                                                                                                   
                                            




                                                          

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

#ifndef DBCSAWARE
#define dbcs_off (1)
#endif

#define STOP_LINE (t_lines-3)
static int      chatline;
static FILE    *flog;
static void
printchatline(const char *str)
{
    move(chatline, 0);
    if (*str == '>' && !PERM_HIDE(currutmp))
    return;
    else if (chatline < STOP_LINE - 1)
    chatline++;
    else {
    region_scroll_up(2, STOP_LINE - 2);
    move(STOP_LINE - 2, 0);
    }
    outs(str);
    outc('\n');
    outs("→");

    if (flog)
    fprintf(flog, "%s\n", str);
}

static void
chat_clear(char*unused)
{
    for (chatline = 2; chatline < STOP_LINE; chatline++) {
    move(chatline, 0);
    clrtoeol();
    }
    move(b_lines, 0);
    clrtoeol();
    move(chatline = 2, 0);
    outs("→");
}

static void
print_chatid(const char *chatid)
{
    move(b_lines - 1, 0);
    clrtoeol();
    outs(chatid);
    outc(':');
}

static int
chat_send(int fd, const char *buf)
{
    int             len;
    char            genbuf[200];

    len = snprintf(genbuf, sizeof(genbuf), "%s\n", buf);
    return (send(fd, genbuf, len, 0) == len);
}

struct ChatBuf {
    char buf[128];
    int bufstart;
};

static int
chat_recv(struct ChatBuf *cb, int fd, char *chatroom, char *chatid, size_t chatid_size)
{
    int             c, len;
    char           *bptr;

    len = sizeof(cb->buf) - cb->bufstart - 1;
    if ((c = recv(fd, cb->buf + cb->bufstart, len, 0)) <= 0)
    return -1;
    c += cb->bufstart;

    bptr = cb->buf;
    while (c > 0) {
    len = strlen(bptr) + 1;
    if (len > c && (unsigned)len < (sizeof(cb->buf)/ 2) )
        break;

    if (*bptr == '/') {
        switch (bptr[1]) {
        case 'c':
        chat_clear(NULL);
        break;
        case 'n':
        strlcpy(chatid, bptr + 2, chatid_size);
        print_chatid(chatid);
        clrtoeol();
        break;
        case 'r':
        strlcpy(chatroom, bptr + 2, IDLEN);
        break;
        case 't':
        move(0, 0);
        clrtoeol();
        prints(ANSI_COLOR(1;37;46) " 談天室 [%-12s] " ANSI_COLOR(45) " 話題:%-48s" ANSI_RESET,
               chatroom, bptr + 2);
        }
    } else
        printchatline(bptr);

    c -= len;
    bptr += len;
    }

    if (c > 0) {
    memmove(cb->buf, bptr, sizeof(cb->buf)-(bptr-cb->buf));
    cb->bufstart = len - 1;
    } else
    cb->bufstart = 0;
    return 0;
}

static int
printuserent(const userinfo_t * uentp)
{
    static char     uline[80];
    static int      cnt;
    char            pline[30];

    if (!uentp) {
    if (cnt)
        printchatline(uline);
    bzero(uline, sizeof(uline));
    cnt = 0;
    return 0;
    }
    if (!HasUserPerm(PERM_SYSOP) && !HasUserPerm(PERM_SEECLOAK) && uentp->invisible)
    return 0;

    snprintf(pline, sizeof(pline), "%-13s%c%-10s ", uentp->userid,
         uentp->invisible ? '#' : ' ',
         modestring(uentp, 1));
    if (cnt < 2)
    strlcat(pline, "│", sizeof(pline));
    strlcat(uline, pline, sizeof(uline));
    if (++cnt == 3) {
    printchatline(uline);
    memset(uline, 0, 80);
    cnt = 0;
    }
    return 0;
}

static void
chathelp(const char *cmd, const char *desc)
{
    char            buf[STRLEN];

    snprintf(buf, sizeof(buf), "  %-20s- %s", cmd, desc);
    printchatline(buf);
}

static void
chat_help(char *arg)
{
    if (strstr(arg, " op")) {
    printchatline("談天室管理員專用指令");
    chathelp("[/f]lag [+-][ls]", "設定鎖定、秘密狀態");
    chathelp("[/i]nvite <id>", "邀請 <id> 加入談天室");
    chathelp("[/k]ick <id>", "將 <id> 踢出談天室");
    chathelp("[/o]p <id>", "將 Op 的權力轉移給 <id>");
    chathelp("[/t]opic <text>", "換個話題");
    chathelp("[/w]all", "廣播 (站長專用)");
    } else {
    chathelp("[//]help", "MUD-like 社交動詞");
    chathelp("[/.]help", "chicken 鬥雞用指令");
    chathelp("[/h]elp op", "談天室管理員專用指令");
    chathelp("[/a]ct <msg>", "做一個動作");
    chathelp("[/b]ye [msg]", "道別");
    chathelp("[/c]lear", "清除螢幕");
    chathelp("[/j]oin <room>", "建立或加入談天室");
    chathelp("[/l]ist [room]", "列出談天室使用者");
    chathelp("[/m]sg <id> <msg>", "跟 <id> 說悄悄話");
    chathelp("[/n]ick <id>", "將談天代號換成 <id>");
    chathelp("[/p]ager", "切換呼叫器");
    chathelp("[/q]uery", "查詢網友");
    chathelp("[/r]oom", "列出一般談天室");
    chathelp("[/w]ho", "列出本談天室使用者");
    chathelp("[/w]hoin <room>", "列出談天室<room> 的使用者");
    }
}

static void
chat_date(char *unused)
{
    char            genbuf[200];

    snprintf(genbuf, sizeof(genbuf),
         "◆ " BBSNAME "標準時間: %s", Cdate(&now));
    printchatline(genbuf);
}

static void
chat_pager(char *unused)
{
    char            genbuf[200];

    char           *msgs[PAGER_MODES] = {
    /* Ref: please match PAGER* in modes.h */
    "關閉", "打開", "拔掉", "防水", "好友"
    };

    snprintf(genbuf, sizeof(genbuf), "◆ 您的呼叫器:[%s]",
         msgs[currutmp->pager = (currutmp->pager + 1) % PAGER_MODES]);
    printchatline(genbuf);
}

static void
chat_query(char *arg)
{
    char           *uid;
    int             tuid;
    userec_t        xuser;

    printchatline("");
    strtok(arg, str_space);
    if ((uid = strtok(NULL, str_space)) && (tuid = getuser(uid, &xuser))) {
    char            buf[128], *ptr;
    FILE           *fp;

    snprintf(buf, sizeof(buf), "%s(%s) 共上站 %d 次,發表過 %d 篇文章",
         xuser.userid, xuser.nickname,
         xuser.numlogins, xuser.numposts);
    printchatline(buf);

    snprintf(buf, sizeof(buf),
         "最近(%s)從[%s]上站", Cdate(&xuser.lastlogin),
        (xuser.lasthost[0] ? xuser.lasthost : "(不詳)"));
    printchatline(buf);

    sethomefile(buf, xuser.userid, fn_plans);
    if ((fp = fopen(buf, "r"))) {
        tuid = 0;
        while (tuid++ < MAX_QUERYLINES && fgets(buf, 128, fp)) {
        if ((ptr = strchr(buf, '\n')))
            ptr[0] = '\0';
        printchatline(buf);
        }
        fclose(fp);
    }
    } else
    printchatline(err_uid);
}

static void
chat_users(char* unused)
{
    printchatline("");
    printchatline("【 " BBSNAME "的遊客列表 】");
    printchatline(msg_shortulist);

    if (apply_ulist(printuserent) == -1)
    printchatline("空無一人");
    printuserent(NULL);
}

typedef struct chat_command_t {
    char           *cmdname;    /* Chatroom command length */
    void            (*cmdfunc) (char *);    /* Pointer to function */
}               chat_command_t;

static const chat_command_t chat_cmdtbl[] = {
    {"help", chat_help},
    {"clear", chat_clear},
    {"date", chat_date},
    {"pager", chat_pager},
    {"query", chat_query},
    {NULL, NULL}
};

static int
chat_cmd_match(const char *buf, const char *str)
{
    while (*str && *buf && !isspace((int)*buf))
    if (tolower(*buf++) != *str++)
        return 0;
    return 1;
}

static int
chat_cmd(char *buf, int fd)
{
    int             i;

    if (*buf++ != '/')
    return 0;

    for (i = 0; chat_cmdtbl[i].cmdname; i++) {
    if (chat_cmd_match(buf, chat_cmdtbl[i].cmdname)) {
        chat_cmdtbl[i].cmdfunc(buf);
        return 1;
    }
    }
    return 0;
}

#define MAXLASTCMD 6
static int      chatid_len = 10;

int
t_chat(void)
{
    char     chatroom[IDLEN];/* Chat-Room Name */
    char            inbuf[80], chatid[20], lastcmd[MAXLASTCMD][80], *ptr = "";
    struct sockaddr_in sin;
    int             cfd, cmdpos, ch;
    int             currchar;
    int             chatting = YEA;
    char            fpath[80];
    struct ChatBuf chatbuf;

    if(HasUserPerm(PERM_VIOLATELAW))
        {
         vmsg("請先繳罰單才能使用聊天室!");
         return -1;
        }

    memset(&chatbuf, 0, sizeof(chatbuf));

    outs("                     驅車前往 請梢候........         ");
    memset(&sin, 0, sizeof sin);
#ifdef __FreeBSD__
    sin.sin_len = sizeof(sin);
#endif
    sin.sin_family = PF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    sin.sin_port = htons(NEW_CHATPORT);
    cfd = socket(sin.sin_family, SOCK_STREAM, 0);
    if (connect(cfd, (struct sockaddr *) & sin, sizeof sin) != 0) {
    outs("\n              "
         "哇! 沒人在那邊耶...要有那地方的人先去開門啦!...");
    system("bin/xchatd");
    pressanykey();
    close(cfd);
    return -1;
    }

    while (1) {
    getdata(b_lines - 1, 0, "請輸入聊天代號:", chatid, 9, DOECHO);
    if(!chatid[0])
        strlcpy(chatid, cuser.userid, sizeof(chatid));
    chatid[8] = '\0';
    /*
     * 新格式:    /! UserID ChatID Password
     */
    snprintf(inbuf, sizeof(inbuf), "/! %s %s %s",
        cuser.userid, chatid, cuser.passwd);
    chat_send(cfd, inbuf);
    if (recv(cfd, inbuf, 3, 0) != 3) {
        close(cfd);
        return 0;
    }
    if (!strcmp(inbuf, CHAT_LOGIN_OK))
        break;
    else if (!strcmp(inbuf, CHAT_LOGIN_EXISTS))
        ptr = "這個代號已經有人用了";
    else if (!strcmp(inbuf, CHAT_LOGIN_INVALID))
        ptr = "這個代號是錯誤的";
    else if (!strcmp(inbuf, CHAT_LOGIN_BOGUS))
        ptr = "請勿派遣分身進入聊天室 !!";

    move(b_lines - 2, 0);
    outs(ptr);
    clrtoeol();
    bell();
    }

    add_io(cfd, 0);

    currchar = 0;
    cmdpos = -1;
    memset(lastcmd, 0, sizeof(lastcmd));

    setutmpmode(CHATING);
    currutmp->in_chat = YEA;
    strlcpy(currutmp->chatid, chatid, sizeof(currutmp->chatid));

    clear();
    chatline = 2;

    move(STOP_LINE, 0);
    outs(msg_seperator);
    move(STOP_LINE, 60);
    outs(" /help 查詢指令 ");
    move(1, 0);
    outs(msg_seperator);
    print_chatid(chatid);
    memset(inbuf, 0, sizeof(inbuf));

    setuserfile(fpath, "chat_XXXXXX");
    flog = fdopen(mkstemp(fpath), "w");

    while (chatting) {
    move(b_lines - 1, currchar + chatid_len);
    ch = igetch();

    switch (ch) {
    case KEY_DOWN:
        cmdpos += MAXLASTCMD - 2;
    case KEY_UP:
        cmdpos++;
        cmdpos %= MAXLASTCMD;
        strlcpy(inbuf, lastcmd[cmdpos], sizeof(inbuf));
        move(b_lines - 1, chatid_len);
        clrtoeol();
        outs(inbuf);
        currchar = strlen(inbuf);
        continue;
    case KEY_LEFT:
        if (currchar)
        {
        --currchar;
#ifdef DBCSAWARE
        if(currchar > 0 && 
            ISDBCSAWARE() &&
            getDBCSstatus((unsigned char*)inbuf, currchar) == DBCS_TRAILING)
            currchar --;
#endif
        }
        continue;
    case KEY_RIGHT:
        if (inbuf[currchar])
        {
        ++currchar;
#ifdef DBCSAWARE
        if(inbuf[currchar] &&
            ISDBCSAWARE() &&
            getDBCSstatus((unsigned char*)inbuf, currchar) == DBCS_TRAILING)
            currchar++;
#endif
        }
        continue;
    case KEY_UNKNOWN:
        continue;
    }

    if (ISNEWMAIL(currutmp)) {
        printchatline("◆ 噹!郵差又來了...");
    }
    if (ch == I_OTHERDATA) {/* incoming */
        if (chat_recv(&chatbuf, cfd, chatroom, chatid, 9) == -1) {
        chatting = chat_send(cfd, "/b");
        break;
        }
    } else if (isprint2(ch)) {
        if (currchar < 68) {
        if (inbuf[currchar]) {  /* insert */
            int             i;

            for (i = currchar; inbuf[i] && i < 68; i++);
            inbuf[i + 1] = '\0';
            for (; i > currchar; i--)
            inbuf[i] = inbuf[i - 1];
        } else      /* append */
            inbuf[currchar + 1] = '\0';
        inbuf[currchar] = ch;
        move(b_lines - 1, currchar + chatid_len);
        outs(&inbuf[currchar++]);
        }
    } else if (ch == '\n' || ch == '\r') {
        if (*inbuf) {
        chatting = chat_cmd(inbuf, cfd);
        if (chatting == 0)
            chatting = chat_send(cfd, inbuf);
        if (!strncmp(inbuf, "/b", 2))
            break;

        for (cmdpos = MAXLASTCMD - 1; cmdpos; cmdpos--)
            strlcpy(lastcmd[cmdpos],
                lastcmd[cmdpos - 1], sizeof(lastcmd[cmdpos]));
        strlcpy(lastcmd[0], inbuf, sizeof(lastcmd[0]));

        inbuf[0] = '\0';
        currchar = 0;
        cmdpos = -1;
        }
        print_chatid(chatid);
        move(b_lines - 1, chatid_len);
    } else if (ch == Ctrl('H') || ch == '\177') {
        if (currchar) {
#ifdef DBCSAWARE
        int dbcs_off = 1;
        if (ISDBCSAWARE() && 
            getDBCSstatus((unsigned char*)inbuf, currchar-1) == DBCS_TRAILING)
            dbcs_off = 2;
#endif
        currchar -= dbcs_off;
        inbuf[69] = '\0';
        memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off], 
            69 - currchar);
        move(b_lines - 1, currchar + chatid_len);
        clrtoeol();
        outs(&inbuf[currchar]);
        }
    } else if (ch == Ctrl('Z') || ch == Ctrl('Y')) {
        inbuf[0] = '\0';
        currchar = 0;
        print_chatid(chatid);
        move(b_lines - 1, chatid_len);
    } else if (ch == Ctrl('C')) {
        chat_send(cfd, "/b");
        break;
    } else if (ch == Ctrl('D')) {
        if ((size_t)currchar < strlen(inbuf)) {
#ifdef DBCSAWARE
        int dbcs_off = 1;
        if (ISDBCSAWARE() && inbuf[currchar+1] && 
            getDBCSstatus((unsigned char*)inbuf, currchar+1) == DBCS_TRAILING)
            dbcs_off = 2;
#endif
        inbuf[69] = '\0';
        memcpy(&inbuf[currchar], &inbuf[currchar + dbcs_off], 
            69 - currchar);
        move(b_lines - 1, currchar + chatid_len);
        clrtoeol();
        outs(&inbuf[currchar]);
        }
    } else if (ch == Ctrl('K')) {
        inbuf[currchar] = 0;
        move(b_lines - 1, currchar + chatid_len);
        clrtoeol();
    } else if (ch == Ctrl('A')) {
        currchar = 0;
    } else if (ch == Ctrl('E')) {
        currchar = strlen(inbuf);
    } else if (ch == Ctrl('I')) {
        screen_backup_t old_screen;

        screen_backup(&old_screen);
        add_io(0, 0);
        t_idle();
        screen_restore(&old_screen);
        add_io(cfd, 0);
    } else if (ch == Ctrl('Q')) {
        print_chatid(chatid);
        move(b_lines - 1, chatid_len);
        outs(inbuf);
        continue;
    }
    }

    close(cfd);
    add_io(0, 0);
    currutmp->in_chat = currutmp->chatid[0] = 0;

    if (flog) {
    char            ans[4];

    fclose(flog);
    more(fpath, NA);
    getdata(b_lines - 1, 0, "清除(C) 移至備忘錄(M) (C/M)?[C]",
        ans, sizeof(ans), LCECHO);
    if (*ans == 'm') {
        fileheader_t    mymail;
        char            title[128];
        char            genbuf[200];

        sethomepath(genbuf, cuser.userid);
        stampfile(genbuf, &mymail);
        mymail.filemode = FILE_READ ;
        strlcpy(mymail.owner, "[備.忘.錄]", sizeof(mymail.owner));
        strlcpy(mymail.title, "會議" ANSI_COLOR(1;33) "記錄" ANSI_RESET, sizeof(mymail.title));
        sethomedir(title, cuser.userid);
        append_record(title, &mymail, sizeof(mymail));
        Rename(fpath, genbuf);
    } else
        unlink(fpath);
    }
    return 0;
}