Mercurial > hg > nnchat
comparison nnchat.c @ 30:751cff550992
Hmm.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 03 Aug 2008 08:17:55 +0300 |
parents | a27ef0e359b9 |
children | 9b429b283786 |
comparison
equal
deleted
inserted
replaced
29:a27ef0e359b9 | 30:751cff550992 |
---|---|
12 #include <string.h> | 12 #include <string.h> |
13 #include <errno.h> | 13 #include <errno.h> |
14 #include <time.h> | 14 #include <time.h> |
15 #include <ncurses.h> | 15 #include <ncurses.h> |
16 | 16 |
17 | 17 #define SET_MAX_HISTORY (16) |
18 #define SET_BUFSIZE (4096) | 18 #define SET_BUFSIZE (4096) |
19 #define SET_ALLOC_SIZE (128) | 19 #define SET_ALLOC_SIZE (128) |
20 #define SET_DELAY (15) | 20 #define SET_DELAY (15) |
21 #define SET_DELAY_USEC (SET_DELAY * 1000) | 21 #define SET_DELAY_USEC (SET_DELAY * 1000) |
22 | 22 |
33 BOOL optDaemon = FALSE; | 33 BOOL optDaemon = FALSE; |
34 FILE *optLogFile = NULL; | 34 FILE *optLogFile = NULL; |
35 WINDOW *mainWin = NULL, | 35 WINDOW *mainWin = NULL, |
36 *statusWin = NULL, | 36 *statusWin = NULL, |
37 *editWin = NULL; | 37 *editWin = NULL; |
38 | 38 BOOL setPrvMode = FALSE; |
39 BOOL setInsertMode = TRUE; | |
40 | 39 |
41 /* Arguments | 40 /* Arguments |
42 */ | 41 */ |
43 optarg_t optList[] = { | 42 optarg_t optList[] = { |
44 { 0, '?', "help", "Show this help", OPT_NONE }, | 43 { 0, '?', "help", "Show this help", OPT_NONE }, |
196 { | 195 { |
197 buf->len = 0; | 196 buf->len = 0; |
198 buf->pos = 0; | 197 buf->pos = 0; |
199 } | 198 } |
200 | 199 |
200 editbuf_t * newBuf(void) | |
201 { | |
202 return (editbuf_t *) th_calloc(1, sizeof(editbuf_t)); | |
203 } | |
204 | |
205 void freeBuf(editbuf_t *buf) | |
206 { | |
207 th_free(buf); | |
208 } | |
209 | |
210 editbuf_t * copyBuf(editbuf_t *src) | |
211 { | |
212 editbuf_t *dst = newBuf(); | |
213 | |
214 if (dst == NULL) return NULL; | |
215 | |
216 if (src != NULL) { | |
217 memcpy(dst->data, src->data, SET_BUFSIZE); | |
218 clearBuf(dst); | |
219 } | |
220 | |
221 return dst; | |
222 } | |
223 | |
201 void setBufPos(editbuf_t *buf, ssize_t pos) | 224 void setBufPos(editbuf_t *buf, ssize_t pos) |
202 { | 225 { |
203 /* Check arguments */ | 226 /* Check arguments */ |
204 if (pos < 0) | 227 if (pos < 0) |
205 buf->pos = 0; | 228 buf->pos = 0; |
207 buf->pos = buf->len; | 230 buf->pos = buf->len; |
208 else | 231 else |
209 buf->pos = pos; | 232 buf->pos = pos; |
210 } | 233 } |
211 | 234 |
212 void updateStatus(void) | 235 void updateStatus(BOOL insertMode) |
213 { | 236 { |
214 char tmpStr[128] = ""; | 237 char tmpStr[128] = ""; |
215 time_t timeStamp; | 238 time_t timeStamp; |
216 struct tm *tmpTime;; | 239 struct tm *tmpTime;; |
217 | 240 |
225 | 248 |
226 wattrset(statusWin, A_BOLD); | 249 wattrset(statusWin, A_BOLD); |
227 mvwaddstr(statusWin, 0, 1, tmpStr); | 250 mvwaddstr(statusWin, 0, 1, tmpStr); |
228 | 251 |
229 waddstr(statusWin, " | "); | 252 waddstr(statusWin, " | "); |
230 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | 253 wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); |
231 waddstr(statusWin, optUserName); | 254 waddstr(statusWin, optUserName); |
232 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | 255 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); |
233 | 256 |
234 waddstr(statusWin, " | "); | 257 waddstr(statusWin, " | "); |
235 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | 258 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); |
236 waddstr(statusWin, setInsertMode ? "INS" : "DEL"); | 259 waddstr(statusWin, insertMode ? "INS" : "DEL"); |
237 | 260 |
238 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | 261 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); |
239 waddstr(statusWin, " | Prv: "); | 262 waddstr(statusWin, " | Prv: "); |
240 | 263 |
241 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | 264 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); |
242 waddstr(statusWin, setTarget != NULL ? setTarget : "-"); | 265 waddstr(statusWin, setTarget != NULL ? setTarget : "-"); |
243 | 266 |
244 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | 267 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); |
245 waddstr(statusWin, " | Port: "); | 268 waddstr(statusWin, " | P/C: "); |
246 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | 269 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); |
247 snprintf(tmpStr, sizeof(tmpStr), "%d", optPort); | 270 snprintf(tmpStr, sizeof(tmpStr), "%d / #%06x", optPort, optUserColor); |
248 waddstr(statusWin, tmpStr); | 271 waddstr(statusWin, tmpStr); |
249 | 272 |
250 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
251 waddstr(statusWin, " | Col: "); | |
252 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
253 snprintf(tmpStr, sizeof(tmpStr), "%06x", optUserColor); | |
254 waddstr(statusWin, tmpStr); | |
255 | |
256 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
257 snprintf(tmpStr, sizeof(tmpStr), " | %s v%s", | |
258 th_prog_name, th_prog_version); | |
259 waddstr(statusWin, tmpStr); | |
260 | |
261 wrefresh(statusWin); | 273 wrefresh(statusWin); |
262 } | 274 } |
263 | 275 |
264 void printEditBuf(editbuf_t *buf) | 276 void printEditBuf(char *str, editbuf_t *buf) |
265 { | 277 { |
266 buf->data[buf->len] = 0; | 278 buf->data[buf->len] = 0; |
267 werase(editWin); | 279 werase(editWin); |
280 | |
281 wattrset(editWin, A_BOLD); | |
282 mvwaddstr(editWin, 0, 0, str); | |
283 waddstr(editWin, "> "); | |
284 wattrset(editWin, A_NORMAL); | |
285 | |
268 if (buf->pos < buf->len) { | 286 if (buf->pos < buf->len) { |
269 mvwaddnstr(editWin, 0, 0, buf->data, buf->pos); | 287 waddnstr(editWin, buf->data, buf->pos); |
270 wattrset(editWin, A_REVERSE); | 288 wattrset(editWin, A_REVERSE); |
271 waddch(editWin, buf->data[buf->pos]); | 289 waddch(editWin, buf->data[buf->pos]); |
272 wattrset(editWin, A_NORMAL); | 290 wattrset(editWin, A_NORMAL); |
273 waddnstr(editWin, buf->data + buf->pos + 1, buf->len - buf->pos - 1); | 291 waddnstr(editWin, buf->data + buf->pos + 1, buf->len - buf->pos - 1); |
274 } else { | 292 } else { |
275 mvwaddnstr(editWin, 0, 0, buf->data, buf->len); | 293 waddnstr(editWin, buf->data, buf->len); |
276 wattrset(editWin, A_REVERSE); | 294 wattrset(editWin, A_REVERSE); |
277 waddch(editWin, ' '); | 295 waddch(editWin, ' '); |
278 wattrset(editWin, A_NORMAL); | 296 wattrset(editWin, A_NORMAL); |
279 } | 297 } |
280 wrefresh(editWin); | 298 wrefresh(editWin); |
852 | 870 |
853 /* Check command */ | 871 /* Check command */ |
854 if (*buf == 0) { | 872 if (*buf == 0) { |
855 return 1; | 873 return 1; |
856 } else if (!strncmp(buf, "/color ", 7)) { | 874 } else if (!strncmp(buf, "/color ", 7)) { |
857 if ((optUserColor = getColor(buf+7)) < 0) { | 875 int tmpInt; |
876 if ((tmpInt = getColor(buf+7)) < 0) { | |
858 printMsg("Invalid color value '%s'\n", buf+7); | 877 printMsg("Invalid color value '%s'\n", buf+7); |
859 return 1; | 878 return 1; |
860 } | 879 } |
880 optUserColor = tmpInt; | |
861 printMsg("Setting color to #%06x\n", optUserColor); | 881 printMsg("Setting color to #%06x\n", optUserColor); |
862 sendUserMsg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); | 882 sendUserMsg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); |
863 return 0; | 883 return 0; |
864 } else if (!strncmp(buf, "/flood ", 7)) { | 884 } else if (!strncmp(buf, "/flood ", 7)) { |
865 int i; | 885 int i; |
881 usleep(250); | 901 usleep(250); |
882 } | 902 } |
883 | 903 |
884 th_free(tmpStr); | 904 th_free(tmpStr); |
885 th_free(tmpStr2); | 905 th_free(tmpStr2); |
906 return 0; | |
907 } else if (!strncmp(buf, "/to ", 4)) { | |
908 buf += 4; | |
909 th_free(setTarget); | |
910 setTarget = th_strdup(buf); | |
911 printMsg("Set prv target to '%s'\n", setTarget); | |
886 return 0; | 912 return 0; |
887 } else if (!strncmp(buf, "/msg ", 5)) { | 913 } else if (!strncmp(buf, "/msg ", 5)) { |
888 if (setTarget != NULL) { | 914 if (setTarget != NULL) { |
889 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf+5); | 915 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf+5); |
890 buf = tmpBuf; | 916 buf = tmpBuf; |
891 } else { | 917 } else { |
892 printMsg("No target set!\n"); | 918 printMsg("No target set!\n"); |
893 return 1; | 919 return 1; |
894 } | 920 } |
895 } else if (!strncmp(buf, "/to ", 4)) { | 921 } else if (setPrvMode) { |
896 buf += 4; | 922 if (setTarget != NULL) { |
897 th_free(setTarget); | 923 snprintf(tmpBuf, sizeof(tmpBuf), "/prv -to %s -msg %s", setTarget, buf); |
898 setTarget = th_strdup(buf); | 924 buf = tmpBuf; |
899 printMsg("Set prv target to '%s'\n", setTarget); | 925 } else { |
900 return 0; | 926 printMsg("No target set, exiting prv mode.\n"); |
927 setPrvMode = FALSE; | |
928 return 1; | |
929 } | |
901 } | 930 } |
902 | 931 |
903 { | 932 { |
904 /* Send double-encoded */ | 933 /* Send double-encoded */ |
905 tmpStr = encodeStr2(buf); | 934 tmpStr = encodeStr2(buf); |
926 int tmpSocket, curVis, updateCount = 0; | 955 int tmpSocket, curVis, updateCount = 0; |
927 struct hostent *tmpHost; | 956 struct hostent *tmpHost; |
928 BOOL argsOK, isError = FALSE, | 957 BOOL argsOK, isError = FALSE, |
929 exitProg = FALSE, | 958 exitProg = FALSE, |
930 colorSet = FALSE, | 959 colorSet = FALSE, |
931 cursesInit = FALSE; | 960 cursesInit = FALSE, |
961 insertMode = TRUE; | |
932 struct timeval tv; | 962 struct timeval tv; |
933 fd_set sockfds; | 963 fd_set sockfds; |
934 char *tmpStr; | 964 char *tmpStr; |
935 editbuf_t *editBuf = calloc(1, sizeof(editbuf_t)); | 965 editbuf_t *editBuf = newBuf(); |
936 | 966 editbuf_t *histBuf[SET_MAX_HISTORY+2]; |
967 int histPos = 0, histMax = 0; | |
968 | |
969 memset(histBuf, 0, sizeof(histBuf)); | |
970 | |
937 /* Initialize */ | 971 /* Initialize */ |
938 th_init("NNChat", "Newbie Nudes chat client", "0.4", | 972 th_init("NNChat", "Newbie Nudes chat client", "0.5", |
939 "Written and designed by Anonymous Finnish Guy (C) 2008", | 973 "Written and designed by Anonymous Finnish Guy (C) 2008", |
940 "This software is freeware, use and distribute as you wish."); | 974 "This software is freeware, use and distribute as you wish."); |
941 th_verbosityLevel = 0; | 975 th_verbosityLevel = 0; |
942 | 976 |
943 /* Parse arguments */ | 977 /* Parse arguments */ |
1043 goto err_exit; | 1077 goto err_exit; |
1044 } | 1078 } |
1045 scrollok(mainWin, 1); | 1079 scrollok(mainWin, 1); |
1046 | 1080 |
1047 clearBuf(editBuf); | 1081 clearBuf(editBuf); |
1048 printEditBuf(editBuf); | 1082 printEditBuf("", editBuf); |
1049 updateStatus(); | 1083 updateStatus(insertMode); |
1050 | 1084 |
1051 cursesInit = TRUE; | 1085 cursesInit = TRUE; |
1052 } | 1086 } |
1053 | 1087 |
1054 | 1088 |
1089 /* Enter mainloop */ | |
1055 FD_ZERO(&sockfds); | 1090 FD_ZERO(&sockfds); |
1056 FD_SET(tmpSocket, &sockfds); | 1091 FD_SET(tmpSocket, &sockfds); |
1057 | 1092 |
1058 while (!isError && !exitProg) { | 1093 while (!isError && !exitProg) { |
1059 int result; | 1094 int result; |
1067 printMsg("Error occured in select(sockfds): %s\n", | 1102 printMsg("Error occured in select(sockfds): %s\n", |
1068 strerror(errno)); | 1103 strerror(errno)); |
1069 isError = TRUE; | 1104 isError = TRUE; |
1070 } else if (FD_ISSET(tmpSocket, &tmpfds)) { | 1105 } else if (FD_ISSET(tmpSocket, &tmpfds)) { |
1071 ssize_t gotBuf; | 1106 ssize_t gotBuf; |
1072 char tmpBuf[4096]; | 1107 char tmpBuf[8192]; |
1073 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); | 1108 gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0); |
1074 | 1109 |
1075 if (gotBuf < 0) { | 1110 if (gotBuf < 0) { |
1076 printMsg("Error in recv: %s\n", strerror(errno)); | 1111 printMsg("Error in recv: %s\n", strerror(errno)); |
1077 isError = TRUE; | 1112 isError = TRUE; |
1089 } else if (result < 0) { | 1124 } else if (result < 0) { |
1090 /* Fatal error, quit */ | 1125 /* Fatal error, quit */ |
1091 printMsg("Fatal error with message: %s\n", tmpBuf); | 1126 printMsg("Fatal error with message: %s\n", tmpBuf); |
1092 isError = TRUE; | 1127 isError = TRUE; |
1093 } | 1128 } |
1094 updateStatus(); | 1129 updateStatus(insertMode); |
1095 } | 1130 } |
1096 } | 1131 } |
1097 | 1132 |
1098 /* Handle user input */ | 1133 /* Handle user input */ |
1099 if (!optDaemon) { | 1134 if (!optDaemon) { |
1108 case '\n': | 1143 case '\n': |
1109 case '\r': | 1144 case '\r': |
1110 /* Call the user input handler */ | 1145 /* Call the user input handler */ |
1111 if (editBuf->len > 0) { | 1146 if (editBuf->len > 0) { |
1112 insertBuf(editBuf, editBuf->pos, 0); | 1147 insertBuf(editBuf, editBuf->pos, 0); |
1148 | |
1149 if (histMax > 0) { | |
1150 freeBuf(histBuf[histMax]); | |
1151 memmove(&histBuf[2], &histBuf[1], histMax * sizeof(histBuf[0])); | |
1152 } | |
1153 histPos = 0; | |
1154 histBuf[1] = copyBuf(editBuf); | |
1155 if (histMax < SET_MAX_HISTORY) histMax++; | |
1156 | |
1113 result = handleUserInput(tmpSocket, editBuf->data, editBuf->len); | 1157 result = handleUserInput(tmpSocket, editBuf->data, editBuf->len); |
1158 | |
1114 clearBuf(editBuf); | 1159 clearBuf(editBuf); |
1115 | 1160 |
1116 if (result < 0) { | 1161 if (result < 0) { |
1117 printMsg("Fatal error handling user input: %s\n", editBuf->data); | 1162 printMsg("Fatal error handling user input: %s\n", editBuf->data); |
1118 isError = TRUE; | 1163 isError = TRUE; |
1119 } | 1164 } |
1120 | 1165 |
1121 update = TRUE; | 1166 update = TRUE; |
1122 } | 1167 } |
1123 break; | 1168 break; |
1124 | 1169 |
1170 case 0x09: /* Tab = switch between PRV */ | |
1171 if (setPrvMode) | |
1172 setPrvMode = FALSE; | |
1173 else { | |
1174 if (setTarget != NULL) | |
1175 setPrvMode = TRUE; | |
1176 } | |
1177 update = TRUE; | |
1178 break; | |
1179 | |
1180 case KEY_UP: | |
1181 if (histPos == 0) | |
1182 histBuf[0] = copyBuf(editBuf); | |
1183 if (histPos < histMax) { | |
1184 histPos++; | |
1185 freeBuf(editBuf); | |
1186 editBuf = copyBuf(histBuf[histPos]); | |
1187 update = TRUE; | |
1188 } | |
1189 break; | |
1190 | |
1191 case KEY_DOWN: | |
1192 if (histPos > 0) { | |
1193 histPos--; | |
1194 freeBuf(editBuf); | |
1195 editBuf = copyBuf(histBuf[histPos]); | |
1196 update = TRUE; | |
1197 } | |
1198 break; | |
1199 | |
1125 case 0x109: /* F1 */ | 1200 case 0x109: /* F1 */ |
1126 if (setInsertMode) | 1201 if (insertMode) |
1127 setInsertMode = FALSE; | 1202 insertMode = FALSE; |
1128 else | 1203 else |
1129 setInsertMode = TRUE; | 1204 insertMode = TRUE; |
1130 update = TRUE; | 1205 update = TRUE; |
1131 break; | 1206 break; |
1132 | 1207 |
1133 case 0x204: /* ctrl+left */ | 1208 case 0x204: /* ctrl+left */ |
1134 editBuf->pos--; | 1209 editBuf->pos--; |
1186 /* Ignore */ | 1261 /* Ignore */ |
1187 break; | 1262 break; |
1188 | 1263 |
1189 default: | 1264 default: |
1190 if (isprint(c)) { | 1265 if (isprint(c)) { |
1191 if (setInsertMode) | 1266 if (insertMode) |
1192 insertBuf(editBuf, editBuf->pos, c); | 1267 insertBuf(editBuf, editBuf->pos, c); |
1193 else | 1268 else |
1194 writeBuf(editBuf, editBuf->pos, c); | 1269 writeBuf(editBuf, editBuf->pos, c); |
1195 setBufPos(editBuf, editBuf->pos + 1); | 1270 setBufPos(editBuf, editBuf->pos + 1); |
1196 update = TRUE; | 1271 update = TRUE; |
1201 } | 1276 } |
1202 } while (c != ERR && !exitProg && ++cnt < 10); | 1277 } while (c != ERR && !exitProg && ++cnt < 10); |
1203 | 1278 |
1204 if (update) { | 1279 if (update) { |
1205 /* Update edit line */ | 1280 /* Update edit line */ |
1206 printEditBuf(editBuf); | 1281 printEditBuf(setPrvMode ? setTarget : "", editBuf); |
1207 updateStatus(); | 1282 updateStatus(insertMode); |
1208 } | 1283 } |
1209 } /* !optDaemon */ | 1284 } /* !optDaemon */ |
1210 | 1285 |
1211 if (++updateCount > 10) { | 1286 if (++updateCount > 10) { |
1212 updateStatus(); | 1287 updateStatus(insertMode); |
1213 updateCount = 0; | 1288 updateCount = 0; |
1214 } | 1289 } |
1215 | 1290 |
1216 if (!colorSet) { | 1291 if (!colorSet) { |
1217 colorSet = TRUE; | 1292 colorSet = TRUE; |
1293 printMsg("%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname); | |
1294 printMsg("%s\n", th_prog_author); | |
1295 printMsg("%s\n", th_prog_license); | |
1218 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); | 1296 sendUserMsg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); |
1219 } | 1297 } |
1220 } | 1298 } |
1221 | 1299 |
1222 /* Shutdown */ | 1300 /* Shutdown */ |