IRC gateway: Difference between revisions
(added examples bit) |
m (→{{header|Wren}}: Minor tidy) |
||
(13 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
{{task}} Create an IRC Gateway capable of connecting an IRC server with another IRC server or [[Chat server]] |
{{draft task}} Create an IRC Gateway capable of connecting an IRC server with another IRC server or [[Chat server]] |
||
=={{header|Go}}== |
|||
''' Examples |
|||
{{libheader|go-ircevent}} |
|||
<br> |
|||
Just a bare-bones gateway. |
|||
<syntaxhighlight lang="go">package main |
|||
import ( |
|||
"crypto/tls" |
|||
"fmt" |
|||
"github.com/thoj/go-ircevent" |
|||
"log" |
|||
"os" |
|||
) |
|||
func main() { |
|||
if len(os.Args) != 9 { |
|||
fmt.Println("To use this gateway, you need to pass 8 command line arguments, namely:") |
|||
fmt.Println(" <server1> <channel1> <nick1> <user1> <server2> <channel2> <nick2> <user2>") |
|||
return |
|||
} |
|||
server1, channel1, nick1, user1 := os.Args[1], os.Args[2], os.Args[3], os.Args[4] |
|||
server2, channel2, nick2, user2 := os.Args[5], os.Args[6], os.Args[7], os.Args[8] |
|||
irc1 := irc.IRC(nick1, user1) |
|||
irc1.VerboseCallbackHandler = true |
|||
irc1.Debug = false |
|||
irc1.UseTLS = true |
|||
irc1.TLSConfig = &tls.Config{InsecureSkipVerify: true} |
|||
irc2 := irc.IRC(nick2, user2) |
|||
irc2.VerboseCallbackHandler = true |
|||
irc2.Debug = false |
|||
irc2.UseTLS = true |
|||
irc2.TLSConfig = &tls.Config{InsecureSkipVerify: true} |
|||
irc1.AddCallback("001", func(e *irc.Event) { |
|||
irc1.Join(channel1) |
|||
msg := fmt.Sprintf("<gateway> Hello %s. Please send your first message to %s.", nick1, nick2) |
|||
irc1.Privmsg(nick1, msg) |
|||
log.Println(msg) |
|||
}) |
|||
irc1.AddCallback("366", func(e *irc.Event) {}) |
|||
irc1.AddCallback("PRIVMSG", func(e *irc.Event) { |
|||
msg := fmt.Sprintf("<%s> %s", nick1, e.Message) |
|||
irc2.Privmsg(nick2, msg) |
|||
log.Println(msg) |
|||
}) |
|||
irc2.AddCallback("001", func(e *irc.Event) { |
|||
irc2.Join(channel2) |
|||
msg := fmt.Sprintf("<gateway> Hello %s. Please wait for your first message from %s.", nick2, nick1) |
|||
irc2.Privmsg(nick2, msg) |
|||
log.Println(msg) |
|||
}) |
|||
irc2.AddCallback("366", func(e *irc.Event) {}) |
|||
irc2.AddCallback("PRIVMSG", func(e *irc.Event) { |
|||
msg := fmt.Sprintf("<%s> %s", nick2, e.Message) |
|||
irc1.Privmsg(nick1, msg) |
|||
log.Println(msg) |
|||
}) |
|||
err1 := irc1.Connect(server1) |
|||
if err1 != nil { |
|||
log.Fatal(err1) |
|||
} |
|||
err2 := irc2.Connect(server2) |
|||
if err2 != nil { |
|||
log.Fatal(err2) |
|||
} |
|||
go irc2.Loop() |
|||
irc1.Loop() |
|||
}</syntaxhighlight> |
|||
=={{header|Phix}}== |
|||
<!--<syntaxhighlight lang="phix">(notonline)--> |
|||
For use with [[Chat_server#Phix]] |
|||
<span style="color: #000080;font-style:italic;">-- |
|||
-- demo\rosetta\IRC_Gateway.exw |
|||
-- ============================ |
|||
-- |
|||
-- Run ChatServer first, then this, then ChatClient.exw with bViaGateway set to true. |
|||
-- |
|||
-- Translation between the various IRC protocols left as an exercise for the reader, |
|||
-- this is just a simple passthrough service. |
|||
-- |
|||
-- Also this uses a simpler server <--> gateway <--> {clients} model, rather than |
|||
-- a more sensible server <-> {gateway1 <-> client1, gateway2 <-> client2} model, |
|||
-- probably easily changed, see the {ci,gi} = connection[i] etc comments below. |
|||
-- Hence as is this will broadcast eg /nt (name taken) rather than send it to a |
|||
-- single specific client, which would obviously be better. |
|||
--</span> |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">dl</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">`Download rosetta\eulibnet\ from http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Eulibnet`</span> |
|||
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_file_type</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"eulibnet"</span><span style="color: #0000FF;">)=</span><span style="color: #004600;">FILETYPE_DIRECTORY</span><span style="color: #0000FF;">,</span><span style="color: #000000;">dl</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">/</span><span style="color: #000000;">eulibnet</span><span style="color: #0000FF;">.</span><span style="color: #000000;">ew</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">gateway_listconn</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">server_listconn</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"127.0.0.1"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">server_port</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"29029"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">gateway_port</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"29030"</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">server_address</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">":"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">server_port</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">gateway_address</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IP</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">":"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">gateway_port</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">timeout</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">20</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">MAX_MSG</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">550</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">Escape</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">#1B</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">connections</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- (inbound on the gateway port) |
|||
-- (should maybe {inbound,outbound}) </span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">sequence</span> <span style="color: #000000;">args</span><span style="color: #0000FF;">={})</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">args</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span><span style="color: #000000;">args</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Shutting down euLibnet..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #000080;font-style:italic;">--DEV/SUG |
|||
-- integer {ci,gi} = connections[i] |
|||
-- if net_closeconn(ci) then crash("Error closing client connection!") end if |
|||
-- if net_closeconn(gi) then crash("Error closing gateway connection!") end if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing connection!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">gateway_listconn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing gateway_listconn!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error closing server_listconn!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_shutdown</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error shutting down euLibnet!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000080;font-style:italic;">--DEV to go if {ci,gi} model adopted... probably</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- Send msg to all clients</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">ci</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Sending to connection %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending to connection %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing euLibnet..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_init</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing euLibnet!"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Initializing driver..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_initdriver</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">!=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error initializing WinSock driver!"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Opening port "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">gateway_address</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">"..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">gateway_listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_openconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">gateway_address</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">gateway_listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Couldn't open connection (gateway already running?)"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_listen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">gateway_listconn</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error trying to listen to port"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Listening on port "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">gateway_address</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--DEV some/all probably better as {ci,gi} in connections[i]:</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Opening server connection..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">server_listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_openconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">NET_DRIVER_WSOCK_WIN</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">NULL</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">server_listconn</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Couldn't open connection."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Attempting to connect to chat server..."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_connect_wait_time</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">server_address</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timeout</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error trying to establish connection."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Timeout trying to establish connection."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"done."</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- main loop (poll until Escape keyed)</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #7060A8;">get_key</span><span style="color: #0000FF;">()!=</span><span style="color: #000000;">Escape</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_poll_listen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">gateway_listconn</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- integer ci = net_poll_listen(gateway_listconn), gi</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">!=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000080;font-style:italic;">--DEV make a new gateway connection to the server here...? |
|||
-- gi = <as server_listconn above?> |
|||
-- connections = append(connections, {ci,gi})</span> |
|||
<span style="color: #000000;">connections</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">conn</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"New connection open from "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">net_getpeer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000080;font-style:italic;">-- Check for messages from clients</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">connections</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ci</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">connections</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000080;font-style:italic;">-- {ci,gi} = connections[i]</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_query_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000080;font-style:italic;">--Get the message</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_receive_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">MAX_MSG</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"received msg \"%s\" of length %d from %d"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">],</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">--Exit on error</span> |
|||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_ignore_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Server error: some data may be lost"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Sending to server"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000080;font-style:italic;">-- if net_send_rdm(gi, msg) then</span> |
|||
<span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error sending to server"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000080;font-style:italic;">-- <as below but for gi instead of server_listcomm here?></span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">net_query_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">--Check for message |
|||
-- if net_query_rdm(gi) > 0 then --Check for message</span> |
|||
<span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_receive_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">MAX_MSG</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- sequence msg = net_receive_rdm(gi, MAX_MSG)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;"><</span> <span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Error receiving message!"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">net_ignore_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">server_listconn</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">-- {} = net_ignore_rdm(gi)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000080;font-style:italic;">--DEV maybe instead: |
|||
-- if net_send_rdm(ci, msg) then |
|||
-- crash("Error sending to clent") |
|||
-- end if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span> |
|||
<span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #000080;font-style:italic;">--?"done" |
|||
--{} = wait_key()</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|Tcl}}== |
|||
This code is called as a complete script, perhaps like this: |
|||
<syntaxhighlight lang="sh">./ircgateway.tcl irc://hostA.org/fishing bait irc://hostB.com:6667/haxors botfly</syntaxhighlight> |
|||
{{tcllib|picoirc}} |
|||
<syntaxhighlight lang="tcl">#!/bin/env tclsh8.5 |
|||
package require picoirc |
|||
### Parse script arguments |
|||
# URL form: irc://foobar.org/secret |
|||
if {$argc != 4} { |
|||
puts stderr "wrong # args: should be \"$argv0 ircA nickA ircB nickB\"" |
|||
exit 1 |
|||
} |
|||
lassign $argv url1 nick1 url2 nick2 |
|||
### How to do the forwarding from one side to the other |
|||
proc handle {from to -> state args} { |
|||
upvar #0 conn($from) f conn($to) t chan($to) chan |
|||
switch -exact -- $state { |
|||
"chat" { |
|||
lassign $args target nick message type |
|||
if {![string match "*>>*<<*" $message]} { |
|||
picoirc::post $t $chan ">>$nick said<< $message" |
|||
} |
|||
} |
|||
"traffic" { |
|||
lassign $args action channel nick newnick |
|||
switch -exact -- $action { |
|||
"entered" - "left" { |
|||
picoirc::post $t $chan ">>$nick has $action<<" |
|||
} |
|||
} |
|||
} |
|||
"close" { |
|||
exit |
|||
} |
|||
} |
|||
} |
|||
### Connect and run the event loop |
|||
set chan(1) [lindex [picoirc::splituri $url1] 2] |
|||
set chan(2) [lindex [picoirc::splituri $url1] 2] |
|||
interp alias {} handle1to2 {} handle 1 2 |
|||
interp alias {} handle2to1 {} handle 2 1 |
|||
set conn(1) [picoirc::connect handle1to2 $nick1 $url1] |
|||
set conn(2) [picoirc::connect handle2to1 $nick2 $url2] |
|||
vwait forever</syntaxhighlight> |
|||
=={{header|Wren}}== |
|||
{{trans|Go}} |
|||
{{libheader|WrenGo}} |
|||
{{libheader|go-ircevent}} |
|||
{{libheader|Wren-dynamic}} |
|||
An embedded application with a Go host so we can use the 'go-ircevent' library. |
|||
As it's not possible to access command line arguments directly from Wren when it is being embedded, we instead ask the gateway user to input details of the connections needed. |
|||
<syntaxhighlight lang="wren">/* IRC_gateway.wren */ |
|||
import "./dynamic" for Tuple |
|||
var Connection = Tuple.create("Connection", ["server", "channel", "nick", "user"]) |
|||
foreign class IRC { |
|||
construct new(number, nick, user) {} |
|||
foreign connect(server) |
|||
foreign verboseCallbackHandler=(arg) |
|||
foreign debug=(arg) |
|||
foreign useTLS=(arg) |
|||
foreign configTLS=(arg) |
|||
foreign addCallback(number, code, msg, channel, nick, otherNick) |
|||
} |
|||
foreign class Reader { |
|||
construct new() {} |
|||
foreign readLine() |
|||
} |
|||
var reader = Reader.new() |
|||
var Connections = List.filled(2, null) |
|||
System.print("To use this gateway, please enter the following:\n") |
|||
for (i in 0..1) { |
|||
System.print("Details for connection %(i+1):") |
|||
System.write(" Server : ") |
|||
var server = reader.readLine() |
|||
System.write(" Channel : ") |
|||
var channel = reader.readLine() |
|||
System.write(" Nickname : ") |
|||
var nick = reader.readLine() |
|||
System.write(" User : ") |
|||
var user = reader.readLine() |
|||
Connections[i] = Connection.new(server, channel, nick, user) |
|||
System.print() |
|||
} |
|||
for (i in 0..1) { |
|||
var c = Connections[i] |
|||
var irc = IRC.new(i, c.nick, c.user) |
|||
irc.verboseCallbackHandler = true |
|||
irc.debug = false |
|||
irc.useTLS = true |
|||
irc.configTLS = true |
|||
var otherNick = (i == 0) ? Connections[1].nick : Connections[0].nick |
|||
var msg |
|||
if (i == 0) { |
|||
msg = "<gateway> Hello %(c.nick). Please send your first message to %(otherNick)." |
|||
} else { |
|||
msg = "<gateway> Hello %(c.nick). Please wait for your first message from %(otherNick)." |
|||
} |
|||
irc.addCallback(i, "001", msg, c.channel, c.nick, otherNick) |
|||
irc.addCallback(i, "366", "" , c.channel, c.nick, otherNick) |
|||
irc.addCallback(i, "PRIVMSG", "" , c.channel, c.nick, otherNick) |
|||
irc.connect(c.server) |
|||
}</syntaxhighlight> |
|||
We now embed this script in the following Go program and run it from a terminal. To close the gateway just press Ctrl-C. |
|||
<syntaxhighlight lang="go">/* go run IRC_gateway.go */ |
|||
package main |
|||
import ( |
|||
"bufio" |
|||
"crypto/tls" |
|||
"fmt" |
|||
wren "github.com/crazyinfin8/WrenGo" |
|||
"github.com/thoj/go-ircevent" |
|||
"log" |
|||
"os" |
|||
"strings" |
|||
) |
|||
type any = interface{} // not needed if using Go v1.18 or later |
|||
var ircObjs [2]*irc.Connection |
|||
func newIRC(vm *wren.VM, parameters []any) (any, error) { |
|||
number := int(parameters[1].(float64)) |
|||
nick := parameters[2].(string) |
|||
user := parameters[3].(string) |
|||
ircObjs[number] = irc.IRC(nick, user) |
|||
return &ircObjs[number], nil |
|||
} |
|||
func connect(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
server := parameters[1].(string) |
|||
err := ircObj.Connect(server) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
return nil, nil |
|||
} |
|||
func setVerboseCallbackHandler(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
value := parameters[1].(bool) |
|||
ircObj.VerboseCallbackHandler = value |
|||
return nil, nil |
|||
} |
|||
func setDebug(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
value := parameters[1].(bool) |
|||
ircObj.Debug = value |
|||
return nil, nil |
|||
} |
|||
func setUseTLS(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
value := parameters[1].(bool) |
|||
ircObj.UseTLS = value |
|||
return nil, nil |
|||
} |
|||
func setConfigTLS(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
value := parameters[1].(bool) |
|||
ircObj.TLSConfig = &tls.Config{InsecureSkipVerify: value} |
|||
return nil, nil |
|||
} |
|||
func addCallback(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
ircObj := *(ifc.(**irc.Connection)) |
|||
number := int(parameters[1].(float64)) |
|||
code := parameters[2].(string) |
|||
msg := parameters[3].(string) |
|||
channel := parameters[4].(string) |
|||
nick := parameters[5].(string) |
|||
otherNick := parameters[6].(string) |
|||
if code == "001" { |
|||
ircObj.AddCallback("001", func(e *irc.Event) { |
|||
ircObj.Join(channel) |
|||
ircObj.Privmsg(nick, msg) |
|||
log.Println(msg) |
|||
}) |
|||
} else if code == "366" { |
|||
ircObj.AddCallback("366", func(e *irc.Event) {}) |
|||
} else if code == "PRIVMSG" { |
|||
ircObj.AddCallback("PRIVMSG", func(e *irc.Event) { |
|||
msg := fmt.Sprintf("<%s> %s", nick, e.Message) |
|||
if number == 0 { |
|||
ircObjs[1].Privmsg(otherNick, msg) |
|||
} else { |
|||
ircObjs[0].Privmsg(otherNick, msg) |
|||
} |
|||
log.Println(msg) |
|||
}) |
|||
} |
|||
return nil, nil |
|||
} |
|||
func newReader(vm *wren.VM, parameters []any) (any, error) { |
|||
reader := bufio.NewReader(os.Stdin) |
|||
return &reader, nil |
|||
} |
|||
func readLine(vm *wren.VM, parameters []any) (any, error) { |
|||
handle := parameters[0].(*wren.ForeignHandle) |
|||
ifc, _ := handle.Get() |
|||
bufin := *(ifc.(**bufio.Reader)) |
|||
s, _ := bufin.ReadString('\n') // includes the delimiter |
|||
return s[:len(s)-1], nil |
|||
} |
|||
func moduleFn(vm *wren.VM, name string) (string, bool) { |
|||
if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") { |
|||
name += ".wren" |
|||
} |
|||
return wren.DefaultModuleLoader(vm, name) |
|||
} |
|||
func main() { |
|||
cfg := wren.NewConfig() |
|||
cfg.LoadModuleFn = moduleFn |
|||
vm := cfg.NewVM() |
|||
var fileName = "IRC_gateway.wren" |
|||
IRCMethodMap := wren.MethodMap{ |
|||
"connect(_)": connect, |
|||
"verboseCallbackHandler=(_)": setVerboseCallbackHandler, |
|||
"debug=(_)": setDebug, |
|||
"useTLS=(_)": setUseTLS, |
|||
"configTLS=(_)": setConfigTLS, |
|||
"addCallback(_,_,_,_,_,_)": addCallback, |
|||
} |
|||
readerMethodMap := wren.MethodMap{"readLine()": readLine} |
|||
classMap := wren.ClassMap{ |
|||
"IRC": wren.NewClass(newIRC, nil, IRCMethodMap), |
|||
"Reader": wren.NewClass(newReader, nil, readerMethodMap), |
|||
} |
|||
module := wren.NewModule(classMap) |
|||
vm.SetModule(fileName, module) |
|||
vm.InterpretFile(fileName) |
|||
go ircObjs[1].Loop() |
|||
ircObjs[0].Loop() |
|||
vm.Free() |
|||
}</syntaxhighlight> |
|||
{{omit from|AWK}} |
|||
{{omit from|GUISS}} |
|||
{{omit from|HTML}} |
|||
{{omit from|Locomotive Basic}} |
|||
{{omit from|Lotus 123 Macro Scripting}} |
|||
{{omit from|Openscad}} |
|||
{{omit from|Mathematica}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|ZX Spectrum Basic}} |
|||
[[Category:Internet_Protocol]] |
Latest revision as of 11:58, 11 December 2023
Create an IRC Gateway capable of connecting an IRC server with another IRC server or Chat server
IRC gateway is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Go
Just a bare-bones gateway.
package main
import (
"crypto/tls"
"fmt"
"github.com/thoj/go-ircevent"
"log"
"os"
)
func main() {
if len(os.Args) != 9 {
fmt.Println("To use this gateway, you need to pass 8 command line arguments, namely:")
fmt.Println(" <server1> <channel1> <nick1> <user1> <server2> <channel2> <nick2> <user2>")
return
}
server1, channel1, nick1, user1 := os.Args[1], os.Args[2], os.Args[3], os.Args[4]
server2, channel2, nick2, user2 := os.Args[5], os.Args[6], os.Args[7], os.Args[8]
irc1 := irc.IRC(nick1, user1)
irc1.VerboseCallbackHandler = true
irc1.Debug = false
irc1.UseTLS = true
irc1.TLSConfig = &tls.Config{InsecureSkipVerify: true}
irc2 := irc.IRC(nick2, user2)
irc2.VerboseCallbackHandler = true
irc2.Debug = false
irc2.UseTLS = true
irc2.TLSConfig = &tls.Config{InsecureSkipVerify: true}
irc1.AddCallback("001", func(e *irc.Event) {
irc1.Join(channel1)
msg := fmt.Sprintf("<gateway> Hello %s. Please send your first message to %s.", nick1, nick2)
irc1.Privmsg(nick1, msg)
log.Println(msg)
})
irc1.AddCallback("366", func(e *irc.Event) {})
irc1.AddCallback("PRIVMSG", func(e *irc.Event) {
msg := fmt.Sprintf("<%s> %s", nick1, e.Message)
irc2.Privmsg(nick2, msg)
log.Println(msg)
})
irc2.AddCallback("001", func(e *irc.Event) {
irc2.Join(channel2)
msg := fmt.Sprintf("<gateway> Hello %s. Please wait for your first message from %s.", nick2, nick1)
irc2.Privmsg(nick2, msg)
log.Println(msg)
})
irc2.AddCallback("366", func(e *irc.Event) {})
irc2.AddCallback("PRIVMSG", func(e *irc.Event) {
msg := fmt.Sprintf("<%s> %s", nick2, e.Message)
irc1.Privmsg(nick1, msg)
log.Println(msg)
})
err1 := irc1.Connect(server1)
if err1 != nil {
log.Fatal(err1)
}
err2 := irc2.Connect(server2)
if err2 != nil {
log.Fatal(err2)
}
go irc2.Loop()
irc1.Loop()
}
Phix
For use with Chat_server#Phix
-- -- demo\rosetta\IRC_Gateway.exw -- ============================ -- -- Run ChatServer first, then this, then ChatClient.exw with bViaGateway set to true. -- -- Translation between the various IRC protocols left as an exercise for the reader, -- this is just a simple passthrough service. -- -- Also this uses a simpler server <--> gateway <--> {clients} model, rather than -- a more sensible server <-> {gateway1 <-> client1, gateway2 <-> client2} model, -- probably easily changed, see the {ci,gi} = connection[i] etc comments below. -- Hence as is this will broadcast eg /nt (name taken) rather than send it to a -- single specific client, which would obviously be better. -- without js constant dl = `Download rosetta\eulibnet\ from http://phix.x10.mx/pmwiki/pmwiki.php?n=Main.Eulibnet` assert(get_file_type("eulibnet")=FILETYPE_DIRECTORY,dl) include eulibnet/eulibnet.ew atom gateway_listconn, server_listconn constant IP = "127.0.0.1", server_port = "29029", gateway_port = "29030", server_address = IP & ":" & server_port, gateway_address = IP & ":" & gateway_port, timeout = 20, MAX_MSG = 550, Escape = #1B sequence connections = {} -- (inbound on the gateway port) -- (should maybe {inbound,outbound}) procedure message(string msg, sequence args={}) if length(args) then msg = sprintf(msg,args) end if printf(1,"%s\n",{msg}) end procedure procedure shutDown() message("Shutting down euLibnet...") for i = 1 to length(connections) do --DEV/SUG -- integer {ci,gi} = connections[i] -- if net_closeconn(ci) then crash("Error closing client connection!") end if -- if net_closeconn(gi) then crash("Error closing gateway connection!") end if if net_closeconn(connections[i]) then crash("Error closing connection!") end if end for if net_closeconn(gateway_listconn) then crash("Error closing gateway_listconn!") end if if net_closeconn(server_listconn) then crash("Error closing server_listconn!") end if if net_shutdown() then crash("Error shutting down euLibnet!") end if end procedure --DEV to go if {ci,gi} model adopted... probably procedure sendToAll(string msg) -- Send msg to all clients for i=1 to length(connections) do atom ci = connections[i] message("Sending to connection %d",{ci}) if net_send_rdm(ci, msg) then message("Error sending to connection %d",{ci}) end if end for end procedure message("Initializing euLibnet...") if net_init() then crash("Error initializing euLibnet!") end if message("done.") message("Initializing driver...") if net_initdriver(NET_DRIVER_WSOCK_WIN) != 1 then crash("Error initializing WinSock driver!") end if message("done.") message("Opening port " & gateway_address & "...") gateway_listconn = net_openconn(NET_DRIVER_WSOCK_WIN, gateway_address) if gateway_listconn = NULL then crash("Couldn't open connection (gateway already running?)") end if message("done.") if net_listen(gateway_listconn) then crash("Error trying to listen to port") end if message("Listening on port " & gateway_address) --DEV some/all probably better as {ci,gi} in connections[i]: message("Opening server connection...") server_listconn = net_openconn(NET_DRIVER_WSOCK_WIN, NULL) if server_listconn = NULL then crash("Couldn't open connection.") end if message("done.") message("Attempting to connect to chat server...") integer ret = net_connect_wait_time(server_listconn, server_address, timeout) if ret < 0 then crash("Error trying to establish connection.") elsif ret > 0 then crash("Timeout trying to establish connection.") end if message("done.") -- main loop (poll until Escape keyed) while get_key()!=Escape do integer conn = net_poll_listen(gateway_listconn) -- integer ci = net_poll_listen(gateway_listconn), gi if conn != NULL then --DEV make a new gateway connection to the server here...? -- gi = <as server_listconn above?> -- connections = append(connections, {ci,gi}) connections = append(connections, conn) message("New connection open from " & net_getpeer(conn)) end if -- Check for messages from clients for i=1 to length(connections) do integer ci = connections[i] -- {ci,gi} = connections[i] if net_query_rdm(ci) > 0 then --Get the message sequence msg = net_receive_rdm(ci, MAX_MSG) message("received msg \"%s\" of length %d from %d",{msg[2],msg[1],ci}) if msg[1] < 0 then --Exit on error {} = net_ignore_rdm(ci) crash("Server error: some data may be lost") end if msg = msg[2] message("Sending to server") if net_send_rdm(server_listconn, msg) then -- if net_send_rdm(gi, msg) then crash("Error sending to server") end if end if -- <as below but for gi instead of server_listcomm here?> end for if net_query_rdm(server_listconn) > 0 then --Check for message -- if net_query_rdm(gi) > 0 then --Check for message sequence msg = net_receive_rdm(server_listconn, MAX_MSG) -- sequence msg = net_receive_rdm(gi, MAX_MSG) if msg[1] < 0 then message("Error receiving message!") {} = net_ignore_rdm(server_listconn) -- {} = net_ignore_rdm(gi) end if msg = msg[2] message(msg) sendToAll(msg) --DEV maybe instead: -- if net_send_rdm(ci, msg) then -- crash("Error sending to clent") -- end if end if sleep(1) end while shutDown() --?"done" --{} = wait_key()
Tcl
This code is called as a complete script, perhaps like this:
./ircgateway.tcl irc://hostA.org/fishing bait irc://hostB.com:6667/haxors botfly
#!/bin/env tclsh8.5
package require picoirc
### Parse script arguments
# URL form: irc://foobar.org/secret
if {$argc != 4} {
puts stderr "wrong # args: should be \"$argv0 ircA nickA ircB nickB\""
exit 1
}
lassign $argv url1 nick1 url2 nick2
### How to do the forwarding from one side to the other
proc handle {from to -> state args} {
upvar #0 conn($from) f conn($to) t chan($to) chan
switch -exact -- $state {
"chat" {
lassign $args target nick message type
if {![string match "*>>*<<*" $message]} {
picoirc::post $t $chan ">>$nick said<< $message"
}
}
"traffic" {
lassign $args action channel nick newnick
switch -exact -- $action {
"entered" - "left" {
picoirc::post $t $chan ">>$nick has $action<<"
}
}
}
"close" {
exit
}
}
}
### Connect and run the event loop
set chan(1) [lindex [picoirc::splituri $url1] 2]
set chan(2) [lindex [picoirc::splituri $url1] 2]
interp alias {} handle1to2 {} handle 1 2
interp alias {} handle2to1 {} handle 2 1
set conn(1) [picoirc::connect handle1to2 $nick1 $url1]
set conn(2) [picoirc::connect handle2to1 $nick2 $url2]
vwait forever
Wren
An embedded application with a Go host so we can use the 'go-ircevent' library.
As it's not possible to access command line arguments directly from Wren when it is being embedded, we instead ask the gateway user to input details of the connections needed.
/* IRC_gateway.wren */
import "./dynamic" for Tuple
var Connection = Tuple.create("Connection", ["server", "channel", "nick", "user"])
foreign class IRC {
construct new(number, nick, user) {}
foreign connect(server)
foreign verboseCallbackHandler=(arg)
foreign debug=(arg)
foreign useTLS=(arg)
foreign configTLS=(arg)
foreign addCallback(number, code, msg, channel, nick, otherNick)
}
foreign class Reader {
construct new() {}
foreign readLine()
}
var reader = Reader.new()
var Connections = List.filled(2, null)
System.print("To use this gateway, please enter the following:\n")
for (i in 0..1) {
System.print("Details for connection %(i+1):")
System.write(" Server : ")
var server = reader.readLine()
System.write(" Channel : ")
var channel = reader.readLine()
System.write(" Nickname : ")
var nick = reader.readLine()
System.write(" User : ")
var user = reader.readLine()
Connections[i] = Connection.new(server, channel, nick, user)
System.print()
}
for (i in 0..1) {
var c = Connections[i]
var irc = IRC.new(i, c.nick, c.user)
irc.verboseCallbackHandler = true
irc.debug = false
irc.useTLS = true
irc.configTLS = true
var otherNick = (i == 0) ? Connections[1].nick : Connections[0].nick
var msg
if (i == 0) {
msg = "<gateway> Hello %(c.nick). Please send your first message to %(otherNick)."
} else {
msg = "<gateway> Hello %(c.nick). Please wait for your first message from %(otherNick)."
}
irc.addCallback(i, "001", msg, c.channel, c.nick, otherNick)
irc.addCallback(i, "366", "" , c.channel, c.nick, otherNick)
irc.addCallback(i, "PRIVMSG", "" , c.channel, c.nick, otherNick)
irc.connect(c.server)
}
We now embed this script in the following Go program and run it from a terminal. To close the gateway just press Ctrl-C.
/* go run IRC_gateway.go */
package main
import (
"bufio"
"crypto/tls"
"fmt"
wren "github.com/crazyinfin8/WrenGo"
"github.com/thoj/go-ircevent"
"log"
"os"
"strings"
)
type any = interface{} // not needed if using Go v1.18 or later
var ircObjs [2]*irc.Connection
func newIRC(vm *wren.VM, parameters []any) (any, error) {
number := int(parameters[1].(float64))
nick := parameters[2].(string)
user := parameters[3].(string)
ircObjs[number] = irc.IRC(nick, user)
return &ircObjs[number], nil
}
func connect(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
server := parameters[1].(string)
err := ircObj.Connect(server)
if err != nil {
log.Fatal(err)
}
return nil, nil
}
func setVerboseCallbackHandler(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
value := parameters[1].(bool)
ircObj.VerboseCallbackHandler = value
return nil, nil
}
func setDebug(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
value := parameters[1].(bool)
ircObj.Debug = value
return nil, nil
}
func setUseTLS(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
value := parameters[1].(bool)
ircObj.UseTLS = value
return nil, nil
}
func setConfigTLS(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
value := parameters[1].(bool)
ircObj.TLSConfig = &tls.Config{InsecureSkipVerify: value}
return nil, nil
}
func addCallback(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
ircObj := *(ifc.(**irc.Connection))
number := int(parameters[1].(float64))
code := parameters[2].(string)
msg := parameters[3].(string)
channel := parameters[4].(string)
nick := parameters[5].(string)
otherNick := parameters[6].(string)
if code == "001" {
ircObj.AddCallback("001", func(e *irc.Event) {
ircObj.Join(channel)
ircObj.Privmsg(nick, msg)
log.Println(msg)
})
} else if code == "366" {
ircObj.AddCallback("366", func(e *irc.Event) {})
} else if code == "PRIVMSG" {
ircObj.AddCallback("PRIVMSG", func(e *irc.Event) {
msg := fmt.Sprintf("<%s> %s", nick, e.Message)
if number == 0 {
ircObjs[1].Privmsg(otherNick, msg)
} else {
ircObjs[0].Privmsg(otherNick, msg)
}
log.Println(msg)
})
}
return nil, nil
}
func newReader(vm *wren.VM, parameters []any) (any, error) {
reader := bufio.NewReader(os.Stdin)
return &reader, nil
}
func readLine(vm *wren.VM, parameters []any) (any, error) {
handle := parameters[0].(*wren.ForeignHandle)
ifc, _ := handle.Get()
bufin := *(ifc.(**bufio.Reader))
s, _ := bufin.ReadString('\n') // includes the delimiter
return s[:len(s)-1], nil
}
func moduleFn(vm *wren.VM, name string) (string, bool) {
if name != "meta" && name != "random" && !strings.HasSuffix(name, ".wren") {
name += ".wren"
}
return wren.DefaultModuleLoader(vm, name)
}
func main() {
cfg := wren.NewConfig()
cfg.LoadModuleFn = moduleFn
vm := cfg.NewVM()
var fileName = "IRC_gateway.wren"
IRCMethodMap := wren.MethodMap{
"connect(_)": connect,
"verboseCallbackHandler=(_)": setVerboseCallbackHandler,
"debug=(_)": setDebug,
"useTLS=(_)": setUseTLS,
"configTLS=(_)": setConfigTLS,
"addCallback(_,_,_,_,_,_)": addCallback,
}
readerMethodMap := wren.MethodMap{"readLine()": readLine}
classMap := wren.ClassMap{
"IRC": wren.NewClass(newIRC, nil, IRCMethodMap),
"Reader": wren.NewClass(newReader, nil, readerMethodMap),
}
module := wren.NewModule(classMap)
vm.SetModule(fileName, module)
vm.InterpretFile(fileName)
go ircObjs[1].Loop()
ircObjs[0].Loop()
vm.Free()
}