Chat server: Difference between revisions

m
m (Added BaCon version.)
m (→‎{{header|Wren}}: Minor tidy)
 
(13 intermediate revisions by 9 users not shown)
Line 6:
People should be able to connect via ‘telnet’, sign on with a nickname, and type messages which will then be seen by all other connected users. Arrivals and departures of chat members should generate appropriate notification messages.
<br><br>
 
=={{header|Ada}}==
{{libheader|AdaSockets}}
 
<langsyntaxhighlight Adalang="ada">with Ada.Containers.Vectors;
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Exceptions; use Ada.Exceptions;
Line 94 ⟶ 93:
Dummy.Start (Incoming_Socket);
end loop;
end Chat_Server;</langsyntaxhighlight>
 
=={{header|BaConBASIC}}==
==={{header|BaCon}}===
Requires BaCon 4.2 or higher. Clients have to login with an alias and can use the command 'say' or 'quit'.
Requires BaCon 4.2 or higher. Clients have to login with an alias and can use the commands 'say' or 'quit'. Notifications are submitted when users enter the chat or leave the chat.
<lang>DECLARE user$ ASSOC STRING
<syntaxhighlight lang="text">DECLARE user$ ASSOC STRING
DECLARE connect ASSOC long
OPEN "localhost:51000" FOR SERVER AS mynet
Line 132:
ENDIF
ENDIF
WEND</langsyntaxhighlight>
 
==={{header|Visual Basic .NET}}===
{{trans|C#}}
<syntaxhighlight lang="vbnet">Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
 
Module Module1
 
Class State
Private ReadOnly client As TcpClient
Private ReadOnly sb As New StringBuilder
 
Public Sub New(name As String, client As TcpClient)
Me.Name = name
Me.client = client
End Sub
 
Public ReadOnly Property Name As String
 
Public Sub Send(text As String)
Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
client.GetStream().Write(bytes, 0, bytes.Length)
End Sub
End Class
 
ReadOnly connections As New Dictionary(Of Integer, State)
Dim listen As TcpListener
Dim serverThread As Thread
 
Sub Main()
listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
serverThread = New Thread(New ThreadStart(AddressOf DoListen))
serverThread.Start()
End Sub
 
Private Sub DoListen()
listen.Start()
Console.WriteLine("Server: Started server")
 
Do
Console.Write("Server: Waiting...")
Dim client = listen.AcceptTcpClient()
Console.WriteLine(" Connected")
 
' New thread with client
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))
 
clientThread.Start(client)
Loop
End Sub
 
Private Sub DoClient(client As TcpClient)
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
 
Dim done As Boolean
Dim name As String
Do
If Not client.Connected Then
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort() ' Kill thread
End If
 
name = Receive(client)
done = True
 
For Each cl In connections
Dim state = cl.Value
If state.Name = name Then
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
done = False
End If
Next
Loop While Not done
 
connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Broadcast(String.Format("+++ {0} arrived +++", name))
 
Do
Dim text = Receive(client)
If text = "/quit" Then
Broadcast(String.Format("Connection from {0} closed.", name))
connections.Remove(Thread.CurrentThread.ManagedThreadId)
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Exit Do
End If
 
If Not client.Connected Then
Exit Do
End If
 
Broadcast(String.Format("{0}> {1}", name, text))
Loop
 
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort()
End Sub
 
Private Function Receive(client As TcpClient) As String
Dim sb As New StringBuilder
Do
If client.Available > 0 Then
While client.Available > 0
Dim ch = Chr(client.GetStream.ReadByte())
If ch = vbCr Then
' ignore
Continue While
End If
If ch = vbLf Then
Return sb.ToString()
End If
sb.Append(ch)
End While
 
' pause
Thread.Sleep(100)
End If
Loop
End Function
 
Private Sub Broadcast(text As String)
Console.WriteLine(text)
For Each client In connections
If client.Key <> Thread.CurrentThread.ManagedThreadId Then
Dim state = client.Value
state.Send(text)
End If
Next
End Sub
 
End Module</syntaxhighlight>
 
=={{header|C}}==
Line 141 ⟶ 278:
A glitch occurs if a connection is made using the Telnet protocol - user names are preceded by garbled text.
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
Line 388 ⟶ 525:
 
return 0;
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Net.Sockets;
Line 534 ⟶ 670:
}
}
}</langsyntaxhighlight>
 
=={{header|CoffeeScript}}==
This is ported from the JavaScript version. The tool js2coffee got me a mostly working version, and then I manually converted JS-style classes to CS "classic-style class" syntax.
 
<langsyntaxhighlight lang="coffeescript">
net = require("net")
sys = require("sys")
Line 647 ⟶ 782:
 
server = new ChatServer()
</syntaxhighlight>
</lang>
 
=={{header|D}}==
<lang d>
import std.getopt;
import std.socket;
import std.stdio;
import std.string;
 
struct client {
int pos;
char[] name;
char[] buffer;
Socket socket;
}
 
void broadcast(client[] connections, size_t self, const char[] message) {
writeln(message);
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;
 
connections[i].socket.send(message);
connections[i].socket.send("\r\n");
}
}
 
bool registerClient(client[] connections, size_t self) {
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;
 
if (icmp(connections[i].name, connections[self].name) == 0) {
return false;
}
}
 
return true;
}
 
void main(string[] args) {
ushort port = 4004;
 
auto helpInformation = getopt
(
args,
"port|p", "The port to listen to chat clients on [default is 4004]", &port
);
 
if (helpInformation.helpWanted) {
defaultGetoptPrinter("A simple chat server based on a task in rosettacode.", helpInformation.options);
return;
}
 
auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(10);
writeln("Listening on port: ", port);
 
enum MAX_CONNECTIONS = 60;
auto socketSet = new SocketSet(MAX_CONNECTIONS + 1);
client[] connections;
 
while(true) {
socketSet.add(listener);
 
foreach (con; connections) {
socketSet.add(con.socket);
}
 
Socket.select(socketSet, null, null);
 
for (size_t i = 0; i < connections.length; i++) {
if (socketSet.isSet(connections[i].socket)) {
char[1024] buf;
auto datLength = connections[i].socket.receive(buf[]);
 
if (datLength == Socket.ERROR) {
writeln("Connection error.");
} else if (datLength != 0) {
if (buf[0] == '\n' || buf[0] == '\r') {
if (connections[i].buffer == "/quit") {
connections[i].socket.close();
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
 
connections[i] = connections[$-1];
connections.length--;
i--;
 
writeln("\tTotal connections: ", connections.length);
continue;
} else if (connections[i].name.length == 0) {
connections[i].buffer = strip(connections[i].buffer);
if (connections[i].buffer.length > 0) {
connections[i].name = connections[i].buffer;
if (registerClient(connections, i)) {
connections.broadcast(i, "+++ " ~ connections[i].name ~ " arrived +++");
} else {
connections[i].socket.send("Name already registered. Please enter your name: ");
connections[i].name.length = 0;
}
} else {
connections[i].socket.send("A name is required. Please enter your name: ");
}
} else {
connections.broadcast(i, connections[i].name ~ "> " ~ connections[i].buffer);
}
connections[i].buffer.length = 0;
} else {
connections[i].buffer ~= buf[0..datLength];
}
} else {
try {
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
} catch (SocketException) {
writeln("Connection closed.");
}
}
}
}
 
if (socketSet.isSet(listener)) {
Socket sn = null;
scope(failure) {
writeln("Error accepting");
 
if (sn) {
sn.close();
}
}
sn = listener.accept();
assert(sn.isAlive);
assert(listener.isAlive);
 
if (connections.length < MAX_CONNECTIONS) {
client newclient;
 
writeln("Connection from ", sn.remoteAddress(), " established.");
sn.send("Enter name: ");
 
newclient.socket = sn;
connections ~= newclient;
 
writeln("\tTotal connections: ", connections.length);
} else {
writeln("Rejected connection from ", sn.remoteAddress(), "; too many connections.");
sn.close();
assert(!sn.isAlive);
assert(listener.isAlive);
}
}
 
socketSet.reset();
}
}
</lang>
 
