changeset 1:f72be2054832

add: reditor.c reditor.h
author atsuki
date Sat, 10 Nov 2007 20:27:44 +0900
parents 76efa0be13f1
children 7c2dca099a7b
files src/ex_cmds.h src/ex_docmd.c src/reditor.c src/reditor.h
diffstat 4 files changed, 2505 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_cmds.h	Sat Nov 10 15:07:22 2007 +0900
+++ b/src/ex_cmds.h	Sat Nov 10 20:27:44 2007 +0900
@@ -745,6 +745,11 @@
 			BANG|TRLBAR|CMDWIN),
 EX(CMD_registers,	"registers",	ex_display,
 			EXTRA|NOTRLCOM|TRLBAR|CMDWIN),
+/* REP: repstart and repend are commands for Remote Editor */
+EX(CMD_repstart,	"repstart",	ex_repstart,
+			RANGE),
+EX(CMD_repend,		"repend",	ex_repend,
+			RANGE),
 EX(CMD_resize,		"resize",	ex_resize,
 			RANGE|NOTADR|TRLBAR|WORD1),
 EX(CMD_retab,		"retab",	ex_retab,
--- a/src/ex_docmd.c	Sat Nov 10 15:07:22 2007 +0900
+++ b/src/ex_docmd.c	Sat Nov 10 20:27:44 2007 +0900
@@ -12,6 +12,7 @@
  */
 
 #include "vim.h"
+#include "reditor.h"  /* REP: for Remote Editor */
 
 #ifdef HAVE_FCNTL_H
 # include <fcntl.h>	    /* for chdir() */
@@ -464,6 +465,12 @@
 #endif
 
 /*
+ * REP: commands for Remote Editor
+ */
+static void	ex_repstart __ARGS((exarg_T *eap));
+static void	ex_repend __ARGS((exarg_T *eap));
+
+/*
  * Declare cmdnames[].
  */
 #define DO_DECLARE_EXCMD
@@ -3429,6 +3436,9 @@
 	case CMD_verbose:
 	case CMD_vertical:
 	case CMD_windo:
+	/* REP: for Remote Editor */
+	case CMD_repstart:
+	case CMD_repend:
 	    return arg;
 
 #ifdef FEAT_CMDL_COMPL
@@ -10944,3 +10954,33 @@
     ml_clearmarked();	   /* clear rest of the marks */
 }
 #endif
