comparison main.c @ 424:aeb24b1b5e77

Refactor the /command handling completely.
author Matti Hamalainen <ccr@tnsp.org>
date Thu, 24 May 2012 11:14:44 +0300
parents 8eb2839a565c
children 143fd51048a9
comparison
equal deleted inserted replaced
423:6727fec3c326 424:aeb24b1b5e77
30 #define SET_CONFIG_FILE ".nnchat" 30 #define SET_CONFIG_FILE ".nnchat"
31 #define SET_DIR_SEPARATOR "/" 31 #define SET_DIR_SEPARATOR "/"
32 #define SET_DELAY (5) 32 #define SET_DELAY (5)
33 #endif 33 #endif
34 34
35 #define SET_PROFILE_PREFIX "http://www.newbienudes.com/profile/%s/"
35 #define SET_NICK_SEPARATOR ':' 36 #define SET_NICK_SEPARATOR ':'
36 37
37 #define SET_MAX_HISTORY (16) // Command history length 38 #define SET_MAX_HISTORY (16) // Command history length
38 #define SET_KEEPALIVE (15*60) // Ping/keepalive period in seconds 39 #define SET_KEEPALIVE (15*60) // Ping/keepalive period in seconds
39 #define SET_MAX_WINDOWS (32) 40 #define SET_MAX_WINDOWS (32)
759 return -2; 760 return -2;
760 } 761 }
761 else if (!nn_conn_buf_strcmp(conn, "SUCCESS>")) 762 else if (!nn_conn_buf_strcmp(conn, "SUCCESS>"))
762 { 763 {
763 printMsg(NULL, "½2½Login success½0½ - ½3½%s½0½\n", tmpStr); 764 printMsg(NULL, "½2½Login success½0½ - ½3½%s½0½\n", tmpStr);
764 nn_conn_send_msg(conn, optUserNameEnc, "%%2FRequestUserList"); 765 nn_conn_send_msg(conn, optUserNameEnc, "%2FRequestUserList");
765 return 0; 766 return 0;
766 } 767 }
767 else 768 else
768 return 1; 769 return 1;
769 } 770 }
880 else 881 else
881 return 1; 882 return 1;
882 } 883 }
883 884
884 885
885 int nn_handle_input(nn_conn_t *conn, char *buf, size_t bufLen) 886 int nncmd_open_profile(nn_conn_t *conn, char *name)
886 { 887 {
887 char *tmpStr, tmpBuf[4096]; 888 char *uri, *enc_name = nn_encode_str1(name);
888 BOOL result; 889 #ifdef __WIN32
889 890 HINSTANCE status;
890 // Trim right 891 #else
891 bufLen--; 892 int status;
892 buf[bufLen--] = 0; 893 int fds[2];
893 while (bufLen > 0 && th_isspace(buf[bufLen])) 894 pid_t pid;
894 buf[bufLen--] = 0; 895 #endif
895 896 (void) conn;
896 // Decode completed usernames 897
897 nn_username_decode(buf); 898 printMsg(currWin, "Opening profile for: '%s'\n", name);
898 899
899 // Check for special user commands 900 #ifdef __WIN32
900 if (*buf == 0) 901 uri = th_strdup_printf(SET_PROFILE_PREFIX, enc_name);
901 { 902 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA);
903 if (status <= (HINSTANCE) 32)
904 {
905 printMsgQ(currWin, "Could not launch default web browser: %d\n", status);
906 }
907 #else
908
909 uri = th_strdup_printf("openurl(" SET_PROFILE_PREFIX ",new-tab)", enc_name);
910
911 if (pipe(fds) == -1)
912 {
913 int ret = errno;
914 printMsgQ(currWin, "Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret));
915 return 0;
916 }
917
918 if ((pid = fork()) < 0)
919 {
920 printMsgQ(currWin, "Could not create sub-process!\n");
921 }
922 else if (pid == 0)
923 {
924 dup2(fds[1], STDOUT_FILENO);
925 dup2(fds[0], STDERR_FILENO);
926 execlp(setBrowser, setBrowser, "-remote", uri, (void *)NULL);
927 _exit(errno);
928 }
929
930 wait(&status);
931 #endif
932
933 th_free(uri);
934 th_free(enc_name);
935 return 0;
936 }
937
938
939 int nncmd_ignore(nn_conn_t *conn, char *name)
940 {
941 (void) conn;
942
943 if (name[0])
944 {
945 // Add or remove someone to/from ignore
946 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername);
947 if (user != NULL)
948 {
949 printMsgQ(currWin, "Removed user '%s' from ignore.\n", name);
950 th_llist_delete_node(&setIgnoreList, user);
951 }
952 else
953 {
954 printMsgQ(currWin, "Now ignoring '%s'.\n", name);
955 th_llist_append(&setIgnoreList, th_strdup(name));
956 }
957 }
958 else
959 {
960 // Just list whomever is in ignore now
961 qlist_t *user = setIgnoreList;
962 ssize_t nuser = th_llist_length(setIgnoreList);
963 char *result = th_strdup_printf("Users ignored (%d): ", nuser);
964 while (user != NULL)
965 {
966 if (user->data != NULL)
967 {
968 th_pstr_printf(&result, "%s'%s'", result, (char *) user->data);
969 if (--nuser > 0)
970 th_pstr_printf(&result, "%s, ", result);
971 }
972 user = user->next;
973 }
974 printMsgQ(currWin, "%s\n", result);
975 th_free(result);
976 }
977
978 return 0;
979 }
980
981
982 int nncmd_set_color(nn_conn_t *conn, char *arg)
983 {
984 int val;
985 (void) conn;
986
987 if ((val = th_get_hex_triplet(arg)) < 0)
988 {
989 printMsgQ(currWin, "Invalid color value '%s'\n", arg);
902 return 1; 990 return 1;
903 } 991 }
904 else if (!th_strncasecmp(buf, "/color ", 7)) 992
905 { 993 optUserColor = val;
906 // Change color 994 printMsgQ(currWin, "Setting color to #%06x\n", optUserColor);
907 int tmpInt; 995 nn_conn_send_msg_v(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
908 if ((tmpInt = th_get_hex_triplet(str_trim_left(buf + 7))) < 0) 996 return 0;
909 { 997 }
910 printMsgQ(currWin, "Invalid color value '%s'\n", buf+7); 998
999
1000 int nncmd_open_query(nn_conn_t *conn, char *name)
1001 {
1002 (void) conn;
1003
1004 if (name[0])
1005 {
1006 nn_user_t *user = nn_user_find(nnUsers, nn_username_encode(name));
1007 if (user != NULL)
1008 {
1009 name = nn_username_decode(th_strdup(user->name));
1010 printMsgQ(currWin, "Opening PRV query for '%s'.\n", name);
1011 if (nnwin_open(name, TRUE))
1012 printMsgQ(currWin, "In PRV query with '%s'.\n", name);
1013 th_free(name);
1014 return 0;
1015 }
1016 else
1017 {
1018 printMsgQ(currWin, "Could not find username '%s'.\n", name);
911 return 1; 1019 return 1;
912 } 1020 }
913 optUserColor = tmpInt; 1021 }
914 printMsgQ(currWin, "Setting color to #%06x\n", optUserColor); 1022 else
915 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 1023 {
1024 printMsgQ(currWin, "Usage: /query username\n");
1025 printMsgQ(currWin, "To close a PRV query, use /close [username]\n");
1026 printMsgQ(currWin, "/close without username will close the current PRV window, if any.\n");
1027 return 1;
1028 }
1029 }
1030
1031
1032 int nncmd_close_query(nn_conn_t *conn, char *name)
1033 {
1034 (void) conn;
1035
1036 if (name[0])
1037 {
1038 nn_window_t *win = nnwin_find(name);
1039 if (win != NULL)
1040 {
1041 nnwin_close(win);
1042 printMsgQ(currWin, "Closed PRV query to '%s'.\n", name);
1043 }
1044 else
1045 {
1046 printMsgQ(currWin, "No PRV query by name '%s'.\n", name);
1047 }
1048 }
1049 else
1050 {
1051 if (currWin != chatWindows[0])
1052 {
1053 nnwin_close(currWin);
1054 currWin = chatWindows[0];
1055 }
1056 else
1057 {
1058 printMsgQ(currWin, "Usage: /close [username]\n");
1059 printMsgQ(currWin, "/close without username will close the current PRV window. if any.\n");
1060 }
1061 }
1062
1063 return 0;
1064 }
1065
1066
1067 int nncmd_window_info(nn_conn_t *conn, char *arg)
1068 {
1069 (void) conn;
1070
1071 if (arg[0])
1072 {
1073 int val = atoi(arg);
1074 if (val >= 1 && val < SET_MAX_WINDOWS)
1075 {
1076 if (chatWindows[val - 1] != NULL)
1077 currWin = chatWindows[val - 1];
1078 }
1079 else
1080 {
1081 printMsgQ(currWin, "Invalid window number '%s'\n", arg);
1082 return 1;
1083 }
1084 }
1085 else
1086 {
1087 printMsgQ(currWin, "Window : #%d\n", currWin->num);
1088 printMsgQ(currWin, "ID : %s\n", currWin->id);
1089 }
1090 return 0;
1091 }
1092
1093
1094 int nncmd_list_all_users(nn_conn_t *conn, char *buf)
1095 {
1096 (void) buf;
1097
1098 // Alias /listallusers
1099 return nn_conn_send_msg(conn, optUserNameEnc, "%%2Flistallusers");
1100 }
1101
1102
1103 int nncmd_names(nn_conn_t *conn, char *buf)
1104 {
1105 (void) conn;
1106 (void) buf;
1107
1108 printMsgQ(currWin, "Not implemented yet.\n");
1109 return 0;
1110 }
1111
1112
1113 int nncmd_save_config(nn_conn_t *conn, char *buf)
1114 {
1115 (void) conn;
1116 (void) buf;
1117
1118 FILE *cfgfile = fopen(setConfigFile, "w");
1119 if (cfgfile == NULL)
1120 {
1121 printMsgQ(currWin, "Could not create configuration to file '%s': %s\n",
1122 setConfigFile, strerror(errno));
916 return 0; 1123 return 0;
917 } 1124 }
918 else if (!th_strncasecmp(buf, "/ignore", 7)) 1125
919 { 1126 printMsgQ(currWin, "Configuration saved in file '%s', res=%d\n",
920 char *name = str_trim_left(buf + 7); 1127 setConfigFile,
921 if (strlen(name) > 0) 1128 th_cfg_write(cfgfile, setConfigFile, cfg));
922 { 1129
923 // Add or remove someone to/from ignore 1130 fclose(cfgfile);
924 qlist_t *user = th_llist_find_func(setIgnoreList, name, compareUsername); 1131 return 0;
925 if (user != NULL) 1132 }
1133
1134
1135 enum
1136 {
1137 CMDARG_NONE,
1138 CMDARG_STRING,
1139 CMDARG_OPTIONAL,
1140 CMDARG_NICK,
1141 };
1142
1143 typedef struct
1144 {
1145 char *cmd;
1146 int flags;
1147 ssize_t len;
1148 int (*handler)(nn_conn_t *, char *buf);
1149 } nn_usercmd_t;
1150
1151
1152 static nn_usercmd_t userCmds[] =
1153 {
1154 // Server side commands, we just implement completion
1155 { "me", CMDARG_STRING, -1, NULL },
1156 { "status", CMDARG_STRING, -1, NULL },
1157 { "list", CMDARG_NONE, -1, nncmd_list_all_users },
1158
1159 // List internal username list
1160 { "who", CMDARG_NONE, -1, nncmd_names },
1161 { "names", CMDARG_NONE, -1, nncmd_names },
1162
1163 { "w", CMDARG_NICK, -1, nncmd_open_profile },
1164 { "profile", CMDARG_NICK, -1, nncmd_open_profile },
1165
1166 { "query", CMDARG_NICK, -1, nncmd_open_query },
1167 { "close", CMDARG_OPTIONAL, -1, nncmd_close_query },
1168 { "win", CMDARG_OPTIONAL, -1, nncmd_window_info },
1169
1170 { "ignore", CMDARG_NICK, -1, nncmd_ignore },
1171 { "color", CMDARG_STRING, -1, nncmd_set_color },
1172 { "save", CMDARG_NONE, -1, nncmd_save_config },
1173 };
1174
1175 static const int nuserCmds = sizeof(userCmds) / sizeof(userCmds[0]);
1176
1177
1178 int nn_handle_command(nn_conn_t *conn, char *buf)
1179 {
1180 static BOOL userCmdsInit = FALSE;
1181 int i;
1182
1183 // Initialize command structure
1184 if (!userCmdsInit)
1185 {
1186 for (i = 0; i < nuserCmds; i++)
1187 userCmds[i].len = strlen(userCmds[i].cmd);
1188
1189 userCmdsInit = TRUE;
1190 }
1191
1192
1193 for (i = 0; i < nuserCmds; i++)
1194 {
1195 nn_usercmd_t *cmd = &userCmds[i];
1196 if (!th_strncasecmp(buf, cmd->cmd, cmd->len))
1197 {
1198 char *nbuf = str_trim_left(buf + cmd->len);
1199
1200 switch (cmd->flags)
926 { 1201 {
927 printMsgQ(currWin, "Removed user '%s' from ignore.\n", name); 1202 case CMDARG_NICK:
928 th_llist_delete_node(&setIgnoreList, user); 1203 case CMDARG_STRING:
1204 if (!nbuf[0])
1205 {
1206 printMsgQ(currWin, "Command: /%s requires an argument.\n", cmd->cmd);
1207 return 1;
1208 }
1209 break;
1210
1211 case CMDARG_NONE:
1212 if (nbuf[0])
1213 {
1214 printMsgQ(currWin, "Command: /%s does not take arguments.\n", cmd->cmd);
1215 return 1;
1216 }
1217 break;
1218
1219 case CMDARG_OPTIONAL:
1220 break;
1221 }
1222
1223 // Check if there is a handler function
1224 if (cmd->handler)
1225 {
1226 printMsgQ(currWin, "%s[%p]->handler('%s')\n", cmd->cmd, cmd->handler, nbuf);
1227 // Internal commands have a handler
1228 return cmd->handler(conn, nbuf);
929 } 1229 }
930 else 1230 else
931 { 1231 {
932 printMsgQ(currWin, "Now ignoring '%s'.\n", name); 1232 // Server-side commands are just pass-through here
933 th_llist_append(&setIgnoreList, th_strdup(name)); 1233 char *tmp = nn_dblencode_str(buf);
1234 BOOL result;
1235 if (tmp == NULL) return -2;
1236 result = nn_conn_send_msg(conn, optUserNameEnc, tmp);
1237 th_free(tmp);
1238 return result ? 0 : -1;
934 } 1239 }
935 } 1240 }
936 else 1241 }
937 { 1242
938 // Just list whomever is in ignore now 1243 printMsgQ(currWin, "Unknown command: /%s\n", buf);
939 qlist_t *user = setIgnoreList; 1244 return 1;
940 ssize_t nuser = th_llist_length(setIgnoreList); 1245 }
941 char *result = th_strdup_printf("Users ignored (%d): ", nuser); 1246
942 while (user != NULL) 1247
1248 int nn_handle_input(nn_conn_t *conn, char *buf, size_t bufLen)
1249 {
1250 BOOL result;
1251 char *tmp;
1252
1253 // Trim right side
1254 if (bufLen > 0) buf[--bufLen] = 0;
1255 while (bufLen > 0 && th_isspace(buf[bufLen - 1]))
1256 buf[--bufLen] = 0;
1257
1258 if (buf[0] == 0)
1259 return 1;
1260
1261 // Decode completed usernames
1262 nn_username_decode(buf);
1263
1264 // Check for commands
1265 if (buf[0] == '/')
1266 return nn_handle_command(conn, buf + 1);
1267
1268 // If current window is not the main room window, send private
1269 if (currWin != chatWindows[0])
1270 {
1271 if (currWin->id != NULL)
1272 {
1273 char *tmp, *msg = th_strdup_printf("/prv -to %s -msg %s", currWin->id, buf);
1274 if (msg == NULL) return -3;
1275 tmp = nn_dblencode_str(msg);
1276 if (tmp == NULL)
943 { 1277 {
944 if (user->data != NULL) 1278 th_free(msg);
945 { 1279 return -2;
946 th_pstr_printf(&result, "%s'%s'", result, (char *) user->data);
947 if (--nuser > 0)
948 th_pstr_printf(&result, "%s, ", result);
949 }
950 user = user->next;
951 } 1280 }
952 printMsgQ(currWin, "%s\n", result); 1281 result = nn_conn_send_msg(conn, optUserNameEnc, tmp);
953 th_free(result); 1282 th_free(tmp);
954 } 1283 th_free(msg);
955 return 0; 1284 return result ? 0 : -1;
956 }
957 else if (!th_strncasecmp(buf, "/query", 6))
958 {
959 char *name = str_trim_left(buf + 6);
960 if (strlen(name) > 0)
961 {
962 nn_user_t *user = nn_user_find(nnUsers, nn_username_encode(name));
963 if (user != NULL)
964 {
965 name = nn_username_decode(th_strdup(user->name));
966 printMsgQ(currWin, "Opening PRV query for '%s'.\n", name);
967 if (nnwin_open(name, TRUE))
968 printMsgQ(currWin, "In PRV query with '%s'.\n", name);
969 th_free(name);
970 }
971 }
972 else
973 {
974 printMsgQ(currWin, "Usage: /query username\n");
975 printMsgQ(currWin, "To close a PRV query, use /close [username]\n");
976 printMsgQ(currWin, "/close without username will close the current PRV window.\n");
977 }
978 return 0;
979 }
980 else if (!th_strncasecmp(buf, "/win", 4))
981 {
982 // Change color
983 char *tmp = str_trim_left(buf + 4);
984 if (strlen(tmp) > 0)
985 {
986 int val = atoi(tmp);
987 if (val >= 1 && val < SET_MAX_WINDOWS)
988 {
989 if (chatWindows[val - 1] != NULL)
990 currWin = chatWindows[val - 1];
991 }
992 else
993 {
994 printMsgQ(currWin, "Invalid window number '%s'\n", tmp);
995 return 1;
996 }
997 }
998 else
999 {
1000 printMsgQ(currWin, "Window : #%d\n", currWin->num);
1001 printMsgQ(currWin, "ID : %s\n", currWin->id);
1002 }
1003 return 0;
1004 }
1005 else if (!th_strncasecmp(buf, "/close", 6))
1006 {
1007 char *name = str_trim_left(buf + 6);
1008 if (strlen(name) > 0)
1009 {
1010 nn_window_t *win = nnwin_find(name);
1011 if (win != NULL)
1012 {
1013 nnwin_close(win);
1014 printMsgQ(currWin, "Closed PRV query to '%s'.\n", name);
1015 }
1016 else
1017 {
1018 printMsgQ(currWin, "No PRV query by name '%s'.\n", name);
1019 }
1020 }
1021 else
1022 {
1023 if (currWin != chatWindows[0])
1024 {
1025 nnwin_close(currWin);
1026 currWin = chatWindows[0];
1027 }
1028 }
1029 return 0;
1030 }
1031 else if (!th_strncasecmp(buf, "/save", 5))
1032 {
1033 // Save configuration
1034 FILE *cfgfile = fopen(setConfigFile, "w");
1035 if (cfgfile == NULL)
1036 {
1037 printMsgQ(currWin, "Could not create configuration to file '%s': %s\n",
1038 setConfigFile, strerror(errno));
1039 return 0;
1040 }
1041 printMsgQ(currWin, "Configuration saved in file '%s', res=%d\n",
1042 setConfigFile,
1043 th_cfg_write(cfgfile, setConfigFile, cfg));
1044
1045 fclose(cfgfile);
1046 return 0;
1047 }
1048 else if (!th_strncasecmp(buf, "/w ", 3))
1049 {
1050 // Open given username's profile via firefox in a new tab
1051 char *name = str_trim_left(buf + 3);
1052
1053 printMsg(currWin, "Opening profile for: '%s'\n", name);
1054
1055 tmpStr = nn_encode_str1(name);
1056 #ifdef __WIN32
1057 {
1058 HINSTANCE status;
1059 snprintf(tmpBuf, sizeof(tmpBuf), "http://www.newbienudes.com/profile/%s/", tmpStr);
1060 th_free(tmpStr);
1061 status = ShellExecute(NULL, "open", tmpBuf, NULL, NULL, SW_SHOWNA);
1062 if (status <= (HINSTANCE) 32)
1063 printMsgQ(currWin, "Could not launch default web browser: %d\n", status);
1064 }
1065 #else
1066 {
1067 int status;
1068 int fds[2];
1069 pid_t pid;
1070 snprintf(tmpBuf, sizeof(tmpBuf), "openurl(http://www.newbienudes.com/profile/%s/,new-tab)", tmpStr);
1071 th_free(tmpStr);
1072
1073 if (pipe(fds) == -1)
1074 {
1075 int ret = errno;
1076 printMsgQ(currWin, "Could not open process communication pipe! (%d, %s)\n", ret, strerror(ret));
1077 return 0;
1078 }
1079
1080 if ((pid = fork()) < 0)
1081 {
1082 printMsgQ(currWin, "Could not create sub-process!\n");
1083 }
1084 else if (pid == 0)
1085 {
1086 dup2(fds[1], STDOUT_FILENO);
1087 dup2(fds[0], STDERR_FILENO);
1088 execlp(setBrowser, setBrowser, "-remote", tmpBuf, (void *)NULL);
1089 _exit(errno);
1090 }
1091
1092 wait(&status);
1093 }
1094 #endif
1095 return 0;
1096 }
1097 else if (!th_strncasecmp(buf, "/who", 4))
1098 {
1099 // Alias /who to /listallusers
1100 snprintf(tmpBuf, sizeof(tmpBuf), "/listallusers");
1101 buf = tmpBuf;
1102 }
1103
1104 if (currWin != chatWindows[0])
1105 {
1106 if (currWin->id != NULL)
1107 {
1108 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", currWin->id, buf);
1109 buf = tmpBuf;
1110 } 1285 }
1111 else 1286 else
1112 { 1287 {
1113 printMsgQ(NULL, "No target set, exiting prv mode.\n"); 1288 printMsgQ(NULL, "No target set, exiting prv mode.\n");
1114 return 1; 1289 return 1;
1115 } 1290 }
1116 } 1291 }
1117 1292
1118 // Send double-encoded 1293 // Send double-encoded message
1119 tmpStr = nn_dblencode_str(nn_username_decode(buf)); 1294 tmp = nn_dblencode_str(buf);
1120 if (tmpStr == 0) return -2; 1295 if (tmp == NULL) return -2;
1121 result = nn_conn_send_msg(conn, optUserNameEnc, "%s", tmpStr); 1296 result = nn_conn_send_msg(conn, optUserNameEnc, tmp);
1122 th_free(tmpStr); 1297 th_free(tmp);
1123
1124 return result ? 0 : -1; 1298 return result ? 0 : -1;
1125 } 1299 }
1126 1300
1127 1301
1128 void nnwin_close_windows(void) 1302 void nnwin_close_windows(void)
1680 } 1854 }
1681 1855
1682 // Send login command 1856 // Send login command
1683 optUserNameEnc = nn_dblencode_str(optUserName); 1857 optUserNameEnc = nn_dblencode_str(optUserName);
1684 tmpStr = nn_dblencode_str(optSite); 1858 tmpStr = nn_dblencode_str(optSite);
1685 nn_conn_send_msg(conn, optUserNameEnc, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword); 1859 nn_conn_send_msg_v(conn, optUserNameEnc, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword);
1686 th_free(tmpStr); 1860 th_free(tmpStr);
1687 1861
1688 // Initialize random numbers 1862 // Initialize random numbers
1689 prevTime = time(NULL); 1863 prevTime = time(NULL);
1690 srandom((int) prevTime); 1864 srandom((int) prevTime);
2086 } 2260 }
2087 2261
2088 if (!colorSet) 2262 if (!colorSet)
2089 { 2263 {
2090 colorSet = TRUE; 2264 colorSet = TRUE;
2091 nn_conn_send_msg(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); 2265 nn_conn_send_msg_v(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
2092 } 2266 }
2093 2267
2094 nnwin_update_statusline(); 2268 nnwin_update_statusline();
2095 nnwin_update_editbuf(editBuf); 2269 nnwin_update_editbuf(editBuf);
2096 updateCount = 0; 2270 updateCount = 0;