=={{header|Common Lisp}}==
{{libheader|usocket}}
Line 835 ⟶ 806:
*USER-MANAGER*, or upon an error occurring.
 
<langsyntaxhighlight lang="common-lisp">
(ql:quickload '(:usocket :simple-actors :bordeaux-threads))
 
Line 1,011 ⟶ 982:
 
(make-thread #'accept-connections)
</syntaxhighlight>
</lang>
=={{header|D}}==
<syntaxhighlight lang="d">
import std.getopt;
import std.socket;
import std.stdio;
import std.string;
 
struct client {
int pos;
char[] name;
char[] buffer;
Socket socket;
}
 
void broadcast(client[] connections, size_t self, const char[] message) {
writeln(message);
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;
 
connections[i].socket.send(message);
connections[i].socket.send("\r\n");
}
}
 
bool registerClient(client[] connections, size_t self) {
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;
 
if (icmp(connections[i].name, connections[self].name) == 0) {
return false;
}
}
 
return true;
}
 
void main(string[] args) {
ushort port = 4004;
 
auto helpInformation = getopt
(
args,
"port|p", "The port to listen to chat clients on [default is 4004]", &port
);
 
if (helpInformation.helpWanted) {
defaultGetoptPrinter("A simple chat server based on a task in rosettacode.", helpInformation.options);
return;
}
 
auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(10);
writeln("Listening on port: ", port);
 
enum MAX_CONNECTIONS = 60;
auto socketSet = new SocketSet(MAX_CONNECTIONS + 1);
client[] connections;
 
while(true) {
socketSet.add(listener);
 
foreach (con; connections) {
socketSet.add(con.socket);
}
 
Socket.select(socketSet, null, null);
 
for (size_t i = 0; i < connections.length; i++) {
if (socketSet.isSet(connections[i].socket)) {
char[1024] buf;
auto datLength = connections[i].socket.receive(buf[]);
 
if (datLength == Socket.ERROR) {
writeln("Connection error.");
} else if (datLength != 0) {
if (buf[0] == '\n' || buf[0] == '\r') {
if (connections[i].buffer == "/quit") {
connections[i].socket.close();
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
 
connections[i] = connections[$-1];
connections.length--;
i--;
 
writeln("\tTotal connections: ", connections.length);
continue;
} else if (connections[i].name.length == 0) {
connections[i].buffer = strip(connections[i].buffer);
if (connections[i].buffer.length > 0) {
connections[i].name = connections[i].buffer;
if (registerClient(connections, i)) {
connections.broadcast(i, "+++ " ~ connections[i].name ~ " arrived +++");
} else {
connections[i].socket.send("Name already registered. Please enter your name: ");
connections[i].name.length = 0;
}
} else {
connections[i].socket.send("A name is required. Please enter your name: ");
}
} else {
connections.broadcast(i, connections[i].name ~ "> " ~ connections[i].buffer);
}
connections[i].buffer.length = 0;
} else {
connections[i].buffer ~= buf[0..datLength];
}
} else {
try {
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
} catch (SocketException) {
writeln("Connection closed.");
}
}
}
}
 
if (socketSet.isSet(listener)) {
Socket sn = null;
scope(failure) {
writeln("Error accepting");
 
if (sn) {
sn.close();
}
}
sn = listener.accept();
assert(sn.isAlive);
assert(listener.isAlive);
 
if (connections.length < MAX_CONNECTIONS) {
client newclient;
 
writeln("Connection from ", sn.remoteAddress(), " established.");
sn.send("Enter name: ");
 
newclient.socket = sn;
connections ~= newclient;
 
writeln("\tTotal connections: ", connections.length);
} else {
writeln("Rejected connection from ", sn.remoteAddress(), "; too many connections.");
sn.close();
assert(!sn.isAlive);
assert(listener.isAlive);
}
}
 
socketSet.reset();
}
}
</syntaxhighlight>
=={{header|Erlang}}==
<langsyntaxhighlight lang="erlang">
-module(chat).
 
Line 1,078 ⟶ 1,210:
Response -> Response
end.
</syntaxhighlight>
</lang>
 
=={{header|Go}}==
This example uses the Go idiom of [http://blog.golang.org/share-memory-by-communicating ''Do not communicate by sharing memory; instead, share memory by communicating'']; there are no explicit locks used, instead Go channels are used to safely synchronize where required.
Line 1,087 ⟶ 1,218:
This example handles the case of one specific client "falling behind" by relying on the underlying TCP stack to do a reasonable job of buffering. Once that buffer fills, a write to the that client's connection will time out and the connection will dropped. Other minor improvements would include enabling TCP keep alives, handling temporary errors from accept, and better logging. Not ideal, but it should be good enough for this example.
 
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,268 ⟶ 1,399:
}
c.server.rem <- c.name
}</langsyntaxhighlight>
 
=={{header|Groovy}}==
{{trans|Java}}
<langsyntaxhighlight lang="groovy">class ChatServer implements Runnable {
private int port = 0
private List<Client> clientList = new ArrayList<>()
Line 1,427 ⟶ 1,557:
new ChatServer(port).run()
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">{-# LANGUAGE OverloadedStrings #-}
import Network
import System.IO
Line 1,514 ⟶ 1,643:
T.putStrLn "Server started"
newMVar (M.empty) >>= clientLoop server
</syntaxhighlight>
</lang>
 
==Icon and {{header|Unicon}}==
 
This is Unicon-specific:
<langsyntaxhighlight lang="unicon">global mlck, nCons, cons
 
procedure main()
Line 1,545 ⟶ 1,674:
critical mlck: nCons -:= 1
}
end</langsyntaxhighlight>
 
=={{header|Java}}==
 
Line 1,553 ⟶ 1,681:
I think ideally, NIO would be used to select() sockets available/ready for I/O, to eliminate the possibility of a bad connection disrupting the server, but this increases the complexity.
 
<langsyntaxhighlight lang="java">import java.io.*;
import java.net.*;
import java.util.*;
Line 1,705 ⟶ 1,833:
}
}
</syntaxhighlight>
</lang>
 
=={{header|JavaScript}}==
{{works with|Node.js}}
<langsyntaxhighlight lang="javascript">varconst net = require("net");
varconst sysEventEmitter = require("sysevents").EventEmitter;
var EventEmitter = require("events").EventEmitter;
 
