view src/reditor.c @ 1:f72be2054832

add: reditor.c reditor.h
author atsuki
date Sat, 10 Nov 2007 20:27:44 +0900
parents
children 7c2dca099a7b
line wrap: on
line source

#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>

#include "vim.h"
#include "reditor.h"

/* Global variables of Vim */
#include "globals.h"

/* Wrapper for Vim */
static void e_msg_wrp(char *msg);
static void e_msg2_wrp(char *msg1, char *msg2);
static void puts_msg_wrpt(char *msg);
static void free_wrp(void *p);
static BUFTYPE* make_new_buf_wrp(char *name);
static void free_buf_wrp(BUFTYPE *buf);
static BUFTYPE* find_buf_by_name_wrp(char *name);
static void open_buffer_memline_wrp(BUFTYPE *buf);
static BUFTYPE* get_curbuf_wrp();
static BUFTYPE* set_curbuf_wrp(BUFTYPE *buf);
static char* get_memline_wrp(BUFTYPE *buf, long lnum);
static int append_memline_wrp(long lnum, char *text);
static int delete_memline_wrp(long lnum);
static int replace_memline_wrp(long lnum, char *text);
static void update_screen_now_wrp();
static void update_screen_later_wrp(BUFTYPE *buf);
static long get_bufmaxline_wrp(BUFTYPE* buf);
static char* getstr_input_wrp(char *msg);
static char *get_fullpath_wrp(BUFTYPE *buf);
static char *get_shortname_wrp(BUFTYPE *buf);
/* Wrapper END */


static rep_T* get_rep();

static int del_ignored_cmd(rep_cmdlist *cmdlist);
static int translate(rep_cmdlist *userlist, rep_cmdlist *tokenlist);
static void set_header_to_pkt(rep_cmdlist *cmdlist);
static int rep_get_listened_fd();
static int set_hostnamebysock(int sock, char *hostname, int maxlen);
static int rep_accept();
static int rep_connect(char *host);

static void* rep_alloc(int size);
static void rep_free(void *obj);

static BUFTYPE* get_buf_by_name(char *name);
static Session* init_session(Session *sn);
static Session* make_session(char *name, BUFTYPE *buf);
static void free_session(Session *sn);
static void free_session_list(Session *head);
static void register_session(Session *sn);
static Session* set_cursession(Session *sn);
static Session* find_session_by_buf(BUFTYPE *buf);
static Session* find_session_by_name(char *name);
static int set_session_info(char *dest_sinfo, char *sname, char *hostname, int port);
static char* get_fullpath(Session *session);
static char* get_shortname(Session *session);

static int make_local_slineup(Session *slineup,
                              char *hostname,
                              Session *my_sessions);
static int get_slineup_from_sm(char *servername,
                               Session *slineup,
                               char *hostname,
                               Session *my_sessions);
static char* get_sname_by_snum(int snum);
static int writen(int fd, char *textbuf, unsigned int len);

static char* make_packet(unsigned int cmd,
                         unsigned int sid,
                         unsigned int eid,
                         unsigned int seq,
                         unsigned int lnum,
                         char *text);
static char* make_open_packet(char *file_name);
static rep_cmd* make_cmd(unsigned int cmd,
                         unsigned int sid,
                         unsigned int eid,
                         unsigned int seq,
                         unsigned int lnum,
                         char *text);
static int free_cmd(rep_cmd *cmd);
static int free_cmdlist(rep_cmdlist *cmdlist);
static void add_cmd_to_list(rep_cmdlist *cmdlist, rep_cmd *cmd);
static int add_pkt_to_list(rep_cmdlist *cmdlist, char *pkt);

static void check_line_change(Session *sn, unsigned int lnum);

static unsigned int get_header(char *buf,int offset);
static int set_header(unsigned int num, char *pkt, int offset);

static int rep_exe_cmd(unsigned int cmd,
                       unsigned int sid,
                       unsigned int eid,
                       unsigned int seq,
                       unsigned int lnum,
                       unsigned int textsize,
                       char *text);
static int rep_exe_pkt(char *pkt);
static int rep_exe_pktlist(rep_cmdlist *cmdlist);
static int rep_exe_cmdlist(rep_cmdlist *cmdlist);

static int rep_recv_cmds(int fd, rep_cmdlist *smcmdlist,rep_cmdlist *txtcmdlist);
static int rep_send_cmds(int fd, rep_cmdlist *cmdlist);

static int session_fd_check(Session *sn, fd_set *rfds_p, fd_set *efds_p);
static int session_fd_set(Session *sn, fd_set *rfds_p, fd_set *efds_p, int max_fds);
static int append_newline_sep_text(Session *sn, char *text);

/* g_rep has an all information of Remote Editor */
rep_T g_rep;



/*
 * Wrapper for vim
 */

/* エラーメッセージ出力 */
static void
e_msg_wrp(msg)
    char * msg;
{
    EMSG(msg);
}

static void
e_msg2_wrp(msg1, msg2)
    char * msg1;
    char * msg2;
{
    EMSG2(msg1,msg2);
}

/* 通常のメッセージを出力 */
static void
puts_msg_wrp(msg)
    char * msg;
{
    MSG_PUTS(msg);
}

static void
free_wrp(p)
    void *p;
{
    vim_free(p);
    return;
}


/* 空の新しいバッファを取得 */
static BUFTYPE *
make_new_buf_wrp(name)
    char * name;
{
    return buflist_new((char_u*)name, NULL, 0, BLN_LISTED);
}

static void
free_buf_wrp(buf)
    BUFTYPE *buf;
{
    close_buffer(NULL, buf, DOBUF_DEL);
    return;
}


/* 名前からバッファへのポインタを取得 */
static BUFTYPE *
find_buf_by_name_wrp(name)
    char * name;
{
    char *sfname = NULL; // sfname is used name's address
    BUFTYPE *buf;
    BUFTYPE *orgbuf;

    /* make a full file name.  name is changed to absolute path.
     * name's address is assigned to sfname. */
    fname_expand((char_u**)&name, (char_u**)&sfname);
    buf = buflist_findname((char_u*)name);

    free_wrp(name);
    return buf;
}

static void
open_buffer_memline_wrp(buf)
    BUFTYPE *buf;
{
    BUFTYPE *oldbuf;
    /*
    oldbuf = set_curbuf_wrp(buf);
    set_curbuf_wrp(oldbuf);
    */
    oldbuf = curbuf;
    curbuf = buf;
    open_buffer(FALSE, NULL);
    curbuf = oldbuf;
    return;
}


/* 現在編集中のバッファへのポインタを取得 */
extern BUFTYPE *curbuf;
static BUFTYPE *
get_curbuf_wrp()
{
    return curbuf;
}

/* buf を編集対象にする。
 *それまで編集対象だったバッファへのポインタを返す */
static BUFTYPE *
set_curbuf_wrp(buf)
    BUFTYPE *buf;
{
    BUFTYPE *cb;
    if (buf == NULL)
        return NULL;

    cb = get_curbuf_wrp();
    set_curbuf(buf,DOBUF_GOTO);

    return cb;
}

/* 指定した行番号の行のテキスト(文字列)のポインタを取得 */
static char *
get_memline_wrp(buf, lnum)
    BUFTYPE *buf;  // buf is curbuf
    long lnum;
{
//    return ml_get(lnum);
    return (char*)ml_get_buf(buf, lnum, FALSE);
}

/* 編集中のバッファの行の挿入 */
/* "text" does NOT need to be allocated */
static int
append_memline_wrp(lnum, text)
    long lnum;
    char *text;
{
    int r;
    int permit;
    rep_T *rep;
    rep = get_rep();
    permit = rep->permit;
    rep->permit = FALSE;
    
    r = ml_append(lnum-1, (char_u*)text, strlen(text)+1, FALSE);
    appended_lines_mark(lnum-1,1);

    rep->permit = permit;
    return r;
}

