1 /++ 2 Connects to a server and joins all specified channels. 3 Logs all events that occur to stdout. 4 +/ 5 module app; 6 7 import core.time; 8 import std.functional; 9 import std.stdio; 10 import std.string; 11 12 import vibe.core.args; 13 import vibe.core.core; 14 15 import vibeirc; 16 17 IRCClient bot; 18 string host; 19 string nickname; 20 string password; 21 string[] channels; 22 ushort port = 6667; 23 24 shared static this() 25 { 26 host = readRequiredOption!string( 27 "a|host", 28 "Host to connect to", 29 ); 30 nickname = readRequiredOption!string( 31 "n|nickname", 32 "Nickname to use", 33 ); 34 35 //readOption can't handle string[] :( 36 auto channelList = readRequiredOption!string( 37 "c|channels", 38 "List of channels to join, separated by commas", 39 ); 40 channels = channelList.split(","); 41 42 readOption( 43 "p|port", 44 &port, 45 "Port to connect on", 46 ); 47 readOption( 48 "P|password", 49 &password, 50 "Password to use when connecting, if any", 51 ); 52 53 bot = new IRCClient; 54 bot.nickname = nickname; 55 bot.onDisconnect = toDelegate(&onDisconnect); 56 bot.onLogin = toDelegate(&onLogin); 57 bot.onMessage = toDelegate(&onMessage); 58 bot.onNotice = toDelegate(&onMessage); 59 bot.onUserJoin = toDelegate(&onUserJoin); 60 bot.onUserPart = toDelegate(&onUserPart); 61 bot.onUserQuit = toDelegate(&onUserQuit); 62 bot.onUserRename = toDelegate(&onUserRename); 63 bot.onUserKick = toDelegate(&onUserKick); 64 65 //defer connection until after arguments have been processed 66 runTask(toDelegate(&connect)); 67 } 68 69 void connect() 70 { 71 bot.connect(host, port, password); 72 } 73 74 void onDisconnect(string reason) 75 { 76 writeln("Disconnected: ", reason); 77 sleep(10.seconds); 78 writeln("Attempting to reconnect"); 79 connect; 80 } 81 82 void onLogin() 83 { 84 writeln("Logged in"); 85 86 foreach(channel; channels) 87 { 88 writeln("Joining ", channel); 89 bot.join(channel); 90 } 91 } 92 93 void onMessage(Message message) 94 { 95 string bodyFormat; 96 string bracketText; 97 98 if(message.isCTCP) 99 { 100 if(message.ctcpCommand != "ACTION") 101 { 102 writefln( 103 "%s sends CTCP %s", 104 message.sender.nickname, 105 message.ctcpCommand, 106 ); 107 108 return; 109 } 110 111 bodyFormat = "* %s %s"; 112 } 113 else 114 bodyFormat = "<%s> %s"; 115 116 if(message.target == bot.nickname) 117 bracketText = "Private Message"; 118 else 119 bracketText = message.target; 120 121 writefln( 122 "[%s] " ~ bodyFormat, 123 bracketText, 124 message.sender.nickname, 125 message.message, 126 ); 127 } 128 129 void onUserJoin(User user, string channel) 130 { 131 writefln( 132 "[%s] %s joined", 133 channel, 134 user.nickname, 135 ); 136 } 137 138 void onUserPart(User user, string channel, string reason) 139 { 140 writefln( 141 "[%s] %s left (%s)", 142 channel, 143 user.nickname, 144 reason == null ? "No reason given" : reason, 145 ); 146 } 147 148 void onUserQuit(User user, string reason) 149 { 150 writefln( 151 "%s quit (%s)", 152 user.nickname, 153 reason == null ? "No reason given" : reason, 154 ); 155 } 156 157 void onUserRename(User user, string newNick) 158 { 159 writefln( 160 "%s is now known as %s", 161 user.nickname, 162 newNick, 163 ); 164 } 165 166 void onUserKick(User kicker, string kickee, string channel, string reason) 167 { 168 writefln( 169 "[%s] %s kicked %s (%s)", 170 channel, 171 kicker.nickname, 172 kickee, 173 reason == null ? "No reason given" : reason, 174 ); 175 }