Skip to content

Commit c199912

Browse files
committed
new at 0.0.1
0 parents  commit c199912

File tree

4 files changed

+330
-0
lines changed

4 files changed

+330
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Michael Czigler
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CFLAGS += -std=c99 -Wall -Wextra -pedantic -Wold-style-declaration
2+
PREFIX ?= /usr
3+
BINDIR ?= $(PREFIX)/bin
4+
CC ?= gcc
5+
6+
all: kirc
7+
8+
kfc: kirc.c Makefile
9+
$(CC) -O3 $(CFLAGS) -o $@ $< -lX11 $(LDFLAGS)
10+
11+
install: all
12+
install -Dm755 kirc $(DESTDIR)$(BINDIR)/kirc
13+
14+
uninstall:
15+
rm -f $(DESTDIR)$(BINDIR)/kirc
16+
17+
clean:
18+
rm -f kirc *.o
19+
20+
.PHONY: all install uninstall clean

README

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
kirc
2+
3+
KISS for IRC, an IRC client written in POSIX C99.
4+
5+
6+
BACKGROUND
7+
----------
8+
9+
After having tried multiple IRC clients, I decided to develope my own. The
10+
result is a portable <250 sloc application that has no dependencies other
11+
than a C99 compiler.
12+
13+
14+
FEATURES
15+
--------
16+
17+
- automatic host PING response.
18+
- vi-like shortcuts:
19+
20+
:m <message> send a message to the connected channel
21+
:q close the host connection and quit kirc
22+
23+
24+
INSTALLATION
25+
------------
26+
27+
Building and installing from source:
28+
29+
git clone https://github.com/mcpcpc/kirc.git
30+
cd kirc
31+
make
32+
make install
33+
34+
35+
USAGE
36+
-----
37+
38+
usage: kirc [-s hostname] [-p port] [-c channel] [-n nick] [-v|V]
39+
-s server address (default: 'irc.freenode.org')
40+
-p server port (default: '6667')
41+
-c channel name (default: '#kisslinux')
42+
-n user nickname
43+
-v version information
44+
-V verbose output (e.g. raw stream)