/* 編集中のバッファの行の削除 */
static int
delete_memline_wrp(lnum)
    long lnum;
{
    int r;
    int permit;
    rep_T *rep;
    rep = get_rep();
    permit = rep->permit;
    rep->permit = FALSE;

    r = ml_delete(lnum, FALSE);
    deleted_lines_mark(lnum,1);

    rep->permit = permit;
    return r;
}

/* 編集中のバッファの行の置換 */
static int
replace_memline_wrp(lnum, text)
    long lnum;
    char * text;
{
    int r;
    int permit;
    rep_T *rep;
    rep = get_rep();
    permit = rep->permit;
    rep->permit = FALSE;

    r = ml_replace(lnum, (char_u*)text, TRUE);

    rep->permit = permit;
    return r;
}

/* バッファの編集後の後処理 */
static void 
update_screen_now_wrp()
{
    check_cursor();
    update_screen(CLEAR);
    return;
}

static void
update_screen_later_wrp(buf)
    BUFTYPE *buf;
{
    check_cursor();
    return redraw_buf_later(buf, CLEAR);
}

/* 編集中のバッファの行数を返す */
static long
get_bufmaxline_wrp(buf)
    BUFTYPE *buf;
{
    return buf->b_ml.ml_line_count;
}

/* ユーザに文字列を入力させる */
static char *
getstr_input_wrp(msg)
    char *msg; // 入力時のメッセージ
{
    char *cmdline;

    /* 受け取る文字列は使用後 vim_free() する */
    cmdline = (char*)getcmdline_prompt('@', (char_u*)msg, 0);

    return cmdline;
}

/* get full path of buffer */
static char *
get_fullpath_wrp(buf)
    BUFTYPE *buf;
{
    return (char*)buf->b_ffname;
}

/* get short name of buffer */
static char *
get_shortname_wrp(buf)
    BUFTYPE *buf;
{
    return (char*)buf->b_sfname;
}

/* Wrapper END */


static void
puts_sys_err()
{
    char errmsg[50];

    sprintf(errmsg, "rep>> %d:%s", errno, strerror(errno));
    e_msg_wrp(errmsg);
    return;
}


static rep_T*
get_rep()
{
    return(&g_rep);
}

int
rep_permit()
{
    return(g_rep.permit);
}

int
rep_session_permit()
{
    return(g_rep.permit && g_rep.cursession && g_rep.cursession->permit);
}

void
rep_start_create_cmds()
{
    if (g_rep.cursession) {
        g_rep.cursession->permit = TRUE;
    }
    return;
}

void
rep_stop_create_cmds()
{
    if (g_rep.cursession) {
        g_rep.cursession->permit = FALSE;
    }
    return;
}


int
rep_init()
{
    /*
     * g_rep is global variable and it is zero cleared.
     */

    char def_hostname[] = "localhost";
    
    // 現在編集対象のバッファはセッションに加える?
    g_rep.shead = NULL; //make_session();
    g_rep.slineup = NULL;

    g_rep.cursession = NULL;
    g_rep.servername = NULL;
    g_rep.waiting_session_name = NULL;
    
    g_rep.smfd = -1;

    g_rep.eid = 0;
    g_rep.seqno = 0;
    
    g_rep.permit = FALSE;
    
    if (gethostname(g_rep.hostname, sizeof(g_rep.hostname)) < 0) {
        strncpy(g_rep.hostname, def_hostname, sizeof(def_hostname)+1);
    }
    
    return(TRUE);
}


/*
 * cmdlistを辿り、statメンバが REP_IGNORE であるREPコマンドを削除する。
 */
static int
del_ignored_cmd(cmdlist)
    rep_cmdlist *cmdlist;
{
    rep_cmd *curcmd;
    rep_cmd *next;

    for (;(cmdlist->head) && (cmdlist->head->stat == REP_IGNORE); cmdlist->head=next) {
        next = cmdlist->head->next;
        free_cmd(cmdlist->head);
    }
    
    if (cmdlist->head == NULL) return(TRUE);
    
    for (curcmd=cmdlist->head; curcmd->next;) {
        next = curcmd->next->next;
        if (curcmd->next->stat == REP_IGNORE) {
            free_cmd(curcmd->next);
            curcmd->next = next;
            cmdlist->num--;
        } else {
            curcmd = curcmd->next;
        }
    }
    return(TRUE);
}


/***** translate(UserList, ToknList) *****
  入力はトークンとユーザ入力からのREPコマンドのリストで、
  それらを比較・変換して、二つのREPコマンドリストを生成する。

              -------------
  UserList  ->|           | -> UserList'
              | translate |
  ToknList  ->|           | -> ToknList'
              -------------

  Session ID が異なるときは、可換なので、何もしない。

  ToknList + UserList' をトークンとして次のリモートエディタに渡し、
  ToknList' は自分のバッファに反映させる。
              
  比較時に行番号が重なったときの処理は以下の表。
  なるべくテキストが残るようにしている。
  x\y は、TOKEN を x, USER を y するという意味。
  0  -- なにもしない
  +1 -- 行番号を +1
  i  -- コマンド id を 'i' にする。
  X  -- コマンドを削除(無視に)する。

              USER
       |  i   |  r   |  d
    ---|--------------------
  T  i | 0\+1 | 0\+1 | 0\+1
  O ---|--------------------
  K  r | +1\0 | 0\X  | i\X
  E ---|--------------------
  N  d | +1\0 | X\i  | X\X

  無視にされた(stat に REP_IGNORE が入っている)REPコマンドは、
  全ての比較が終了したときにリストから削除される。
*/
static int
translate(userlist, tokenlist) /* userのREPコマンドリスト, tokenのREPコマンドリスト */
    rep_cmdlist *userlist;
    rep_cmdlist *tokenlist;
{
    rep_cmd *usercmd;
    rep_cmd *tokencmd;
    rep_cmd *unext;
    rep_cmd *tnext;

    rep_cmd *h_pricmd; // high priority command
    rep_cmd *l_pricmd; // low priority command
    
    for (usercmd=userlist->head; usercmd; usercmd=unext) {
        unext = usercmd->next;
        
        /* 削除される(予定)のREPコマンドの比較は無視 */
        if (usercmd->stat == REP_IGNORE) continue;

        for (tokencmd=tokenlist->head; tokencmd; tokencmd=tnext) {
            tnext=tokencmd->next;

            /* 削除される(予定)のREPコマンドの比較は無視 */
            if (tokencmd->stat == REP_IGNORE) continue;
            /* XXX 消してもいい??*/
            if ( tokencmd->cmd  != REP_INSERT_CMD &&
                 tokencmd->cmd  != REP_DELETE_LINE_CMD &&
                 tokencmd->cmd  != REP_REPLACE_CMD) {
                 tokencmd->stat = REP_IGNORE;
                 continue;
            }
            if (usercmd->stat == REP_IGNORE) break;
            if ( usercmd->cmd  != REP_INSERT_CMD &&
                 usercmd->cmd  != REP_DELETE_LINE_CMD &&
                 usercmd->cmd  != REP_REPLACE_CMD) {
                 usercmd->stat = REP_IGNORE;
                 break;
            }
	    if (usercmd->sid != tokencmd->sid) {
		// session id が違う場合は何しない
		continue;
	    }
            if (usercmd->lnum < tokencmd->lnum) {        /* UsersLineNumber < TokensLineNumber */
                if (usercmd->cmd == REP_INSERT_CMD) {
                    tokencmd->lnum++;
                } else if (usercmd->cmd == REP_DELETE_LINE_CMD) {
                    tokencmd->lnum--;
                }
            } else if (usercmd->lnum > tokencmd->lnum) {  /* UsersLineNumber > TokensLineNumber */
                if (tokencmd->cmd == REP_INSERT_CMD) {
                    usercmd->lnum++;
                } else if (tokencmd->cmd == REP_DELETE_LINE_CMD) {
                    usercmd->lnum--;
                }
            } else if (usercmd->lnum == tokencmd->lnum) { /* UsersLineNumber == TokensLineNumber */

#if 0
                /*
                 * 行番号が重なるとREPコマンドの競合が起こるので、
                 * どちらかが譲らないといけない。
                 * uid が小さい方を優先(h_pricmdに)し、
                 * uid が大きい方(l_pricmd)を変更する。
                 */
                
                if (usercmd->eid < tokencmd->eid) {
                    h_pricmd = usercmd;
                    l_pricmd = tokencmd;
                } else {
                    h_pricmd = tokencmd;
                    l_pricmd = usercmd;
                }
#else
		/*
		    無条件に、自分の方が優先
	         */
		h_pricmd = usercmd;
		l_pricmd = tokencmd;
#endif
                
                if (h_pricmd->cmd == REP_INSERT_CMD) {
                    l_pricmd->lnum++;
                } else if (h_pricmd->cmd == REP_REPLACE_CMD) {

                    if (l_pricmd->cmd == REP_INSERT_CMD) {
                        h_pricmd->lnum++;
                    } else if (l_pricmd->cmd == REP_REPLACE_CMD) {
                        /* h_pricmd が優先され,l_pricmd は削除(無視に)する */
                        l_pricmd->stat = REP_IGNORE;
                    } else if (l_pricmd->cmd == REP_DELETE_LINE_CMD) {
                        /*
                         * l_pricmd 側ではすでにdeleteされているので、
                         * h_pricmd を REP_REPLACE_CMD -> REP_INSERT_CMD へ変更。
                         */
                        h_pricmd->cmd = REP_INSERT_CMD;
                        l_pricmd->stat = REP_IGNORE;
                    }
                    
                } else if (h_pricmd->cmd == REP_DELETE_LINE_CMD) {

                    if (l_pricmd->cmd == REP_INSERT_CMD) {
                        h_pricmd->lnum++;
                    } else if (l_pricmd->cmd == REP_REPLACE_CMD) {
                        /*
                         * h_pricmd 側ではすでにdeleteされているので、
                         * l_pricmd 側を REP_REPLACE_CMD -> REP_INSERT_CMD へ変更。
                         */
                        l_pricmd->cmd = REP_INSERT_CMD;
                        h_pricmd->stat= REP_IGNORE;
                    } else if (l_pricmd->cmd == REP_DELETE_LINE_CMD) {
                        /*
                         * 相手と削除する行が重なるので、
                         * 両方のコマンドを無視にする。
                         * 相手先ではすでにこの行は削除されている。
                         */
                        h_pricmd->stat = REP_IGNORE;
                        l_pricmd->stat = REP_IGNORE;
                        break;
                    } else {
                    }
                } else {
                }
            }
        }
    }

    return(TRUE);    
}