/*******************************************************************************
* ChatServer
Line 1,718 ⟶ 1,844:
* Manages connections, users, and chat messages.
******************************************************************************/
class ChatServer {
constructor() {
this.chatters = {};
this.server = net.createServer(this.handleConnection.bind(this));
this.server.listen(1212, "localhost");
}
isNicknameLegal(nickname) {
// A nickname may contain letters or numbers only,
// and may only be used once.
if (nickname.replace(/[A-Za-z0-9]*/, '') !== "") {
return false;
}
for (const used_nick in this.chatters) {
if (used_nick === nickname) {
return false;
}
}
return true;
}
handleConnection(connection) {
console.log(`Incoming connection from ${connection.remoteAddress}`);
connection.setEncoding("utf8");
 
let chatter = new Chatter(connection, this);
function ChatServer() {
chatter.on("chat", this.handleChat.bind(this));
this.chatters = {};
this.server = net chatter.createServeron("join", this.handleConnectionhandleJoin.bind(this));
chatter.on("leave", this.handleLeave.bind(this));
this.server.listen(1212, "localhost");
}
 
ChatServer.prototype.isNicknameLegal = function(nickname) {
// A nickname may contain letters or numbers only,
// and may only be used once.
if(nickname.replace(/[A-Za-z0-9]*/, '') != "") {
return false
}
for(used_nick in this.chatters) {
if(used_nick == nickname) {
return false;
}
handleChat(chatter, message) {
}
this.sendToEveryChatterExcept(chatter, chatter.nickname + ": " + message);
return true;
}
};
handleJoin(chatter) {
 
console.log(`${chatter.nickname} has joined the chat.`);
ChatServer.prototype.handleConnection = function(connection) {
this.sendToEveryChatter(`${chatter.nickname} has joined the chat.`);
console.log("Incoming connection from " + connection.remoteAddress);
this.addChatter(chatter);
connection.setEncoding("utf8");
 
var chatter = new Chatter(connection, this);
chatter.on("chat", this.handleChat.bind(this));
chatter.on("join", this.handleJoin.bind(this));
chatter.on("leave", this.handleLeave.bind(this));
};
 
ChatServer.prototype.handleChat = function(chatter, message) {
this.sendToEveryChatterExcept(chatter, chatter.nickname + ": " + message);
};
 
ChatServer.prototype.handleJoin = function(chatter) {
console.log(chatter.nickname + " has joined the chat.");
this.sendToEveryChatter(chatter.nickname + " has joined the chat.");
this.addChatter(chatter);
};
 
ChatServer.prototype.handleLeave = function(chatter) {
console.log(chatter.nickname + " has left the chat.");
this.removeChatter(chatter);
this.sendToEveryChatter(chatter.nickname + " has left the chat.");
};
 
ChatServer.prototype.addChatter = function(chatter) {
this.chatters[chatter.nickname] = chatter;
};
 
ChatServer.prototype.removeChatter = function(chatter) {
delete this.chatters[chatter.nickname];
};
 
ChatServer.prototype.sendToEveryChatter = function(data) {
for(nickname in this.chatters) {
this.chatters[nickname].send(data);
}
};
 
ChatServer.prototype.sendToEveryChatterExcept = function(chatter, data) {
for(nickname in this.chatters) {
if(nickname != chatter.nickname) {
this.chatters[nickname].send(data);
}
handleLeave(chatter) {
}
console.log(`${chatter.nickname} has left the chat.`);
};
this.removeChatter(chatter);
 
this.sendToEveryChatter(`${chatter.nickname} has left the chat.`);
}
addChatter(chatter) {
this.chatters[chatter.nickname] = chatter;
}
removeChatter(chatter) {
delete this.chatters[chatter.nickname];
}
sendToEveryChatter(data) {
for (const nickname in this.chatters) {
this.chatters[nickname].send(data);
}
}
sendToEveryChatterExcept(chatter, data) {
for (const nickname in this.chatters) {
if (nickname !== chatter.nickname) {
this.chatters[nickname].send(data);
}
}
}
}
/*******************************************************************************
* Chatter
Line 1,792 ⟶ 1,912:
* Represents a single user/connection in the chat server.
******************************************************************************/
class Chatter extends EventEmitter {
constructor(socket, server) {
super();
 
function Chatter( this.socket, server)= {socket;
this.server = server;
EventEmitter.call(this);
this.nickname = "";
this.lineBuffer = new SocketLineBuffer(socket);
 
this.lineBuffer.on("line", this.handleNickname.bind(this));
this.socket = socket;
this.socket.on("close", this.handleDisconnect.bind(this));
this.server = server;
this.nickname = "";
this.lineBuffer = new SocketLineBuffer(socket);
 
this.send("Welcome! What is your nickname?");
this.lineBuffer.on("line", this.handleNickname.bind(this));
}
this.socket.on("close", this.handleDisconnect.bind(this));
handleNickname(nickname) {
 
if (server.isNicknameLegal(nickname)) {
this.send("Welcome! What is your nickname?");
this.nickname = nickname;
this.lineBuffer.removeAllListeners("line");
this.lineBuffer.on("line", this.handleChat.bind(this));
this.send(`Welcome to the chat, ${nickname}!`);
this.emit("join", this);
} else {
this.send("Sorry, but that nickname is not legal or is already in use!");
this.send("What is your nickname?");
}
}
handleChat(line) {
this.emit("chat", this, line);
}
handleDisconnect() {
this.emit("leave", this);
}
send(data) {
this.socket.write(data + "\r\n");
}
};
 
sys.inherits(Chatter, EventEmitter);
 
Chatter.prototype.handleNickname = function(nickname) {
if(server.isNicknameLegal(nickname)) {
this.nickname = nickname;
this.lineBuffer.removeAllListeners("line");
this.lineBuffer.on("line", this.handleChat.bind(this));
this.send("Welcome to the chat, " + nickname + "!");
this.emit("join", this);
} else {
this.send("Sorry, but that nickname is not legal or is already in use!");
this.send("What is your nickname?");
}
};
 
Chatter.prototype.handleChat = function(line) {
this.emit("chat", this, line);
};
 
Chatter.prototype.handleDisconnect = function() {
this.emit("leave", this);
};
 
Chatter.prototype.send = function(data) {
this.socket.write(data + "\r\n");
};
 
/*******************************************************************************
* SocketLineBuffer
Line 1,840 ⟶ 1,957:
* whenever a complete line is detected.
******************************************************************************/
class SocketLineBuffer extends EventEmitter {
constructor(socket) {
super();
 
this.socket = socket;
function SocketLineBuffer(socket) {
this.buffer = "";
EventEmitter.call(this);
 
this.socket.on("data", = socketthis.handleData.bind(this));
this.buffer = "";}
handleData(data) {
 
for (let i = 0; i < data.length; i++) {
this.socket.on("data", this.handleData.bind(this));
const char = data.charAt(i);
};
this.buffer += char;
 
if (char == "\n") {
sys.inherits(SocketLineBuffer, EventEmitter);
this.buffer = this.buffer.replace("\r\n", "");
 
this.buffer = this.buffer.replace("\n", "");
SocketLineBuffer.prototype.handleData = function(data) {
this.emit("line", this.buffer);
for(var i = 0; i < data.length; i++) {
var char = data this.charAt(i)buffer = "";
this.buffer += char; }
if(char == "\n") { }
this.buffer = this.buffer.replace("\r\n", "");
this.buffer = this.buffer.replace("\n", "");
this.emit("line", this.buffer);
this.buffer = "";
}
}
};
 
// Start the server!
server = new ChatServer();</langsyntaxhighlight>
 
=={{header|Julia}}==
Modified to fit the Rosetta Code task from example code for the WebSockets module written by Leah Hanson.
To test, start the code and use a browser to connect to localhost:8000.
<langsyntaxhighlight lang="julia">
using HttpServer
using WebSockets
Line 1,954 ⟶ 2,070:
println("Chat server listening on 8000...")
run(server,8000)
</syntaxhighlight>
</lang>
 
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
Line 2,110 ⟶ 2,225:
}
}
}</langsyntaxhighlight>
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import asyncnet, asyncdispatch
 
type
Line 2,154 ⟶ 2,268:
 
asyncCheck serve()
runForever()</langsyntaxhighlight>
 
=={{header|Objeck}}==
<langsyntaxhighlight lang="objeck">
use System.IO.Net;
use System.Concurrency;
Line 2,267 ⟶ 2,380:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Ol}}==
<langsyntaxhighlight lang="scheme">
(import (otus vm))
(define (timestamp) (syscall 201 "%c"))
 
