diff --git a/mailnews/addrbook/src/nsAbBaseCID.h b/mailnews/addrbook/src/nsAbBaseCID.h index 697c705d919..0eae38af9b5 100644 --- a/mailnews/addrbook/src/nsAbBaseCID.h +++ b/mailnews/addrbook/src/nsAbBaseCID.h @@ -451,4 +451,11 @@ #define NS_MSGVCARDSERVICE_CONTRACTID \ "@mozilla.org/addressbook/msgvcardservice;1" +#define NS_MSGVCARDSTREAMLISTENER_CID \ +{ 0xf4045da, 0x6187, 0x42ff, \ + { 0x9d, 0xf4, 0x80, 0x65, 0x44, 0xf, 0x76, 0x21 }} + +#define NS_MSGVCARDSTREAMLISTENER_CONTRACTID \ + "@mozilla.org/addressbook/msgvcardstreamlistener;1" + #endif // nsAbBaseCID_h__ diff --git a/mailnews/addrbook/src/nsAddressBook.cpp b/mailnews/addrbook/src/nsAddressBook.cpp index 8ea97eea4aa..7c626a79404 100644 --- a/mailnews/addrbook/src/nsAddressBook.cpp +++ b/mailnews/addrbook/src/nsAddressBook.cpp @@ -86,6 +86,8 @@ #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIDocShell.h" +#include "nsNetCID.h" +#include "nsIIOService.h" // according to RFC 2849 // SEP = (CR LF / LF) @@ -2065,10 +2067,36 @@ NS_IMETHODIMP nsAddressBook::HandleContent(const char * aContentType, rv = NS_OK; } } - else { - // The content-type was not x-application-addvcard... - return NS_ERROR_WONT_HANDLE_CONTENT; + else if (nsCRT::strcasecmp(aContentType, "text/x-vcard") == 0) { + // create a vcard stream listener that can parse the data stream + // and bring up the appropriate UI + + // (1) cancel the current load operation. We'll restart it + request->Cancel(NS_ERROR_ABORT); + // get the url we were trying to open + nsCOMPtr uri; + nsCOMPtr channel = do_QueryInterface(request); + NS_ENSURE_TRUE(channel, NS_ERROR_FAILURE); + + rv = channel->GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, rv); + + // create a stream listener to handle the v-card data + nsCOMPtr strListener = do_CreateInstance(NS_MSGVCARDSTREAMLISTENER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, NS_ERROR_WONT_HANDLE_CONTENT); // no registered v-card handler so just return that we won't handle the content + + // create a new channel and run the url again + nsCOMPtr netService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = netService->NewChannelFromURI(uri, getter_AddRefs(channel)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = channel->AsyncOpen(strListener, aWindowContext); + } + else // The content-type was not x-application-addvcard... + return NS_ERROR_WONT_HANDLE_CONTENT; return rv; } diff --git a/mailnews/addrbook/src/nsMsgVCardService.cpp b/mailnews/addrbook/src/nsMsgVCardService.cpp index 566bc35c79f..c0965b5dd66 100644 --- a/mailnews/addrbook/src/nsMsgVCardService.cpp +++ b/mailnews/addrbook/src/nsMsgVCardService.cpp @@ -36,9 +36,21 @@ * ***** END LICENSE BLOCK ***** */ #include "nsMsgVCardService.h" +#include "nsIDOMWindowInternal.h" + +#include "nsVCardObj.h" +#include "nsISupportsPrimitives.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIAbCard.h" +#include "nsIAddressBook.h" +#include "nsAbBaseCID.h" + #include "prmem.h" #include "plstr.h" +#define FOUR_K 4096 + NS_IMPL_ISUPPORTS1(nsMsgVCardService, nsIMsgVCardService) nsMsgVCardService::nsMsgVCardService() @@ -106,3 +118,103 @@ NS_IMETHODIMP_(char *) nsMsgVCardService::VObjectAnyValue(VObject * o) PL_strcpy(retval, (char *) vObjectAnyValue(o)); return retval; } + +// helper class used to process a stream of vcard data + +NS_IMPL_ISUPPORTS1(nsMsgVCardStreamListener, nsIStreamListener) + +nsMsgVCardStreamListener::nsMsgVCardStreamListener() +{ + m_dataBuffer = nsnull; +} + +nsMsgVCardStreamListener::~nsMsgVCardStreamListener() +{ + PR_Free(m_dataBuffer); +} + +NS_IMETHODIMP +nsMsgVCardStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aSupport) +{ + if (!m_dataBuffer) + m_dataBuffer = (char*) PR_CALLOC(FOUR_K+1); + return NS_OK; +} + +NS_IMETHODIMP +nsMsgVCardStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aSupport, + nsresult status) +{ + NS_ENSURE_ARG_POINTER(aSupport); + NS_ENSURE_SUCCESS(status, status); // don't process the vcard if we got a status error + nsresult rv = NS_OK; + + // take our vCard string and open up an address book window based on it + nsCOMPtr vCardService = do_GetService(NS_MSGVCARDSERVICE_CONTRACTID); + if (vCardService) + { + VObject * vObj = vCardService->Parse_MIME(mVCardData.get(), mVCardData.Length()); + if (vObj) + { + nsCAutoString vCard; + int len = 0; + + vCard.Adopt(vCardService->WriteMemoryVObjects(0, &len, vObj, PR_FALSE)); + delete vObj; + + nsCOMPtr parentWindow = do_GetInterface(aSupport); + NS_ENSURE_TRUE(parentWindow, NS_ERROR_FAILURE); + + nsCOMPtr addressbook = do_CreateInstance(NS_ADDRESSBOOK_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr cardFromVCard; + rv = addressbook->EscapedVCardToAbCard(vCard.get(), getter_AddRefs(cardFromVCard)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr ifptr = do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + ifptr->SetData(cardFromVCard); + ifptr->SetDataIID(&NS_GET_IID(nsIAbCard)); + + nsCOMPtr dialogWindow; + + rv = parentWindow->OpenDialog( + NS_LITERAL_STRING("chrome://messenger/content/addressbook/abNewCardDialog.xul"), + EmptyString(), + NS_LITERAL_STRING("chrome,resizable=no,titlebar,modal,centerscreen"), + ifptr, getter_AddRefs(dialogWindow)); + } + } + + PR_FREEIF(m_dataBuffer); + + return rv; +} + +NS_IMETHODIMP nsMsgVCardStreamListener::OnDataAvailable(nsIRequest* request, nsISupports* aSupport, + nsIInputStream* inStream, + PRUint32 srcOffset, + PRUint32 count) +{ + PRUint32 available, readCount, maxReadCount = FOUR_K; + PRUint32 writeCount; + nsresult rv = inStream->Available(&available); + while (NS_SUCCEEDED(rv) && available) + { + if (maxReadCount > available) + maxReadCount = available; + memset(m_dataBuffer, 0, FOUR_K+1); + rv = inStream->Read(m_dataBuffer, maxReadCount, &readCount); + + if (NS_SUCCEEDED(rv)) + { + // m_dataBuffer is null terminated so we can safely just append it to our vcard string + mVCardData += m_dataBuffer; + available -= readCount; + } + } + + return rv; +} diff --git a/mailnews/addrbook/src/nsMsgVCardService.h b/mailnews/addrbook/src/nsMsgVCardService.h index 847f42a8e14..cba2646d7f7 100644 --- a/mailnews/addrbook/src/nsMsgVCardService.h +++ b/mailnews/addrbook/src/nsMsgVCardService.h @@ -40,6 +40,7 @@ #include "nsIMsgVCardService.h" #include "nsISupports.h" +#include "nsIStreamListener.h" class nsMsgVCardService : public nsIMsgVCardService { @@ -51,4 +52,23 @@ public: virtual ~nsMsgVCardService(); }; +// a helper class for the vcard service which can process a vcard as an incoming +// stream and open it. + +class nsMsgVCardStreamListener : public nsIStreamListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSIREQUESTOBSERVER + + nsMsgVCardStreamListener(); + virtual ~nsMsgVCardStreamListener(); + +protected: + char *m_dataBuffer; + nsCString mVCardData; + +}; + #endif /* nsMsgVCardService_h___ */ diff --git a/mailnews/build/nsMailModule.cpp b/mailnews/build/nsMailModule.cpp index eed8849ae42..5f1aaed4883 100644 --- a/mailnews/build/nsMailModule.cpp +++ b/mailnews/build/nsMailModule.cpp @@ -139,7 +139,7 @@ #include "nsAbDirectoryQuery.h" #include "nsAbBooleanExpression.h" #include "nsAbDirectoryQueryProxy.h" -#include "nsAbView.h" +#include "nsAbView.h" #include "nsMsgVCardService.h" #if defined(MOZ_LDAP_XPCOM) @@ -372,8 +372,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbLDAPProcessChangeLogData) #endif NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbDirectoryQueryProxy) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsAbView) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardService) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgVCardStreamListener) //////////////////////////////////////////////////////////////////////////////// // bayesian spam filter factories @@ -802,8 +803,9 @@ static const nsModuleComponentInfo gComponents[] = { { "The addbook URL Interface", NS_ADDBOOKURL_CID, NS_ADDBOOKURL_CONTRACTID, nsAddbookUrlConstructor }, { "The addbook Protocol Handler", NS_ADDBOOK_HANDLER_CID, - NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "addbook", nsAddbookProtocolHandlerConstructor }, - { "add vCard content handler", NS_ADDRESSBOOK_CID, NS_CONTENT_HANDLER_CONTRACTID_PREFIX"x-application-addvcard", nsAddressBookConstructor }, + NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "addbook", nsAddbookProtocolHandlerConstructor }, + { "add vCard content handler", NS_ADDRESSBOOK_CID, NS_CONTENT_HANDLER_CONTRACTID_PREFIX"x-application-addvcard", nsAddressBookConstructor }, + { "add vCard content handler", NS_ADDRESSBOOK_CID, NS_CONTENT_HANDLER_CONTRACTID_PREFIX"text/x-vcard", nsAddressBookConstructor }, { "The directory factory service interface", NS_ABDIRFACTORYSERVICE_CID, NS_ABDIRFACTORYSERVICE_CONTRACTID, nsAbDirFactoryServiceConstructor }, @@ -849,8 +851,10 @@ static const nsModuleComponentInfo gComponents[] = { #endif { "The directory query proxy interface", NS_ABDIRECTORYQUERYPROXY_CID, NS_ABDIRECTORYQUERYPROXY_CONTRACTID, nsAbDirectoryQueryProxyConstructor}, - { "addressbook view", NS_ABVIEW_CID, NS_ABVIEW_CONTRACTID, nsAbViewConstructor}, + { "addressbook view", NS_ABVIEW_CID, NS_ABVIEW_CONTRACTID, nsAbViewConstructor}, { "vcard helper service", NS_MSGVCARDSERVICE_CID, NS_MSGVCARDSERVICE_CONTRACTID, nsMsgVCardServiceConstructor }, + { "vcard stream listener", NS_MSGVCARDSTREAMLISTENER_CID, NS_MSGVCARDSTREAMLISTENER_CONTRACTID, + nsMsgVCardStreamListenerConstructor }, //////////////////////////////////////////////////////////////////////////////// // bayesian spam filter components