static void
set_header_to_pkt(cmdlist)
    rep_cmdlist *cmdlist;
{
    rep_cmd *curcmd;
    for (curcmd=cmdlist->head; curcmd; curcmd=curcmd->next) {
        set_header(curcmd->cmd, curcmd->pkt, REP_CMD_OFFSET);
        set_header(curcmd->sid, curcmd->pkt, REP_SID_OFFSET);
        set_header(curcmd->eid, curcmd->pkt, REP_EID_OFFSET);
        set_header(curcmd->seq, curcmd->pkt, REP_SEQNUM_OFFSET);
        set_header(curcmd->len, curcmd->pkt, REP_T_SIZE_OFFSET);
        set_header(curcmd->lnum, curcmd->pkt, REP_LNUM_OFFSET);
    }
    return;
}

static int
rep_get_listened_fd()
{
    int sock;
    int value;
    struct sockaddr_in addr;
    
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        e_msg_wrp("socket(): ERROR");
        return(-1);
    }

    /* Allow other programs to bind to the socket */
    value = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0) {
        e_msg_wrp("setsockopt() REUSEADDR failed");
        exit(1);
    }

    bzero((char*)&addr, sizeof(addr));
    
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(REP_PORT);
    
    if ((bind(sock, (struct sockaddr*)&addr, sizeof(addr))) == -1) {
        e_msg_wrp("bind(): ERROR");
        return(-1);
    }
    
    if ((listen(sock, SOCK_MAX)) < 0) {
        e_msg_wrp("listen(): ERROR");
        return(-1);
    }
    
    return(sock);
}

static int
set_hostnamebysock(sock,hostname,maxlen)
    int sock;
    char *hostname;
    int maxlen;
{
    int sinlen;
    struct sockaddr_in sin;
    struct hostent *host;
    int namelen;
    
    sinlen = sizeof sin;
    if (getpeername(sock, (struct sockaddr *) &sin, (socklen_t *)&sinlen) < 0){
        return(FALSE);
    }
    
    if ((host = gethostbyaddr((char *) &sin.sin_addr, sizeof(sin.sin_addr), AF_INET)) == NULL){
        return(FALSE);
    }

    namelen = strlen(host->h_name);
    if (namelen > maxlen) {
        e_msg_wrp("host name is too long.");
        return(FALSE);
    }

    strncpy(hostname,host->h_name,namelen);
    hostname[namelen] = '\0';
    return(TRUE);
}

static char default_host[] = "localhost";

static int
rep_connect(host)
    char *host; /* "hostname:portnumber" */
{
    int sock;
    struct hostent        *hp;
    struct sockaddr_in    sin;
    char *tmp;
    int port;
   
    if (host == NULL || host == '\n') {
	host = default_host;
	port = REP_PORT;
    } else {
	if ((tmp = strchr(host, ':')) == NULL ) {
	    return(-1);
	}
	*tmp = '\0';
	tmp++;
	port = atol(tmp);
    }
    
    if ((hp = gethostbyname(host)) == NULL) {
        e_msg_wrp("rep_open: gethostbyname: ERROR");
        return(-1);
    }
    
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        e_msg_wrp("rep_open: socket : ERROR");
        return(-1);
    }
    
    bzero(&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);

    if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
        e_msg_wrp("rep_open: connect: ERROR");
        return(-1);
    }
    
    return(sock);
}


static BUFTYPE *
get_buf_by_name(name)
    char *name;
{
    BUFTYPE *buf;
    if ((buf = find_buf_by_name_wrp(name)) == NULL) {
        buf = make_new_buf_wrp(name);
    }

    if (buf && (buf->b_ml.ml_mfp == NULL)) {
        open_buffer_memline_wrp(buf);
    }
    
    return buf;
}


/* About Session */

static Session *
init_session(sn)
    Session *sn;
{
    sn->next = NULL;
    sn->buf = NULL;
    sn->sname = NULL;
    sn->new_cmdlist.head = NULL;
    sn->new_cmdlist.num = 0;
    sn->sent_cmdlist.head = NULL;
    sn->sent_cmdlist.num = 0;
    sn->sid = 0;
    sn->permit = FALSE;
    sn->prevline = -1;

    return sn;
}

/*
 * Make a new session.
 * if buf is NULL, buffer is found or made new one.
 */
static Session *
make_session(name, buf)
    char *name;
    BUFTYPE *buf;
{
    Session *s;

    char *sname;
    int namelen = strlen(name)+1;
    
    s = (Session*)rep_alloc(sizeof(Session));
    if (s == NULL) {
        return(NULL);
    }
    
    if ((sname = (char*)rep_alloc(namelen)) == NULL) {
        return NULL;
    }
    strncpy(sname,name,namelen);

    init_session(s);

    if (buf == NULL) buf = get_buf_by_name(sname);
    s->buf = buf;

    s->sname = sname;
    
    return s;
}