Line 2,336 ⟶ 2,447:
;(print "\n# " (timestamp) ": new request from " (syscall 51 fd))
(fork (on-accept (syscall 51 fd) fd))))
(set-ticker-valuesleep 0)
(loop))))
 
(run 8080)
</syntaxhighlight>
</lang>
{{Out}}
 
Line 2,395 ⟶ 2,506:
(127.0.0.1 . 55320): see you..
</pre>
 
 
=={{header|Perl}}==
{{trans|Python}}
<langsyntaxhighlight lang="perl">use 5.010;
use strict;
use warnings;
Line 2,506 ⟶ 2,615:
 
sleep(0.1);
}</langsyntaxhighlight>
===Alternate with both read and write queuing===
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # http://www.rosettacode.org/wiki/Chat_server
Line 2,587 ⟶ 2,696:
}
}
}</langsyntaxhighlight>
=={{header|Phix}}==
 
===server===
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\ChatServer.exw
-- ========================
--
-- translation of (qchat) chatServ.exw
--
-- Run this first, then ChatClient.exw, see also IRC_Gateway.exw
--
-- Note that I've only got a 32-bit windows eulibnet.dll, but it should not
-- be dificult to use a "real" libnet.dll/so, or something a little newer.
--</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</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;">Ihandle</span> <span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">log_window</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timer</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">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;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"29029"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">IPaddress</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;">port</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">MAX_MSG</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">550</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: #000000;">nicknames</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">max_log_len</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">300</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">log_to_window</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">to_number</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"COUNT"</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">count</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">max_log_len</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">count</span><span style="color: #0000FF;">-</span><span style="color: #000000;">max_log_len</span> <span style="color: #008080;">do</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"REMOVEITEM"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"1"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"APPENDITEM"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">txt</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TOPITEM"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"COUNT"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupUpdate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</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;">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;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">log_to_window</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: #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;">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 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: #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 (%s)"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ci</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</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: #008080;">procedure</span> <span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</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;">IPaddress</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">"..."</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">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;">IPaddress</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">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 (server 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;">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;">IPaddress</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*timer*/</span><span style="color: #0000FF;">)</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;">listconn</span><span style="color: #0000FF;">)</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: #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;">nicknames</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nicknames</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">""</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: #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: #004080;">string</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</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 aka %s"</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: #000000;">ni</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: #000000;">sendToAll</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;">exit</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: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">4</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</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;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/n:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)],</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</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: #008000;">"/nt"</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 %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;">else</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">prevname</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ni</span>
<span style="color: #000000;">ni</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)]</span>
<span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ni</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">prevname</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;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/j:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has joined"</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- send fake "has joined"s to the new joiner,
-- so that it can build a full members list (see allj)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">n</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;">nicknames</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">i</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"/j:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">n</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has joined"</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;">exit</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: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/c:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">prevname</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has changed name to "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</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: #008080;">elsif</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/d"</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: #008000;">"/l:"</span><span style="color: #0000FF;">&</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" has left"</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;">nicknames</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</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;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</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: #008080;">exit</span>
<span style="color: #000080;font-style:italic;">-- Aside: bunch of popup and file transfer stuff was here in qchat.exw,
-- all ripped out in the name of keeping this short and sweet.</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">sendToAll</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ni</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">": "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (Add nickname to message)</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: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_IGNORE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">close_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">log_list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupList</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=YES, CANFOCUS=NO, MULTIPLE=YES"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">statusbar</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Loading..."</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">log_window</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">}),</span>
<span style="color: #008000;">`TITLE="Chat Server", RASTERSIZE=400x400`</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_window</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CLOSE_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"close_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_window</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">500</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
===client===
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\ChatClient.exw
-- ===========================
--
-- translation of (qchat) QChat.exw
--
-- Probably best to run ChatServer.exw before this.
--</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
<span style="color: #008080;">constant</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">bViaGateway</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #000080;font-style:italic;">--constant bool bViaGateway = true -- see IRC_Gateway.exw</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</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;">Ihandle</span> <span style="color: #000000;">about</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">help</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">quit</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nickle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">login</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">memble</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">members</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">logle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">messle</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">input</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">chat_window</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">timer</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">allj</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span> <span style="color: #000080;font-style:italic;">-- (suppress initial flurry of fake "has joined" messages)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">conTextBack</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</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;">port</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">bViaGateway</span><span style="color: #0000FF;">?</span><span style="color: #008000;">"29030"</span><span style="color: #0000FF;">:</span><span style="color: #008000;">"29029"</span><span style="color: #0000FF;">),</span> <span style="color: #000080;font-style:italic;">-- See IRC_Gateway.exw</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;">IPaddress</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;">port</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">cr</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"\r\n"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">MAX_MSG</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">80</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">about_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Translated by Pete Lomax from qchat by Andrew/Norman (and win32lib ==&gt; pGUI).
Uses Libnet by George Foot and Chad Catlet as wrapped by Ray Smith."
"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">about_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"About"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">about_text</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">help_text</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"""
Make sure ChatServer.exw is running first...
Enter a nickname and press the Connect Button (or Return), then
enter your messages in the message area.
"""</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandln</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMessage</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Chat client"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help_text</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</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;">message</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">statusbar</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">message</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- This should probably be cropped once it gets too long...</span>
<span style="color: #000000;">conTextBack</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">message</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">cr</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">conTextBack</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"SCROLLTOPOS"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conTextBack</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;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">conFlag</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;">"You must be connected to do this"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">net_send_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</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 message \'"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">"\'"</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: #008080;">procedure</span> <span style="color: #000000;">shutDown</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;">nick</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;">"Disconnecting from 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;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/d"</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 disconnecting from 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: #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;">if</span> <span style="color: #000000;">conn</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: #008080;">if</span> <span style="color: #000000;">net_closeconn</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</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;">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: #000000;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">quit_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">connect_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*ih*/</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">nick</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</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;">nick</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;">"Opening connection..."</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">conn</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;">conn</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Couldn't open connection."</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</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;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">IPaddress</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: #000000;">message</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;">return</span> <span style="color: #004600;">IUP_DEFAULT</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: #000000;">message</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;">return</span> <span style="color: #004600;">IUP_DEFAULT</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;">conFlag</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Chat Client - "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">({</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">login</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/n:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">timer</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"RUN"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetFocus</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</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: #7060A8;">IupSetFocus</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nickname</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;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">joiner</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ml</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">unique</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">,</span><span style="color: #000000;">joiner</span><span style="color: #0000FF;">)),</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">mt</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;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">leaver</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">mt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">ml</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">split</span><span style="color: #0000FF;">(</span><span style="color: #000000;">mt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">leaver</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ml</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #7060A8;">IupSetStrAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">members</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">join</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ml</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">timer_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*timer*/</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">net_query_rdm</span><span style="color: #0000FF;">(</span><span style="color: #000000;">conn</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</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;">conn</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">MAX_MSG</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: #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;">conn</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: #008080;">if</span> <span style="color: #7060A8;">equal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"/nt"</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;">"Nickname "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" already taken"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">nick</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">"b"</span>
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Trying "</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span> <span style="color: #0000FF;">&</span> <span style="color: #008000;">" instead"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">message</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Type /n:nickname to try a different one"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"/n:"</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">nick</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- As per ChatServer, bunch of popup and file transfer stuff was
-- all ripped out in the name of keeping this short and sweet.</span>
<span style="color: #008080;">else</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</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;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/j:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" has joined"</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: #008080;">if</span> <span style="color: #000000;">allj</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</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;">4</span><span style="color: #0000FF;">..$]</span>
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</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;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/l:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" has left"</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;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..$]</span>
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)></span><span style="color: #000000;">3</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">equal</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;">3</span><span style="color: #0000FF;">],</span> <span style="color: #008000;">"/c:"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">shcnts</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" has changed name to "</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">match</span><span style="color: #0000FF;">(</span><span style="color: #000000;">shcnts</span><span style="color: #0000FF;">,</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">member_has_left</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">4</span><span style="color: #0000FF;">..</span><span style="color: #000000;">k</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">member_has_joined</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">shcnts</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$])</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;">4</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: #000000;">msg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">allj</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">key_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_ESC</span> <span style="color: #008080;">then</span> <span style="color: #000000;">shutDown</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">return</span> <span style="color: #004600;">IUP_CLOSE</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">=</span><span style="color: #004600;">K_F1</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">help_cb</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</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;">c</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'\r'</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">=</span><span style="color: #000000;">input</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">sendMsg</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupGetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">ih</span><span style="color: #0000FF;">=</span><span style="color: #000000;">nickname</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">connect_cb</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ih</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: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">about</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"About"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"about_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">help</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Help"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"help_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">quit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Exit"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"quit_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">nickle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Nickname"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">nickname</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">login</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupButton</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Connect"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"connect_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">memble</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Members online"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">members</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=VERTICAL, CANFOCUS=NO, MULTILINE=YES, SIZE=70x"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">logle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Incoming text"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">log_list</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=YES, CANFOCUS=NO, MULTILINE=YES"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">messle</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Message"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">input</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupText</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">({</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">input</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"KEY_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"key_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CUEBANNER"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"This Is Where You Type"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"NC"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">72</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- Max 72 characters allowed</span>
<span style="color: #7060A8;">IupSetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">input</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ACTIVE"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">statusbar</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Loading..."</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"EXPAND=HORIZONTAL"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">chat_window</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">about</span><span style="color: #0000FF;">,</span><span style="color: #000000;">help</span><span style="color: #0000FF;">,</span><span style="color: #000000;">quit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nickle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">nickname</span><span style="color: #0000FF;">,</span><span style="color: #000000;">login</span><span style="color: #0000FF;">},</span>
<span style="color: #008000;">"NORMALIZESIZE=VERTICAL,GAP=10,MARGIN=5x5"</span><span style="color: #0000FF;">),</span>
<span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">memble</span><span style="color: #0000FF;">,</span><span style="color: #000000;">members</span><span style="color: #0000FF;">}),</span>
<span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">logle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">log_list</span><span style="color: #0000FF;">})},</span>
<span style="color: #008000;">"NGAP=10,NMARGIN=5x5"</span><span style="color: #0000FF;">),</span>
<span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">messle</span><span style="color: #0000FF;">,</span><span style="color: #000000;">input</span><span style="color: #0000FF;">},</span><span style="color: #008000;">"GAP=10,MARGIN=5x5"</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">statusbar</span><span style="color: #0000FF;">}),</span>
<span style="color: #008000;">`TITLE="Chat Client", RASTERSIZE=400x400`</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"CLOSE_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"quit_cb"</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"PARENTDIALOG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">chat_window</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">mainWindow_onOpen</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">timer</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupTimer</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"timer_cb"</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">500</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
 
