diff --git a/build.xml b/build.xml index 545d59e7f..6b9328d54 100644 --- a/build.xml +++ b/build.xml @@ -1255,7 +1255,7 @@ javax.swing.event, javax.swing.border"/> manifest="${src}/net/java/sip/communicator/impl/protocol/msn/msn.provider.manifest.mf"> - + @@ -1270,7 +1270,7 @@ javax.swing.event, javax.swing.border"/> manifest="${testsrc}/net/java/sip/communicator/slick/protocol/msn/msn.provider.slick.manifest.mf"> - + diff --git a/lib/bundle/org.apache.felix.servicebinder-0.8.0-SNAPSHOT.jar b/lib/bundle/org.apache.felix.servicebinder-0.8.0-SNAPSHOT.jar deleted file mode 100644 index f071d23f1..000000000 Binary files a/lib/bundle/org.apache.felix.servicebinder-0.8.0-SNAPSHOT.jar and /dev/null differ diff --git a/lib/installer-exclude/jml-1.0b1.jar b/lib/installer-exclude/jml-1.0b1.jar deleted file mode 100644 index 4c64491e9..000000000 Binary files a/lib/installer-exclude/jml-1.0b1.jar and /dev/null differ diff --git a/lib/installer-exclude/jml-1.0b2.jar b/lib/installer-exclude/jml-1.0b2.jar new file mode 100644 index 000000000..068b1b9d4 Binary files /dev/null and b/lib/installer-exclude/jml-1.0b2.jar differ diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ContactMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ContactMsnImpl.java index 7bf917739..99b946fd7 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/ContactMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/ContactMsnImpl.java @@ -72,8 +72,19 @@ public boolean isLocal() public byte[] getImage() { + if(image == null) + ssclCallback.addContactForImageUpdate(this); + return image; } + + /** + * Set the image of the contact + */ + void setImage(byte[] imgBytes) + { + this.image = imgBytes; + } /** * Returns a hashCode for this contact. The returned hashcode is actually diff --git a/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java b/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java index e3a98657d..d977b618c 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/EventManager.java @@ -81,7 +81,7 @@ public void removeModificationListener(MsnContactListEventListener listener) * @param message Message * @throws Exception */ - public void messageSent(SocketSession session, Message message) throws Exception + public void messageSent(Session session, Message message) throws Exception { logger.trace(msnMessenger.getOwner().getEmail().getEmailAddress() + " outgoing " + message); @@ -93,7 +93,7 @@ public void messageSent(SocketSession session, Message message) throws Exception * @param message Message * @throws Exception */ - public void messageReceived(SocketSession session, Message message) + public void messageReceived(Session session, Message message) throws Exception { MsnIncomingMessage incoming = (MsnIncomingMessage)((WrapperMessage)message) @@ -220,7 +220,7 @@ else if(incoming instanceof IncomingQNG) private boolean connected = false; private Timer connectionTimer = new Timer(); - public void sessionTimeout(SocketSession socketSession) throws Exception + public void sessionTimeout(Session socketSession) throws Exception { connectionTimer.schedule(new TimerTask() { diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java index a78244041..7037893f8 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java @@ -7,6 +7,7 @@ package net.java.sip.communicator.impl.protocol.msn; import java.util.*; +import java.text.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; @@ -15,6 +16,7 @@ import net.sf.jml.*; import net.sf.jml.event.*; import net.sf.jml.message.*; +import net.java.sip.communicator.impl.protocol.msn.mail.utils.*; /** * A straightforward implementation of the basic instant messaging operation @@ -244,6 +246,8 @@ public void registrationStateChanged(RegistrationStateChangeEvent evt) msnProvider.getMessenger(). addMessageListener(new MsnMessageListener()); + msnProvider.getMessenger(). + addEmailListener(new MsnMessageListener()); } } } @@ -284,6 +288,7 @@ else if (evt instanceof MessageDeliveryFailedEvent) private class MsnMessageListener extends MsnMessageAdapter + implements MsnEmailListener { public void instantMessageReceived(MsnSwitchboard switchboard, MsnInstantMessage message, @@ -308,5 +313,74 @@ public void instantMessageReceived(MsnSwitchboard switchboard, fireMessageEvent(msgReceivedEvt); } - } + + public void initialEmailNotificationReceived(MsnSwitchboard switchboard, + MsnEmailInitMessage message, + MsnContact contact) + { + } + + public void initialEmailDataReceived(MsnSwitchboard switchboard, + MsnEmailInitEmailData message, + MsnContact contact) + { + } + + public void newEmailNotificationReceived(MsnSwitchboard switchboard, + MsnEmailNotifyMessage message, + MsnContact contact) + { + // we don't process incoming event without email. + if ((message.getFromAddr() == null) + || (message.getFromAddr().indexOf('@') < 0)) + { + return; + } + + String subject = message.getSubject(); + + try + { + subject = MimeUtility.decodeText(subject); + } + catch (Exception exception) + { + exception.printStackTrace(); + } + + Message newMailMessage = new MessageMsnImpl( + MessageFormat.format(Resources.getString("newMail"), + new Object[]{message.getFrom(), + message.getFromAddr(), + subject}), + DEFAULT_MIME_TYPE, + DEFAULT_MIME_ENCODING, + subject); + + Contact sourceContact = opSetPersPresence. + findContactByID(message.getFromAddr()); + + if (sourceContact == null) + { + logger.debug("received a new mail from an unknown contact: " + + message.getFrom() + + " <" + message.getFromAddr() + ">"); + //create the volatile contact + sourceContact = opSetPersPresence + .createVolatileContact(message.getFromAddr()); + } + MessageReceivedEvent msgReceivedEvt + = new MessageReceivedEvent( + newMailMessage, sourceContact, new Date(), + MessageReceivedEvent.SYSTEM_MESSAGE_RECEIVED); + + fireMessageEvent(msgReceivedEvt); + } + + public void activityEmailNotificationReceived(MsnSwitchboard switchboard, + MsnEmailActivityMessage message, + MsnContact contact) + { + } + } } diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java index 8cfbfd3aa..5afd80e7e 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetPersistentPresenceMsnImpl.java @@ -951,6 +951,46 @@ private void fireContactPresenceStatusChangeEvent( listener.contactPresenceStatusChanged(evt); } } + + /** + * Notify all subscription listeners of the corresponding contact property + * change event. + * + * @param eventID the String ID of the event to dispatch + * @param sourceContact the ContactJabberImpl instance that this event is + * pertaining to. + * @param oldValue the value that the changed property had before the change + * occurred. + * @param newValue the value that the changed property currently has (after + * the change has occurred). + */ + void fireContactPropertyChangeEvent( String eventID, + ContactMsnImpl sourceContact, + Object oldValue, + Object newValue) + { + ContactPropertyChangeEvent evt = + new ContactPropertyChangeEvent(sourceContact, eventID + , oldValue, newValue); + + logger.debug("Dispatching a Contact Property Change Event to" + +subscriptionListeners.size() + " listeners. Evt="+evt); + + Iterator listeners = null; + + synchronized (subscriptionListeners) + { + listeners = new ArrayList(subscriptionListeners).iterator(); + } + + while (listeners.hasNext()) + { + SubscriptionListener listener + = (SubscriptionListener) listeners.next(); + + listener.contactModified(evt); + } + } /** * Sets the messenger instance impl of the lib diff --git a/src/net/java/sip/communicator/impl/protocol/msn/Resources.java b/src/net/java/sip/communicator/impl/protocol/msn/Resources.java new file mode 100644 index 000000000..7077827b4 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/Resources.java @@ -0,0 +1,60 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ + +package net.java.sip.communicator.impl.protocol.msn; + +import java.io.*; +import java.util.*; + +import net.java.sip.communicator.util.*; + +/** + * The Resources class manages the access to the internationalization + * properties files. + * + * @author Yana Stamcheva + */ +public class Resources +{ + + /** + * Logger for this class. + */ + private static Logger log = Logger.getLogger(Resources.class); + + /** + * Name of the bundle were we will search for localized string. + */ + private static final String BUNDLE_NAME + = "net.java.sip.communicator.impl.protocol.msn.resources"; + + /** + * Bundle which handle access to localized resources. + */ + private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle + .getBundle(BUNDLE_NAME); + + /** + * Returns an internationalized string corresponding to the given key. + * + * @param key The key of the string. + * + * @return An internationalized string corresponding to the given key. + */ + public static String getString(String key) + { + try + { + return RESOURCE_BUNDLE.getString(key); + + } + catch (MissingResourceException e) { + + return '!' + key + '!'; + } + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java index 13f2b7efa..8b55e7913 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/ServerStoredContactListMsnImpl.java @@ -14,6 +14,7 @@ import net.sf.jml.*; import net.sf.jml.event.*; import net.sf.jml.impl.*; +import net.sf.jml.message.p2p.*; /** * This class encapsulates the Roster class. Once created, it will @@ -1202,6 +1203,25 @@ void setMessenger(MsnMessenger messenger) messenger.addContactListListener(new ContactListListener()); } + + /** + * when there is no image for contact we must retreive it + * add contacts for image update + * + * @param c ContactJabberImpl + */ + protected void addContactForImageUpdate(ContactMsnImpl c) + { + // Get the MSnObject + MsnObject avatar = c.getSourceContact().getAvatar(); + + if (avatar != null) + { + messenger.retrieveDisplayPicture( + avatar, + new ImageUpdater(c)); + } + } /** * used for debuging. Printing the serverside lists that msn supports @@ -1263,4 +1283,32 @@ public void printList() } logger.info("---=End Printing contact list=---"); } + + private class ImageUpdater + implements DisplayPictureListener + { + private ContactMsnImpl contact; + ImageUpdater(ContactMsnImpl contact) + { + this.contact = contact; + } + + public void notifyMsnObjectRetrieval(MsnMessenger arg0messenger, + DisplayPictureRetrieveWorker worker, + MsnObject msnObject, + ResultStatus result, + byte[] resultBytes, + Object context) + { + if (result == ResultStatus.GOOD) + { + contact.setImage(resultBytes); + + parentOperationSet.fireContactPropertyChangeEvent( + ContactPropertyChangeEvent.PROPERTY_IMAGE, + contact, null, resultBytes); + } + } + + } } diff --git a/src/net/java/sip/communicator/impl/protocol/msn/VolatileContact.java b/src/net/java/sip/communicator/impl/protocol/msn/VolatileContact.java index 31219eec7..19f7596e2 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/VolatileContact.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/VolatileContact.java @@ -56,4 +56,6 @@ public String getFriendlyName() public MsnUserStatus getOldStatus(){return null;} public String getPersonalMessage(){return "";} + + public MsnObject getAvatar(){return null;} } diff --git a/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/Base64InputStream.java b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/Base64InputStream.java new file mode 100644 index 000000000..785ff057c --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/Base64InputStream.java @@ -0,0 +1,184 @@ +/* + * Base64InputStream.java + * Copyright(C) 2002 The Free Software Foundation + * + * This file is part of GNU JavaMail, a library. + * + * GNU JavaMail is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + *(at your option) any later version. + * + * GNU JavaMail is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, if you link this library with other files to + * produce an executable, this library does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU General Public License. + */ + +package net.java.sip.communicator.impl.protocol.msn.mail.utils; + +import java.io.*; + +/** + * A Base64 content transfer encoding filter stream. + *

+ * From RFC 2045, section 6.8: + *

+ * The Base64 Content-Transfer-Encoding is designed to represent + * arbitrary sequences of octets in a form that need not be humanly + * readable. The encoding and decoding algorithms are simple, but the + * encoded data are consistently only about 33 percent larger than the + * unencoded data. + * + * @author Chris Burdess + */ +public class Base64InputStream + extends FilterInputStream +{ + + private byte[] buffer; + private int buflen; + private int index; + private byte[] decodeBuf; + + private static final char[] src = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' + }; + private static final byte[] dst; + + private static final int LF = 10, CR = 13, EQ = 61; + + static + { + dst = new byte[256]; + for (int i = 0; i<255; i++) + dst[i] = -1; + for (int i = 0; i=buflen) + { + decode(); + if (buflen==0) + return -1; + index = 0; + } + return buffer[index++] & 0xff; + } + + /** + * Reads up to len bytes of data from the input stream into an array of + * bytes. + */ + public int read(byte[] b, int off, int len) + throws IOException + { + try + { + int l = 0; + for (; l>>4 & 0x3); + if (decodeBuf[2]!=EQ) + { + b0 = b2; + b2 = dst[decodeBuf[2] & 0xff]; + buffer[buflen++] = (byte)(b0<<4 & 0xf0 | b2>>>2 & 0xf); + if (decodeBuf[3]!=EQ) + { + b0 = b2; + b2 = dst[decodeBuf[3] & 0xff]; + buffer[buflen++] = (byte)(b0<<6 & 0xc0 | b2 & 0x3f); + } + } + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/MimeUtility.java b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/MimeUtility.java new file mode 100644 index 000000000..71066dc46 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/MimeUtility.java @@ -0,0 +1,193 @@ +/* + * MimeUtility.java + * Copyright (C) 2002, 2004, 2005 The Free Software Foundation + * + * This file is part of GNU JavaMail, a library. + * + * GNU JavaMail is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNU JavaMail is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, if you link this library with other files to + * produce an executable, this library does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU General Public License. + */ + +package net.java.sip.communicator.impl.protocol.msn.mail.utils; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.StringTokenizer; + +/** + * This is a utility class providing micellaneous MIME-related functionality. + * + * @author Chris Burdess + * @version 1.4 + */ +public class MimeUtility +{ + + /* + * Uninstantiable. + */ + private MimeUtility() + { + } + + /** + * Decodes headers that are defined as '*text' in RFC 822. + * @param etext the possibly encoded value + * @exception UnsupportedEncodingException if the charset conversion failed + */ + public static String decodeText(String etext) + throws UnsupportedEncodingException + { + String delimiters = "\t\n\r "; + if (etext.indexOf("=?") == -1) + { + return etext; + } + StringTokenizer st = new StringTokenizer(etext, delimiters, true); + StringBuffer buffer = new StringBuffer(); + StringBuffer extra = new StringBuffer(); + boolean decoded = false; + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + char c = token.charAt(0); + if (delimiters.indexOf(c) > -1) + { + extra.append(c); + } + else + { + try + { + token = decodeWord(token); + if (!decoded && extra.length() > 0) + { + buffer.append(extra); + } + decoded = true; + } + catch (Exception e) + { + if (extra.length() > 0) + { + buffer.append(extra); + } + decoded = false; + } + buffer.append(token); + extra.setLength(0); + } + } + return buffer.toString(); + } + + /** + * Decodes the specified string using the RFC 2047 rules for parsing an + * "encoded-word". + * @param eword the possibly encoded value + * @exception Exception if the string is not an encoded-word + * @exception UnsupportedEncodingException if the decoding failed + */ + public static String decodeWord(String text) + throws Exception, UnsupportedEncodingException + { + if (!text.startsWith("=?")) + { + throw new Exception(); + } + int start = 2; + int end = text.indexOf('?', start); + if (end < 0) + { + throw new Exception(); + } + String charset = text.substring(start, end); + // Allow for RFC2231 language + int si = charset.indexOf('*'); + if (si != -1) + { + charset = charset.substring(0, si); + } + + start = end + 1; + end = text.indexOf('?', start); + if (end < 0) + { + throw new Exception(); + } + String encoding = text.substring(start, end); + start = end + 1; + end = text.indexOf("?=", start); + if (end < 0) + { + throw new Exception(); + } + text = text.substring(start, end); + try + { + // The characters in the remaining string must all be 7-bit clean. + // Therefore it is safe just to copy them verbatim into a byte array. + char[] chars = text.toCharArray(); + int len = chars.length; + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) + { + bytes[i] = (byte) chars[i]; + } + + ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + InputStream is; + if (encoding.equalsIgnoreCase("B")) + { + is = new Base64InputStream(bis); + } + else if (encoding.equalsIgnoreCase("Q")) + { + is = new QInputStream(bis); + } + else + { + throw new UnsupportedEncodingException("Unknown encoding: " + + encoding); + } + len = bis.available(); + bytes = new byte[len]; + len = is.read(bytes, 0, len); + String ret = new String(bytes, 0, len, charset); + if (text.length() > end + 2) + { + String extra = text.substring(end + 2); + + ret = ret + extra; + } + return ret; + } + catch (IOException e) + { + throw new Exception(); + } + catch (IllegalArgumentException e) + { + throw new UnsupportedEncodingException(); + } + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QInputStream.java b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QInputStream.java new file mode 100644 index 000000000..c8568020e --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QInputStream.java @@ -0,0 +1,104 @@ +/* + * QInputStream.java + * Copyright(C) 2002 The Free Software Foundation + * + * This file is part of GNU JavaMail, a library. + * + * GNU JavaMail is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + *(at your option) any later version. + * + * GNU JavaMail is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, if you link this library with other files to + * produce an executable, this library does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU General Public License. + */ + +package net.java.sip.communicator.impl.protocol.msn.mail.utils; + +import java.io.*; + +/** + * Provides RFC 2047 "B" transfer encoding. + * See section 4.2: + *

+ * The "Q" encoding is similar to the "Quoted-Printable" content- + * transfer-encoding defined in RFC 2045. It is designed to allow text + * containing mostly ASCII characters to be decipherable on an ASCII + * terminal without decoding. + *

    + *
  1. Any 8-bit value may be represented by a "=" followed by two + * hexadecimal digits. For example, if the character set in use + * were ISO-8859-1, the "=" character would thus be encoded as + * "=3D", and a SPACE by "=20". (Upper case should be used for + * hexadecimal digits "A" through "F".) + *
  2. The 8-bit hexadecimal value 20(e.g., ISO-8859-1 SPACE) may be + * represented as "_"(underscore, ASCII 95.). (This character may + * not pass through some internetwork mail gateways, but its use + * will greatly enhance readability of "Q" encoded data with mail + * readers that do not support this encoding.) Note that the "_" + * always represents hexadecimal 20, even if the SPACE character + * occupies a different code position in the character set in use. + *
  3. 8-bit values which correspond to printable ASCII characters other + * than "=", "?", and "_"(underscore), MAY be represented as those + * characters. (But see section 5 for restrictions.) In + * particular, SPACE and TAB MUST NOT be represented as themselves + * within encoded words. + * + * @author Chris Burdess + */ +public class QInputStream + extends QPInputStream +{ + + private static final int SPACE = 32; + private static final int EQ = 61; + private static final int UNDERSCORE = 95; + + /** + * Constructor. + * @param in the underlying input stream. + */ + public QInputStream(InputStream in) + { + super(in); + } + + /** + * Read a character. + */ + public int read() + throws IOException + { + int c = in.read(); + if (c==UNDERSCORE) + return SPACE; + if (c==EQ) + { + buf[0] = (byte)in.read(); + buf[1] = (byte)in.read(); + try + { + return Integer.parseInt(new String(buf, 0, 2), 16); + } + catch (NumberFormatException e) + { + throw new IOException("Quoted-Printable encoding error: "+ + e.getMessage()); + } + } + return c; + } + +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QPInputStream.java b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QPInputStream.java new file mode 100644 index 000000000..3abe72c9f --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/mail/utils/QPInputStream.java @@ -0,0 +1,167 @@ +/* + * QPInputStream.java + * Copyright(C) 2002 The Free Software Foundation + * + * This file is part of GNU JavaMail, a library. + * + * GNU JavaMail is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + *(at your option) any later version. + * + * GNU JavaMail is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * As a special exception, if you link this library with other files to + * produce an executable, this library does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * This exception does not however invalidate any other reasons why the + * executable file might be covered by the GNU General Public License. + */ + +package net.java.sip.communicator.impl.protocol.msn.mail.utils; + +import java.io.*; + +/** + * A Quoted-Printable decoder stream. + * + * @author Chris Burdess + */ +public class QPInputStream + extends FilterInputStream +{ + + protected byte[] buf; + + /** + * The number of times read() will return a space. + */ + protected int spaceCount; + + private static final int LF = 10; + private static final int CR = 13; + private static final int SPACE = 32; + private static final int EQ = 61; + + /** + * Constructor. + * @param in the underlying input stream. + */ + public QPInputStream(InputStream in) + { + super(new PushbackInputStream(in, 2)); + buf = new byte[2]; + } + + /** + * Read a character from the stream. + */ + public int read() + throws IOException + { + if (spaceCount>0) + { + spaceCount--; + return SPACE; + } + + int c = in.read(); + if (c==SPACE) + { + while ((c = in.read())==SPACE) + spaceCount++; + if (c==LF || c==CR || c==-1) + spaceCount = 0; + else + { + ((PushbackInputStream)in).unread(c); + c = SPACE; + } + return c; + } + if (c==EQ) + { + int c2 = super.in.read(); + if (c2==LF) + return read(); + if (c2==CR) + { + int peek = in.read(); + if (peek!=LF) + ((PushbackInputStream)in).unread(peek); + return read(); + } + if (c2==-1) + return c2; + + buf[0] = (byte)c2; + buf[1] = (byte)in.read(); + try + { + return Integer.parseInt(new String(buf, 0, 2), 16); + } + catch (NumberFormatException e) + { + ((PushbackInputStream)in).unread(buf); + } + return c; + } + else + return c; + } + + /** + * Reads from the underlying stream into the specified byte array. + */ + public int read(byte[] bytes, int off, int len) + throws IOException + { + int pos = 0; + try + { + while (pos