Contiki 3.x
irc.c
1 /*
2  * Copyright (c) 2004, Adam Dunkels.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  * Author: Adam Dunkels <adam@sics.se>
32  *
33  */
34 
35 #include <string.h>
36 #include <stddef.h>
37 
38 #include "contiki-conf.h"
39 #include "contiki.h"
40 #include "contiki-net.h"
41 #include "ircc.h"
42 
43 #include "ctk/ctk.h"
44 #include "ctk/ctk-textentry-cmdline.h"
45 
46 #include "lib/petsciiconv.h"
47 
48 #ifdef IRC_CONF_WIDTH
49 #define LOG_WIDTH IRC_CONF_WIDTH
50 #else
51 #define LOG_WIDTH 37
52 #endif
53 
54 #ifdef IRC_CONF_HEIGHT
55 #define LOG_HEIGHT IRC_CONF_HEIGHT
56 #else
57 #define LOG_HEIGHT 17
58 #endif
59 
60 PROCESS(irc_process, "IRC client");
61 
62 AUTOSTART_PROCESSES(&irc_process);
63 
64 static struct ctk_menu menu;
65 unsigned char menuitem_setup, menuitem_quit;
66 
67 static struct ctk_window window;
68 static char log[LOG_WIDTH * LOG_HEIGHT];
69 static char line[LOG_WIDTH*2];
70 static struct ctk_label loglabel =
71  {CTK_LABEL(0, 0, LOG_WIDTH, LOG_HEIGHT, log)};
72 static struct ctk_textentry lineedit =
73  {CTK_TEXTENTRY_INPUT(0, LOG_HEIGHT, LOG_WIDTH - 2, 1, line, sizeof(line) - 1,
74  ctk_textentry_cmdline_input)};
75 
76 static struct ctk_window setupwindow;
77 #define SETUPWINDOW_WIDTH 18
78 #define SETUPWINDOW_HEIGHT 9
79 #define MAX_SERVERLEN 32
80 #define MAX_NICKLEN 16
81 static uip_ipaddr_t serveraddr;
82 static char server[MAX_SERVERLEN + 1];
83 static char nick[MAX_NICKLEN + 1];
84 static struct ctk_label serverlabel =
85  {CTK_LABEL(1, 1, 11, 1, "IRC server: ")};
86 static struct ctk_textentry serverentry =
87  {CTK_TEXTENTRY(0, 2, 16, 1, server, MAX_SERVERLEN)};
88 
89 static struct ctk_label nicklabel =
90  {CTK_LABEL(1, 4, 13, 1, "IRC nickname: ")};
91 static struct ctk_textentry nickentry =
92  {CTK_TEXTENTRY(0, 5, 16, 1, nick, MAX_NICKLEN)};
93 
94 static struct ctk_button connectbutton =
95  {CTK_BUTTON(0, 7, 7, "Connect")};
96 
97 /*static char nick[] = "asdf";
98  static char server[] = "efnet.demon.co.uk";*/
99 
100 static struct ircc_state s;
101 
102 /*---------------------------------------------------------------------------*/
103 static void
104 quit(void)
105 {
106  ctk_window_close(&window);
107  ctk_window_close(&setupwindow);
108  ctk_menu_remove(&menu);
109  process_exit(&irc_process);
110  LOADER_UNLOAD();
111 }
112 /*---------------------------------------------------------------------------*/
113 void
114 ircc_text_output(struct ircc_state *s, char *text1, char *text2)
115 {
116  char *ptr;
117  int len;
118 
119  if(text1 == NULL) {
120  text1 = "";
121  }
122 
123  if(text2 == NULL) {
124  text2 = "";
125  }
126 
127  /* Scroll previous entries upwards */
128  memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
129 
130  ptr = &log[LOG_WIDTH * (LOG_HEIGHT - 1)];
131  len = (int)strlen(text1);
132 
133  memset(ptr, 0, LOG_WIDTH);
134  strncpy(ptr, text1, LOG_WIDTH);
135  if(len < LOG_WIDTH) {
136  ptr += len;
137  *ptr = ':';
138  ++len;
139  if(LOG_WIDTH - len > 0) {
140  strncpy(ptr + 1, text2, LOG_WIDTH - len);
141  }
142  } else {
143  len = 0;
144  }
145 
146  if((int)strlen(text2) > LOG_WIDTH - len) {
147  memcpy(log, &log[LOG_WIDTH], LOG_WIDTH * (LOG_HEIGHT - 1));
148  strncpy(&log[LOG_WIDTH * (LOG_HEIGHT - 1)],
149  text2 + LOG_WIDTH - len, LOG_WIDTH);
150  }
151  CTK_WIDGET_REDRAW(&loglabel);
152 
153 }
154 /*---------------------------------------------------------------------------*/
155 static void
156 parse_line(void)
157 {
158  int i;
159  for(i = 0; i < (int)strlen(line); ++i) {
160  line[i] &= 0x7f;
161  }
162 
163 
164  if(line[0] == '/') {
165  if(strncmp(&line[1], "join", 4) == 0) {
166  ircc_join(&s, &line[6]);
167  ircc_text_output(&s, "Join", &line[6]);
168  } else if(strncmp(&line[1], "list", 4) == 0) {
169  ircc_list(&s);
170  ircc_text_output(&s, "Channel list", "");
171  } else if(strncmp(&line[1], "part", 4) == 0) {
172  ircc_part(&s);
173  ircc_text_output(&s, "Leaving channel", "");
174  } else if(strncmp(&line[1], "quit", 4) == 0) {
175  ircc_quit(&s);
176  } else if(strncmp(&line[1], "me", 2) == 0) {
177  petsciiconv_toascii(&line[4], strlen(&line[4]));
178  ircc_actionmsg(&s, &line[4]);
179  ircc_text_output(&s, "*", &line[4]);
180  } else {
181  ircc_text_output(&s, &line[1], "Not implemented");
182  ircc_sent(&s);
183  }
184  } else {
185  petsciiconv_toascii(line, sizeof(line) - 1);
186  ircc_msg(&s, &line[0]);
187  ircc_text_output(&s, nick, line);
188  }
189 }
190 /*---------------------------------------------------------------------------*/
191 void
192 ircc_sent(struct ircc_state *s)
193 {
194  /* ctk_textedit_init(&lineedit);*/
195  CTK_TEXTENTRY_CLEAR(&lineedit);
196  CTK_WIDGET_REDRAW(&lineedit);
197 }
198 /*---------------------------------------------------------------------------*/
199 PROCESS_THREAD(irc_process, ev, data)
200 {
201  ctk_arch_key_t c;
202  uip_ipaddr_t *ipaddr;
203 
204  PROCESS_BEGIN();
205 
206  /* ctk_textedit_init(&lineedit);*/
207  CTK_TEXTENTRY_CLEAR(&lineedit);
208  memset(log, 0, sizeof(log));
209  ctk_window_new(&window, LOG_WIDTH, LOG_HEIGHT + 1, "IRC");
210  CTK_WIDGET_ADD(&window, &loglabel);
211  /* ctk_textedit_add(&window, &lineedit); */
212  CTK_WIDGET_ADD(&window, &lineedit);
213  CTK_WIDGET_FOCUS(&window, &lineedit);
214 
215  ctk_window_new(&setupwindow, SETUPWINDOW_WIDTH, SETUPWINDOW_HEIGHT,
216  "IRC setup");
217 
218  CTK_WIDGET_ADD(&setupwindow, &serverlabel);
219  CTK_WIDGET_ADD(&setupwindow, &serverentry);
220  CTK_WIDGET_ADD(&setupwindow, &nicklabel);
221  CTK_WIDGET_ADD(&setupwindow, &nickentry);
222  CTK_WIDGET_ADD(&setupwindow, &connectbutton);
223 
224  CTK_WIDGET_FOCUS(&setupwindow, &serverentry);
225 
226  ctk_window_open(&setupwindow);
227 
228  ctk_menu_new(&menu, "IRC");
229  menuitem_setup = ctk_menuitem_add(&menu, "Setup");
230  menuitem_quit = ctk_menuitem_add(&menu, "Quit");
231  ctk_menu_add(&menu);
232 
233  while(1) {
235 
236  if(ev == PROCESS_EVENT_EXIT) {
237  quit();
238  } else if(ev == tcpip_event) {
239  ircc_appcall(data);
240  } else if(ev == ctk_signal_widget_activate) {
241  if(data == (process_data_t)&lineedit) {
242  parse_line();
243  } else if(data == (process_data_t)&connectbutton) {
244  ctk_window_close(&setupwindow);
245  ctk_window_open(&window);
246  ipaddr = &serveraddr;
247 #if UIP_UDP
248  if(uiplib_ipaddrconv(server, &serveraddr) == 0) {
249  if(resolv_lookup(server, &ipaddr) != RESOLV_STATUS_CACHED) {
250  resolv_query(server);
251  } else {
252  uip_ipaddr_copy(&serveraddr, ipaddr);
253  }
254  }
255 #else /* UIP_UDP */
256  uiplib_ipaddrconv(server, &serveraddr);
257 #endif /* UIP_UDP */
258  if(ipaddr != NULL) {
259 
260  ircc_connect(&s, server, &serveraddr, nick);
261  }
262  }
263 #if UIP_UDP
264  } else if(ev == resolv_event_found) {
265 
266  if(resolv_lookup(server, &ipaddr) != RESOLV_STATUS_CACHED) {
267  ircc_text_output(&s, server, "hostname not found");
268  } else {
269  uip_ipaddr_copy(&serveraddr, ipaddr);
270  ircc_connect(&s, server, &serveraddr, nick);
271  }
272 #endif /* UIP_UDP */
273  } else if(ev == ctk_signal_keypress) {
274  c = (ctk_arch_key_t)(size_t)data;
275  if(c == CH_ENTER) {
276  parse_line();
277  } else {
278  /* ctk_textedit_eventhandler(&lineedit, ev, data);*/
279  CTK_WIDGET_FOCUS(&window, &lineedit);
280  }
281  } else if(ev == ctk_signal_menu_activate) {
282  if((struct ctk_menu *)data == &menu) {
283  if(menu.active == menuitem_setup) {
284  ctk_window_open(&setupwindow);
285  } else if(menu.active == menuitem_quit) {
286  quit();
287  }
288  }
289  }
290  }
291  PROCESS_END();
292 }
293 /*---------------------------------------------------------------------------*/
294 void
295 ircc_closed(struct ircc_state *s)
296 {
297  ircc_text_output(s, server, "connection closed");
298 }
299 /*---------------------------------------------------------------------------*/
300 void
301 ircc_connected(struct ircc_state *s)
302 {
303  ircc_text_output(s, server, "connected");
304 }
305 /*---------------------------------------------------------------------------*/
#define CTK_WIDGET_ADD(win, widg)
Add a widget to a window.
Definition: ctk.h:752
char ctk_arch_key_t
The keyboard character type of the system.
Definition: ctk-conio.h:40
#define CTK_TEXTENTRY_CLEAR(e)
Clears a text entry widget and sets the cursor to the start of the text line.
Definition: ctk.h:231
unsigned char ctk_menuitem_add(CC_REGISTER_ARG struct ctk_menu *menu, char *name)
Adds a menu item to a menu.
Definition: ctk.c:800
Hostname is fresh and usable.
Definition: resolv.h:68
void ctk_window_open(CC_REGISTER_ARG struct ctk_window *w)
Open a window, or bring window to front if already open.
Definition: ctk.c:347
#define CTK_WIDGET_FOCUS(win, widg)
Set focus to a widget.
Definition: ctk.h:763
void ctk_window_close(struct ctk_window *w)
Close a window if it is open.
Definition: ctk.c:400
unsigned char active
The currently active menu item.
Definition: ctk.h:601
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void ctk_menu_add(struct ctk_menu *menu)
Add a menu to the menu bar.
Definition: ctk.c:504
#define CTK_TEXTENTRY(x, y, w, h, text, len)
Instantiating macro for the ctk_textentry widget.
Definition: ctk.h:275
#define NULL
The null pointer.
process_event_t ctk_signal_menu_activate
Emitted when a menu item is activated.
Definition: ctk.c:151
#define uiplib_ipaddrconv
Convert a textual representation of an IP address to a numerical representation.
Definition: uiplib.h:71
#define CTK_LABEL(x, y, w, h, text)
Instantiating macro for the ctk_label widget.
Definition: ctk.h:171
process_event_t ctk_signal_keypress
Emitted for every key being pressed.
Definition: ctk.c:126
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void ctk_window_new(struct ctk_window *window, unsigned char w, unsigned char h, char *title)
Create a new window.
Definition: ctk.c:732
CCIF process_event_t resolv_event_found
Event that is broadcasted when a DNS name has been resolved.
#define uip_ipaddr_copy(dest, src)
Copy an IP address from one place to another.
Definition: uip.h:1026
PETSCII/ASCII conversion functions.
#define LOADER_UNLOAD()
Unload a program from memory.
Definition: loader.h:104
void ctk_menu_new(CC_REGISTER_ARG struct ctk_menu *menu, char *title)
Creates a new menu.
Definition: ctk.c:775
void ctk_menu_remove(struct ctk_menu *menu)
Remove a menu from the menu bar.
Definition: ctk.c:532
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
process_event_t ctk_signal_widget_activate
Emitted when a widget is activated (pressed).
Definition: ctk.c:126
process_event_t tcpip_event
The uIP event.
Definition: tcpip.c:75
Representation of an individual menu.
Definition: ctk.h:586
#define CTK_BUTTON(x, y, w, text)
Instantiating macro for the ctk_button widget.
Definition: ctk.h:140
Representation of a CTK window.
Definition: ctk.h:506
#define CTK_WIDGET_REDRAW(widg)
Add a widget to the redraw queue.
Definition: ctk.h:771
CTK header file.
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202