(de chat Lst
Line 2,617 ⟶ 3,142:
(tell 'chat "--- " *Name " left ---")
(bye) ) ) )
(wait)</langsyntaxhighlight>
After starting the above script, connect to the chat server from two terminals:
<pre> Terminal 1 | Terminal 2
Line 2,649 ⟶ 3,174:
| Connection closed.
| $</pre>
 
=={{header|Prolog}}==
Works with Swi-Prolog as of Jan 2019.
 
This version will load the server automatically on port 5000, adapt to your needs.
<langsyntaxhighlight lang="prolog">:- initialization chat_server(5000).
 
chat_server(Port) :-
Line 2,734 ⟶ 3,258:
msg_username_taken('That username is already taken, choose another\n\r').
msg_new_line('\n\r').
msg_by_user('~w> ~w').</langsyntaxhighlight>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">#!/usr/bin/env python
 
import socket
Line 2,814 ⟶ 3,337:
time.sleep(.1)
except (SystemExit, KeyboardInterrupt):
break</langsyntaxhighlight>
=={{header|R}}==
This implementation relies on the new server socket connection type introduced in R 4.0.0.
<syntaxhighlight lang="r">
chat_loop <- function(server, sockets, delay = 0.5) {
repeat {
Sys.sleep(delay) # Saves CPU resources
 
## Exhausts queue each iteration
while (in_queue(server))
sockets <- new_socket_entry(server, sockets)
 
## Update which sockets have sent messages
sockets <- check_messages(sockets)
 
## No sockets, nothing to do
if (nrow(sockets) == 0)
next
 
## No new messages, nothing to do
if (all(!sockets$message_ready))
next
 
 
sockets <- read_messages(sockets) # Messages are stored until sent
sockets <- drop_dead(sockets) # Dead = ready to read, but no data
 
## In case all sockets were dropped
if (nrow(sockets) == 0)
next
 
sockets <- update_nicknames(sockets)
sockets <- send_messages(sockets) # Only to users with nicknames
}
}
 
check_messages <- function(sockets) {
if (nrow(sockets) != 0)
sockets$message_ready <- socketSelect(sockets$conn, timeout = 0)
 
sockets
}
 
drop_dead <- function(sockets) {
lapply(with(sockets, conn[!alive]), close)
dropped <- with(sockets, nickname[nickname_exists(sockets) & !alive])
sockets <- sockets[sockets$alive, ]
 
if (length(dropped) != 0) {
send_named(sockets, paste0(dropped, " has disconnected."))
}
 
sockets
}
 
in_queue <- function(server) socketSelect(list(server), timeout = 0)
is_valid_name <- function(nicks) gsub("[A-Za-z0-9]*", "", nicks) == ""
message_exists <- function(sockets) !is.na(sockets$message)
 
new_row <- function(df) {
df[nrow(df) + 1, ] <- NA
df
}
 
new_socket_entry <- function(server, sockets) {
sockets <- new_row(sockets)
n <- nrow(sockets)
within(sockets, {
conn[[n]] <- new_user(server)
alive[n] <- TRUE
message_ready[n] <- FALSE
})
}
 
new_user <- function(server) {
conn <- socketAccept(server)
writeLines("Hello! Please enter a nickname.", conn)
conn
}
 
nickname_exists <- function(sockets) !is.na(sockets$nickname)
 
read_messages <- function(sockets) {
if (all(!sockets$message_ready))
return(sockets)
 
msgs <- lapply(with(sockets, conn[message_ready]), readLines, n = 1)
empty_msgs <- sapply(msgs, identical, character(0))
sockets <- within(sockets, alive[message_ready & empty_msgs] <- FALSE)
msgs <- unlist(ifelse(empty_msgs, NA, msgs))
within(sockets, message[message_ready] <- msgs)
}
 
send_messages <- function(sockets) {
named_message <- message_exists(sockets) & nickname_exists(sockets)
 
if (all(!named_message))
return(sockets)
 
rows <- which(named_message)
socksub <- sockets[rows, ]
time <- format(Sys.time(), "[%H:%M:%S] ")
with(socksub, send_named(sockets, paste0(time, nickname, ": ", message)))
within(sockets, message[rows] <- NA)
}
 
send_named <- function(sockets, msg) {
has_nickname <- nickname_exists(sockets)
invisible(lapply(sockets$conn[has_nickname], writeLines, text = msg))
}
 
start_chat_server <- function(port = 50525) {
server <- serverSocket(port) # Start listening
on.exit(closeAllConnections()) # Cleanup connections
 
## All socket data is stored and passed using this object
sockets <- data.frame(conn = I(list()), nickname = character(),
message = character(), alive = logical(),
message_ready = logical())
 
## Main event loop
chat_loop(server, sockets)
}
 
