Sync up to the latest version of my source code
[funambol-citadel-connector.git] / jcitadel / src / main / java / org / citadel / lite / CitadelToolkit.java
blob8fc1c7a010efc020a9b4025ea4144010b6199c37
1 /*
2 * JCitadel
3 * Copyright (c) 2007-2008 Mathew McBride <matt@mcbridematt.dhs.org>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
25 * SUCH DAMAGE.
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;
36 import java.util.Map;
37 import java.util.logging.Level;
38 import java.util.logging.Logger;
40 /**
42 * @author matt
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;
55 static {
56 try {
57 GTSN_BYTE = GTSN.getBytes("UTF-8");
58 } catch (Exception e) {
59 e.printStackTrace();
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 {
72 int c = 0;
73 byte[] buf = new byte[4096];
74 int i = 0;
75 do {
76 c = serverInputStream.read();
77 if (c != 10 && c != 13 && c != -1) {
78 buf[i++] = (byte) c;
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) {
88 try {
89 this.user = user;
90 this.pass = 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");
98 return null;
100 String sendPass = "PASS " + pass + "\n";
101 serverOutputStream.write(sendPass.getBytes("UTF-8"));
102 response = serv_getln();
103 System.out.println(response);
104 return response;
105 } catch (IOException ex) {
106 Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex);
108 return null;
111 public String gotoRoom(String room) {
112 try {
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);
120 return response;
121 } catch (IOException ex) {
122 Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex);
124 return null;
127 public int getMessageCountForRoom() {
128 return totalMsgsInCurRoom;
131 public List getMessagesInRoom() {
132 try {
133 serverOutputStream.write(MSGS.getBytes("UTF-8"));
134 String initialResponse = serv_getln();
135 if (!initialResponse.substring(0, 3).equals("100")) {
136 return null;
138 ArrayList list = new ArrayList();
139 String resp = null;
140 while (true) {
141 resp = serv_getln();
142 if (resp.equals("000")) {
143 break;
145 list.add(resp);
147 return list;
148 } catch (IOException ex) {
149 Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex);
151 return null;
154 public GTSNRuleSet getSeenRule() {
155 String ruleset = "";
156 try {
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")) {
175 return false;
177 return true;
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();
188 while (true) {
189 resp = serv_getln();
190 if (resp.equals("000")) {
191 break;
193 msg.parserFeedLine(resp);
195 return msg;
198 public CtdlMessage getMessageHeaders(String msgId) {
199 try {
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();
207 while (true) {
208 resp = serv_getln();
209 if (resp.equals("000")) {
210 break;
212 msg.parserFeedLine(resp);
214 return msg;
215 } catch (IOException ex) {
216 Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex);
218 return null;
221 public boolean setSeenStatus(String message, boolean seen) {
222 try {
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);
230 return false;
233 public void postMessage(String room,
234 String toAddress,
235 String subject,
236 String fromName,
237 String ccs,
238 String bccs,
239 String email,
240 String contents) throws CitadelException, IOException {
241 gotoRoom(room);
242 String ent0 = String.format("ENT0 1|%s||4|%s|%s|0|%s|%s||%s\r\n", toAddress,
243 subject,
244 fromName,
245 ccs,
246 bccs,
247 email);
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());
262 serv_getln();
265 public void moveToTrash(String room, String msgId)
266 throws IOException, CitadelException {
267 gotoRoom(room);
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)];
287 int totalRead = 0;
288 while ((totalRead < downloaded.length)) {
289 totalRead = totalRead + serverInputStream.read(downloaded, totalRead, downloaded.length - totalRead);
291 return downloaded;
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) {
312 return true;
314 return false;