static void 
free_session(sn)
    Session *sn;
{
    
    free_cmdlist(&sn->new_cmdlist);
    free_cmdlist(&sn->sent_cmdlist);
    free_buf_wrp(sn->buf);
    
    if (sn->sname) rep_free(sn->sname);

    init_session(sn);
    
    rep_free(sn);
    return;
}

static void
free_session_list(head)
    Session *head;
{
    Session *next;
    for (; head; head=next) {
        next = head->next;
        head->next = NULL;
        free_session(head);
    }
    return;
}

static void
register_session(sn)
    Session *sn;
{
    rep_T *rep;

    rep = get_rep();

    sn->next = rep->shead;
    rep->shead = sn;

    return;
}

static Session*
set_cursession(sn)
    Session *sn;
{
    BUFTYPE *oldbuf;
    Session *oldsn;
    rep_T *rep = get_rep();

    if (sn) oldbuf = set_curbuf_wrp(sn->buf);
    rep->cursession = sn;

    oldsn = find_session_by_buf(oldbuf);
    return oldsn;
}

static Session*
find_session_by_id(id)
    unsigned int id;
{
    Session *cursn = NULL;
    rep_T *rep = get_rep();

    if (rep->slineup && rep->slineup->sid == id) {
        return rep->slineup;
    }

    for (cursn = rep->shead; cursn; cursn = cursn->next) {
        if (cursn->sid == id) {
            return cursn;
        }
    }

    return NULL;
}

static Session*
find_session_by_buf(buf)
    BUFTYPE *buf;
{
    Session *cursn = NULL;
    rep_T *rep  = get_rep();

    if (buf == NULL) return NULL;
    
    if(rep->slineup->buf == buf)
        return rep->slineup;
    for (cursn = rep->shead; cursn; cursn = cursn->next) {
        if (cursn->buf == buf) break;
    }
    return cursn;
}

static Session*
find_session_by_name(name)
    char *name;
{
    BUFTYPE *buf;
    buf = find_buf_by_name_wrp(name);
    return find_session_by_buf(buf);
}

int
rep_input_reg_session() // input own session(s)
{
    char *sname;
    
    while (1) {
        // retrun value (sname) is allocated.
        sname = getstr_input_wrp("Session to offer = ");
        if (sname == NULL) return FALSE;
        if (*sname=='\0') {  // input pert is finished
            free_wrp(sname);
            break;
        }
        register_session(make_session(sname, NULL));
        
        free_wrp(sname);
    }

    update_screen_now_wrp(); /* ウィンドウを再描画 */
    return TRUE;
}


static int
set_session_info(dest_sinfo, sname, hostname, port)
    char *dest_sinfo;
    char *sname;
    char *hostname;
    int port;
{
    int size;
    size = sprintf(dest_sinfo, "%s:%d:%s",hostname, port, sname);
    dest_sinfo[size] = '\0';
    return 0;
}

static char*
get_fullpath(session)
    Session *session;
{
    BUFTYPE *buf;
    if (session == NULL) {
        buf = get_curbuf_wrp();
    } else {
        buf = session->buf;
    }
    return get_fullpath_wrp(buf);
}

static char*
get_shortname(session)
    Session *session;
{
    return get_shortname_wrp(session->buf);
}



/* End Session */

#define SINFO_MAX 255
/*
 * 自身が提供するセッションのみをセッションリストに書き出す
 * あらかじめセッションリストのバッファを編集対象のバッファに
 *指定しておく(set_curbuf_wrp(slineup)しておく)
 */
static int
make_local_slineup(slineup, hostname, my_sessions)
    Session *slineup;
    char *hostname;
    Session *my_sessions;
{
    Session *s;
    BUFTYPE *oldcurbuf;
    char sinfo[SINFO_MAX];

    if (my_sessions == NULL) return FALSE;
    
    for (; my_sessions; my_sessions=my_sessions->next) {
        set_session_info(sinfo, my_sessions->sname, hostname, REP_PORT);
        /* 現在の編集対象のバッファ curbuf に対して書き込みを行なう */
        append_memline_wrp(1, sinfo);
    }

    return TRUE;
}


/*
 * セッションマネージャからセッションリストを取得
 * あらかじめセッションリストのバッファを編集対象のバッファに
 *指定しておく(set_curbuf_wrp(buf)しておく)
 */
static int
get_slineup_from_sm(servername, slineup, hostname, my_sessions)
    char *servername;
    Session *slineup;
    char *hostname;
    Session *my_sessions;  // linked list
{
    return TRUE;
}


char *
rep_input_param(msg, err_msg)
    char *msg;
    char *err_msg;
{
    char *input_string;

    if ((input_string = getstr_input_wrp(msg)) == NULL) {
        return NULL;
    }

    if (*input_string == '\0') {
        if (err_msg) {
            puts_msg_wrp(err_msg);
        }
        free_wrp(input_string);
        return NULL;
    }

    return input_string;
}

int
rep_join()
    char *server; /* "hostname:portnumber" */
{
    int sock;
    rep_T *rep;
    
    rep_cmdlist cmdlist = {NULL,0};

    rep = get_rep();
/*    
    if (server == NULL) {
        return FALSE;
    }
*/
    if ((sock = rep_connect(server)) < 0) {
        return FALSE;
    }
    if (rep->smfd > 0) {
        close(rep->smfd);
    }

    rep->smfd = sock;
    rep->permit = TRUE;
    
    add_cmd_to_list(&cmdlist, make_cmd(REP_JOIN_CMD, 0, rep->eid, rep->seqno++, 0, NULL));
    rep_send_cmds(sock, &cmdlist);

    free_cmdlist(&cmdlist);

    return TRUE;

}

int 
rep_select_command(session_no)
    char *session_no;
{
    rep_T *rep = get_rep();
    rep_cmdlist cmdlist = {NULL, 0};
    int sid;


    if (rep->smfd < 0 || session_no == NULL) {
        return FALSE;
    }

    if (rep->waiting_session_name) {
        rep_free(rep->waiting_session_name);
    }
   sid = atol(session_no); 
    if ((rep->waiting_session_name = get_sname_by_snum(sid)) == NULL) {
        e_msg_wrp("Session Selection is false.");
        return FALSE;
    }
    
    add_cmd_to_list(&cmdlist, make_cmd(REP_SELECT_CMD, sid, rep->eid, rep->seqno++, 0, session_no));
    rep_send_cmds(rep->smfd, &cmdlist);

    free_cmdlist(&cmdlist);

    return TRUE;
}

int
rep_put(sname)
    char *sname;
{
    rep_T *rep = get_rep();
    rep_cmdlist cmdlist = {NULL, 0};
    char *server = NULL;
    int len;
    Session *sn;

    while (rep->smfd < 0) {     /* Until does NOT connect to Session Manager */
        server = rep_input_param("Session Manager = ", NULL);
	/*
        if (server == NULL) {  // input nothing means cancel
            return FALSE;
        }
	*/
        if ((rep->smfd = rep_connect(server)) < 0) {
	    free_wrp(server);
	    return FALSE;
	}
        free_wrp(server);
    }
    
    if (sname == NULL) {
        /* get current buffer name */
        if ((sname = get_fullpath(rep->cursession)) == NULL) {
            sname = NO_NAME;  /* the buffer has not name */
        }
    }

    if (find_session_by_name(sname) == NULL) {
        sn = make_session(sname, get_buf_by_name(sname));
        register_session(sn);
    }
    
    if (rep->waiting_session_name) {
        rep_free(rep->waiting_session_name);
    }
    len = strlen(sname) +1;
    rep->waiting_session_name = (char *)rep_alloc(len);
    memcpy(rep->waiting_session_name, sname, len);
        
    add_cmd_to_list(&cmdlist, make_cmd(REP_PUT_CMD, 0, rep->eid, rep->seqno++, 0, sname));

    rep_send_cmds(rep->smfd, &cmdlist);

    free_cmdlist(&cmdlist);

    return TRUE;
}


