PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/modules/stream.c

http://github.com/lordi/Eiwic
C | 399 lines | 332 code | 66 blank | 1 comment | 64 complexity | 0b9ae2b221961d84e5b5fbd47ad9279f MD5 | raw file
Possible License(s): GPL-2.0
  1. /* Eiwic IRC2WWW stream, by lordi@styleliga.org */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <signal.h>
  8. #include <arpa/inet.h>
  9. #include <ctype.h>
  10. #include <dlfcn.h>
  11. #include <time.h>
  12. #include "eiwic.h"
  13. #include "plugins.h"
  14. #define TITLE "%s - Eiwic Live stream v1.2"
  15. #define MAX_CLIENTS 40
  16. #define MAX_LINES 20
  17. #define STREAM_PORT 1600
  18. EP_SETNAME("stream");
  19. struct _stream_client {
  20. char used;
  21. CONN *conn;
  22. CHANNEL *chan;
  23. } stream_clients[MAX_CLIENTS];
  24. struct _stream_channel {
  25. CHANNEL *chan;
  26. char *lines[MAX_LINES];
  27. } **stream_channels;
  28. int ep_help(OUTPUT *out)
  29. {
  30. eiwic->output_printf(out, "The stream module allows you to view the channel\n");
  31. eiwic->output_printf(out, "via a HTTP connection. It is configured to run on\n");
  32. eiwic->output_printf(out, "port %d.\n", STREAM_PORT);
  33. eiwic->output_printf(out, "So, try 'http://<MYIP>:%d/chan/<CHANNELNAMEWITHOUT#>'.\n", STREAM_PORT);
  34. eiwic->output_printf(out, "You can add '?<URLTOCSSFILE>' at the end to use a\n");
  35. eiwic->output_printf(out, "CSS file.\n");
  36. eiwic->output_printf(out, "With 'http://<MYIP>:%d/say/<CHANNELNAMEWITHOUT#>/<SENTENCE>\n", STREAM_PORT);
  37. eiwic->output_printf(out, "a user can say something to the channel through Eiwic.\n");
  38. eiwic->output_printf(out, "Note: You can embed those URLs into a PHP script, to build\n");
  39. eiwic->output_printf(out, "a simple webchat.\n");
  40. }
  41. void stream_send(CHANNEL *chan, char *text);
  42. void stream_send_history(struct _stream_client *c)
  43. {
  44. int i=0, j=0;
  45. while (stream_channels[j]->chan != c->chan) ++j;
  46. while (i<MAX_LINES&&stream_channels[j]->lines[i])
  47. {
  48. send(c->conn->sock,
  49. stream_channels[j]->lines[i],
  50. strlen(stream_channels[j]->lines[i]),
  51. 0);
  52. ++i;
  53. }
  54. }
  55. int stream_read(CONN *conn, char *data, u_int data_len)
  56. {
  57. char *url, *sd, sf[2000], sx[2040];
  58. int i=0;
  59. while(i<MAX_CLIENTS)
  60. if (stream_clients[i].used&&stream_clients[i].conn==conn)
  61. break;
  62. else i++;
  63. if (i==MAX_CLIENTS)
  64. return -1;
  65. if (stream_clients[i].chan)
  66. return -1;
  67. if (data_len < 10 || strncmp(data, "GET ", 4))
  68. {
  69. mlink->conn_close(conn);
  70. return -1;
  71. }
  72. if (NULL == (url = strtok(data+4, " \r\n")) || *url != '/')
  73. {
  74. mlink->conn_close(conn);
  75. return -1;
  76. }
  77. mlink->log(LOG_DEBUG, "Client asked for %s", url);
  78. sd = "HTTP/1.0 200 OK\r\n"
  79. "Server: "NAME"/"VERSION"\r\n"
  80. "Content-Type: multipart/mixed;boundary=xxThisRandomString\r\n"
  81. "Pragma: no-cache\r\n"
  82. "Cache-control: no-cache\r\n"
  83. "\r\n"
  84. "--xxThisRandomString\r\n"
  85. "Content-Type: text/html\r\n"
  86. "\r\n"
  87. ;
  88. send(conn->sock, sd, strlen(sd), 0);
  89. if (strncmp(url, "/chan/", 6) == 0)
  90. {
  91. char *style=NULL;
  92. url += 5;
  93. *url = '#';
  94. if (style = strchr(url, '?'))
  95. {
  96. *style++ = '\0';
  97. }
  98. if ((stream_clients[i].chan = mlink->channel_find(url)) == NULL)
  99. {
  100. sprintf(sf, "<html><head><title>404 Channel not found</title></head>"
  101. "<body bgcolor='#8888ff'>Channel %s not found</body></html>", url);
  102. send(conn->sock, sf, strlen(sf), 0);
  103. mlink->conn_close(conn);
  104. }
  105. else
  106. {
  107. mlink->log(LOG_DEBUG, "Accepted streaming client %d", i);
  108. if (style)
  109. sprintf(sf, "<HTML><HEAD><TITLE>"NAME" - %s stream</TITLE>"
  110. "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">"
  111. "</HEAD>"
  112. "<BODY CLASS='stream'><B>"TITLE"</B><BR>\n\n",
  113. stream_clients[i].chan->name, style, stream_clients[i].chan->name);
  114. else
  115. sprintf(sf, "<HTML><HEAD><TITLE>"NAME" - %s stream</TITLE></HEAD>"
  116. "<BODY CLASS='stream'><B>"TITLE"</B><BR>\n\n",
  117. stream_clients[i].chan->name, stream_clients[i].chan->name);
  118. send(conn->sock, sf, strlen(sf), 0);
  119. sprintf(sf, "<script language=\"JavaScript\">\n"
  120. "<!--\n"
  121. " function moves() {\n"
  122. " window.scroll(1,500000)\n"
  123. " window.setTimeout(\"moves()\", 100);\n"
  124. " }\n"
  125. " moves();\n"
  126. "//-->\n"
  127. "</script>\n\n");
  128. send(conn->sock, sf, strlen(sf), 0);
  129. sprintf(sf, "Pr&auml;sentiert von "NAME" "VERSION"<BR>\n");
  130. send(conn->sock, sf, strlen(sf), 0);
  131. stream_send_history(&stream_clients[i]);
  132. }
  133. }
  134. else
  135. if (strncmp(url, "/say/", 5) == 0)
  136. {
  137. char *x,*y,z[3];
  138. CHANNEL *chan;
  139. z[2] = 0;
  140. url += 4;
  141. *url = '#';
  142. if ((x = strchr(url, '/')) == NULL)
  143. return -1;
  144. *x++ = '\0';
  145. if ((chan = mlink->channel_find(url)) == NULL)
  146. return -1;
  147. for (y = x; *x; x++)
  148. if (*x == '%' && !(*(x+1)==0||*(x+2)==0) && *(x+1)!='0')
  149. {
  150. strncpy(z, x + 1, 2);
  151. *x++ = (unsigned char)strtol(z, NULL, 16);
  152. memmove(x, x + 2, strlen(x + 2) + 1);
  153. x--;
  154. }
  155. if (conn->host == inet_addr("127.0.0.1"))
  156. {
  157. mlink->plug_sendf("PRIVMSG %s :%s\r\n",
  158. chan->name,y);
  159. } else
  160. {
  161. mlink->plug_sendf("PRIVMSG %s :<%s> %s\r\n",
  162. chan->name,
  163. inet_ntoa(*(struct in_addr *)&conn->host),
  164. y);
  165. }
  166. sprintf(sx, "<b>-&gt;</b> %s<br>\n", y);
  167. stream_send(chan, sx);
  168. mlink->conn_close(conn);
  169. }
  170. else
  171. {
  172. CHANNEL *channel;
  173. FOR_EACH_DATA(&e_global->channels, channel)
  174. {
  175. sprintf(sf, "<li><a href=\"/chan/%s\">%s</a></li>", channel->name+1,channel->name);
  176. send(conn->sock, sf, strlen(sf), 0);
  177. }
  178. END_DATA;
  179. sprintf(sf, "<hr size=1>Eiwic "VERSION"<BR>", channel->name+1,channel->name);
  180. send(conn->sock, sf, strlen(sf), 0);
  181. mlink->conn_close(conn);
  182. }
  183. }
  184. int stream_close(CONN *conn)
  185. {
  186. int i=0;
  187. while(i<MAX_CLIENTS)
  188. {
  189. if(stream_clients[i].conn==conn&&stream_clients[i].used==1)
  190. {
  191. mlink->log(LOG_DEBUG, "Client %d disconnected.", i);
  192. stream_clients[i].used=0;
  193. stream_clients[i].chan=NULL;
  194. }
  195. ++i;
  196. }
  197. return 0;
  198. }
  199. int stream_incoming(CONN *new_conn)
  200. {
  201. int i=0;
  202. while(stream_clients[i].used&&i<MAX_CLIENTS) ++i;
  203. if (i==MAX_CLIENTS)
  204. {
  205. mlink->log(LOG_WARNING, "All connections in use, disconecting client...");
  206. mlink->conn_close(new_conn);
  207. return -1;
  208. }
  209. mlink->log(LOG_DEBUG, "Client %d connected.", i);
  210. stream_clients[i].used = 1;
  211. stream_clients[i].conn = new_conn;
  212. stream_clients[i].chan = NULL;
  213. return 1;
  214. }
  215. void stream_send(CHANNEL *chan, char *text)
  216. {
  217. int i=0,j=0;
  218. #ifdef VV_DEBUG
  219. mlink->log(LOG_DEBUG, "Sending \"%s\" to %s", text, chan->name);
  220. #endif
  221. while (stream_channels[i]->chan != chan) ++i;
  222. while (stream_channels[i]->lines[j] != NULL && j<MAX_LINES) ++j;
  223. if (j==MAX_LINES) /* the lines are full.. so letz move it.. */
  224. {
  225. free(stream_channels[i]->lines[0]);
  226. memmove(&stream_channels[i]->lines[0], &stream_channels[i]->lines[1], sizeof(void *)*(MAX_LINES-1));
  227. stream_channels[i]->lines[MAX_LINES-1] = malloc(strlen(text)+1);
  228. strcpy(stream_channels[i]->lines[MAX_LINES-1], text);
  229. }
  230. else /* yea.. found a free line! inserting.. */
  231. {
  232. stream_channels[i]->lines[j] = malloc(strlen(text)+1);
  233. strcpy(stream_channels[i]->lines[j], text);
  234. }
  235. i=0;
  236. while(i<MAX_CLIENTS)
  237. {
  238. if (stream_clients[i].used&&stream_clients[i].chan==chan)
  239. {
  240. if (-1 == send(stream_clients[i].conn->sock, text, strlen(text), 0))
  241. {
  242. mlink->log(LOG_WARNING, "disconnecting client");
  243. stream_clients[i].used = 0;
  244. mlink->conn_close(stream_clients[i].conn);
  245. }
  246. }
  247. ++i;
  248. }
  249. #ifdef VV_DEBUG
  250. mlink->log(LOG_DEBUG, "done");
  251. #endif
  252. }
  253. int ep_parse(MSG *ircmsg)
  254. {
  255. CHANNEL *m;
  256. char *buf, y[1024]; u_char c1, c2, c3;
  257. if ((m = mlink->channel_find(ircmsg->to)) || (m = mlink->channel_find(ircmsg->args)))
  258. {
  259. int i=0,x;
  260. struct tm *t;
  261. time_t v;
  262. v = time(NULL);
  263. t = localtime(&v);
  264. sprintf(y, "<I>(%2.2d:%2.2d)</I> ", t->tm_hour, t->tm_min);
  265. buf = y + strlen(y);
  266. *buf = '\0';
  267. c1 = (u_char)(*ircmsg->nick * 10);
  268. c2 = (u_char)(*(ircmsg->nick+1) * 100);
  269. c3 = (u_char)(*(ircmsg->nick+2) * 100);
  270. if (c1+c2+c3>560)
  271. {
  272. if (c1>190)c1=190;
  273. if (c1>190)c1=190;
  274. if (c1>190)c1=190;
  275. }
  276. if (strcmp(ircmsg->cmd, "privmsg") == 0)
  277. {
  278. if (*ircmsg->args == 1)
  279. {
  280. if (strncmp(ircmsg->args +1, "ACTION ", 7) == 0)
  281. sprintf(buf, "<FONT COLOR='#%2.2X%2.2X%2.2X'><B>%s</B></FONT> %s<BR>\n",
  282. c1, c2, c3, ircmsg->nick, ircmsg->args+8);
  283. for (x=0;buf[x];x++)if(buf[x]==1)memmove(buf+x, buf+x+1,strlen(buf+x+1));
  284. }
  285. else
  286. {
  287. sprintf(buf, "(<FONT COLOR='#%2.2X%2.2X%2.2X'><B>%s</B></FONT>) %s<BR>\n",
  288. c1, c2, c3, ircmsg->nick, ircmsg->args);
  289. }
  290. }
  291. else
  292. if (strcmp(ircmsg->cmd, "join") == 0)
  293. sprintf(buf, "* <FONT COLOR='#%2.2X%2.2X%2.2X'>%s</FONT> enters.<BR>\n",
  294. c1,c2,c3,ircmsg->nick);
  295. else
  296. if (strcmp(ircmsg->cmd, "part") == 0)
  297. sprintf(buf, "* <FONT COLOR='#%2.2X%2.2X%2.2X'>%s</FONT> leaves.<BR>\n",
  298. c1,c2,c3,ircmsg->nick);
  299. if (*buf)
  300. stream_send(m, y);
  301. }
  302. }
  303. int ep_main(OUTPUT *out)
  304. {
  305. int num = 0;
  306. CHANNEL *chan;
  307. memset(stream_clients, 0, sizeof(stream_clients));
  308. if (!eiwic->conn_listen(STREAM_PORT, 0, stream_incoming, stream_read, NULL, stream_close))
  309. {
  310. eiwic->output_printf(out, "Could not set up a listening socket on port %d.\n",
  311. STREAM_PORT);
  312. return 0;
  313. }
  314. FOR_EACH_DATA(&e_global->channels, chan)
  315. ++num;
  316. END_DATA;
  317. eiwic->log(LOG_DEBUG, "Setting up stream structures (%d channel[s])..", num);
  318. stream_channels = malloc(sizeof(struct _stream_channel *) * num);
  319. num = 0;
  320. FOR_EACH_DATA(&e_global->channels, chan)
  321. {
  322. #ifdef VV_DEBUG
  323. eiwic->log(LOG_DEBUG, "-> %d/%s", num, chan->name);
  324. #endif
  325. stream_channels[num] = calloc(1, sizeof(struct _stream_channel));
  326. stream_channels[num]->chan = chan;
  327. ++num;
  328. }
  329. END_DATA;
  330. eiwic->output_printf(out, "Okay, stream module successfully set up for %d channel(s),\n", num);
  331. eiwic->output_printf(out, "the url is http://<MYIP>:%d/, have fun :).\n", STREAM_PORT);
  332. return 1;
  333. }