update_nicknames <- function(sockets) {
sent_nickname <- message_exists(sockets) & !nickname_exists(sockets)
nickname_valid <- is_valid_name(sockets$message)
 
if (all(!sent_nickname))
return(sockets)
 
is_taken <- with(sockets, (tolower(message) %in% tolower(sockets$nickname)) &
!is.na(message))
sent_ok <- sent_nickname & nickname_valid & !is_taken
sockets <- within(sockets, {
nickname[sent_ok] <- message[sent_ok]
message[sent_nickname] <- NA
lapply(conn[sent_nickname & !nickname_valid], writeLines,
text = "Alphanumeric characters only. Try again.")
lapply(conn[is_taken], writeLines,
text = "Name already taken. Try again.")
})
 
if (any(sent_ok))
send_named(sockets, paste0(sockets$nickname[sent_ok], " has connected."))
 
sockets
}
 
start_chat_server()</syntaxhighlight>
=={{header|Racket}}==
 
This is a very basic chat server, but it does everything that is needed for this task.
 
<langsyntaxhighlight lang="racket">
#lang racket
 
Line 2,842 ⟶ 3,513:
(void (thread (λ() (chat-server (tcp-listen 12321)))))
((client (current-input-port) (current-output-port)))
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
Line 2,849 ⟶ 3,519:
<div style="display:inline-block">{{trans|Python}}</div> (or at least started out that way)
{{works with|Rakudo|2016.07}}
<syntaxhighlight lang="raku" perl6line>react {
my %connections;
Line 2,891 ⟶ 3,561:
}
}
}</langsyntaxhighlight>
 
Notes:
Line 2,897 ⟶ 3,567:
* It accepts messages encoded in UTF-8.
* It tokenizes the message streams at newline boundaries (using the <tt>Supply.lines</tt> method), which I think makes the most sense for a chat application.
 
=={{header|Ruby}}==
<langsyntaxhighlight Rubylang="ruby">require 'gserver'
 
class ChatServer < GServer
Line 2,967 ⟶ 3,636:
#Turn on informational messages
ChatServer.new(7000, '0.0.0.0', 100, $stderr, true).start.join
</syntaxhighlight>
</lang>
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use std::collections::HashMap;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, RwLock};
use std::thread;
 
type Username = String;
 
/// Sends a message to all clients except the sending client.
fn broadcast_message(
user: &str,
clients: &mut HashMap<String, TcpStream>,
message: &str,
) -> io::Result<()> {
for (client, stream) in clients.iter_mut() {
if client != user {
writeln!(stream, "{}", message)?;
}
}
 
Ok(())
}
 
fn chat_loop(listener: &TcpListener) -> io::Result<()> {
let local_clients: Arc<RwLock<HashMap<Username, TcpStream>>> =
Arc::new(RwLock::new(HashMap::new()));
 
println!("Accepting connections on {}", listener.local_addr()?.port());
 
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let client_clients = Arc::clone(&local_clients);
thread::spawn(move || -> io::Result<()> {
let mut reader = BufReader::new(stream.try_clone()?);
let mut writer = stream;
 
let mut name = String::new();
loop {
write!(writer, "Please enter a username: ")?;
reader.read_line(&mut name)?;
name = name.trim().to_owned();
 
let clients = client_clients.read().unwrap();
if !clients.contains_key(&name) {
writeln!(writer, "Welcome, {}!", &name)?;
break;
}
 
writeln!(writer, "That username is taken.")?;
name.clear();
}
 
{
let mut clients = client_clients.write().unwrap();
clients.insert(name.clone(), writer);
broadcast_message(
&name,
&mut *clients,
&format!("{} has joined the chat room.", &name),
)?;
}
 
for line in reader.lines() {
let mut clients = client_clients.write().unwrap();
broadcast_message(&name, &mut *clients, &format!("{}: {}", &name, line?))?;
}
 
{
let mut clients = client_clients.write().unwrap();
clients.remove(&name);
broadcast_message(
&name,
&mut *clients,
&format!("{} has left the chat room.", &name),
)?;
}
 
Ok(())
});
}
Err(e) => {
println!("Connection failed: {}", e);
}
}
}
 
Ok(())
}
 
fn main() {
let listener = TcpListener::bind(("localhost", 7000)).unwrap();
chat_loop(&listener).unwrap();
}
</syntaxhighlight>
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
 
# Write a message to everyone except the sender of the message
Line 3,031 ⟶ 3,798:
socket -server {coroutine c[incr count] chat} 4004
set ::cmap {}; # Dictionary mapping nicks to channels
vwait forever; # Run event loop</langsyntaxhighlight>
 