int
rep_remove()
{
    rep_T *rep = get_rep();
    rep_cmd *cmd;
    rep_cmdlist cmdlist = {NULL, 0};
    Session *sn = rep->cursession;

    if (rep->smfd < 0) {     /* session does not exist */
        EMSG("Session does not exist.");
        return FALSE;
    }
    
    cmd = make_cmd(REP_DEREGISTER_CMD, sn->sid, rep->eid, rep->seqno, 0, NULL);
    add_cmd_to_list(&cmdlist, cmd);
    rep_send_cmds(rep->smfd, &cmdlist);
    free_cmdlist(&cmdlist);

    return TRUE;
}

static int
rep_make_slineup()
{
    BUFTYPE buf;
//    BUFTYPE *oldcurbuf;
    Session *oldsn;

    rep_T *rep;
    rep = get_rep();

    if (rep->slineup) {
        free_session(rep->slineup);
    }
    
    rep->slineup = make_session(SLINEUP_NAME, make_new_buf_wrp(SLINEUP_NAME));
    
    oldsn = set_cursession(rep->slineup);

    /* セッション一覧リストを作成 */
    if ((get_slineup_from_sm(rep->servername, rep->slineup, rep->hostname, rep->shead) == FALSE)) {
        make_local_slineup(rep->slineup, rep->hostname, rep->shead);
    }

    update_screen_now_wrp(); /* ウィンドウを再描画 */
        
    return TRUE;
}


static int
enter_session(session_name)
    char *session_name;
{
    return TRUE;
}


/* Session End */

static void *
rep_alloc(size)
    int size;   /* byte */
{
    void *allocated;
    if ((allocated = malloc(size)) == NULL) {
        e_msg_wrp("no memory!");
    }

    return allocated;
}

static void
rep_free(obj)
    void *obj;
{
    if (obj) free(obj);
    return;
}


static int
writen(sock, pkt, len)
    int sock;
    char *pkt;
    unsigned int len;
{
    int offset;
    int written;

    if (len == 0) return 0;

    for (offset=0, written=0; offset<len; offset += written) {
        if ((written = write(sock, pkt + offset, len - offset)) < 0) {
            puts_sys_err();
            return written;
        }
    }
    return offset;
}

static int
readn(sock, pkt, len)
    int sock;
    char *pkt;
    unsigned int len;
{
    unsigned int r;
    unsigned int offset;

    if (len == 0) return 0;
    
    for (offset=0, r=0; offset<len; offset += r) {
        if ((r = read(sock, pkt + offset, len - offset)) < 0) {
            puts_sys_err();
            return r;
        }
    }
    return offset;
}


static char*
make_packet(cmd, sid, eid, seq, lnum, text)
    unsigned int cmd;
    unsigned int sid;
    unsigned int eid;
    unsigned int seq;
    unsigned int lnum;
    char * text;
{
    char *packet;
    unsigned int len = 0;

    if (text) len += strlen(text);// + 1; /* for include '\0' */

    if ((packet = (char *)rep_alloc(REP_HEADER_SIZE+len)) == NULL) {
        return(NULL);
    }
    
	set_header(cmd, packet, REP_CMD_OFFSET);
	set_header(sid, packet, REP_SID_OFFSET);
	set_header(eid, packet, REP_EID_OFFSET);
	set_header(seq, packet, REP_SEQNUM_OFFSET);
	set_header(lnum, packet, REP_LNUM_OFFSET);
	set_header(len, packet, REP_T_SIZE_OFFSET);

    if (text) {
        memcpy(packet+REP_TEXT_OFFSET, text, len);
    }

    return(packet);
}


static rep_cmd*
make_cmd(cmd, sid, eid, seq, lnum, text)
    unsigned int cmd;
    unsigned int sid;
    unsigned int eid;
    unsigned int seq;
    unsigned int lnum;
    char *text;
{
    rep_cmd *cmd_p;
    char *pkt;
    unsigned int length = 0;
    
    pkt = make_packet(cmd, sid, eid, seq, lnum, text);
    if (pkt == NULL) {
        e_msg_wrp("make_cmd: no memory: ERROR");
        return(NULL);
    }

    cmd_p = (rep_cmd*)rep_alloc(sizeof(rep_cmd));
    if (cmd_p == NULL) {
        e_msg_wrp("make_cmd: no memory: ERROR");
        return(NULL);
    }

    if (text) {
        length = strlen(text); //+1; // include '\0'
    }
    
    cmd_p->next = NULL;

    cmd_p->cmd  = cmd;
    cmd_p->sid  = sid;
    cmd_p->eid  = eid;
    cmd_p->seq  = seq;
    cmd_p->len  = length;
    cmd_p->lnum = lnum;
    
    cmd_p->stat = REP_AVAIL;
    cmd_p->pkt  = pkt;

    return(cmd_p);
}

static int
free_cmd(cmd)
    rep_cmd *cmd;
{
    if (cmd == NULL) return(FALSE);
    
    if (cmd->pkt) {
        rep_free(cmd->pkt);
        cmd->pkt=NULL;
    }
    rep_free(cmd);
    cmd = 0;
    return(TRUE);
}

static int
free_cmdlist(cmdlist)
    rep_cmdlist *cmdlist;
{
    rep_cmd *cur;
    rep_cmd *next;
    
    if (cmdlist->head==NULL) return(FALSE);
    for (cur=cmdlist->head; cur; cur=next) {
        next=cur->next;
        free_cmd(cur);
    }
    cmdlist->head = NULL;
    cmdlist->num = 0;
    return(TRUE);
}

static void
add_cmd_to_list(cmdlist, cmd)
    rep_cmdlist *cmdlist;
    rep_cmd *cmd;
{
    rep_cmd *p;
    int count = 0;

    for (p=cmd; p; p=p->next) count++;

    if (cmdlist->head) {
        for (p = cmdlist->head; p->next; p = p->next);
        p->next = cmd;
    } else {
        cmdlist->head = cmd;
    }
    cmdlist->num += count;
    return;
}

static int
add_pkt_to_list(cmdlist, pkt) /* pkt is allocated */
    rep_cmdlist *cmdlist;
    char *pkt;
{
    rep_cmd *cmd_p;

    if (pkt == NULL) return(FALSE);
    
    cmd_p = (rep_cmd*)rep_alloc(sizeof(rep_cmd));
    if (cmd_p == NULL) {
        e_msg_wrp("add_pkt_to_list: no memory: ERROR");
        return(FALSE);
    }

    cmd_p->next = NULL;

    cmd_p->cmd  = get_header(pkt, REP_CMD_OFFSET);
    cmd_p->sid  = get_header(pkt, REP_SID_OFFSET);
    cmd_p->eid  = get_header(pkt, REP_EID_OFFSET);
    cmd_p->seq  = get_header(pkt, REP_SEQNUM_OFFSET);
    cmd_p->lnum = get_header(pkt, REP_LNUM_OFFSET);

    cmd_p->stat = REP_AVAIL;
    cmd_p->len  = strlen(pkt)+1 - REP_HEADER_SIZE;
    cmd_p->pkt  = pkt;

    add_cmd_to_list(cmdlist, cmd_p);
    
    return(TRUE);
}


