IRC gateway: Difference between revisions
Content deleted Content added
m {{omit from|GUISS}} |
m →{{header|Wren}}: Minor tidy |
||
(8 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
{{draft 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}}== |
|||
{{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}}== |
=={{header|Tcl}}== |
||
This code is called as a complete script, perhaps like this: |
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}} |
{{tcllib|picoirc}} |
||
< |
<syntaxhighlight lang="tcl">#!/bin/env tclsh8.5 |
||
package require picoirc |
package require picoirc |
||
Line 47: | Line 290: | ||
set conn(1) [picoirc::connect handle1to2 $nick1 $url1] |
set conn(1) [picoirc::connect handle1to2 $nick1 $url1] |
||
set conn(2) [picoirc::connect handle2to1 $nick2 $url2] |
set conn(2) [picoirc::connect handle2to1 $nick2 $url2] |
||
vwait forever</ |
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|GUISS}} |
||
{{omit from|HTML}} |
|||
{{omit from|Locomotive Basic}} |
{{omit from|Locomotive Basic}} |
||
{{omit from|Lotus 123 Macro Scripting}} |
{{omit from|Lotus 123 Macro Scripting}} |
||
{{omit from|Openscad}} |
|||
{{omit from|Mathematica}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|ZX Spectrum Basic}} |
{{omit from|ZX Spectrum Basic}} |
||
Latest revision as of 11:58, 11 December 2023
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.
Create an IRC Gateway capable of connecting an IRC server with another IRC server or Chat server
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()
}