=={{header|Visual Basic .NETWren}}==
An embedded solution using a C host since Wren has no built in support for either networking or multi-threading.
{{trans|C#}}
<lang vbnet>Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
 
The following is based on the C code [https://github.com/yorickdewid/Chat-Server/blob/master/chat_server.c here] and runs fine on my Ubuntu 20.04 box.
Module Module1
 
As Wren's VM is single threaded we create separate VMs to service each potential client connection (limited to 10) which run in their own thread. As the only way for the VMs to share mutable state is to use global variables within the host, synchronization is needed when accessing such variables.
Class State
<syntaxhighlight lang="wren">/* Chat_server.wren */
Private ReadOnly client As TcpClient
Private ReadOnly sb As New StringBuilder
 
class Clients {
Public Sub New(name As String, client As TcpClient)
foreign static max
Me.Name = name
foreign static count
Me.client = client
foreign static isActive(vmi)
End Sub
foreign static connfd(vmi)
foreign static uid(vmi)
foreign static name(vmi)
foreign static setName(vmi, s)
foreign static printAddr(vmi)
foreign static delete(vmi)
}
 
class Mutex {
Public ReadOnly Property Name As String
foreign static clientsLock()
foreign static clientsUnlock()
 
foreign static topicLock()
Public Sub Send(text As String)
foreign static topicUnlock()
Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
}
client.GetStream().Write(bytes, 0, bytes.Length)
End Sub
End Class
 
class Chat {
ReadOnly connections As New Dictionary(Of Integer, State)
// send message to all clients but the sender
Dim listen As TcpListener
static sendMessage(s, uid) {
Dim serverThread As Thread
Mutex.clientsLock()
for (i in 0...Clients.max) {
if (Clients.isActive(i) && Clients.uid(i) != uid) {
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
break
}
}
}
Mutex.clientsUnlock()
}
 
// send message to all clients
Sub Main()
static sendMessageAll(s) {
listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
Mutex.clientsLock()
serverThread = New Thread(New ThreadStart(AddressOf DoListen))
for (i in 0...Clients.max) {
serverThread.Start()
if (Clients.isActive(i)) {
End Sub
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
break
}
}
}
Mutex.clientsUnlock()
}
 
// send message to sender
Private Sub DoListen()
static sendMessageSelf(s, connfd) {
listen.Start()
if (write(connfd, s, s.bytes.count) < 0) {
Console.WriteLine("Server: Started server")
Fiber.abort("Write to descriptor %(connfd) failed.")
}
}
 
// send message to Doclient
static sendMessageClient(s, uid) {
Console.Write("Server: Waiting...")
Dim client = listenMutex.AcceptTcpClientclientsLock()
for (i in Console0.WriteLine(" Connected"..Clients.max) {
if (Clients.isActive(i) && Clients.uid(i) == uid) {
if (write(Clients.connfd(i), s, s.bytes.count) < 0) {
System.print("Write to descriptor %(Clients.connfd(i)) failed.")
break
}
}
}
Mutex.clientsUnlock()
}
 
// send list of active clients
' New thread with client
static sendActiveClients(connfd) {
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))
Mutex.clientsLock()
for (i in 0...Clients.max) {
if (Clients.isActive(i)) {
var s = "<< [%(Clients.uid(i))] %(Clients.name(i))\r\n"
sendMessageSelf(s, connfd)
}
}
Mutex.clientsUnlock()
}
 
// handle all communication with the clientThread.Start(client)
static handleClient(vmi) {
Loop
if (!Clients.isActive(vmi)) {
End Sub
Fiber.abort("The client handled by VM[%(vmi)] is inactive.")
}
var connfd = Clients.connfd(vmi)
var uid = Clients.uid(vmi)
var name = Clients.name(vmi)
System.write("<< accept ")
Clients.printAddr(vmi)
System.print(" referenced by %(uid)")
var buffOut = "<< %(name) has joined\r\n"
sendMessageAll(buffOut)
Mutex.topicLock()
if (topic != "") {
buffOut = "<< topic: %(topic)\r\n"
sendMessageSelf(buffOut, connfd)
}
Mutex.topicUnlock()
sendMessageSelf("<< see /help for assistance\r\n", connfd)
 
/* receive input from client */
Private Sub DoClient(client As TcpClient)
var buffIn = ""
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
while ((buffIn = read(connfd, bufferSize/2 - 1)) && buffIn.bytes.count > 0) {
Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
buffOut = ""
client.GetStream().Write(bytes, 0, bytes.Length)
buffIn = buffIn.trimEnd("\r\n")
/* ignore empty buffer */
if (buffIn == "") continue
 
Dim done As Boolean /* special options */
Dim name As String if (buffIn[0] == "/") {
var split = buffIn.split(" ")
Do
If Not client.Connected Then var command = split[0]
if (command == "/quit") {
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close() break
Thread.CurrentThread.Abort} else if ()command '== Kill"/ping") thread{
End If sendMessageSelf("<< pong\r\n", connfd)
} else if (command == "/topic") {
if (split.count > 0) {
Mutex.topicLock()
topic = split[1..-1].join(" ")
Mutex.topicUnlock()
buffOut = "<< topic changed to: %(topic)\r\n"
sendMessageAll(buffOut)
} else {
sendMessageSelf("<< message cannot be null\r\n", connfd)
}
} else if (command == "/nick") {
if (split.count > 0) {
var newName = split[1..-1].join(" ")
buffOut = "<< %(name) is now known as %(newName)\r\n"
Clients.setName(vmi, newName)
name = newName
sendMessageAll(buffOut)
} else {
sendMessageSelf("<< name cannot be null\r\n", connfd)
}
} else if (command == "/msg") {
if (split.count > 0) {
var toUid = Num.fromString(split[1])
if (split.count > 1) {
buffOut = "[PM][%(name)] "
buffOut = buffOut + split[2..-1].join(" ") + "\r\n"
sendMessageClient(buffOut, toUid)
} else {
sendMessageSelf("<< message cannot be null\r\n", connfd)
}
} else {
sendMessageSelf("<< reference cannot be null\r\n", connfd)
}
} else if (command == "/list") {
buffOut = "<< clients %(Clients.count)\r\n"
sendMessageSelf(buffOut, connfd)
sendActiveClients(connfd)
} else if (command == "/help") {
buffOut = ""
buffOut = buffOut + "<< /quit Quit chatroom\r\n"
buffOut = buffOut + "<< /ping Server test\r\n"
buffOut = buffOut + "<< /topic <message> Set chat topic\r\n"
buffOut = buffOut + "<< /nick <name> Change nickname\r\n"
buffOut = buffOut + "<< /msg <reference> <message> Send private message\r\n"
buffOut = buffOut + "<< /list Show active clients\r\n"
buffOut = buffOut + "<< /help Show help\r\n"
sendMessageSelf(buffOut, connfd)
} else {
sendMessageSelf("<< unknown command\r\n", connfd)
}
} else {
/* send message */
buffOut = "[%(name)] %(buffIn)\r\n"
sendMessage(buffOut, uid)
}
}
 
/* close connection name = Receive(client)*/
buffOut = "<< done[%(name)] =has Trueleft\r\n"
sendMessageAll(buffOut)
close(connfd)
 
/* delete client Forfrom Eachqueue cland Inyield connectionsthread (from C side) */
System.write("<< quit ")
Dim state = cl.Value
If stateClients.Name = name ThenprintAddr(vmi)
System.print(" referenced by %(uid)")
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
Clients.delete(vmi) client.GetStream().Write(bytes, 0, bytes.Length)
}
done = False
End If
Next
Loop While Not done
 
foreign static topic
connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
foreign static topic=(s)
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Broadcast(String.Format("+++ {0} arrived +++", name))
 
foreign static DobufferSize
foreign static write(connfd, buf, count)
Dim text = Receive(client)
foreign static read(connfd, count)
If text = "/quit" Then
foreign static close(connfd)
Broadcast(String.Format("Connection from {0} closed.", name))
}</syntaxhighlight>
connections.Remove(Thread.CurrentThread.ManagedThreadId)
<br>
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
We now embed this in the following C program, build and run it to start the server. To end the server, just press control-C. For testing purposes, clients can use telnet from separate terminals to connect to the server on port 5000.
Exit Do
<syntaxhighlight lang="c">/* gcc Chat_server.c -o Chat_server -lpthread -lwren -lm */
End If
 
#include <sys/socket.h>
If Not client.Connected Then
#include <netinet/in.h>
Exit Do
#include <arpa/inet.h>
End If
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <signal.h>
#include <wren.h>
 
#define MAX_CLIENTS 10
Broadcast(String.Format("{0}> {1}", name, text))
#define BUFFER_SZ 2048
Loop
 
static _Atomic unsigned int cli_count = 0;
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
static int listenfd = 0, uid = 10;
client.Close()
char *script = NULL;
Thread.CurrentThread.Abort()
End Sub
 
/* Client structure */
Private Function Receive(client As TcpClient) As String
typedef struct {
Dim sb As New StringBuilder
struct sockaddr_in addr; /* Client remote address */
Do
int connfd; /* Connection file descriptor */
If client.Available > 0 Then
int uid; While client.Available > 0 /* Client unique identifier */
int vmi; Dim ch =/* The index of the VM which handles this Chr(client.GetStream.ReadByte()) */
char name[32]; /* Client name If ch = vbCr Then*/
} client_t;
' ignore
Continue While
End If
If ch = vbLf Then
Return sb.ToString()
End If
sb.Append(ch)
End While
 
client_t *clients[MAX_CLIENTS];
' pause
Thread.Sleep(100)
End If
Loop
End Function
 
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
Private Sub Broadcast(text As String)
Console.WriteLine(text)
For Each client In connections
If client.Key <> Thread.CurrentThread.ManagedThreadId Then
Dim state = client.Value
state.Send(text)
End If
Next
End Sub
 
static char topic[BUFFER_SZ/2];
End Module</lang>
 
pthread_mutex_t topic_mutex = PTHREAD_MUTEX_INITIALIZER;
 
WrenVM* vms[MAX_CLIENTS]; // array of VMs
 
