first commit, unfinished wip
This commit is contained in:
92
src/IRC.c
Normal file
92
src/IRC.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "IRC.h"
|
||||
#include "defines.h"
|
||||
#include "netcode.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
int IRC_ParseMessage(char *line, irc_message_t *msg)
|
||||
{
|
||||
strncpy(msg->line, line, sizeof(msg->line) - 1);
|
||||
char *ptr = msg->line;
|
||||
ptr[sizeof(msg->line)] = NUL;
|
||||
|
||||
char *source = NULL;
|
||||
char *command = NULL;
|
||||
|
||||
// get the source, if it exists (the : at the beginning of an IRC message)
|
||||
if(*ptr == ':')
|
||||
{
|
||||
ptr++;
|
||||
source = ptr;
|
||||
|
||||
while (*ptr && *ptr != ' ') ptr++;
|
||||
if (*ptr) *ptr++ = NUL;
|
||||
|
||||
while (*ptr == ' ') ptr++; // skip any extra spaces
|
||||
}
|
||||
|
||||
msg->source = source;
|
||||
|
||||
// read the command
|
||||
command = ptr;
|
||||
|
||||
while(*ptr && *ptr != ' ') ptr++;
|
||||
if (*ptr) *ptr++ = NUL;
|
||||
|
||||
msg->command = command;
|
||||
|
||||
while (*ptr == ' ') ptr++;
|
||||
|
||||
// read its arguments (until we encounter a colon/nullbyte)
|
||||
msg->argc = 0;
|
||||
|
||||
while(*ptr && msg->argc <= 15)
|
||||
{
|
||||
if(*ptr == ':') // if it's a trailing arg
|
||||
{
|
||||
ptr++;
|
||||
msg->argv[msg->argc] = ptr;
|
||||
msg->argc++;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->argv[msg->argc] = ptr;
|
||||
|
||||
while(*ptr && *ptr != ' ') ptr++;
|
||||
|
||||
if (*ptr)
|
||||
{
|
||||
*ptr++ = NUL;
|
||||
while (*ptr == ' ') ptr++; // skip spaces for next arg
|
||||
}
|
||||
|
||||
msg->argc++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handlePing(irc_message_t *msg, irc_client_t *irc)
|
||||
{
|
||||
char buf[128];
|
||||
snprintf(buf, sizeof buf, "PONG :%s", msg->argv[0]);
|
||||
NET_Send(irc->sockfd, buf);
|
||||
}
|
||||
|
||||
void IRC_ProcessMessage(irc_message_t *msg, irc_client_t *irc)
|
||||
{
|
||||
command_t commands[] =
|
||||
{
|
||||
{"PING", handlePing},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
for(int i = 0; commands[i].name; i++)
|
||||
{
|
||||
if(strcmp(msg->command, commands[i].name) == 0)
|
||||
{
|
||||
commands[i].handler(msg, irc);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/main.c
Normal file
105
src/main.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "IRC.h"
|
||||
#include "defines.h"
|
||||
#include "netcode.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sockfd = NET_Connect("irc.libera.chat", 6667);
|
||||
|
||||
fd_set readfds;
|
||||
static char linebuf[1026];
|
||||
static size_t lineLen = 0;
|
||||
char recvline[513];
|
||||
char sendline[513];
|
||||
|
||||
irc_client_t irc;
|
||||
irc.sockfd = sockfd;
|
||||
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
NET_Send(sockfd, "NICK BareBonesDude\r\n");
|
||||
NET_Send(sockfd, "USER BareBonesDude 0 * :The Postal Dudesksleton\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
FD_SET(sockfd, &readfds);
|
||||
|
||||
int maxfd = (sockfd > 0) ? sockfd + 1 : 1;
|
||||
|
||||
select(maxfd, &readfds, NULL, NULL, NULL);
|
||||
|
||||
if(FD_ISSET(STDIN_FILENO, &readfds))
|
||||
{
|
||||
fgets(sendline, sizeof(sendline), stdin);
|
||||
NET_Send(sockfd, sendline);
|
||||
}
|
||||
|
||||
if(FD_ISSET(sockfd, &readfds))
|
||||
{
|
||||
ssize_t n = recv(sockfd, recvline, sizeof(recvline), 0);
|
||||
|
||||
if(n <= 0) break;
|
||||
recvline[n] = NUL;
|
||||
|
||||
for(ssize_t i = 0; i < n; i++)
|
||||
{
|
||||
linebuf[lineLen++] = recvline[i];
|
||||
|
||||
if(lineLen >= 2 && linebuf[lineLen - 2] == '\r' && linebuf[lineLen - 1] == '\n')
|
||||
{
|
||||
// we found a complete line
|
||||
linebuf[lineLen] = NUL;
|
||||
|
||||
// parse the message
|
||||
irc_message_t msg;
|
||||
IRC_ParseMessage(linebuf, &msg);
|
||||
|
||||
// try to print it
|
||||
|
||||
if(msg.source != NULL)
|
||||
{
|
||||
printf("%s: %s ", msg.source, msg.command);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Server: %s ", msg.command);
|
||||
}
|
||||
|
||||
for(int i = 0; i < msg.argc; i++)
|
||||
{
|
||||
printf("%s ", msg.argv[i]);
|
||||
}
|
||||
|
||||
lineLen = 0;
|
||||
}
|
||||
|
||||
if(lineLen >= sizeof(linebuf) - 1)
|
||||
{
|
||||
lineLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Connection closed by foreign host.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
123
src/netcode.c
Normal file
123
src/netcode.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "netcode.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
int NET_Connect(const char *host, int port)
|
||||
{
|
||||
int status;
|
||||
struct addrinfo hints, *res;
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
// save us from user or programmer stupidity
|
||||
if(!host)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
char portNumber[6];
|
||||
snprintf(portNumber, 6, "%d", port);
|
||||
|
||||
printf("Looking up %s...\n", host);
|
||||
|
||||
if ((status = getaddrinfo(host, portNumber, &hints, &res)) == -1)
|
||||
{
|
||||
fprintf(stderr, "Unable to lookup %s: %s\n", host, gai_strerror(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
char ipstr[INET6_ADDRSTRLEN];
|
||||
int sockfd = -1;
|
||||
|
||||
for(struct addrinfo *p = res; p != NULL; p = p->ai_next)
|
||||
{
|
||||
void *addr;
|
||||
struct sockaddr_in *ipv4;
|
||||
struct sockaddr_in6 *ipv6;
|
||||
|
||||
if(p->ai_family == AF_INET)
|
||||
{
|
||||
ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
addr = &(ipv4->sin_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ipv6 = (struct sockaddr_in6 *)p->ai_addr;
|
||||
addr = &(ipv6->sin6_addr);
|
||||
}
|
||||
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
printf("Connecting to %s (%s)...\n", host, ipstr);
|
||||
|
||||
if((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
|
||||
{
|
||||
char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr];
|
||||
snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr);
|
||||
perror(perrorMsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if((connect(sockfd, p->ai_addr, p->ai_addrlen)) == -1)
|
||||
{
|
||||
close(sockfd);
|
||||
char perrorMsg[sizeof("Failed to connect to ") + sizeof ipstr];
|
||||
snprintf(perrorMsg, sizeof perrorMsg, "Failed to connect to %s", ipstr);
|
||||
perror(perrorMsg);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Connected!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
return sockfd;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void NET_Send(int sockfd, const char *toSend)
|
||||
{
|
||||
size_t bytesSent = 0;
|
||||
size_t sendLen = strlen(toSend);
|
||||
|
||||
while(bytesSent < sendLen)
|
||||
{
|
||||
ssize_t sent = send(sockfd, toSend, sendLen - bytesSent, 0);
|
||||
if(sent == -1)
|
||||
{
|
||||
perror("NET_Send");
|
||||
return;
|
||||
}
|
||||
|
||||
if(sent == 0)
|
||||
{
|
||||
fprintf(stderr, "NET_Send: connection closed");
|
||||
return;
|
||||
}
|
||||
|
||||
bytesSent += sent;
|
||||
}
|
||||
}
|
||||
|
||||
void NET_Close(int sockfd)
|
||||
{
|
||||
if(sockfd >= 0)
|
||||
{
|
||||
shutdown(sockfd, SHUT_RDWR);
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user