kirc.c

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#define _POSIX_C_SOURCE 200809L
2+
#include <stdarg.h>
3+
#include <netdb.h>
4+
#include <stdio.h>
5+
#include <unistd.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <netdb.h>
9+
#include <sys/ioctl.h>
10+
#include <fcntl.h>
11+
#include <sys/wait.h>
12+
#include <termios.h>
13+
14+
#define BUFF 512 /* buffer size (see RFC 2812) */
15+
#define CMAX 102 /* max number of columns */
16+
#define GUTL 10 /* left gutter width and alignment */
17+
18+
static int conn; /* socket connection */
19+
static char sbuf[BUFF]; /* string buffer */
20+
static int verb = 0; /* verbose output (e.g. raw stream) */
21+
static char *host = "irc.freenode.org"; /* irc host address */
22+
static char *chan = "kisslinux"; /* channel */
23+
static char *port = "6667"; /* port */
24+
static char *nick = NULL; /* nickname */
25+
26+
static int
27+
kbhit(void)
28+
{
29+
int byteswaiting;
30+
struct termios term;
31+
32+
tcgetattr(0, &term);
33+
34+
struct termios term2 = term;
35+
36+
term2.c_lflag &= ~ICANON;
37+
tcsetattr(0, TCSANOW, &term2);
38+
ioctl(0, FIONREAD, &byteswaiting);
39+
tcsetattr(0, TCSANOW, &term);
40+
41+
return byteswaiting > 0;
42+
}
43+
44+
static void
45+
raw(char *fmt, ...) {
46+
va_list ap;
47+
48+
va_start(ap, fmt);
49+
vsnprintf(sbuf, BUFF, fmt, ap);
50+
va_end(ap);
51+
52+
if (verb) printf("<< %s", sbuf);
53+
54+
write(conn, sbuf, strlen(sbuf));
55+
}
56+
57+
static void
58+
con(void)
59+
{
60+
struct addrinfo hints, *res;
61+
62+
memset(&hints, 0, sizeof hints);
63+
hints.ai_family = AF_INET;
64+
hints.ai_socktype = SOCK_STREAM;
65+
getaddrinfo(host, port, &hints, &res);
66+
conn = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
67+
connect(conn, res->ai_addr, res->ai_addrlen);
68+
69+
if (nick) raw("NICK %s\r\n", nick);
70+
if (nick) raw("USER %s - - :%s\r\n", nick, nick);
71+
72+
fcntl(conn, F_SETFL, O_NONBLOCK);
73+
}
74+
75+
static void
76+
printw(const char *format, ...)
77+
{
78+
int s1 = 0, s2, i, o;
79+
va_list argptr;
80+
char *line = malloc(sizeof(char) * (BUFF + 1));
81+
va_start(argptr, format);
82+
vsnprintf(line, BUFF + 1, format, argptr);
83+
if (strlen(line) <= CMAX) printf(line);
84+
else if (strlen(line) > CMAX)
85+
{
86+
87+
for (i = 0; i < CMAX; i++)
88+
{
89+
if (line[i] == ' ') s1 = i;
90+
if (i == CMAX - 1) printf("%-*.*s\n", s1, s1, line);
91+
}
92+
s2 = o = s1;
93+
for (i = s1; line[i] != '\0'; i++)
94+
{
95+
if (line[i] == ' ') s2 = i;
96+
if ((i - o) == (CMAX - GUTL))
97+
{
98+
printf("%*s %-*.*s\n", GUTL, " ", s2 - o, s2 - o, &line[o + 1]);
99+
o = i = s2;
100+
}
101+
else if (line[i + 1] == '\0')
102+
{
103+
printf("%*s %-*.*s", GUTL, " ", i - o, i - o, &line[o + 1]);
104+
}
105+
}
106+
}
107+
va_end(argptr);
108+
free(line);
109+
}
110+
111+
static void
112+
pars(int sl, char *buf)
113+
{
114+
char buf_c[BUFF + 1], ltr[200], cha[200], nic[200], hos[200], \
115+
usr[200], cmd[200], msg[200], pre[200];
116+
int i = 0;
117+
int o = -1;
118+
119+
for (i = 0; i < sl; i++)
120+
{
121+
o++;
122+
buf_c[o] = buf[i];
123+
124+
if ((i > 0 && buf[i] == '\n' && buf[i - 1] == '\r') || o == BUFF)
125+
{
126+
buf_c[o + 1] = '\0';
127+
o = -1;
128+
129+
if (verb) printf(">> %s", buf_c);
130+
131+
if (!strncmp(buf_c, "PING", 4))
132+
{
133+
buf_c[1] = 'O';
134+
raw(buf_c);
135+
}
136+
137+
else if (buf_c[0] == ':')
138+
{
139+
sscanf(buf_c, ":%[^ ] %[^:]:%[^\r]", pre, cmd, msg);
140+
sscanf(pre, "%[^!]!%[^@]@%s", nic, usr, hos);
141+
sscanf(cmd, "%[^#& ]%s", ltr, cha);
142+
143+
if (!strncmp(ltr, "001", 3)) raw("JOIN #%s\r\n", chan);
144+
145+
if (!strncmp(ltr, "QUIT", 4))
146+
{
147+
printw("%*.*s \x1b[34;1m%s\x1b[0m left %s\n", \
148+
GUTL, GUTL, "<--", nic, cha);
149+
}
150+
else if (!strncmp(ltr, "JOIN", 4))
151+
{
152+
printw("%*.*s \x1b[32;1m%s\x1b[0m joined %s\n", \
153+
GUTL, GUTL, "-->", nic, cha);
154+
}
155+
else
156+
{
157+
printw("\x1b[1m%*.*s\x1b[0m %s\n", \
158+
GUTL, GUTL, nic, msg);
159+
}
160+
}
161+
}
162+
}
163+
}
164+
165+
int
166+
main(int argc, char **argv)
167+
{
168+
extern char *optarg;
169+
extern int optind, optopt;
170+
int fd[2], cval;
171+
172+
while ((cval = getopt(argc, argv, "s:p:n:k:c:vV")) != -1)
173+
{
174+
switch (cval)
175+
{
176+
case 'v' : printf("kirc 0.0.1\n"); break;
177+
case 'V' : verb = 1; break;
178+
case 's' : host = optarg; break;
179+
case 'p' : port = optarg; break;
180+
case 'n' : nick = optarg; break;
181+
case 'c' : chan = optarg; break;
182+
}
183+
}
184+
185+
if (pipe(fd) < 0)
186+
{
187+
fprintf(stderr, "pipe() failed");
188+
exit(2);
189+
}
190+
191+
pid_t pid = fork();
192+
193+
if (pid == 0)
194+
{
195+
int sl;
196+
char u[BUFF];
197+
198+
con();
199+
200+
while ((sl = read(conn, sbuf, BUFF)))
201+
{
202+
pars(sl, sbuf);
203+
if ((read(fd[0], u, CMAX) > 0) && !strstr(u, "WAIT_SIG"))
204+
{
205+
raw("%s\r\n", u);
206+
}
207+
}
208+
printf("CONNECTION TERMINATED (press <ENTER> to quit)\n");
209+
}
210+
else
211+
{
212+
char usrin[CMAX];
213+
char cmd = '\n';
214+
char *cmd_val = malloc(sizeof(char) * (CMAX - 3));
215+
216+
while (waitpid(pid, NULL, WNOHANG) == 0)
217+
{
218+
while (!kbhit() && waitpid(pid, NULL, WNOHANG) == 0)
219+
{
220+
write(fd[1], "WAIT_SIG", CMAX);
221+
}
222+
223+
fgets(usrin, CMAX, stdin);
224+
225+
if (usrin[0] == ':')
226+
{
227+
sscanf(usrin, ":%c %s", &cmd, cmd_val);
228+
229+
switch (cmd)
230+
{
231+
case 'q':
232+
snprintf(usrin, CMAX, "quit");
233+
break;
234+
case 'm':
235+
snprintf(usrin, CMAX, "privmsg %s %s", chan, cmd_val);
236+
break;
237+
}
238+
}
239+
write(fd[1], usrin, CMAX);
240+
fflush(stdout);
241+
}
242+
}
243+
244+
return 0;
245+
}

0 commit comments

Comments
 (0)