/* add client to queue */
void queue_add(client_t *cl){
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (!clients[i]) {
cl->vmi = i;
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
 
/* Delete client from queue */
void queue_delete(int uid){
pthread_mutex_lock(&clients_mutex);
for (int i = 0; i < MAX_CLIENTS; ++i) {
if (clients[i]) {
if (clients[i]->uid == uid) {
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
 
/* print ip address */
void print_client_addr(struct sockaddr_in addr){
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
 
/* enable Wren to handle all client communication */
void *handle_client(void *arg) {
client_t *cli = (client_t *)arg;
cli_count++;
int vmi = cli->vmi;
WrenHandle *callHandle = wrenMakeCallHandle(vms[vmi], "handleClient(_)");
wrenEnsureSlots(vms[vmi], 2);
wrenGetVariable(vms[vmi], "main", "Chat", 0);
wrenSetSlotDouble(vms[vmi], 1, (double)vmi);
wrenCall(vms[vmi], callHandle);
}
 
/* C <= Wren interface functions */
 
void C_max(WrenVM* vm) {
wrenSetSlotDouble(vm, 0, (double)MAX_CLIENTS);
}
 
void C_count(WrenVM* vm) {
wrenSetSlotDouble(vm, 0, (double)cli_count);
}
 
void C_isActive(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
bool res = clients[vmi] != NULL;
wrenSetSlotBool(vm, 0, res);
}
 
void C_connfd(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
wrenSetSlotDouble(vm, 0, (double)clients[vmi]->connfd);
}
 
void C_uid(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
wrenSetSlotDouble(vm, 0, (double)clients[vmi]->uid);
}
 
void C_name(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
wrenSetSlotString(vm, 0, (const char *)clients[vmi]->name);
}
 
void C_setName(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
const char *name = wrenGetSlotString(vm, 2);
size_t size = sizeof(clients[vmi]->name);
strncpy(clients[vmi]->name, name, size);
clients[vmi]->name[size-1] = '\0';
}
 
void C_clientsLock(WrenVM* vm) {
pthread_mutex_lock(&clients_mutex);
}
 
void C_clientsUnlock(WrenVM* vm) {
pthread_mutex_unlock(&clients_mutex);
}
 
void C_topicLock(WrenVM* vm) {
pthread_mutex_lock(&topic_mutex);
}
 
void C_topicUnlock(WrenVM* vm) {
pthread_mutex_unlock(&topic_mutex);
}
 
void C_printAddr(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
print_client_addr(clients[vmi]->addr);
}
 
void C_topic(WrenVM* vm) {
wrenSetSlotString(vm, 0, (const char *)topic);
}
 
void C_setTopic(WrenVM* vm) {
const char *t = wrenGetSlotString(vm, 1);
strncpy(topic, t, sizeof(topic));
topic[sizeof(topic)-1] = '\0';
}
 
void C_bufferSize(WrenVM* vm) {
wrenSetSlotDouble(vm, 0, (double)BUFFER_SZ);
}
 
void C_write(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
const void *buf = (const void *)wrenGetSlotString(vm, 2);
size_t count = (size_t)wrenGetSlotDouble(vm, 3);
ssize_t res = write(fd, buf, count);
wrenSetSlotDouble(vm, 0, (double)res);
}
 
void C_read(WrenVM* vm) {
char buf[BUFFER_SZ / 2];
int fd = (int)wrenGetSlotDouble(vm, 1);
size_t count = (size_t)wrenGetSlotDouble(vm, 2);
ssize_t rlen = read(fd, buf, count);
buf[rlen] = '\0';
wrenSetSlotString(vm, 0, (const char *)buf);
}
 
void C_close(WrenVM* vm) {
int connfd = (int)wrenGetSlotDouble(vm, 1);
close(connfd);
}
 
void C_delete(WrenVM* vm) {
int vmi = (int)wrenGetSlotDouble(vm, 1);
client_t *cli = clients[vmi];
queue_delete(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Clients") == 0) {
if (isStatic && strcmp(signature, "max") == 0) return C_max;
if (isStatic && strcmp(signature, "count") == 0) return C_count;
if (isStatic && strcmp(signature, "isActive(_)") == 0) return C_isActive;
if (isStatic && strcmp(signature, "connfd(_)") == 0) return C_connfd;
if (isStatic && strcmp(signature, "uid(_)") == 0) return C_uid;
if (isStatic && strcmp(signature, "name(_)") == 0) return C_name;
if (isStatic && strcmp(signature, "setName(_,_)") == 0) return C_setName;
if (isStatic && strcmp(signature, "printAddr(_)") == 0) return C_printAddr;
if (isStatic && strcmp(signature, "delete(_)") == 0) return C_delete;
} else if (strcmp(className, "Mutex") == 0) {
if (isStatic && strcmp(signature, "clientsLock()") == 0) return C_clientsLock;
if (isStatic && strcmp(signature, "clientsUnlock()") == 0) return C_clientsUnlock;
if (isStatic && strcmp(signature, "topicLock()") == 0) return C_topicLock;
if (isStatic && strcmp(signature, "topicUnlock()") == 0) return C_topicUnlock;
} else if (strcmp(className, "Chat") == 0) {
if (isStatic && strcmp(signature, "topic") == 0) return C_topic;
if (isStatic && strcmp(signature, "topic=(_)") == 0) return C_setTopic;
if (isStatic && strcmp(signature, "bufferSize") == 0) return C_bufferSize;
if (isStatic && strcmp(signature, "write(_,_,_)") == 0) return C_write;
if (isStatic && strcmp(signature, "read(_,_)") == 0) return C_read;
if (isStatic && strcmp(signature, "close(_)") == 0) return C_close;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
void catch_ctrl_c(int sig) {
/* clean up and exit */
for (int i = 0; i < MAX_CLIENTS; ++i) {
wrenFreeVM(vms[i]);
if (clients[i]) {
close(clients[i]->connfd);
free(clients[i]);
}
}
close(listenfd);
free(script);
printf("\n<[ SERVER ENDED ]>\n");
exit(EXIT_SUCCESS);
}
 
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
const char* module = "main";
const char* fileName = "Chat_server.wren";
script = readFile(fileName);
 
/* config the VMs and interpret the script */
for (int i = 0; i < MAX_CLIENTS; ++i) {
vms[i] = wrenNewVM(&config);
wrenInterpret(vms[i], module, script);
}
 
/* prepare to start the server */
int connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
 
/* socket settings */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(5000);
 
/* ignore pipe signals */
signal(SIGPIPE, SIG_IGN);
 
/* catch ctrl-c being pressed */
signal(SIGINT, catch_ctrl_c);
 
/* bind */
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Socket binding failed");
return EXIT_FAILURE;
}
 
/* listen */
if (listen(listenfd, 10) < 0) {
perror("Socket listening failed");
return EXIT_FAILURE;
}
 
printf("<[ SERVER STARTED ]>\n");
 
/* accept clients */
while (1) {
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
 
/* check if max clients is reached */
if ((cli_count + 1) == MAX_CLIENTS) {
printf("<< max clients reached\n");
printf("<< reject ");
print_client_addr(cli_addr);
printf("\n");
close(connfd);
continue;
}
 
/* client settings */
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->addr = cli_addr;
cli->connfd = connfd;
cli->uid = uid++;
sprintf(cli->name, "%d", cli->uid);
 
/* add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
 
/* reduce CPU usage */
sleep(1);
}
 
return 0;
}</syntaxhighlight>
 
=={{header|zkl}}==
{{trans|Python}}
On my Linux box, telnet seems to only want to connect to port 23.
<langsyntaxhighlight lang="zkl">const PORT=23;
var users=Dictionary(); // ( handle:socket, ...)
Line 3,221 ⟶ 4,412:
server:=Network.TCPServerSocket.open(PORT);
println("Listening on %s:%s".fmt(server.hostname,server.port));
server.listen(pipe); // Main event loop </langsyntaxhighlight>
{{out}}
Start the server:
Line 3,264 ⟶ 4,455:
Connection closed by foreign host.
</pre>
 
{{omit from|AutoHotkey}}
{{omit from|Lilypond}}
{{omit from|ML/I}}
{{omit from|Mathematica}}
{{omit from|Maxima}}
{{omit from|ML/I}}
{{omit from|PARI/GP|No good way to access network}}
{{omit from|Retro}}
9,476

edits