void
rep_prevline_flush()
{
    BUFTYPE *cbuf;
    Session *cursn;
    rep_cmd *cmd;
    rep_T *rep = get_rep();
    char *text;
    
    cursn = rep->cursession;

    if ((cursn == NULL) || (cursn->prevline == -1)) return;

    // バッファが変更された場合には rep->cursession も合わす
    if ((cbuf = get_curbuf_wrp()) != cursn->buf) {
        cursn = find_session_by_buf(cbuf);
        if (cursn == NULL)
            return;
        rep->cursession = cursn;
    }

    text = get_memline_wrp(cursn->buf, cursn->prevline);
    
    cmd = make_cmd(REP_REPLACE_CMD, cursn->sid, rep->eid, rep->seqno++, cursn->prevline, text);
    
    add_cmd_to_list(&(cursn->new_cmdlist), cmd);

    
    
    if (cursn->sent_cmdlist.num == 0) { // 自トークンを送信してない場合
        rep_send_cur_cmdlist();
    }
    
    cursn->prevline = -1;
}


static void
check_line_change(sn, lnum)
    Session *sn;
    unsigned int lnum;
{
    rep_cmd *cmd;
    rep_T *rep = get_rep();

    
    if (sn->prevline == lnum) {
        return;
    }

    if (sn->prevline == -1) {
        sn->prevline = lnum;
        return;
    }
    cmd = make_cmd(REP_REPLACE_CMD, sn->sid, rep->eid, rep->seqno++, sn->prevline,
                   get_memline_wrp(sn->buf, sn->prevline));
    add_cmd_to_list(&(sn->new_cmdlist), cmd);

    sn->prevline = lnum;
    return;
}

int
rep_register(lnum, lnume, xtra)
    unsigned int lnum;
    unsigned int lnume;
    int xtra;
{
    int i;
    BUFTYPE *cbuf;
    Session *cursn;
    rep_cmd *cmd;
    rep_T *rep = get_rep();
    
    if ((cursn = rep->cursession) == NULL) return FALSE;

    // バッファが変更された場合には rep->cursession も合わす
    if ((cbuf = get_curbuf_wrp()) != cursn->buf) {
        cursn = find_session_by_buf(cbuf);
        if (cursn == NULL)
            return FALSE;
        rep->cursession = cursn;
    }
        
    if (xtra == 0) {
        for (i = 0; lnume-lnum > i; i++) {
            check_line_change(cursn,lnum+i);
        }
    } else if (xtra > 0) {
        if (lnum != lnume) { /* 行の途中から改行 */
            cmd = make_cmd( REP_REPLACE_CMD, cursn->sid, rep->eid, rep->seqno++, lnum,
                            get_memline_wrp(cursn->buf, lnum));
            add_cmd_to_list(&(cursn->new_cmdlist), cmd);
            lnum++;
        }
        for (i = 0; xtra > 0; i++, xtra--) {
            cmd = make_cmd( REP_INSERT_CMD, cursn->sid, rep->eid, rep->seqno++, lnum+i,
                            get_memline_wrp(cursn->buf, lnum+i));
            add_cmd_to_list(&(cursn->new_cmdlist), cmd);
        } 
    } else { /* xtra < 0 */
        xtra = -xtra;
        for (; xtra > 0; xtra--) {
            cmd = make_cmd(REP_DELETE_LINE_CMD, cursn->sid, rep->eid, rep->seqno++, lnum,
                           NULL);
            add_cmd_to_list(&(cursn->new_cmdlist), cmd);
        }
    }

    if (cursn->sent_cmdlist.num == 0) {
        rep_send_cur_cmdlist();
    }
    
    return(lnume - lnum);
}


static int
set_header(data, pkt, offset)
    unsigned int data;
    char         *pkt;
    int          offset;
{
    int *ipkt;
    int ndata = htonl(data);

    ipkt = (int*)pkt;
    ipkt[offset/4] = ndata;

    return(TRUE);    
}

static unsigned int
get_header(pkt, offset)
	char  *pkt;
	int offset;
{
	int *ipkt;
	int data;
	unsigned int header;

	ipkt   = (int *)pkt;
	data   = ipkt[offset/4];
	header = (unsigned int)ntohl(data);

	return(header);
}


static int
rep_exe_cmd(cmd, sid, eid, seq, lnum, textsize, text)
    unsigned int cmd;
    unsigned int sid;
    unsigned int eid;
    unsigned int seq;
    unsigned int lnum;
    unsigned int textsize;
    char *text;
{
    char h_name[50];
    rep_cmdlist tmplist = {NULL, 0};
    rep_cmd *repcmd;
    BUFTYPE *buf;
    rep_T *rep = get_rep();
    Session *session;
    
    unsigned int buflenmax;

    session = find_session_by_id(sid);

    /*XXX 無理矢理 */
    if (textsize == 0) {
        text = NULL;
    }
    
    switch (cmd) {
    case REP_JOIN_ACK:
        /* show session lineup */
        if (rep->slineup) {
            free_session(rep->slineup);
        }
        rep->slineup = make_session(SLINEUP_NAME, make_new_buf_wrp(SLINEUP_NAME));
        append_newline_sep_text(rep->slineup, text);
        set_cursession(rep->slineup);
        update_screen_now_wrp();

        if (rep->eid == 0) {
            rep->eid = eid;
        }
        break;
    case REP_SELECT_ACK:
        // text is error message. means occur ERROR in session manager
        if (text) {
            e_msg_wrp(text);
            return FALSE;
        }

        // DON'T wait session from session manager
        if (! rep->waiting_session_name) {
            return FALSE;
        }

        session = make_session(rep->waiting_session_name,
                               make_new_buf_wrp(rep->waiting_session_name));
        session->sid = sid;
        register_session(session);

        rep_free(rep->waiting_session_name);
        rep->waiting_session_name = NULL;
        
        set_cursession(session);

        rep_start_create_cmds();

        /* get window size */
        /* send read command */
        break;
    case REP_REGISTER_ACK:
    case REP_PUT_ACK:
        /* Enter Session */

        if (text) {  // text is error message.
            e_msg_wrp(text);
            return FALSE;
        }

        /* Use wating_session_name for assign session id */
        if ((session = find_session_by_name(rep->waiting_session_name)) == NULL) {
            if (rep->waiting_session_name) {
                rep_free(rep->waiting_session_name);
                rep->waiting_session_name = NULL;
            }
            return FALSE;
        }
        session->sid = sid;

        /* set session to cursession */
        set_cursession(session);
        rep_start_create_cmds();
        
        break;
    case REP_DEREGISTER_CMD:
    case REP_DEREGISTER_ACK:
    case REP_QUIT_CMD:
    case REP_QUIT_ACK:
    case REP_GET_CMD:
    case REP_GET_ACK:
        break;
    case REP_OPEN_CMD:
        /* REP_OPEN_CMD is handled in list part. (may be upper function) */
        break;

        /* connection commands */

    case REP_OPEN_ACK:
    case REP_CLOSE_CMD:
        break;
    case REP_CLOSE_ACK:
        break;
    case REP_READ_CMD:
        break;
    case REP_READ_ACK:
        break;
    case REP_READ_FIN:
        break;
        /* buffer edit commands */
        /* session's buffer is set to current buffer */
    case REP_INSERT_CMD:
        append_memline_wrp(lnum, text);
        break;
    case REP_DELETE_LINE_CMD:
        delete_memline_wrp(lnum);
        break;
    case REP_REPLACE_CMD:
        if (lnum > get_bufmaxline_wrp(session->buf)) {
            append_memline_wrp(lnum, text);
        }
        replace_memline_wrp(lnum, text);  /* text was allocated */
        break;
    default:
        break;
    }

    free_cmdlist(&(tmplist));

    return(TRUE);
}


