#include "chat.h" /* (C) 2008 Bryce Schroeder * Usage: ./client [SERVER [name [passwd]]] * Uses port 41000 * Note: if you want, you can also use telnet as the client * for the server, as I did when I was developing it. * This is based of off beej's simple stream client, * http://www.beej.us/guide/bgnet/output/html/multipage/clientserver.html * * */ #include /* for host names */ #define STDIN 0 FILE *chlog = NULL; /* This function wraps the error checking for sending. */ void safer_send(int socket, char *buffer) { int rv = send(socket, buffer, strlen(buffer), 0); if (rv < 0) perror("send"); } /* This function processes the commands given by the user */ void process_line(int sockfd, char *buffer) { if (buffer[0] != '.') { safer_send(sockfd, buffer); return; } if (buffer[1] == 'w' && buffer[2] == 's') { safer_send(sockfd, buffer); return; } int argc = chrcnt(buffer, " ") + 1; char *token; char **argv = calloc(argc, sizeof (char*)); ++buffer; /* skip . */ /* parse the arguments */ for (int i = 0; i < argc; ++i) { token = buffer; while (*buffer != ' ') ++buffer; *buffer++ = '\0'; argv[i] = malloc(strlen(token)+1); strcpystrip(argv[i], token); } if (!strcmp(argv[0], "lc")) { if (chlog != NULL) fclose(chlog); exit(0); } else if (!strcmp(argv[0], "wr")) { if (argc != 2) { printf("Specify a file name.\n"); return; } if (chlog != NULL) fclose(chlog); chlog = fopen(argv[1],"w"); if (chlog == NULL) { printf("Coudln't open the log.\n"); return; } printf("Conversations will be logged to %s\n",argv[1]); } else if (!strcmp(argv[0], "ap")) { if (argc != 2) { printf("Specify a file name.\n"); return; } if (chlog != NULL) fclose(chlog); chlog = fopen(argv[1],"a"); if (chlog == NULL) { printf("Coudln't open the log.\n"); return; } printf("Conversations will be logged to %s\n",argv[1]); } else if (!strcmp(argv[0], "en")) { printf("Ended recording.\n"); if (chlog != NULL) fclose(chlog); chlog = NULL; } else if (!strcmp(argv[0], "rd")) { /* this feature was seriously underspecified. * I have little idea as to what it should do. * So what it does is send a file. * Usually this results in your getting muted by * the flood control... */ if (argc != 2) { printf("Specify a file name.\n"); return; } FILE *tmp = fopen(argv[1],"r"); if (tmp == NULL) { printf("Coudln't open the file.\n"); return; } /* send the top line */ while (fgets(buffer, 2040, tmp) != NULL) { safer_send(sockfd, buffer); } fclose(tmp); printf(" -- Transmission complete -- \n"); return; } else if (!strcmp(argv[0], "cmd")) { /* cmd works by sending a suspend signal to * this process, so you can use your normal shell * and everything. */ printf("To resume, type 'fg'.\n"); kill(getpid(),SIGSTOP); printf("Welcome back.\n"); } } int main(int argc, char *argv[]) { char login_name[30] = ""; char login_passwd[30] = ""; char host_name[30] = "localhost"; char buffer[2048] = ""; if (argc >= 2) strncpy(host_name, argv[1], 29); if (argc >= 3) strncpy(login_name, argv[2], 29); if (argc >= 4) strncpy(login_passwd, argv[3], 29); printf("Welcome to the client for Bryce's chat program.\n" "Connecting to %s...", host_name); struct hostent *he; struct sockaddr_in their_addr; int sockfd; if ((he=gethostbyname(host_name)) == NULL) { // get the host info herror("gethostbyname"); exit(1); } if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(2); } their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(41000); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof their_addr) == -1) { perror("connect"); exit(1); } /* We are connected to the chat server... */ if (login_name[0]!='\0') { sprintf(buffer, "!name %s\n\r", login_name); printf("\n(Setting name)\n[%s]\n",buffer); safer_send(sockfd, buffer); } if (login_passwd[0] != '\0') { sleep(1); sprintf(buffer, "!login %s\n\r", login_passwd); printf("(Sending password)\n[%s]\n\n",buffer); safer_send(sockfd, buffer); } buffer[0] = '\0'; printf(" ---------- Chatting on %s ------------\n",host_name); /* set up for nonblocking IO */ fcntl(sockfd, F_SETFL, O_NONBLOCK); fcntl(STDIN, F_SETFL, O_NONBLOCK); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 50000; int rv; /* select: the fount of awesomeness and arcane power. :) */ fd_set inputs; FD_ZERO(&inputs); while (1) { FD_SET(STDIN,&inputs); FD_SET(sockfd, &inputs); select(MAX(STDIN,sockfd)+1, &inputs,NULL,NULL,&tv); if (FD_ISSET(sockfd, &inputs)) { rv=recv(sockfd, buffer, 2040, 0); buffer[rv] = '\0'; printf(buffer); if (chlog != NULL) fprintf(chlog,buffer); } if (FD_ISSET(STDIN, &inputs)) { fgets(buffer, 2040, stdin); if (chlog != NULL) fprintf(chlog,buffer); process_line(sockfd, buffer); } FD_ZERO(&inputs); } /* if we ever fall through that loop, it is by syscall error */ perror("select"); return 1; }