# HG changeset patch # User atsuki # Date 1194694064 -32400 # Node ID f72be20548328484be689c5b033bdc49206f0114 # Parent 76efa0be13f1272d1b2e88b415fbb3b01966b61d add: reditor.c reditor.h diff -r 76efa0be13f1 -r f72be2054832 src/ex_cmds.h --- 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, diff -r 76efa0be13f1 -r f72be2054832 src/ex_docmd.c --- 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 /* 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")); +} diff -r 76efa0be13f1 -r f72be2054832 src/reditor.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; offsetnext = 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; + +} diff -r 76efa0be13f1 -r f72be2054832 src/reditor.h --- /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();