static int
rep_exe_pkt(pkt)
    char *pkt;
{
    unsigned int cmd;
    unsigned int sid;
    unsigned int eid;
    unsigned int seq;
    unsigned int lnum;
    unsigned int len;
    char *text;
    
    cmd = get_header(pkt, REP_CMD_OFFSET);
    sid = get_header(pkt, REP_SID_OFFSET);
    eid = get_header(pkt, REP_EID_OFFSET);
    seq = get_header(pkt, REP_SEQNUM_OFFSET);
    lnum = get_header(pkt, REP_LNUM_OFFSET);
    len = get_header(pkt, REP_T_SIZE_OFFSET);
    text = pkt + REP_TEXT_OFFSET;

    rep_exe_cmd(cmd, sid, eid, seq, lnum, len, text);
    
    return(TRUE);
}

/* execute command list based cmd packet */
static int
rep_exe_pktlist(cmdlist)
    rep_cmdlist *cmdlist;
{
    rep_cmd *repcmd;
    BUFTYPE *orgbuf;
    char *sname;
    
    if ((cmdlist == NULL) || (cmdlist->head == NULL)) {
        return(FALSE);
    }

    for (repcmd = cmdlist->head; repcmd; repcmd = repcmd->next) {
        if (repcmd->stat == REP_AVAIL) {
            rep_exe_pkt(repcmd->pkt);
        }
    }
    
    return(TRUE);
}


/* execute command list based cmd structure */
/* sn must be already exists */
static int
rep_exe_cmdlist(cmdlist)
    rep_cmdlist *cmdlist;
{
    rep_cmd *cmd;
    BUFTYPE *orgbuf;
    unsigned short uid;
    
    if ((cmdlist == NULL) || (cmdlist->head == NULL)) {
        return(FALSE);
    }

    for (cmd = cmdlist->head; cmd; cmd = cmd->next) {
        if (cmd->stat == REP_AVAIL) {
            rep_exe_cmd(cmd->cmd, cmd->sid, cmd->eid, cmd->seq,
                        cmd->lnum, cmd->len, cmd->pkt + REP_TEXT_OFFSET);
        }
    }
    
    return(TRUE);
}




static int
rep_recv_cmds(fd, smcmdlist, txtcmdlist)
    int fd;
    rep_cmdlist *smcmdlist;
    rep_cmdlist *txtcmdlist;
{
    unsigned int cmd;
    unsigned int sid;
    unsigned int eid;
    unsigned int seq;
    unsigned int lnum;
    unsigned int textsize;

    char header[REP_HEADER_SIZE];

    char *text = NULL;
    int retval;
    
    if (fd < 0) {
        return(FALSE);
    }
    
    /* 一定時間読み取るようにしたい */

    /* read header part */
    if (readn(fd, header, REP_HEADER_SIZE) < 0) {
        puts_sys_err();
        return(FALSE);
    }

    cmd = get_header(header, REP_CMD_OFFSET);
    sid = get_header(header, REP_SID_OFFSET);
    eid = get_header(header, REP_EID_OFFSET);
    seq = get_header(header, REP_SEQNUM_OFFSET);
    lnum = get_header(header, REP_LNUM_OFFSET);
    textsize = get_header(header, REP_T_SIZE_OFFSET);

    if (textsize > 0) {
        if ((text = (char*)rep_alloc(textsize)) == NULL) {
            return(FALSE);
        }
        /* read text part */
        if (readn(fd, text, textsize) < 0) {
            puts_sys_err();
            rep_free(text);
            return(FALSE);
        }
    }

    if (cmd == REP_INSERT_CMD ||
        cmd == REP_DELETE_LINE_CMD ||
        cmd == REP_REPLACE_CMD) {
        add_cmd_to_list(txtcmdlist, make_cmd(cmd, sid, eid, seq, lnum, text));
    } else {
        add_cmd_to_list(smcmdlist, make_cmd(cmd, sid, eid, seq, lnum, text));
    }
    return(TRUE);
}

void
rep_send_cur_cmdlist()
{
    rep_T *rep_p = get_rep();
    
    rep_send_cmds(rep_p->smfd,&(rep_p->cursession->new_cmdlist));

    free_cmdlist(&rep_p->cursession->sent_cmdlist);

    rep_p->cursession->sent_cmdlist.head = rep_p->cursession->new_cmdlist.head;
    rep_p->cursession->sent_cmdlist.num = rep_p->cursession->new_cmdlist.num;
    
    rep_p->cursession->new_cmdlist.head = NULL;
    rep_p->cursession->new_cmdlist.num  = 0;
    
    return;
}

static int
rep_send_cmds(fd,cmdlist)
    int fd;
    rep_cmdlist *cmdlist;
{
    rep_cmd *cur;
    unsigned int nlen;
    
    if ((fd<0) || (cmdlist == NULL)) {
        return(FALSE);
    }

    if ((cmdlist->head == NULL) || (cmdlist->num == 0)) {
        return(TRUE);
    }
    
    for (cur = cmdlist->head; cur; cur = cur->next) {
        if (writen(fd, cur->pkt, cur->len+REP_HEADER_SIZE) < 0) {
            return(FALSE);
        }    
    }
    return(TRUE);
}

/*
static int
session_fd_check(sn, rfds_p, efds_p)
    Session *sn;
    fd_set *rfds_p;
    fd_set *efds_p;
{
    rep_cmdlist smcmdlist = {NULL,0};
    rep_cmdlist txtcmdlist = {NULL,0};

    if (sn == NULL) return FALSE;
    
    if (sn->smfd > 0) {
        if (FD_ISSET(sn->smfd, efds_p)) {
            if (sn->rfd != sn->sfd) close(sn->rfd);
            sn->rfd = -1;
            // 再接続処理をしたい
            return FALSE;
        } else if (FD_ISSET(sn->rfd, rfds_p)) {
            if (rep_recv_cmds(sn->rfd, &(smcmdlist), &(txtcmdlist)) == FALSE) {
                if (sn->rfd != sn->sfd) close(sn->rfd);
                sn->rfd = -1;
                return(FALSE);
            }
            
            if ((cmdlist.head) && (cmdlist.head->uid == 99)) {   // 単方向コマンド
                rep_exe_cmdlist(sn, sn->rfd, &(cmdlist));
                free_cmdlist(&(cmdlist));
            } else if ((cmdlist.head) && (cmdlist.head->uid == sn->uid)) { // 自分のコマンド
                free_cmdlist(&cmdlist);

                if (rep_send_cmds(sn->sfd, &(sn->new_cmdlist)) == FALSE) {
                    if (sn->rfd != sn->sfd) close(sn->sfd);
                    sn->sfd = -1;
                    return FALSE;
                }

                sn->sent_cmdlist.head = sn->new_cmdlist.head;
                sn->sent_cmdlist.num = sn->new_cmdlist.num;
                sn->new_cmdlist.head = NULL;
                sn->new_cmdlist.num = 0;
                
            } else {  // リングに流すコマンド
                // 受け取ったトークンとユーザからのREPコマンドを比較・マージする
                // 既に送信した REPコマンド列 と比較
                translate(&(sn->sent_cmdlist), &(cmdlist));
                del_ignored_cmd(&(cmdlist));
                set_header_to_pkt(&(cmdlist));

                if (rep_send_cmds(sn->sfd, &(cmdlist)) == FALSE) {
                    if (sn->rfd != sn->sfd) close(sn->sfd);
                    sn->sfd = -1;
                    free_cmdlist(&(cmdlist));
                    return FALSE;
                }

                // 新規に追加された REPコマンド列 との比較
                translate(&(sn->new_cmdlist), &(cmdlist));
                del_ignored_cmd(&(cmdlist));
                set_header_to_pkt(&(sn->new_cmdlist));
            
                // 変換したトークンREPコマンドを自分のバッファに反映する。
                //各パケットにはその変換は反映されていない.
                rep_exe_cmdlist(sn, sn->rfd, &(cmdlist));

                free_cmdlist(&(cmdlist));
            }
        }
    }
    if (sn->sfd > 0) {
        if (FD_ISSET(sn->sfd, efds_p)) {
            if (sn->rfd != sn->sfd) close(sn->sfd);
            sn->sfd = -1;
            // 再接続処理をしたい
            return FALSE;
        } else if (FD_ISSET(sn->sfd, rfds_p)) {  // from send client
            if (rep_recv_cmds(sn->sfd, &cmdlist) == FALSE) {
                if (sn->rfd != sn->sfd) close(sn->sfd);
                sn->sfd = -1;
                return(FALSE);
            }
            rep_exe_cmdlist(sn, sn->sfd, &cmdlist);
            free_cmdlist(&cmdlist);
        }
    }
}

 */

