/***************************************************************************** * Copyright (c) 2009, Kenneth Falck http://kfalck.net * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Kenneth Falck nor the names of his contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ package main import "fmt" import "bytes" import "flag" import "./ncurses" import "./irc" /**************************************************************************************************** * Windowing (ncurses-based). ****************************************************************************************************/ var mainWin, statusWin, inputWin ncurses.WINDOW; func PrintInit() { ncurses.Init(); my, mx := ncurses.Getmaxyx(ncurses.Stdscr()); mainWin = ncurses.Newwin(my-2, mx, 0, 0); ncurses.Syncok(mainWin, true); ncurses.Scrollok(mainWin, true); ncurses.Wrefresh(mainWin); ncurses.Wmove(mainWin, my-3, 0); statusWin = ncurses.Newwin(1, mx, my-2, 0); ncurses.Syncok(statusWin, true); ncurses.Wrefresh(statusWin); ncurses.Wcolor_set(statusWin, 4*8+7); for i := 0; i < mx; i++ { ncurses.Waddch(statusWin, ' '); } inputWin = ncurses.Newwin(1, mx, my-1, 0); ncurses.Syncok(inputWin, true); ncurses.Wrefresh(inputWin); ncurses.Refresh(); } func PrintError(format string, args ...) { ncurses.Wcolor_set(mainWin, 1); ncurses.Waddstr(mainWin, fmt.Sprintf("\n" + format, args)); ncurses.Wcolor_set(mainWin, 7); ncurses.Wrefresh(mainWin); ncurses.Wrefresh(inputWin); } func PrintLine(format string, args ...) { ncurses.Waddstr(mainWin, fmt.Sprintf("\n" + format, args)); ncurses.Wrefresh(mainWin); ncurses.Wrefresh(inputWin); } func PrintNotice(format string, args ...) { ncurses.Wcolor_set(mainWin, 6); ncurses.Waddstr(mainWin, fmt.Sprintf("\n" + format, args)); ncurses.Wcolor_set(mainWin, 7); ncurses.Wrefresh(mainWin); ncurses.Wrefresh(inputWin); } func Print(format string, args ...) { ncurses.Waddstr(mainWin, fmt.Sprintf("\n" + format, args)); ncurses.Wrefresh(mainWin); ncurses.Wrefresh(inputWin); } func SetStatus(format string, args ...) { buf := fmt.Sprintf(format, args); _, mx := ncurses.Getmaxyx(statusWin); ncurses.Mvwaddstr(statusWin, 0, 0, buf); for i := len(buf); i < mx; i++ { ncurses.Waddch(statusWin, ' '); } ncurses.Wrefresh(statusWin); ncurses.Wrefresh(inputWin); } /**************************************************************************************************** * Main program. ****************************************************************************************************/ func main() { // Parse command line args var nickname = flag.String("n", "", "Nickname"); var hostname = flag.String("c", "", "Server hostname"); var port = flag.Uint("p", 6667, "Server port (default 6667)"); var password = flag.String("w", "", "Server password"); var channel = flag.String("j", "", "Join channel"); flag.Parse(); username := nickname; realname := nickname; if len(*nickname) <= 0 || len(*hostname) <= 0 { flag.Usage(); return; } PrintInit(); PrintLine("goirc (C) 2009 Kenneth Falck http://kfalck.net"); SetStatus(" goirc [Console]"); // Keyboard input reader, sends lines to keyboardInput channel. keyboardInput := make(chan string); go func() { buf := new(bytes.Buffer); for { ch := ncurses.Getch(); switch ch { case 13: keyboardInput <- buf.String(); buf.Reset(); case 8, 127: if buf.Len() > 0 { buf.Truncate(buf.Len()-1) } default: buf.WriteByte(byte(ch)); } ncurses.Mvwaddstr(inputWin, 0, 0, buf.String()); ncurses.Wclrtoeol(inputWin); ncurses.Wrefresh(inputWin); } keyboardInput <- "/quit"; }(); // IRC client client := irc.NewIRCClient(keyboardInput); config := &irc.ServerConfig{Host:*hostname, Port:*port, Password:*password, Nickname:*nickname, Username:*username, Realname:*realname}; client.AddServer(config); // Handle join/part responses client.AddResponseHandler("JOIN", func (line *irc.IRCLine) bool { if len(line.Args) >= 1 { name := irc.NewIRCName(line.Prefix); PrintLine("* %s (%s@%s) has joined %s", name.Nickname, name.Username, name.Hostname, line.Args[0]); if line.IsFromSelf() { SetStatus(" goirc %s", line.Args[0]); } } return true }); client.AddResponseHandler("PART", func (line *irc.IRCLine) bool { if len(line.Args) >= 1 { name := irc.NewIRCName(line.Prefix); PrintLine("* %s (%s@%s) has joined %s", name.Nickname, name.Username, name.Hostname, line.Args[0]); if line.IsFromSelf() { SetStatus(" goirc [Console]"); } } return true }); // Handle messages client.AddResponseHandler("PRIVMSG", func (line *irc.IRCLine) bool { if len(line.Args) >= 2 { name := irc.NewIRCName(line.Prefix); if line.IsToSelf() { PrintLine("*%s* %s", name.Nickname, line.Args[1]); } else if (line.Args[0] == client.CurrentChannel) { PrintLine("<%s> %s", name.Nickname, line.Args[1]); } else { PrintLine("<%s:%s> %s", name.Nickname, line.Args[0], line.Args[1]); } return true; } return true }); // Handle numeric responses, just print them client.AddResponseHandler("[0-9]+", func (line *irc.IRCLine) bool { PrintNotice("%s", line.String()); return true; }); // Handle internal errors client.AddResponseHandler("INTERNAL:ERROR", func (line *irc.IRCLine) bool { PrintError("%s", line.Args[0]); return true; }); client.AddResponseHandler("INTERNAL:MESSAGE", func (line *irc.IRCLine) bool { PrintLine("%s", line.Args[0]); return true; }); // Join initial channel if specified if len(*channel) > 0 { client.JoinChannel(*channel); } client.Run(); ncurses.Endwin(); }