3 * Copyright (c) 2007-2008 Mathew McBride <matt@mcbridematt.dhs.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 package org
.citadel
.lite
;
29 import java
.io
.BufferedInputStream
;
30 import java
.io
.IOException
;
31 import java
.io
.InputStream
;
32 import java
.io
.OutputStream
;
33 import java
.net
.Socket
;
34 import java
.util
.ArrayList
;
35 import java
.util
.List
;
37 import java
.util
.logging
.Level
;
38 import java
.util
.logging
.Logger
;
44 public class CitadelToolkit
{
46 static final byte[] endSeq
= "000\r\n".getBytes();
47 private Socket serverSocket
;
48 private InputStream serverInputStream
;
49 private OutputStream serverOutputStream
;
50 private static final String MSGS
= "MSGS\n";
51 private static final String GTSN
= "GTSN\n";
52 private static byte[] GTSN_BYTE
= null;
57 GTSN_BYTE
= GTSN
.getBytes("UTF-8");
58 } catch (Exception e
) {
62 private static final String MSGP
= "MSGP ";
63 private int newline
= 10;
64 private String user
= null;
65 private String pass
= null;
66 private int totalMsgsInCurRoom
= 0;
68 /** Function inspired by webcit. We can't use BufferedReader.readLine()
69 * since on some environments (IBM..) it barfs on non-unicode bytes
71 private String
serv_getln() throws IOException
{
73 byte[] buf
= new byte[4096];
76 c
= serverInputStream
.read();
77 if (c
!= 10 && c
!= 13 && c
!= -1) {
80 } while (c
!= 10 && c
!= -1);
81 return new String(buf
, 0, i
, "UTF-8");
84 public CitadelToolkit() {
87 public String
login(String user
, String pass
) {
91 String sendUser
= "USER " + user
+ "\n";
92 serverOutputStream
.write(sendUser
.getBytes("UTF-8"));
93 String response
= serv_getln();
94 if (!response
.substring(0, 3).equals("300")) {
95 System
.out
.print("Received ");
96 System
.out
.print(response
);
97 System
.out
.println(" instead of 300");
100 String sendPass
= "PASS " + pass
+ "\n";
101 serverOutputStream
.write(sendPass
.getBytes("UTF-8"));
102 response
= serv_getln();
103 System
.out
.println(response
);
105 } catch (IOException ex
) {
106 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
111 public String
gotoRoom(String room
) {
113 String gotoRoom
= "GOTO " + room
+ "\n";
114 serverOutputStream
.write(gotoRoom
.getBytes("UTF-8"));
115 String response
= serv_getln();
116 // Parse the response to get some data out of it
117 String
[] params
= response
.split("|");
118 String totalMsgCount
= params
[2];
119 totalMsgsInCurRoom
= Integer
.parseInt(totalMsgCount
);
121 } catch (IOException ex
) {
122 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
127 public int getMessageCountForRoom() {
128 return totalMsgsInCurRoom
;
131 public List
getMessagesInRoom() {
133 serverOutputStream
.write(MSGS
.getBytes("UTF-8"));
134 String initialResponse
= serv_getln();
135 if (!initialResponse
.substring(0, 3).equals("100")) {
138 ArrayList list
= new ArrayList();
142 if (resp
.equals("000")) {
148 } catch (IOException ex
) {
149 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
154 public GTSNRuleSet
getSeenRule() {
157 serverOutputStream
.write(GTSN_BYTE
);
158 String response
= serv_getln();
159 String status
= response
.substring(0, 3);
160 if (status
.equals("200")) {
161 ruleset
= response
.substring(4);
163 } catch (IOException ex
) {
164 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
166 return new GTSNRuleSet(ruleset
);
169 public boolean setPreferredType(String preferred
) throws IOException
{
170 serverOutputStream
.write(MSGP
.getBytes("UTF-8"));
171 serverOutputStream
.write(preferred
.getBytes("UTF-8"));
172 serverOutputStream
.write(newline
);
173 String response
= serv_getln();
174 if (!response
.substring(0, 3).equals("200")) {
180 public CtdlMessage
getMessage4(String msgId
) throws CitadelException
, IOException
{
181 String getMsg4
= "MSG4 " + msgId
+ "\n";
182 serverOutputStream
.write(getMsg4
.getBytes("UTF-8"));
183 String resp
= serv_getln();
184 if (isErrorMsg(resp
)) {
185 throw new CitadelException(resp
);
187 CtdlMessage msg
= new CtdlMessage();
190 if (resp
.equals("000")) {
193 msg
.parserFeedLine(resp
);
198 public CtdlMessage
getMessageHeaders(String msgId
) {
200 String getMsg4
= "MSG0 " + msgId
+ "|1\n";
201 serverOutputStream
.write(getMsg4
.getBytes("UTF-8"));
202 String resp
= serv_getln();
203 if (!resp
.substring(0, 3).equals("100")) {
204 return null; // Failed
206 CtdlMessage msg
= new CtdlMessage();
209 if (resp
.equals("000")) {
212 msg
.parserFeedLine(resp
);
215 } catch (IOException ex
) {
216 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
221 public boolean setSeenStatus(String message
, boolean seen
) {
223 int seenInt
= (seen
) ?
1 : 0;
224 String setSeen
= String
.format("SEEN %s|%d\n", message
, seenInt
);
225 serverOutputStream
.write(setSeen
.getBytes());
226 String feedback
= serv_getln();
227 return !isErrorMsg(feedback
);
228 } catch (IOException ex
) {
229 Logger
.getLogger(CitadelToolkit
.class.getName()).log(Level
.SEVERE
, null, ex
);
233 public void postMessage(String room
,
240 String contents
) throws CitadelException
, IOException
{
242 String ent0
= String
.format("ENT0 1|%s||4|%s|%s|0|%s|%s||%s\r\n", toAddress
,
248 serverOutputStream
.write(ent0
.getBytes());
249 String resp
= serv_getln();
250 if (isErrorMsg(resp
)) {
251 throw new CitadelException(resp
);
253 serverOutputStream
.write(contents
.getBytes());
254 serverOutputStream
.write(new byte[]{'\r', '\n'});
255 serverOutputStream
.write(endSeq
);
259 public void deleteMessage(String msgId
) throws IOException
{
260 String deleteString
= "DELE " + msgId
+ "\r\n";
261 serverOutputStream
.write(deleteString
.getBytes());
265 public void moveToTrash(String room
, String msgId
)
266 throws IOException
, CitadelException
{
268 String moveString
= String
.format("MOVE %s|%s|0\r\n", msgId
, "Trash");
269 serverOutputStream
.write(moveString
.getBytes());
270 String resp
= serv_getln();
271 if (isErrorMsg(resp
)) {
272 throw new CitadelException(resp
);
277 public byte[] downloadPart(String msgId
, String partNum
, int sizeOfPart
) throws Exception
{
278 String DLAT
= "DLAT " + msgId
+ "|" + partNum
+ "\r\n";
279 serverOutputStream
.write(DLAT
.getBytes());
280 String dlatResp
= serv_getln();
281 int locationOfNextDelim
= dlatResp
.indexOf("|", 4);
282 if (isErrorMsg(dlatResp
)) {
283 throw new CitadelException(dlatResp
);
285 String siz
= dlatResp
.substring(4,locationOfNextDelim
);
286 byte[] downloaded
= new byte[Integer
.parseInt(siz
)];
288 while ((totalRead
< downloaded
.length
)) {
289 totalRead
= totalRead
+ serverInputStream
.read(downloaded
, totalRead
, downloaded
.length
- totalRead
);
294 public void close() throws IOException
{
295 serverSocket
.close();
298 public void open(String host
, int port
) throws IOException
{
299 serverSocket
= new Socket(host
, port
);
300 //serverSocket.open();
301 // Wrap input stream in buffer
302 serverInputStream
= new BufferedInputStream(
303 serverSocket
.getInputStream(), 350);
304 serverOutputStream
= serverSocket
.getOutputStream();
305 System
.out
.println(serv_getln());
308 public boolean isErrorMsg(String line
) {
309 String errCode
= line
.substring(0, 3);
310 int code
= Integer
.parseInt(errCode
);
311 if (code
>= 500 && code
< 600) {