int
rep_fd_check(fd, rfds_p, efds_p)
    int fd;         // input from keyboard or something...
    fd_set *rfds_p; // readable fds
    fd_set *efds_p; // include a error fd
{
    int newfd;
    rep_T *rep_p;
    rep_cmdlist smcmdlist = {NULL,0};
    rep_cmdlist txtcmdlist = {NULL,0};

    Session *sn;
    
    /* input from keyboard is most important.
     * reditor has nothing to do */
    if (FD_ISSET(fd, rfds_p) || FD_ISSET(fd, efds_p)) {
        return(TRUE);
    }
    
    rep_p = get_rep();

    if ((rep_p->smfd > 0) && (FD_ISSET(rep_p->smfd, rfds_p))) {
		/* we don't need this?
                // 受け取ったトークンとユーザからのREPコマンドを比較・マージする
                // 既に送信した REPコマンド列 と比較
                translate(&(sn->sent_cmdlist), &(cmdlist));
                del_ignored_cmd(&(cmdlist));
                set_header_to_pkt(&(cmdlist));
		*/

        if (rep_recv_cmds(rep_p->smfd, &(smcmdlist), &(txtcmdlist)) == FALSE) {
            close(rep_p->smfd);
            rep_p->smfd = -1;
            return FALSE;
        }
        /* Session ごとに行う↓*/
	for(sn = rep_p->shead; sn ; sn = sn->next) {
	    translate( &sn->new_cmdlist , &txtcmdlist);
	}
        del_ignored_cmd(&txtcmdlist);
        rep_exe_pktlist(&txtcmdlist);

	if (rep_send_cmds(rep_p->smfd, &(txtcmdlist)) == FALSE) {
	    close(sn->smfd);
	    sn->smfd = -1;
	    free_cmdlist(&(txtcmdlist));
	    return FALSE;
	}
	free_cmdlist(&(txtcmdlist));
        
        rep_exe_pktlist( &smcmdlist);
	free_cmdlist(&(smcmdlist));

        return TRUE;
    }
    rep_exe_pktlist( &smcmdlist);
    free_cmdlist(&(smcmdlist));
    
/*
    session_fd_check(rep_p->slineup, rfds_p, efds_p);

    for (sn=rep_p->shead; sn; sn=sn->next) {
        session_fd_check(sn, rfds_p, efds_p);
    }
*/
 
}

/*
static int
session_fd_set(sn, rfds_p, efds_p, max_fds)
    Session *sn;
    fd_set *rfds_p;
    fd_set *efds_p;
    int max_fds;
{
    if (sn == NULL) return max_fds;
    
    if (sn->rfd > 0) {
        FD_SET(sn->rfd, rfds_p);
        FD_SET(sn->rfd, efds_p);
        if (max_fds < sn->rfd) {
            max_fds = sn->rfd;
        }
    }
    if (sn->sfd > 0) {
        FD_SET(sn->sfd, rfds_p);
        FD_SET(sn->sfd, efds_p);
        if (max_fds < sn->sfd) {
            max_fds = sn->sfd;
        }
    }
    return max_fds;
}
*/


int
rep_fd_set(rfds_p, efds_p, max_fds)
    fd_set *rfds_p;
    fd_set *efds_p;
    int max_fds;
{  
    rep_T *rep_p;
    Session *sn;
    int i;
    
    rep_p = get_rep();
    
    if (rep_p->smfd > 0) {
        FD_SET(rep_p->smfd,rfds_p);
        FD_SET(rep_p->smfd,efds_p);
        if(max_fds < rep_p->smfd){
            max_fds = rep_p->smfd;
        }
    }

/*
    max_fds = session_fd_set(rep_p->slineup, rfds_p, efds_p, max_fds);
    
    for (sn=rep_p->shead; sn; sn=sn->next) {
        max_fds = session_fd_set(sn, rfds_p, efds_p, max_fds);
    }
*/

    return(max_fds);
}



/*
 * read などで待つ場合に、この関数で REP 関連のデータをチェックする
 * 指定した fd ( read で読みこむ) から入力があるとぬける。
 */
int
rep_select(fd)
    int fd;
{
    fd_set rfds_p;
    fd_set efds_p;
    int sk;
    int max_fds = MAX_FDS;

    struct timeval tv;

    if (fd < 0) return(FALSE);

    while (1) {
        /* select の中で modify されてるので、初期化 */
        tv.tv_sec = 0;
        tv.tv_usec = 100000;
        FD_ZERO(&rfds_p);
        FD_ZERO(&efds_p);

        FD_SET(fd,&rfds_p);

        max_fds = rep_fd_set(&rfds_p, &efds_p, max_fds);
    
        if ((sk = select(max_fds+1, &rfds_p, NULL, &efds_p, &tv)) < 0) {
            e_msg_wrp("rep_select(): ERROR");
            return(FALSE);
        }
        
        rep_fd_check(fd, &rfds_p, &efds_p);
        return(TRUE);
    }
}

void
rep_end()
{
    rep_T *rep_p;
    rep_p = get_rep();
    
    if (rep_p->shead) free_session_list(rep_p->shead); // cursession is freed 
    if (rep_p->slineup) free_session(rep_p->slineup);
    if (rep_p->servername) free_wrp(rep_p->servername);
    if (rep_p->smfd > 0) close(rep_p->smfd);

    set_curbuf_wrp(rep_p->scratch_buf);
    
    rep_init();
}


/* append newline separated text to session buf */
static int
append_newline_sep_text(sn, text)
    Session *sn;
    char *text;
{
    char *str;
    char *cur;
//    BUFTYPE *oldbuf;
    Session *oldsn;

    /*
     *"append_memline()" is available "curbuf" only
     * thus, we must set buffer to "curbuf"
     */
    oldsn = set_cursession(sn);
    
    for (str = cur = text; cur && *cur ; str = cur) {
        cur = strchr(str, '\n');
        if (cur) {
            *cur = '\0';
            cur++;
        }

        append_memline_wrp(1, str);
    }

    set_cursession(oldsn);
    
    return TRUE;
}

/* return value (file name) is allocated */
static char *
get_sname_by_snum(snum)
    int snum;
{
    char *tmp, *text, *sname;
    int i, len;
    int maxlnum;
    rep_T *rep = get_rep();
    
    maxlnum = get_bufmaxline_wrp(rep->slineup->buf);
    
    for (i = 1; i <= maxlnum; i++) {
        // text is "filename:hostname:sessionnumber"
        text = get_memline_wrp(rep->slineup->buf, i);
        
        
        // get ':' separated last parameter (session number)
        if ((tmp = strrchr(text, ':')) == NULL) {
            return NULL;
        }
        tmp++;

        if (snum == atol(tmp)) {
            // get ':' separated first parameter (filename)
            tmp = strchr(text, ':');
            len = tmp - text;
            if ((sname = (char *)rep_alloc(len+1)) == NULL){
                e_msg_wrp("no memory!");
                return NULL;
            }
            memcpy(sname, text, len);
            sname[len] = '\0';
            return sname;
        }
    }

    return NULL;
    
}