Introduction
Introduction Statistics Contact Development Disclaimer Help
sic.c - sic - simple irc client
git clone git://git.suckless.org/sic
Log
Files
Refs
README
LICENSE
---
sic.c (4393B)
---
1 /* See LICENSE file for license details. */
2 #include <sys/select.h>
3
4 #include <ctype.h>
5 #include <errno.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <unistd.h>
12
13 #include "arg.h"
14 #include "config.h"
15
16 char *argv0;
17 static char *host = DEFAULT_HOST;
18 static char *port = DEFAULT_PORT;
19 static char *password;
20 static char nick[32];
21 static char bufin[4096];
22 static char bufout[4096];
23 static char channel[256];
24 static time_t trespond;
25 static FILE *srv;
26
27 #undef strlcpy
28 #include "strlcpy.c"
29 #include "util.c"
30
31 static void
32 pout(char *channel, char *fmt, ...) {
33 static char timestr[80];
34 time_t t;
35 va_list ap;
36
37 va_start(ap, fmt);
38 vsnprintf(bufout, sizeof bufout, fmt, ap);
39 va_end(ap);
40 t = time(NULL);
41 strftime(timestr, sizeof timestr, TIMESTAMP_FORMAT, localtime(&t…
42 fprintf(stdout, "%-12s: %s %s\n", channel, timestr, bufout);
43 }
44
45 static void
46 sout(char *fmt, ...) {
47 va_list ap;
48
49 va_start(ap, fmt);
50 vsnprintf(bufout, sizeof bufout, fmt, ap);
51 va_end(ap);
52 fprintf(srv, "%s\r\n", bufout);
53 }
54
55 static void
56 privmsg(char *channel, char *msg) {
57 if(channel[0] == '\0') {
58 pout("", "No channel to send to");
59 return;
60 }
61 pout(channel, "<%s> %s", nick, msg);
62 sout("PRIVMSG %s :%s", channel, msg);
63 }
64
65 static void
66 parsein(char *s) {
67 char c, *p;
68
69 if(s[0] == '\0')
70 return;
71 skip(s, '\n');
72 if(s[0] != COMMAND_PREFIX_CHARACTER) {
73 privmsg(channel, s);
74 return;
75 }
76 c = *++s;
77 if(c != '\0' && isspace((unsigned char)s[1])) {
78 p = s + 2;
79 switch(c) {
80 case 'j':
81 sout("JOIN %s", p);
82 if(channel[0] == '\0')
83 strlcpy(channel, p, sizeof channel);
84 return;
85 case 'l':
86 s = eat(p, isspace, 1);
87 p = eat(s, isspace, 0);
88 if(!*s)
89 s = channel;
90 if(*p)
91 *p++ = '\0';
92 if(!*p)
93 p = DEFAULT_PARTING_MESSAGE;
94 sout("PART %s :%s", s, p);
95 return;
96 case 'm':
97 s = eat(p, isspace, 1);
98 p = eat(s, isspace, 0);
99 if(*p)
100 *p++ = '\0';
101 privmsg(s, p);
102 return;
103 case 's':
104 strlcpy(channel, p, sizeof channel);
105 return;
106 }
107 }
108 sout("%s", s);
109 }
110
111 static void
112 parsesrv(char *cmd) {
113 char *usr, *par, *txt;
114
115 usr = host;
116 if(!cmd || !*cmd)
117 return;
118 if(cmd[0] == ':') {
119 usr = cmd + 1;
120 cmd = skip(usr, ' ');
121 if(cmd[0] == '\0')
122 return;
123 skip(usr, '!');
124 }
125 skip(cmd, '\r');
126 par = skip(cmd, ' ');
127 txt = skip(par, ':');
128 trim(par);
129 if(!strcmp("PONG", cmd))
130 return;
131 if(!strcmp("PRIVMSG", cmd))
132 pout(par, "<%s> %s", usr, txt);
133 else if(!strcmp("PING", cmd))
134 sout("PONG %s", txt);
135 else {
136 pout(usr, ">< %s (%s): %s", cmd, par, txt);
137 if(!strcmp("NICK", cmd) && !strcmp(usr, nick))
138 strlcpy(nick, txt, sizeof nick);
139 }
140 }
141
142
143 static void
144 usage(void) {
145 eprint("usage: sic [-h host] [-p port] [-n nick] [-k keyword] [-…
146 }
147
148 int
149 main(int argc, char *argv[]) {
150 struct timeval tv;
151 const char *user = getenv("USER");
152 int n;
153 fd_set rd;
154
155 strlcpy(nick, user ? user : "unknown", sizeof nick);
156 ARGBEGIN {
157 case 'h':
158 host = EARGF(usage());
159 break;
160 case 'p':
161 port = EARGF(usage());
162 break;
163 case 'n':
164 strlcpy(nick, EARGF(usage()), sizeof nick);
165 break;
166 case 'k':
167 password = EARGF(usage());
168 break;
169 case 'v':
170 eprint("sic-"VERSION", © 2005-2014 Kris Maglione, Ansel…
171 break;
172 default:
173 usage();
174 } ARGEND;
175
176 /* init */
177 srv = fdopen(dial(host, port), "r+");
178 if (!srv)
179 eprint("fdopen:");
180 /* login */
181 if(password)
182 sout("PASS %s", password);
183 sout("NICK %s", nick);
184 sout("USER %s localhost %s :%s", nick, host, nick);
185 fflush(srv);
186 setbuf(stdout, NULL);
187 setbuf(srv, NULL);
188 setbuf(stdin, NULL);
189 #ifdef __OpenBSD__
190 if (pledge("stdio", NULL) == -1)
191 eprint("error: pledge:");
192 #endif
193 for(;;) { /* main loop */
194 FD_ZERO(&rd);
195 FD_SET(0, &rd);
196 FD_SET(fileno(srv), &rd);
197 tv.tv_sec = 120;
198 tv.tv_usec = 0;
199 n = select(fileno(srv) + 1, &rd, 0, 0, &tv);
200 if(n < 0) {
201 if(errno == EINTR)
202 continue;
203 eprint("sic: error on select():");
204 }
205 else if(n == 0) {
206 if(time(NULL) - trespond >= 300)
207 eprint("sic shutting down: parse timeout…
208 sout("PING %s", host);
209 continue;
210 }
211 if(FD_ISSET(fileno(srv), &rd)) {
212 if(fgets(bufin, sizeof bufin, srv) == NULL)
213 eprint("sic: remote host closed connecti…
214 parsesrv(bufin);
215 trespond = time(NULL);
216 }
217 if(FD_ISSET(0, &rd)) {
218 if(fgets(bufin, sizeof bufin, stdin) == NULL)
219 eprint("sic: broken pipe\n");
220 parsein(bufin);
221 }
222 }
223 return 0;
224 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.