+
+
+/*
+ * REP: Remote Editor's Ex commands
+ */
+/* start REP mode */
+static void
+ex_repstart(eap)
+    exarg_T *eap;
+{
+    if (curbuf->b_sfname == NULL) {
+	MSG(_("[REP MODE] start without file"));
+	if (rep_join() == FALSE) {
+	    rep_end();
+	}
+    } else {
+	MSG(_("[REP MODE] start with file"));
+	if (rep_put(curbuf->b_ffname) == FALSE) {
+	    rep_end();
+	}
+    }
+}
+
+/* end REP mode */
+static void
+ex_repend(eap)
+    exarg_T *eap;
+{
+    MSG(_("[REP MODE] end"));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/reditor.c	Sat Nov 10 20:27:44 2007 +0900
@@ -0,0 +1,2283 @@
+#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;
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/reditor.h	Sat Nov 10 20:27:44 2007 +0900
@@ -0,0 +1,177 @@
+#define REP_PORT 8766
+//#define OTHER_REP_PORT 8765
+#define BUFFSIZE   200
+#define SOCK_MAX   5
+#define MAX_FDS    10
+
+#define REP_OPEN_CMD          1
+#define REP_OPEN_ACK          2
+#define REP_READ_CMD          3
+#define REP_READ_ACK          4
+#define REP_READ_FIN          5
+#define REP_INSERT_CMD         6
+#define REP_INSERT_STILL_ACK   7
+#define REP_INSERT_FINISH_ACK  8
+#define REP_DELETE_LINE_CMD   9
+#define REP_DELETE_LINE_ACK  10
+#define REP_CLOSE_CMD        11
+#define REP_CLOSE_ACK        12
+#define REP_REPLACE_CMD      13
+
+//#define REP_CHANGE_FD_CMD    14
+//#define REP_ENTER_RING_CMD   15
+//#define REP_ENTER_RING_ACK   16
+
+#define REP_JOIN_CMD         41
+#define REP_JOIN_ACK         42
+#define REP_GET_CMD          43
+#define REP_GET_ACK          44
+#define REP_PUT_CMD          45
+#define REP_PUT_ACK          46
+#define REP_SELECT_CMD       47
+#define REP_SELECT_ACK       48
+#define REP_REGISTER_CMD     49
+#define REP_REGISTER_ACK     50
+#define REP_DEREGISTER_CMD   51
+#define REP_DEREGISTER_ACK   52
+#define REP_QUIT_CMD         53
+#define REP_QUIT_ACK         54
+
+
+/* header and text
++-------+--------+--------+-------+--------+---------+--------------+
+| rep   | session| editor | seqid | lineno | textsiz | text         |
+| cmd   | id     | id     |       |        |         | include '\0' |
++-------+--------+--------+-------+--------+---------+--------------+
+ o-----header section (network byte order)----------o
+*/
+/* header OFFSET */
+#define REP_CMD_OFFSET      0 /* REP Command     */
+#define REP_SID_OFFSET      4 /* Session ID      */
+#define REP_EID_OFFSET      8 /* Editor ID       */
+#define REP_SEQNUM_OFFSET  12 /* Sequence number */
+#define REP_LNUM_OFFSET    16 /* Line number     */
+#define REP_T_SIZE_OFFSET  20 /* TEXT size       */
+#define REP_TEXT_OFFSET    24 /* TEXT            */
+
+#define REP_HEADER_SIZE 24
+
+#define REP_IGNORE    0
+#define REP_AVAIL     1
+
+#define SLINEUP_NAME "SessionLineup"
+#define NO_NAME      "NO_NAME"       /* has not name like scratch */
+
+#define SESSION_MAX 50
+
+#define SESSION_NAME_MAX 50
+#define HOSTNAME_LEN 50
+
+//#define UID_MAX 99
+
+ /* Wrapper for vim */
+
+/* 扱うテキストバッファの型 */
+//extern buf_T;
+#define BUFTYPE buf_T
+//#define CHAR char
+
+ /* Wrapper END */
+
+typedef struct rep_cmd {
+    struct rep_cmd *next;
+    unsigned int   lnum; /* line number */
+    int            stat; /* REP_AVAIL or REP_IGNORE */
+    
+    unsigned int cmd;  /* command id */
+    unsigned int sid;  /* session id */
+    unsigned int eid;  /* editor id */
+    unsigned int seq;  /* sequence number */
+    unsigned int len;  /* length of text */
+    
+    char         *pkt; /* packed rep command */
+} rep_cmd;
+
+typedef struct rep_cmdlist {
+    rep_cmd *head;
+    int num;
+} rep_cmdlist;
+
+typedef struct session {
+    struct session *next;
+    
+//    BUFTYPE *sbuf; /* Session Buffer */
+    BUFTYPE *buf;   /* Editing Buffer */
+
+    unsigned int sid;
+    unsigned int smfd;
+    unsigned int rfd;
+    unsigned int sfd;
+    char *sname;
+    
+    rep_cmdlist new_cmdlist; /* my REP command list */
+    rep_cmdlist sent_cmdlist; /* my REP command list */
+    rep_cmdlist fromsmcmlist; /* from sm */
+
+    int permit; /* TRUE or FALSE */
+//    rep_cmdlist others;  /* others REP command list*/
+    
+//    int sbuf_changed;
+
+//    unsigned short uid;       /* user id */
+//    int usercount; /* joined user number */
+
+//    int sfd;    /* send fd       */
+//    int rfd;    /* receive fd    */
+
+    int prevline; /* Previous Edited line */
+} Session;
+
+typedef struct rep {
+    Session *shead;  // linked list of session
+    Session *slineup;  // buffer of session lineup 
+    Session *cursession;
+
+    BUFTYPE *scratch_buf;
+    
+    char *servername;
+    char hostname[HOSTNAME_LEN];
+
+    char *waiting_session_name;
+
+    int eid;  /* editor id */
+    int seqno; /* sequence number of REP command*/
+    
+    int smfd; /* socket connected to SessionManager */
+
+    int permit;
+} rep_T;
+
+
+// extern rep_T * get_rep();
+extern int rep_permit();
+extern int rep_session_permit();
+extern int rep_init();
+extern void rep_start_create_cmds();
+extern void rep_stop_create_cmds();
+
+extern char* rep_input_param(char*, char*);
+
+//extern int rep_connect(char*);
+//extern int rep_add_cmd(rep_cmdlist*,unsigned short,unsigned short,unsigned int,char*);
+//extern void rep_check_line_change(Session*,unsigned int);
+extern int rep_register(unsigned int, unsigned int, int);
+//extern int rep_clear_cmdlist(rep_cmdlist*);
+//extern int rep_recv_cmds(int fd,rep_cmdlist*);
+//extern int rep_send_cmds(int fd,rep_cmdlist*);
+extern int rep_fd_check(int, fd_set*, fd_set*);
+extern int rep_fd_set(fd_set*, fd_set*, int);
+extern int rep_select(int);
+extern void rep_prevline_flush();
+extern void rep_end();
+
+extern int rep_join(char *);
+extern int rep_select_command(char *);
+extern int rep_put(char *);
+
+extern void rep_send_cur_cmdlist();