/* * JCitadel * Copyright (c) 2007-2008 Mathew McBride <matt@mcbridematt.dhs.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package org.citadel.lite; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author matt */ public class CitadelToolkit { static final byte[] endSeq = "000\r\n".getBytes(); private Socket serverSocket; private InputStream serverInputStream; private OutputStream serverOutputStream; private static final String MSGS = "MSGS\n"; private static final String GTSN = "GTSN\n"; private static byte[] GTSN_BYTE = null; static { try { GTSN_BYTE = GTSN.getBytes("UTF-8"); } catch (Exception e) { e.printStackTrace(); } } private static final String MSGP = "MSGP "; private int newline = 10; private String user = null; private String pass = null; private int totalMsgsInCurRoom = 0; /** Function inspired by webcit. We can't use BufferedReader.readLine() * since on some environments (IBM..) it barfs on non-unicode bytes */ private String serv_getln() throws IOException { int c = 0; byte[] buf = new byte[4096]; int i = 0; do { c = serverInputStream.read(); if (c != 10 && c != 13 && c != -1) { buf[i++] = (byte) c; } } while (c != 10 && c != -1); return new String(buf, 0, i, "UTF-8"); } public CitadelToolkit() { } public String login(String user, String pass) { try { this.user = user; this.pass = pass; String sendUser = "USER " + user + "\n"; serverOutputStream.write(sendUser.getBytes("UTF-8")); String response = serv_getln(); if (!response.substring(0, 3).equals("300")) { System.out.print("Received "); System.out.print(response); System.out.println(" instead of 300"); return null; } String sendPass = "PASS " + pass + "\n"; serverOutputStream.write(sendPass.getBytes("UTF-8")); response = serv_getln(); System.out.println(response); return response; } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); } return null; } public String gotoRoom(String room) { try { String gotoRoom = "GOTO " + room + "\n"; serverOutputStream.write(gotoRoom.getBytes("UTF-8")); String response = serv_getln(); // Parse the response to get some data out of it String[] params = response.split("|"); String totalMsgCount = params[2]; totalMsgsInCurRoom = Integer.parseInt(totalMsgCount); return response; } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); } return null; } public int getMessageCountForRoom() { return totalMsgsInCurRoom; } public List getMessagesInRoom() { try { serverOutputStream.write(MSGS.getBytes("UTF-8")); String initialResponse = serv_getln(); if (!initialResponse.substring(0, 3).equals("100")) { return null; } ArrayList list = new ArrayList(); String resp = null; while (true) { resp = serv_getln(); if (resp.equals("000")) { break; } list.add(resp); } return list; } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); } return null; } public GTSNRuleSet getSeenRule() { String ruleset = ""; try { serverOutputStream.write(GTSN_BYTE); String response = serv_getln(); String status = response.substring(0, 3); if (status.equals("200")) { ruleset = response.substring(4); } } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); } return new GTSNRuleSet(ruleset); } public boolean setPreferredType(String preferred) throws IOException { serverOutputStream.write(MSGP.getBytes("UTF-8")); serverOutputStream.write(preferred.getBytes("UTF-8")); serverOutputStream.write(newline); String response = serv_getln(); if (!response.substring(0, 3).equals("200")) { return false; } return true; } public CtdlMessage getMessage4(String msgId) throws CitadelException, IOException { String getMsg4 = "MSG4 " + msgId + "\n"; serverOutputStream.write(getMsg4.getBytes("UTF-8")); String resp = serv_getln(); if (isErrorMsg(resp)) { throw new CitadelException(resp); } CtdlMessage msg = new CtdlMessage(); while (true) { resp = serv_getln(); if (resp.equals("000")) { break; } msg.parserFeedLine(resp); } return msg; } public CtdlMessage getMessageHeaders(String msgId) { try { String getMsg4 = "MSG0 " + msgId + "|1\n"; serverOutputStream.write(getMsg4.getBytes("UTF-8")); String resp = serv_getln(); if (!resp.substring(0, 3).equals("100")) { return null; // Failed } CtdlMessage msg = new CtdlMessage(); while (true) { resp = serv_getln(); if (resp.equals("000")) { break; } msg.parserFeedLine(resp); } return msg; } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); } return null; } public boolean setSeenStatus(String message, boolean seen) { try { int seenInt = (seen) ? 1 : 0; String setSeen = String.format("SEEN %s|%d\n", message, seenInt); serverOutputStream.write(setSeen.getBytes()); String feedback = serv_getln(); return !isErrorMsg(feedback); } catch (IOException ex) { Logger.getLogger(CitadelToolkit.class.getName()).log(Level.SEVERE, null, ex); return false; } } public void postMessage(String room, String toAddress, String subject, String fromName, String ccs, String bccs, String email, String contents) throws CitadelException, IOException { gotoRoom(room); String ent0 = String.format("ENT0 1|%s||4|%s|%s|0|%s|%s||%s\r\n", toAddress, subject, fromName, ccs, bccs, email); serverOutputStream.write(ent0.getBytes()); String resp = serv_getln(); if (isErrorMsg(resp)) { throw new CitadelException(resp); } serverOutputStream.write(contents.getBytes()); serverOutputStream.write(new byte[]{'\r', '\n'}); serverOutputStream.write(endSeq); } public void deleteMessage(String msgId) throws IOException { String deleteString = "DELE " + msgId + "\r\n"; serverOutputStream.write(deleteString.getBytes()); serv_getln(); } public void moveToTrash(String room, String msgId) throws IOException, CitadelException { gotoRoom(room); String moveString = String.format("MOVE %s|%s|0\r\n", msgId, "Trash"); serverOutputStream.write(moveString.getBytes()); String resp = serv_getln(); if (isErrorMsg(resp)) { throw new CitadelException(resp); } } public byte[] downloadPart(String msgId, String partNum, int sizeOfPart) throws Exception { String DLAT = "DLAT " + msgId + "|" + partNum + "\r\n"; serverOutputStream.write(DLAT.getBytes()); String dlatResp = serv_getln(); int locationOfNextDelim = dlatResp.indexOf("|", 4); if (isErrorMsg(dlatResp)) { throw new CitadelException(dlatResp); } String siz = dlatResp.substring(4,locationOfNextDelim); byte[] downloaded = new byte[Integer.parseInt(siz)]; int totalRead = 0; while ((totalRead < downloaded.length)) { totalRead = totalRead + serverInputStream.read(downloaded, totalRead, downloaded.length - totalRead); } return downloaded; } public void close() throws IOException { serverSocket.close(); } public void open(String host, int port) throws IOException { serverSocket = new Socket(host, port); //serverSocket.open(); // Wrap input stream in buffer serverInputStream = new BufferedInputStream( serverSocket.getInputStream(), 350); serverOutputStream = serverSocket.getOutputStream(); System.out.println(serv_getln()); } public boolean isErrorMsg(String line) { String errCode = line.substring(0, 3); int code = Integer.parseInt(errCode); if (code >= 500 && code < 600) { return true; } return false; } }