4 * This module handles the tasks involving establishing a connection to a
5 * Citadel/UX server and moving data across the connection. It also handles
6 * server "keepalives", the dispatching of "express messages", the
7 * registration & termination of multiple threads, and a semaphore mechanism
8 * to prevent multiple threads from executing server commands at the same
17 * We send 'keepalive' commands (actually just a NOOP) to the server every
18 * fifteen seconds, as a separate thread. This prevents the server session
19 * from timing out, and also allows the client to be notified of any incoming
20 * express messages if the user isn't doing anything.
22 class wcKeepAlive extends Thread {
24 wcCitServer serv; /* Pointer to server connection class */
25 boolean FullKeepAlives; /* TRUE for full keepalives, FALSE for half keepalives */
28 } public void PointToServer(wcCitServer which_serv,
29 boolean WhatKindOfKeepAlives) {
31 serv.AddClientThread(this);
32 FullKeepAlives = WhatKindOfKeepAlives;
39 /* Sleep for sixty seconds between keepalives. */
43 catch(InterruptedException e) {
45 /* Full keepalives - send a NOOP, wait for a reply, then retrieve
46 * express messages if the server said there are any.
49 buf = serv.ServTrans("NOOP") + " ";
52 /* Half keepalives - blindly send a NOOP and we're done. */
54 serv.ServPuts("NOOP");
65 * the wcCitServer class handles communication with the server.
67 public class wcCitServer {
74 boolean in_trans = false;
75 Vector ClientThreads = new Vector();
76 Vector ServerInfo = new Vector();
77 String PrimaryServerHost;
78 int PrimaryServerPort;
79 String PrimaryServerUser;
80 String PrimaryServerPassword;
82 public void SetTransBuf(String bufstring) {
84 } public String GetTransBuf() {
88 /* attach to the server */
89 private void BuildConnection(String ServerHost, int ServerPort,
95 sock = new Socket(ServerHost, ServerPort);
96 ofp = new DataOutputStream(sock.getOutputStream());
97 ifp = new DataInputStream(sock.getInputStream());
99 catch(UnknownHostException e) {
100 System.out.println(e);
102 catch(IOException e) {
103 System.out.println(e);
106 /* Connection established. At this point, this function
107 * has the server connection all to itself, so we can do
108 * whatever we want with it. */
110 /* Get the 'server ready' message */
113 /* Identify the client software to the server */
114 ServTrans("IDEN 0|5|001|Cit/UX Java Client|");
116 /* Download various information about the server */
118 buf = ServTrans("INFO");
119 StringTokenizer InfoST =
120 new StringTokenizer(TransBuf, "\n");
121 while (InfoST.hasMoreTokens()) {
122 ServerInfo.addElement(InfoST.nextToken());
126 /* At this point, all server accesses must cooperate with
127 * server accesses from other threads by using the BeginTrans
128 * and EndTrans semaphore mechanism.
130 ka = new wcKeepAlive();
131 ka.PointToServer(this, WhichKA);
138 * Attach to server command for the primary socket
140 public void AttachToServer(String ServerHost, int ServerPort) {
142 /* Connect to the server */
143 /* NOTE ... we've changed the primary connection keepalives to HALF because we're using the
144 * primary connection to jump right into a chat window.
146 BuildConnection(ServerHost, ServerPort, false);
148 /* And remember where we connected to, in case we have to
149 * build any piggyback connections later on.
151 PrimaryServerHost = ServerHost;
152 PrimaryServerPort = ServerPort;
157 * Learn info about the primary connection for setting up piggybacks
159 public String GetServerHost() {
160 return PrimaryServerHost;
163 public int GetServerPort() {
164 return PrimaryServerPort;
169 * Set up a piggyback connection
171 public void Piggyback(wcCitServer PrimaryServ,
172 boolean KeepAliveType) {
173 PrimaryServerHost = PrimaryServ.GetServerHost();
174 PrimaryServerPort = PrimaryServ.GetServerPort();
175 PrimaryServerUser = PrimaryServ.GetUserName();
176 PrimaryServerPassword = PrimaryServ.GetPassword();
177 BuildConnection(PrimaryServerHost, PrimaryServerPort,
184 /* return info about the site we're currently connected to */
185 public String ServInfo(int index) {
187 if (index >= ServerInfo.size()) {
190 retbuf = ServerInfo.elementAt(index).toString();
196 /* read a line from the server */
197 public String ServGets() {
202 buf = ifp.readLine();
204 catch(IOException e) {
205 System.out.println(e);
211 /* write a line to the server */
212 public void ServPuts(String buf) {
215 ofp.writeBytes(buf + "\n");
217 catch(IOException e) {
218 System.out.println(e);
223 /* lock the server connection so other threads don't screw us up */
224 public synchronized void BeginTrans() {
227 System.out.println("-sleeping-"); /* trace */
230 catch(InterruptedException e) {
237 /* release the lock */
238 public void EndTrans() {
243 /* perform an autonomous server transaction */
244 public String ServTrans(String ServCmd) {
247 buf = DataTrans(ServCmd);
252 /* perform a non-autonomous server transaction */
253 public String DataTrans(String ServCmd) {
258 /* perform the transaction */
260 System.out.println(">" + ServCmd); /* trace */
263 System.out.println("<" + buf); /* trace */
266 if (buf.startsWith("4")) {
267 ofp.writeBytes(TransBuf);
268 if (!TransBuf.endsWith("\n")) {
269 ofp.writeBytes("\n");
271 ofp.writeBytes("000");
275 if (buf.startsWith("1")) {
280 if (!TransBuf.equals("")) {
281 TransBuf = TransBuf + "\n";
283 if (!inbuf.equals("000")) {
287 } while (!inbuf.equals("000"));
290 catch(IOException e) {
291 System.out.println(e);
297 public void AddClientThread(Thread ct) {
298 ClientThreads.addElement(ct);
299 System.out.println("--new thread registered--");
302 public void RemoveClientThread(Thread ct) {
303 ClientThreads.removeElement(ct);
304 System.out.println("--thread removed--");
309 /* The following four functions take care of keeping track of the
310 * user name and password being used on the primary server connection
311 * in case we want to use them for a piggyback connection.
313 public void SetUserName(String U) {
314 PrimaryServerUser = U;
317 public void SetPassword(String P) {
318 PrimaryServerPassword = P;
321 public String GetUserName() {
322 return PrimaryServerUser;
325 public String GetPassword() {
326 return PrimaryServerPassword;