Issue #1258 - Part 1: Import mailnews, ldap, and mork from comm-esr52.9.1

This commit is contained in:
Matt A. Tobin 2019-11-03 00:17:46 -04:00 • committed by Roy Tam
commit e400f4130a
1564 changed files with 510348 additions and 0 deletions

View file

@ -0,0 +1,27 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'nsNewsDownloadDialogArgs.cpp',
'nsNewsDownloader.cpp',
'nsNewsFolder.cpp',
'nsNewsUtils.cpp',
'nsNNTPArticleList.cpp',
'nsNntpIncomingServer.cpp',
'nsNntpMockChannel.cpp',
'nsNNTPNewsgroupList.cpp',
'nsNNTPNewsgroupPost.cpp',
'nsNNTPProtocol.cpp',
'nsNntpService.cpp',
'nsNntpUrl.cpp',
]
EXTRA_COMPONENTS += [
'nsNewsAutoCompleteSearch.js',
'nsNewsAutoCompleteSearch.manifest',
]
FINAL_LIBRARY = 'mail'

View file

@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _NNTPCore_H__
#define _NNTPCore_H__
#define NEWS_MSGS_URL "chrome://messenger/locale/news.properties"
// The following string constants are protocol strings. I'm defining them as macros here
// so I don't have to sprinkle all of the strings throughout the protocol.
#define NNTP_CMD_LIST_EXTENSIONS "LIST EXTENSIONS" CRLF
#define NNTP_CMD_MODE_READER "MODE READER" CRLF
#define NNTP_CMD_LIST_SEARCHES "LIST SEARCHES" CRLF
#define NNTP_CMD_LIST_SEARCH_FIELDS "LIST SRCHFIELDS" CRLF
#define NNTP_CMD_GET_PROPERTIES "GET" CRLF
#define NNTP_CMD_LIST_SUBSCRIPTIONS "LIST SUBSCRIPTIONS" CRLF
#define NNTP_CMD_POST "POST" CRLF
#define NNTP_CMD_QUIT "QUIT" CRLF
// end of protocol strings
#define MK_NNTP_RESPONSE_HELP 100
#define MK_NNTP_RESPONSE_POSTING_ALLOWED 200
#define MK_NNTP_RESPONSE_POSTING_DENIED 201
#define MK_NNTP_RESPONSE_DISCONTINUED 400
#define MK_NNTP_RESPONSE_COMMAND_UNKNOWN 500
#define MK_NNTP_RESPONSE_SYNTAX_ERROR 501
#define MK_NNTP_RESPONSE_PERMISSION_DENIED 502
#define MK_NNTP_RESPONSE_SERVER_ERROR 503
#define MK_NNTP_RESPONSE_ARTICLE_BOTH 220
#define MK_NNTP_RESPONSE_ARTICLE_HEAD 221
#define MK_NNTP_RESPONSE_ARTICLE_BODY 222
#define MK_NNTP_RESPONSE_ARTICLE_NONE 223
#define MK_NNTP_RESPONSE_ARTICLE_NO_GROUP 412
#define MK_NNTP_RESPONSE_ARTICLE_NO_CURRENT 420
#define MK_NNTP_RESPONSE_ARTICLE_NONEXIST 423
#define MK_NNTP_RESPONSE_ARTICLE_NOTFOUND 430
#define MK_NNTP_RESPONSE_GROUP_SELECTED 211
#define MK_NNTP_RESPONSE_GROUP_NO_GROUP 411
#define MK_NNTP_RESPONSE_IHAVE_OK 235
#define MK_NNTP_RESPONSE_IHAVE_ARTICLE 335
#define MK_NNTP_RESPONSE_IHAVE_NOT_WANTED 435
#define MK_NNTP_RESPONSE_IHAVE_FAILED 436
#define MK_NNTP_RESPONSE_IHAVE_REJECTED 437
#define MK_NNTP_RESPONSE_LAST_OK 223
#define MK_NNTP_RESPONSE_LAST_NO_GROUP 412
#define MK_NNTP_RESPONSE_LAST_NO_CURRENT 420
#define MK_NNTP_RESPONSE_LAST_NO_ARTICLE 422
#define MK_NNTP_RESPONSE_LIST_OK 215
#define MK_NNTP_RESPONSE_NEWGROUPS_OK 231
#define MK_NNTP_RESPONSE_NEWNEWS_OK 230
#define MK_NNTP_RESPONSE_NEXT_OK 223
#define MK_NNTP_RESPONSE_NEXT_NO_GROUP 412
#define MK_NNTP_RESPONSE_NEXT_NO_CURRENT 420
#define MK_NNTP_RESPONSE_NEXT_NO_ARTICLE 421
#define MK_NNTP_RESPONSE_POST_OK 240
#define MK_NNTP_RESPONSE_POST_SEND_NOW 340
#define MK_NNTP_RESPONSE_POST_DENIED 440
#define MK_NNTP_RESPONSE_POST_FAILED 441
#define MK_NNTP_RESPONSE_QUIT_OK 205
#define MK_NNTP_RESPONSE_SLAVE_OK 202
#define MK_NNTP_RESPONSE_CHECK_NO_ARTICLE 238
#define MK_NNTP_RESPONSE_CHECK_NO_ACCEPT 400
#define MK_NNTP_RESPONSE_CHECK_LATER 431
#define MK_NNTP_RESPONSE_CHECK_DONT_SEND 438
#define MK_NNTP_RESPONSE_CHECK_DENIED 480
#define MK_NNTP_RESPONSE_CHECK_ERROR 500
#define MK_NNTP_RESPONSE_XHDR_OK 221
#define MK_NNTP_RESPONSE_XHDR_NO_GROUP 412
#define MK_NNTP_RESPONSE_XHDR_NO_CURRENT 420
#define MK_NNTP_RESPONSE_XHDR_NO_ARTICLE 430
#define MK_NNTP_RESPONSE_XHDR_DENIED 502
#define MK_NNTP_RESPONSE_XOVER_OK 224
#define MK_NNTP_RESPONSE_XOVER_NO_GROUP 412
#define MK_NNTP_RESPONSE_XOVER_NO_CURRENT 420
#define MK_NNTP_RESPONSE_XOVER_DENIED 502
#define MK_NNTP_RESPONSE_XPAT_OK 221
#define MK_NNTP_RESPONSE_XPAT_NO_ARTICLE 430
#define MK_NNTP_RESPONSE_XPAT_DENIED 502
#define MK_NNTP_RESPONSE_AUTHINFO_OK 281
#define MK_NNTP_RESPONSE_AUTHINFO_CONT 381
#define MK_NNTP_RESPONSE_AUTHINFO_REQUIRE 480
#define MK_NNTP_RESPONSE_AUTHINFO_REJECT 482
#define MK_NNTP_RESPONSE_AUTHINFO_DENIED 502
#define MK_NNTP_RESPONSE_
#define MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_OK 250
#define MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_CONT 350
#define MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_REQUIRE 450
#define MK_NNTP_RESPONSE_AUTHINFO_SIMPLE_REJECT 452
#define MK_NNTP_RESPONSE_TYPE_INFO 1
#define MK_NNTP_RESPONSE_TYPE_OK 2
#define MK_NNTP_RESPONSE_TYPE_CONT 3
#define MK_NNTP_RESPONSE_TYPE_CANNOT 4
#define MK_NNTP_RESPONSE_TYPE_ERROR 5
#define MK_NNTP_RESPONSE_TYPE(x) (x/100)
// the following used to be defined in allxpstr.h. Until we find a new values for these,
// I'm defining them here because I don't want to link against xplib.lib...(mscott)
#define MK_DATA_LOADED 1
#define MK_EMPTY_NEWS_LIST -227
#define MK_INTERRUPTED -201
#define MK_MALFORMED_URL_ERROR -209
#define MK_NEWS_ERROR_FMT -430
#define MK_NNTP_CANCEL_CONFIRM -426
#define MK_NNTP_CANCEL_DISALLOWED -427
#define MK_NNTP_NOT_CANCELLED -429
#define MK_OUT_OF_MEMORY -207
#define XP_CONFIRM_SAVE_NEWSGROUPS -1
#define XP_HTML_ARTICLE_EXPIRED -1
#define XP_HTML_NEWS_ERROR -1
#define XP_PROGRESS_READ_NEWSGROUPINFO 1
#define XP_PROGRESS_RECEIVE_ARTICLE 1
#define XP_PROGRESS_RECEIVE_LISTARTICLES 1
#define XP_PROGRESS_RECEIVE_NEWSGROUP 1
#define XP_PROGRESS_SORT_ARTICLES 1
#define XP_PROGRESS_READ_NEWSGROUP_COUNTS 1
#define XP_THERMO_PERCENT_FORM 1
#define XP_PROMPT_ENTER_USERNAME 1
#define MK_NNTP_AUTH_FAILED -260
#define MK_NNTP_ERROR_MESSAGE -304
#define MK_NNTP_NEWSGROUP_SCAN_ERROR -305
#define MK_NNTP_SERVER_ERROR -217
#define MK_NNTP_SERVER_NOT_CONFIGURED -307
#define MK_TCP_READ_ERROR -252
#define MK_TCP_WRITE_ERROR -236
#define MK_NNTP_CANCEL_ERROR -428
#define XP_CONNECT_NEWS_HOST_CONTACTED_WAITING_FOR_REPLY 1
#define XP_PLEASE_ENTER_A_PASSWORD_FOR_NEWS_SERVER_ACCESS 1
#define XP_GARBAGE_COLLECTING 1
#define XP_MESSAGE_SENT_WAITING_NEWS_REPLY 1
#define MK_MSG_DELIV_NEWS 1
#define MK_MSG_COLLABRA_DISABLED 1
#define MK_MSG_EXPIRE_NEWS_ARTICLES 1
#define MK_MSG_HTML_IMAP_NO_CACHED_BODY 1
#define MK_MSG_CANT_MOVE_FOLDER 1
#endif /* NNTPCore_H__ */

View file

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h" // precompiled header...
#include "nsCOMPtr.h"
#include "nsNNTPArticleList.h"
#include "nsIMsgFolder.h"
#include "nsAutoPtr.h"
#include "nsMsgKeyArray.h"
NS_IMPL_ISUPPORTS(nsNNTPArticleList, nsINNTPArticleList)
nsNNTPArticleList::nsNNTPArticleList()
{
}
nsNNTPArticleList::~nsNNTPArticleList()
{
if (m_newsDB) {
m_newsDB->Commit(nsMsgDBCommitType::kSessionCommit);
m_newsDB->Close(true);
m_newsDB = nullptr;
}
m_newsFolder = nullptr;
}
NS_IMETHODIMP
nsNNTPArticleList::Initialize(nsIMsgNewsFolder *newsFolder)
{
nsresult rv;
NS_ENSURE_ARG_POINTER(newsFolder);
m_dbIndex = 0;
m_newsFolder = newsFolder;
nsCOMPtr <nsIMsgFolder> folder = do_QueryInterface(m_newsFolder, &rv);
NS_ENSURE_SUCCESS(rv,rv);
rv = folder->GetMsgDatabase(getter_AddRefs(m_newsDB));
NS_ENSURE_SUCCESS(rv,rv);
if (!m_newsDB) return NS_ERROR_UNEXPECTED;
RefPtr<nsMsgKeyArray> keys = new nsMsgKeyArray;
rv = m_newsDB->ListAllKeys(keys);
NS_ENSURE_SUCCESS(rv,rv);
keys->Sort();
m_idsInDB.AppendElements(keys->m_keys);
return NS_OK;
}
NS_IMETHODIMP
nsNNTPArticleList::AddArticleKey(nsMsgKey key)
{
#ifdef DEBUG
m_idsOnServer.AppendElement(key);
#endif
if (m_dbIndex < m_idsInDB.Length())
{
nsMsgKey idInDBToCheck = m_idsInDB[m_dbIndex];
// if there are keys in the database that aren't in the newsgroup
// on the server, remove them. We probably shouldn't do this if
// we have a copy of the article offline.
// We'll add to m_idsDeleted for now and remove the id later
while (idInDBToCheck < key)
{
m_idsDeleted.AppendElement(idInDBToCheck);
if (m_dbIndex >= m_idsInDB.Length())
break;
idInDBToCheck = m_idsInDB[++m_dbIndex];
}
if (idInDBToCheck == key)
m_dbIndex++;
}
return NS_OK;
}
NS_IMETHODIMP
nsNNTPArticleList::FinishAddingArticleKeys()
{
// if the last n messages in the group are cancelled, they won't have gotten removed
// so we have to go and remove them now.
if (m_dbIndex < m_idsInDB.Length())
m_idsDeleted.AppendElements(&m_idsInDB[m_dbIndex],
m_idsInDB.Length() - m_dbIndex);
if (m_idsDeleted.Length())
m_newsFolder->RemoveMessages(m_idsDeleted);
#ifdef DEBUG
// make sure none of the deleted turned up on the idsOnServer list
for (uint32_t i = 0; i < m_idsDeleted.Length(); i++) {
NS_ASSERTION(!m_idsOnServer.Contains((nsMsgKey)m_idsDeleted[i]),
"a deleted turned up on the idsOnServer list");
}
#endif
return NS_OK;
}

View file

@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNNTPArticleList_h___
#define nsNNTPArticleList_h___
#include "nsCOMPtr.h"
#include "nsINNTPArticleList.h"
#include "nsIMsgNewsFolder.h"
#include "nsIMsgDatabase.h"
#include "MailNewsTypes.h"
#include "nsTArray.h"
class nsNNTPArticleList : public nsINNTPArticleList
{
public:
nsNNTPArticleList();
NS_DECL_ISUPPORTS
NS_DECL_NSINNTPARTICLELIST
protected:
virtual ~nsNNTPArticleList();
nsTArray<nsMsgKey> m_idsInDB;
#ifdef DEBUG
nsTArray<nsMsgKey> m_idsOnServer;
#endif
nsTArray<nsMsgKey> m_idsDeleted;
nsCOMPtr <nsIMsgNewsFolder> m_newsFolder;
nsCOMPtr <nsIMsgDatabase> m_newsDB;
uint32_t m_dbIndex;
};
#endif /* nsNNTPArticleList_h___ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,124 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* formerly listngst.h
* This class should ultimately be part of a news group listing
* state machine - either by inheritance or delegation.
* Currently, a folder pane owns one and libnet news group listing
* related messages get passed to this object.
*/
#ifndef nsNNTPNewsgroupListState_h___
#define nsNNTPNewsgroupListState_h___
#include "nsINNTPNewsgroupList.h"
#include "nsIMsgNewsFolder.h"
#include "nsIMsgDatabase.h"
#include "nsMsgKeySet.h"
#include "nsINntpUrl.h"
#include "nsIMsgFilterList.h"
#include "nsIMsgHdr.h"
#include "nsIMsgWindow.h"
#include "nsCOMArray.h"
#include "nsTArray.h"
/* The below is all stuff that we remember for netlib about which
articles we've already seen in the current newsgroup. */
typedef struct MSG_NewsKnown {
nsMsgKeySet* set; /* Set of articles we've already gotten
from the newsserver (if it's marked
"read", then we've already gotten it).
If an article is marked "read", it
doesn't mean we're actually displaying
it; it may be an article that no longer
exists, or it may be one that we've
marked read and we're only viewing
unread messages. */
int32_t first_possible; /* The oldest article in this group. */
int32_t last_possible; /* The newest article in this group. */
bool shouldGetOldest;
} MSG_NewsKnown;
// This class should ultimately be part of a news group listing
// state machine - either by inheritance or delegation.
// Currently, a folder pane owns one and libnet news group listing
// related messages get passed to this object.
class nsNNTPNewsgroupList : public nsINNTPNewsgroupList, public nsIMsgFilterHitNotify
#ifdef HAVE_CHANGELISTENER
/* ,public ChangeListener */
#endif
{
public:
nsNNTPNewsgroupList();
NS_DECL_ISUPPORTS
NS_DECL_NSINNTPNEWSGROUPLIST
NS_DECL_NSIMSGFILTERHITNOTIFY
private:
virtual ~nsNNTPNewsgroupList();
NS_METHOD CleanUp();
bool m_finishingXover;
#ifdef HAVE_CHANGELISTENER
virtual void OnAnnouncerGoingAway (ChangeAnnouncer *instigator);
#endif
nsresult ParseLine(char *line, uint32_t *message_number);
nsresult GetDatabase(const char *uri, nsIMsgDatabase **db);
void SetProgressBarPercent(int32_t percent);
void SetProgressStatus(const char16_t *aMessage);
void UpdateStatus(bool filtering, int32_t numDled, int32_t totToDL);
nsresult AddHeader(const char * header, const char * value);
protected:
bool m_getOldMessages;
bool m_promptedAlready;
bool m_downloadAll;
int32_t m_maxArticles;
int32_t m_lastPercent;
PRTime m_lastStatusUpdate;
nsCOMPtr <nsIMsgNewsFolder> m_newsFolder;
nsCOMPtr <nsIMsgDatabase> m_newsDB;
nsCOMPtr <nsINntpUrl> m_runningURL;
/**
* The last message that we have processed (XOVER or HEAD).
*/
nsMsgKey m_lastProcessedNumber;
/**
* The endpoints of the message chunk we are actually downloading.
*/
nsMsgKey m_firstMsgNumber, m_lastMsgNumber;
/**
* The endpoints of the message chunk we are capable of downloading.
*/
int32_t m_firstMsgToDownload, m_lastMsgToDownload;
struct MSG_NewsKnown m_knownArts;
nsMsgKeySet *m_set;
nsTArray<nsCString> m_filterHeaders;
uint32_t m_currentXHDRIndex;
nsCString m_lastHeader;
nsCString m_thisLine;
private:
nsCOMPtr <nsIMsgWindow> m_msgWindow;
nsCOMPtr <nsIMsgFilterList> m_filterList;
nsCOMPtr <nsIMsgFilterList> m_serverFilterList;
nsCOMPtr <nsIMsgDBHdr> m_newMsgHdr; // current message header we're building
nsCOMArray<nsIMsgDBHdr> m_newHeaders;
bool m_addHdrToDB;
};
#endif /* nsNNTPNewsgroupListState_h___ */

View file

@ -0,0 +1,94 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h" // precompiled header...
#include "nsNNTPNewsgroupPost.h"
NS_IMPL_ISUPPORTS(nsNNTPNewsgroupPost, nsINNTPNewsgroupPost)
nsNNTPNewsgroupPost::nsNNTPNewsgroupPost()
{
m_isControl=false;
}
nsNNTPNewsgroupPost::~nsNNTPNewsgroupPost()
{
}
#define IMPL_GETSET(attribute, member) \
NS_IMETHODIMP nsNNTPNewsgroupPost::Get##attribute(char **result) \
{ \
NS_ENSURE_ARG_POINTER(result); \
*result = ToNewCString(member); \
return NS_OK; \
} \
NS_IMETHODIMP nsNNTPNewsgroupPost::Set##attribute(const char *aValue) \
{ \
member.Assign(aValue); \
return NS_OK; \
}
IMPL_GETSET(RelayVersion, m_header[IDX_HEADER_RELAYVERSION])
IMPL_GETSET(PostingVersion, m_header[IDX_HEADER_POSTINGVERSION])
IMPL_GETSET(From, m_header[IDX_HEADER_FROM])
IMPL_GETSET(Date, m_header[IDX_HEADER_DATE])
IMPL_GETSET(Subject, m_header[IDX_HEADER_SUBJECT])
IMPL_GETSET(Path, m_header[IDX_HEADER_PATH])
IMPL_GETSET(ReplyTo, m_header[IDX_HEADER_REPLYTO])
IMPL_GETSET(Sender, m_header[IDX_HEADER_SENDER])
IMPL_GETSET(FollowupTo, m_header[IDX_HEADER_FOLLOWUPTO])
IMPL_GETSET(DateReceived, m_header[IDX_HEADER_DATERECEIVED])
IMPL_GETSET(Expires, m_header[IDX_HEADER_EXPIRES])
IMPL_GETSET(Control, m_header[IDX_HEADER_CONTROL])
IMPL_GETSET(Distribution, m_header[IDX_HEADER_DISTRIBUTION])
IMPL_GETSET(Organization, m_header[IDX_HEADER_ORGANIZATION])
IMPL_GETSET(Body, m_body)
NS_IMETHODIMP nsNNTPNewsgroupPost::GetNewsgroups(char **result)
{
NS_ENSURE_ARG_POINTER(result);
*result = ToNewCString(m_header[IDX_HEADER_NEWSGROUPS]);
return NS_OK;
}
NS_IMETHODIMP nsNNTPNewsgroupPost::GetReferences(char **result)
{
NS_ENSURE_ARG_POINTER(result);
*result = ToNewCString(m_header[IDX_HEADER_REFERENCES]);
return NS_OK;
}
NS_IMETHODIMP nsNNTPNewsgroupPost::GetIsControl(bool *result)
{
NS_ENSURE_ARG_POINTER(result);
*result = m_isControl;
return NS_OK;
}
nsresult
nsNNTPNewsgroupPost::AddNewsgroup(const char *newsgroup)
{
m_header[IDX_HEADER_NEWSGROUPS].AppendLiteral(", ");
m_header[IDX_HEADER_NEWSGROUPS].Append(newsgroup);
return NS_OK;
}
// the message can be stored in a file....allow accessors for getting and setting
// the file name to post...
nsresult
nsNNTPNewsgroupPost::SetPostMessageFile(nsIFile * aPostMessageFile)
{
m_postMessageFile = aPostMessageFile;
return NS_OK;
}
nsresult
nsNNTPNewsgroupPost::GetPostMessageFile(nsIFile ** aPostMessageFile)
{
if (aPostMessageFile)
NS_IF_ADDREF(*aPostMessageFile = m_postMessageFile);
return NS_OK;
}

View file

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsNNTPNewsgroupPost_h
#define __nsNNTPNewsgroupPost_h
#include "msgCore.h"
#include "nsINNTPNewsgroupPost.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
#include "nsIFile.h"
#define IDX_HEADER_FROM 0
#define IDX_HEADER_NEWSGROUPS 1
#define IDX_HEADER_SUBJECT 2
// set this to the last required header
#define IDX_HEADER_LAST_REQUIRED IDX_HEADER_SUBJECT
#define IDX_HEADER_PATH 3
#define IDX_HEADER_DATE 4
#define IDX_HEADER_REPLYTO 5
#define IDX_HEADER_SENDER 6
#define IDX_HEADER_FOLLOWUPTO 7
#define IDX_HEADER_DATERECEIVED 8
#define IDX_HEADER_EXPIRES 9
#define IDX_HEADER_CONTROL 10
#define IDX_HEADER_DISTRIBUTION 11
#define IDX_HEADER_ORGANIZATION 12
#define IDX_HEADER_REFERENCES 13
// stuff that's required to be in the message,
// but probably generated on the server
#define IDX_HEADER_RELAYVERSION 14
#define IDX_HEADER_POSTINGVERSION 15
#define IDX_HEADER_MESSAGEID 16
// keep this in sync with the above
#define HEADER_LAST IDX_HEADER_MESSAGEID
class nsNNTPNewsgroupPost : public nsINNTPNewsgroupPost {
public:
nsNNTPNewsgroupPost();
NS_DECL_ISUPPORTS
NS_DECL_NSINNTPNEWSGROUPPOST
private:
virtual ~nsNNTPNewsgroupPost();
nsCOMPtr<nsIFile> m_postMessageFile;
nsCString m_header[HEADER_LAST+1];
nsCString m_body;
bool m_isControl;
};
#endif /* __nsNNTPNewsgroupPost_h */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,510 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNNTPProtocol_h___
#define nsNNTPProtocol_h___
#include "nsMsgProtocol.h"
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsINntpUrl.h"
#include "nsINntpIncomingServer.h"
#include "nsINNTPProtocol.h"
#include "nsINNTPNewsgroupList.h"
#include "nsINNTPArticleList.h"
#include "nsIMsgAsyncPrompter.h"
#include "nsIMsgNewsFolder.h"
#include "nsIMsgWindow.h"
#include "nsMsgLineBuffer.h"
#include "nsIStringBundle.h"
#include "nsITimer.h"
#include "nsICacheEntryOpenCallback.h"
// this is only needed as long as our libmime hack is in place
#include "prio.h"
// State Flags (Note, I use the word state in terms of storing
// state information about the connection (authentication, have we sent
// commands, etc. I do not intend it to refer to protocol state)
#define NNTP_PAUSE_FOR_READ 0x00000001 /* should we pause for the next read */
#define NNTP_PROXY_AUTH_REQUIRED 0x00000002 /* is auth required */
#define NNTP_SENT_PROXY_AUTH 0x00000004 /* have we sent a proxy auth? */
#define NNTP_READER_PERFORMED 0x00000010 /* have we sent any cmds to the server yet? */
#define NNTP_USE_FANCY_NEWSGROUP 0x00000020 /* use LIST XACTIVE or LIST */
#define NNTP_DESTROY_PROGRESS_GRAPH 0x00000040 /* do we need to destroy graph progress */
#define NNTP_SOME_PROTOCOL_SUCCEEDED 0x0000080 /* some protocol has suceeded so don't kill the connection */
#define NNTP_NO_XOVER_SUPPORT 0x00000100 /* xover command is not supported here */
/* states of the machine
*/
typedef enum _StatesEnum {
NNTP_RESPONSE,
#ifdef BLOCK_UNTIL_AVAILABLE_CONNECTION
NNTP_BLOCK_UNTIL_CONNECTIONS_ARE_AVAILABLE,
NNTP_CONNECTIONS_ARE_AVAILABLE,
#endif
NNTP_CONNECT,
NNTP_CONNECT_WAIT,
NNTP_LOGIN_RESPONSE,
NNTP_SEND_MODE_READER,
NNTP_SEND_MODE_READER_RESPONSE,
SEND_LIST_EXTENSIONS,
SEND_LIST_EXTENSIONS_RESPONSE,
SEND_LIST_SEARCHES,
SEND_LIST_SEARCHES_RESPONSE,
NNTP_LIST_SEARCH_HEADERS,
NNTP_LIST_SEARCH_HEADERS_RESPONSE,
NNTP_GET_PROPERTIES,
NNTP_GET_PROPERTIES_RESPONSE,
SEND_LIST_SUBSCRIPTIONS,
SEND_LIST_SUBSCRIPTIONS_RESPONSE,
SEND_FIRST_NNTP_COMMAND,
SEND_FIRST_NNTP_COMMAND_RESPONSE,
SETUP_NEWS_STREAM,
NNTP_BEGIN_AUTHORIZE,
NNTP_AUTHORIZE_RESPONSE,
NNTP_PASSWORD_RESPONSE,
NNTP_READ_LIST_BEGIN,
NNTP_READ_LIST,
DISPLAY_NEWSGROUPS,
NNTP_NEWGROUPS_BEGIN,
NNTP_NEWGROUPS,
NNTP_BEGIN_ARTICLE,
NNTP_READ_ARTICLE,
NNTP_XOVER_BEGIN,
NNTP_FIGURE_NEXT_CHUNK,
NNTP_XOVER_SEND,
NNTP_XOVER_RESPONSE,
NNTP_XOVER,
NEWS_PROCESS_XOVER,
NNTP_XHDR_SEND,
NNTP_XHDR_RESPONSE,
NNTP_READ_GROUP,
NNTP_READ_GROUP_RESPONSE,
NNTP_READ_GROUP_BODY,
NNTP_SEND_GROUP_FOR_ARTICLE,
NNTP_SEND_GROUP_FOR_ARTICLE_RESPONSE,
NNTP_SEND_ARTICLE_NUMBER,
NEWS_PROCESS_BODIES,
NNTP_PRINT_ARTICLE_HEADERS,
NNTP_SEND_POST_DATA,
NNTP_SEND_POST_DATA_RESPONSE,
NNTP_CHECK_FOR_MESSAGE,
NEWS_START_CANCEL,
NEWS_DO_CANCEL,
NNTP_XPAT_SEND,
NNTP_XPAT_RESPONSE,
NNTP_SEARCH,
NNTP_SEARCH_RESPONSE,
NNTP_SEARCH_RESULTS,
NNTP_LIST_PRETTY_NAMES,
NNTP_LIST_PRETTY_NAMES_RESPONSE,
NNTP_LIST_XACTIVE,
NNTP_LIST_XACTIVE_RESPONSE,
NNTP_LIST_GROUP,
NNTP_LIST_GROUP_RESPONSE,
NEWS_DONE,
NEWS_POST_DONE,
NEWS_ERROR,
NNTP_ERROR,
NEWS_FREE,
NNTP_SUSPENDED
} StatesEnum;
class nsICacheEntry;
class nsNNTPProtocol : public nsMsgProtocol,
public nsINNTPProtocol,
public nsITimerCallback,
public nsICacheEntryOpenCallback,
public nsIMsgAsyncPromptListener
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINNTPPROTOCOL
NS_DECL_NSICACHEENTRYOPENCALLBACK
NS_DECL_NSITIMERCALLBACK
NS_DECL_NSIMSGASYNCPROMPTLISTENER
// Creating a protocol instance requires the URL
// need to call Initialize after we do a new of nsNNTPProtocol
nsNNTPProtocol(nsINntpIncomingServer *aServer, nsIURI *aURL,
nsIMsgWindow *aMsgWindow);
// stop binding is a "notification" informing us that the stream associated with aURL is going away.
NS_IMETHOD OnStopRequest(nsIRequest *request, nsISupports * aCtxt, nsresult aStatus) override;
char * m_ProxyServer; /* proxy server hostname */
NS_IMETHOD Cancel(nsresult status) override; // handle stop button
NS_IMETHOD GetContentType(nsACString &aContentType) override;
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt) override;
NS_IMETHOD AsyncOpen2(nsIStreamListener *listener) override;
NS_IMETHOD GetOriginalURI(nsIURI* *aURI) override;
NS_IMETHOD SetOriginalURI(nsIURI* aURI) override;
nsresult LoadUrl(nsIURI * aURL, nsISupports * aConsumer) override;
private:
virtual ~nsNNTPProtocol();
/**
* Triggers the protocol state machine.
* Most of the time, this machine will read as much input as it can before
* closing.
*
* This method additionally handles some states not covered by other methods:
* NEWS_DONE: Alias for NEWS_FREE
* NEWS_POST_DONE: Alias for NEWS_FREE that cleans up the URL state
* NEWS_ERROR: An error which permits further use of the connection
* NNTP_ERROR: An error which does not permit further use of the connection
* NEWS_FREE: Cleans up from the current URL and prepares for the next one
* NNTP_SUSPENDED: A state where the state machine does not read input until
* reenabled by a non-network related callback
*
* @note Use of NNTP_SUSPENDED is dangerous: if input comes along the socket,
* the code will not read the input stream at all. Therefore, it is strongly
* advised to suspend the request before using this state.
*/
virtual nsresult ProcessProtocolState(nsIURI * url, nsIInputStream * inputStream,
uint64_t sourceOffset, uint32_t length) override;
virtual nsresult CloseSocket() override;
// we have our own implementation of SendData which writes to the nntp log
// and then calls the base class to transmit the data
nsresult SendData(const char * dataBuffer, bool aSuppressLogging = false) override;
nsresult CleanupAfterRunningUrl();
void Cleanup(); //free char* member variables
void ParseHeaderForCancel(char *buf);
virtual const char* GetType() override { return "nntp"; }
static void CheckIfAuthor(nsIMsgIdentity *aIdentity, const nsCString &aOldFrom, nsCString &aFrom);
nsCOMPtr <nsINNTPNewsgroupList> m_newsgroupList;
nsCOMPtr <nsINNTPArticleList> m_articleList;
nsCOMPtr <nsIMsgNewsFolder> m_newsFolder;
nsCOMPtr <nsIMsgWindow> m_msgWindow;
nsCOMPtr<nsIAsyncInputStream> mDisplayInputStream;
nsCOMPtr<nsIAsyncOutputStream> mDisplayOutputStream;
nsMsgLineStreamBuffer * m_lineStreamBuffer; // used to efficiently extract lines from the incoming data stream
// the nsINntpURL that is currently running
nsCOMPtr<nsINntpUrl> m_runningURL;
bool m_connectionBusy;
bool m_fromCache; // is this connection from the cache?
PRTime m_lastActiveTimeStamp;
nsNewsAction m_newsAction;
// Generic state information -- What state are we in? What state do we want to go to
// after the next response? What was the last response code? etc.
StatesEnum m_nextState;
StatesEnum m_nextStateAfterResponse;
int32_t m_typeWanted; /* Article, List, or Group */
int32_t m_responseCode; /* code returned from NNTP server */
int32_t m_previousResponseCode;
char *m_responseText; /* text returned from NNTP server */
char *m_dataBuf;
uint32_t m_dataBufSize;
/* for group command */
nsCString m_currentGroup; /* current group */
int32_t m_firstArticle;
int32_t m_lastArticle;
int32_t m_firstPossibleArticle;
int32_t m_lastPossibleArticle;
int32_t m_numArticlesLoaded; /* How many articles we got XOVER lines for. */
int32_t m_numArticlesWanted; /* How many articles we wanted to get XOVER lines for. */
int32_t m_maxArticles; /* max articles to get during an XOVER */
// Cancelation specific state. In particular, the headers that should be
// used for the cancelation message.
// mscott: we can probably replace this stuff with nsString
char *m_cancelFromHdr;
char *m_cancelNewsgroups;
char *m_cancelDistribution;
char *m_cancelID;
int32_t m_cancelStatus;
// variable for ReadNewsList
int32_t m_readNewsListCount;
// Per news article state information. (article number, author, subject, id, etc
nsCString m_messageID;
int32_t m_articleNumber; /* current article number */
nsCString m_searchData;
int32_t m_originalContentLength; /* the content length at the time of calling graph progress */
nsCOMPtr<nsIStringBundle> m_stringBundle;
nsCOMPtr<nsINntpIncomingServer> m_nntpServer;
nsresult GetNewsStringByName(const char *aName, char16_t **aString);
nsresult GetNewsStringByID(int32_t stringID, char16_t **aString);
nsresult PostMessageInFile(nsIFile * filePath);
//////////////////////////////////////////////////////////////////////////////
// Communication methods --> Reading and writing protocol
//////////////////////////////////////////////////////////////////////////////
int32_t ReadLine(nsIInputStream * inputStream, uint32_t length, char ** line);
//////////////////////////////////////////////////////////////////////////////
// Protocol Methods --> This protocol is state driven so each protocol method
// is designed to re-act to the current "state". I've attempted to
// group them together based on functionality.
//////////////////////////////////////////////////////////////////////////////
// gets the response code from the nntp server and the response line. Returns the TCP return code
// from the read.
nsresult NewsResponse(nsIInputStream *inputStream, uint32_t length);
// Interpret the server response after the connect.
// Returns negative if the server responds unexpectedly
nsresult LoginResponse();
nsresult SendModeReader();
nsresult SendModeReaderResponse();
nsresult SendListExtensions();
nsresult SendListExtensionsResponse(nsIInputStream *inputStream, uint32_t length);
nsresult SendListSearches();
nsresult SendListSearchesResponse(nsIInputStream *inputStream, uint32_t length);
nsresult SendListSearchHeaders();
nsresult SendListSearchHeadersResponse(nsIInputStream *inputStream, uint32_t length);
nsresult GetProperties();
nsresult GetPropertiesResponse(nsIInputStream *inputStream, uint32_t length);
nsresult SendListSubscriptions();
nsresult SendListSubscriptionsResponse(nsIInputStream *inputStream, uint32_t length);
// Figure out what the first command is and send it.
// Returns the status from the NETWrite.
nsresult SendFirstNNTPCommand(nsIURI *url);
// Interprets the server response from the first command sent.
// returns negative if the server responds unexpectedly.
nsresult SendFirstNNTPCommandResponse();
nsresult SetupForTransfer();
nsresult SendGroupForArticle();
nsresult SendGroupForArticleResponse();
nsresult SendArticleNumber();
nsresult BeginArticle();
nsresult ReadArticle(nsIInputStream *inputStream, uint32_t length);
nsresult DisplayArticle(nsIInputStream *inputStream, uint32_t length);
//////////////////////////////////////////////////////////////////////////////
// News authentication code
//////////////////////////////////////////////////////////////////////////////
/**
* Sends the username via AUTHINFO USER, NNTP_BEGIN_AUTHORIZE.
* This also handles the step of getting authentication credentials; if this
* requires a prompt to run, the connection will be suspended and we will
* come back to this point.
* Followed by: NNTP_AUTHORIZE_RESPONSE if the username was sent
* NNTP_SUSPENDED if we need to wait for the password
*/
nsresult BeginAuthorization();
/**
* Sends the password if necessary, the state NNTP_AUTHORIZE_RESPONSE.
* This also reads the result of the username.
* Followed by: NNTP_PASSWORD_RESPONSE if a password is sent
* NNTP_SEND_MODE_READER if MODE READER needed auth
* SEND_FIRST_NNTP_COMMAND if any other command needed auth
* NNTP_ERROR if the username was rejected
*/
nsresult AuthorizationResponse();
/**
* This state, NNTP_PASSWORD_RESPONSE, reads the password.
* Followed by: NNTP_SEND_MODE_READER if MODE READER needed auth
* SEND_FIRST_NNTP_COMMAND if any other command needed auth
* NNTP_ERROR if the password was rejected
*/
nsresult PasswordResponse();
nsresult BeginReadNewsList();
nsresult ReadNewsList(nsIInputStream *inputStream, uint32_t length);
// Newsgroup specific protocol handlers
nsresult DisplayNewsgroups();
nsresult BeginNewsgroups();
nsresult ProcessNewsgroups(nsIInputStream *inputStream, uint32_t length);
// Protocol handlers used for posting data
nsresult PostData();
nsresult PostDataResponse();
nsresult CheckForArticle();
/////////////////////////////////////////////////////////////////////////////
// XHDR, XOVER, HEAD filtering process handlers
// These are ordered by the rough order of usage
/////////////////////////////////////////////////////////////////////////////
/**
* The first step in the filtering process, the state NNTP_XOVER_BEGIN.
* This method sets up m_newsgroupList.
* Followed by: NNTP_FIGURE_NEXT_CHUNK
*/
nsresult BeginReadXover();
/**
* The loop control for filtering, the state NNTP_FIGURE_NEXT_CHUNK.
* This method contacts the newsgroupList to figure out which articles to
* download and then prepares it for XOVER support.
* Followed by: NEWS_PROCESS_XOVER if everything is finished
* NNTP_READ_GROUP if XOVER doesn't work
* NNTP_XOVER_SEND if XOVER does work
*/
nsresult FigureNextChunk();
// The XOVER process core
/**
* The state NNTP_XOVER_SEND, which actually sends the message.
* Followed by: NNTP_XOVER_RESPONSE
*/
nsresult XoverSend();
/**
* This state, NNTP_XOVER_RESPONSE, actually checks the XOVER capabiliity.
* Followed by: NNTP_XOVER if XOVER is supported
* NNTP_READ_GROUP if it isn't
*/
nsresult ReadXoverResponse();
/**
* This state, NNTP_XOVER, processes the results from the XOVER command.
* It asks nsNNTPNewsgroupList to process the line using ProcessXOVERLINE.
* Followed by: NNTP_XHDR_SEND
*/
nsresult ReadXover(nsIInputStream *inputStream, uint32_t length);
// The XHDR process core
/**
* This state, NNTP_XHDR_SEND, sends the XHDR command.
* The headers are all managed by nsNNTPNewsgroupList, and this picks them up
* one by one as they are needed.
* Followed by: NNTP_XHDR_RESPONSE if there is a header to be sent
* NNTP_FIGURE_NEXT_CHUNK if all headers have been sent
*/
nsresult XhdrSend();
/**
* This state, NNTP_XHDR_RESPONSE, processes the XHDR response.
* It mostly passes the information off to nsNNTPNewsgroupList, and only does
* response code checking and a bit of preprocessing. Note that if XHDR
* doesn't work properly, HEAD fallback is switched on and all subsequent
* chunks will NOT use XOVER.
* Followed by: NNTP_READ_GROUP if XHDR doesn't work properly
* NNTP_XHDR_SEND when finished processing XHR.
*/
nsresult XhdrResponse(nsIInputStream *inputStream);
// HEAD processing core
/**
* This state, NNTP_READ_GROUP, is the control for the HEAD processor.
* It sends the HEAD command and increments the article number until it is
* finished. WARNING: HEAD is REALLY SLOW.
* Followed by: NNTP_FIGURE_NEXT_CHUNK when it is finished
* NNTP_READ_GROUP_RESPONSE when it is not
*/
nsresult ReadHeaders();
/**
* This state, NNTP_READ_GROUP_RESPONSE, checks if the article exists.
* Because it is required by NNTP, if it doesn't work, the only problem would
* be that the article doesn't exist. Passes off article number data to
* nsNNTPNewsgroupList.
* Followed by: NNTP_READ_GROUP_BODY if the article exists
* NNTP_READ_GROUP if it doesn't.
*/
nsresult ReadNewsgroupResponse();
/**
* This state, NNTP_READ_GROUP_BODY, reads the body of the HEAD command.
* Once again, it passes information off to nsNNTPNewsgroupList.
* Followed by: NNTP_READ_GROUP
*/
nsresult ReadNewsgroupBody(nsIInputStream *inputStream, uint32_t length);
/**
* This state, NNTP_PROCESS_XOVER, is the final step of the filter-processing
* code. Currently, all it does is cleans up the unread count and calls the
* filters, both via nsNNTPNewsgroupList.
* Followed by: NEWS_DONE
*/
nsresult ProcessXover();
// Canceling
nsresult StartCancel();
nsresult DoCancel();
// XPAT
nsresult XPATSend();
nsresult XPATResponse(nsIInputStream *inputStream, uint32_t length);
nsresult ListPrettyNames();
nsresult ListPrettyNamesResponse(nsIInputStream *inputStream, uint32_t length);
nsresult ListXActive();
nsresult ListXActiveResponse(nsIInputStream *inputStream, uint32_t length);
// for "?list-ids"
nsresult SendListGroup();
nsresult SendListGroupResponse(nsIInputStream *inputStream, uint32_t length);
// Searching Protocol....
nsresult Search();
nsresult SearchResponse();
nsresult SearchResults(nsIInputStream *inputStream, uint32_t length);
//////////////////////////////////////////////////////////////////////////////
// End of Protocol Methods
//////////////////////////////////////////////////////////////////////////////
nsresult ParseURL(nsIURI *aURL, nsCString &aGroup, nsCString &aMessageID);
void SetProgressBarPercent(uint32_t aProgress, uint32_t aProgressMax);
nsresult SetProgressStatus(const char16_t *aMessage);
nsresult InitializeNewsFolderFromUri(const char *uri);
void TimerCallback();
void HandleAuthenticationFailure();
nsCOMPtr <nsIInputStream> mInputStream;
nsCOMPtr <nsITimer> mUpdateTimer;
nsresult AlertError(int32_t errorCode, const char *text);
int32_t mBytesReceived;
int32_t mBytesReceivedSinceLastStatusUpdate;
PRTime m_startTime;
int32_t mNumGroupsListed;
nsMsgKey m_key;
nsresult SetCurrentGroup(); /* sets m_currentGroup. should be called after doing a successful GROUP command */
nsresult CleanupNewsgroupList(); /* cleans up m_newsgroupList, and set it to null */
// cache related helper methods
void FinishMemCacheEntry(bool valid); // either mark it valid, or doom it
nsresult OpenCacheEntry(); // makes a request to the cache service for a cache entry for a url
bool ReadFromLocalCache(); // attempts to read the url out of our local (offline) cache....
nsresult ReadFromNewsConnection(); // creates a new news connection to read the url
nsresult ReadFromMemCache(nsICacheEntry *entry); // attempts to read the url out of our memory cache
nsresult SetupPartExtractorListener(nsIStreamListener * aConsumer);
};
#endif // nsNNTPProtocol_h___

View file

@ -0,0 +1,141 @@
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.import("resource:///modules/mailServices.js");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var kACR = Ci.nsIAutoCompleteResult;
var kSupportedTypes = new Set(["addr_newsgroups", "addr_followup"]);
function nsNewsAutoCompleteResult(aSearchString) {
// Can't create this in the prototype as we'd get the same array for
// all instances
this._searchResults = [];
this.searchString = aSearchString;
}
nsNewsAutoCompleteResult.prototype = {
_searchResults: null,
// nsIAutoCompleteResult
searchString: null,
searchResult: kACR.RESULT_NOMATCH,
defaultIndex: -1,
errorDescription: null,
get matchCount() {
return this._searchResults.length;
},
getValueAt: function getValueAt(aIndex) {
return this._searchResults[aIndex].value;
},
getLabelAt: function getLabelAt(aIndex) {
return this._searchResults[aIndex].value;
},
getCommentAt: function getCommentAt(aIndex) {
return this._searchResults[aIndex].comment;
},
getStyleAt: function getStyleAt(aIndex) {
return "subscribed-news";
},
getImageAt: function getImageAt(aIndex) {
return "";
},
getFinalCompleteValueAt: function(aIndex) {
return this.getValueAt(aIndex);
},
removeValueAt: function removeValueAt(aRowIndex, aRemoveFromDB) {
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([kACR])
}
function nsNewsAutoCompleteSearch() {}
nsNewsAutoCompleteSearch.prototype = {
// For component registration
classDescription: "Newsgroup Autocomplete",
classID: Components.ID("e9bb3330-ac7e-11de-8a39-0800200c9a66"),
cachedAccountKey: "",
cachedServer: null,
/**
* Find the newsgroup server associated with the given accountKey.
*
* @param accountKey The key of the account.
* @return The incoming news server (or null if one does not exist).
*/
_findServer: function _findServer(accountKey) {
let account = MailServices.accounts.getAccount(accountKey);
if (account.incomingServer.type == 'nntp')
return account.incomingServer;
else
return null;
},
// nsIAutoCompleteSearch
startSearch: function startSearch(aSearchString, aSearchParam,
aPreviousResult, aListener) {
let params = aSearchParam ? JSON.parse(aSearchParam) : {};
let result = new nsNewsAutoCompleteResult(aSearchString);
if (!("type" in params) || !("accountKey" in params) ||
!kSupportedTypes.has(params.type)) {
result.searchResult = kACR.RESULT_IGNORED;
aListener.onSearchResult(this, result);
return;
}
if (("accountKey" in params) && (params.accountKey != this.cachedAccountKey)) {
this.cachedAccountKey = params.accountKey;
this.cachedServer = this._findServer(params.accountKey);
}
if (this.cachedServer) {
let groups = this.cachedServer.rootFolder.subFolders;
while (groups.hasMoreElements()) {
let curr = groups.getNext().QueryInterface(Ci.nsIMsgFolder);
if (curr.prettiestName.includes(aSearchString)) {
result._searchResults.push({
value: curr.prettiestName,
comment: this.cachedServer.prettyName
});
}
}
}
if (result.matchCount) {
result.searchResult = kACR.RESULT_SUCCESS;
// If the user does not select anything, use the first entry:
result.defaultIndex = 0;
}
aListener.onSearchResult(this, result);
},
stopSearch: function stopSearch() {
},
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch])
};
// Module
var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsNewsAutoCompleteSearch]);

View file

@ -0,0 +1,2 @@
component {e9bb3330-ac7e-11de-8a39-0800200c9a66} nsNewsAutoCompleteSearch.js
contract @mozilla.org/autocomplete/search;1?name=news {e9bb3330-ac7e-11de-8a39-0800200c9a66}

View file

@ -0,0 +1,91 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsNewsDownloadDialogArgs.h"
nsNewsDownloadDialogArgs::nsNewsDownloadDialogArgs()
{
mArticleCount = 0;
mServerKey = "";
mHitOK = false;
mDownloadAll = false;
}
nsNewsDownloadDialogArgs::~nsNewsDownloadDialogArgs()
{
}
NS_IMPL_ISUPPORTS(nsNewsDownloadDialogArgs, nsINewsDownloadDialogArgs)
NS_IMETHODIMP nsNewsDownloadDialogArgs::GetGroupName(nsAString & aGroupName)
{
aGroupName = mGroupName;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::SetGroupName(const nsAString & aGroupName)
{
mGroupName = aGroupName;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::GetArticleCount(int32_t *aArticleCount)
{
NS_ENSURE_ARG_POINTER(aArticleCount);
*aArticleCount = mArticleCount;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::SetArticleCount(int32_t aArticleCount)
{
mArticleCount = aArticleCount;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::GetServerKey(char * *aServerKey)
{
NS_ENSURE_ARG_POINTER(aServerKey);
*aServerKey = ToNewCString(mServerKey);
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::SetServerKey(const char * aServerKey)
{
NS_ENSURE_ARG_POINTER(aServerKey);
mServerKey = aServerKey;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::GetHitOK(bool *aHitOK)
{
NS_ENSURE_ARG_POINTER(aHitOK);
*aHitOK = mHitOK;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::SetHitOK(bool aHitOK)
{
mHitOK = aHitOK;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::GetDownloadAll(bool *aDownloadAll)
{
NS_ENSURE_ARG_POINTER(aDownloadAll);
*aDownloadAll = mDownloadAll;
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloadDialogArgs::SetDownloadAll(bool aDownloadAll)
{
mDownloadAll = aDownloadAll;
return NS_OK;
}

View file

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNewsDownloadDialogArgs_h__
#define nsNewsDownloadDialogArgs_h__
#include "nsINewsDownloadDialogArgs.h"
#include "nsStringGlue.h"
class nsNewsDownloadDialogArgs : public nsINewsDownloadDialogArgs
{
public:
nsNewsDownloadDialogArgs();
NS_DECL_ISUPPORTS
NS_DECL_NSINEWSDOWNLOADDIALOGARGS
private:
virtual ~nsNewsDownloadDialogArgs();
nsString mGroupName;
int32_t mArticleCount;
nsCString mServerKey;
bool mHitOK;
bool mDownloadAll;
};
#endif // nsNewsDownloadDialogArgs_h__

View file

@ -0,0 +1,586 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h"
#include "nntpCore.h"
#include "netCore.h"
#include "nsIMsgNewsFolder.h"
#include "nsIStringBundle.h"
#include "nsNewsDownloader.h"
#include "nsINntpService.h"
#include "nsMsgNewsCID.h"
#include "nsIMsgSearchSession.h"
#include "nsIMsgSearchTerm.h"
#include "nsIMsgSearchValidityManager.h"
#include "nsRDFCID.h"
#include "nsIMsgAccountManager.h"
#include "nsMsgFolderFlags.h"
#include "nsIRequestObserver.h"
#include "nsIMsgMailSession.h"
#include "nsMsgMessageFlags.h"
#include "nsIMsgStatusFeedback.h"
#include "nsServiceManagerUtils.h"
#include "nsComponentManagerUtils.h"
#include "nsMsgUtils.h"
#include "mozilla/Services.h"
#include "nsIArray.h"
#include "nsArrayUtils.h"
// This file contains the news article download state machine.
// if pIds is not null, download the articles whose id's are passed in. Otherwise,
// which articles to download is determined by nsNewsDownloader object,
// or subclasses thereof. News can download marked objects, for example.
nsresult nsNewsDownloader::DownloadArticles(nsIMsgWindow *window, nsIMsgFolder *folder, nsTArray<nsMsgKey> *pIds)
{
if (pIds != nullptr)
m_keysToDownload.InsertElementsAt(0, pIds->Elements(), pIds->Length());
if (!m_keysToDownload.IsEmpty())
m_downloadFromKeys = true;
m_folder = folder;
m_window = window;
m_numwrote = 0;
bool headersToDownload = GetNextHdrToRetrieve();
// should we have a special error code for failure here?
return (headersToDownload) ? DownloadNext(true) : NS_ERROR_FAILURE;
}
/* Saving news messages
*/
NS_IMPL_ISUPPORTS(nsNewsDownloader, nsIUrlListener, nsIMsgSearchNotify)
nsNewsDownloader::nsNewsDownloader(nsIMsgWindow *window, nsIMsgDatabase *msgDB, nsIUrlListener *listener)
{
m_numwrote = 0;
m_downloadFromKeys = false;
m_newsDB = msgDB;
m_abort = false;
m_listener = listener;
m_window = window;
m_lastPercent = -1;
m_lastProgressTime = 0;
// not the perfect place for this, but I think it will work.
if (m_window)
m_window->SetStopped(false);
}
nsNewsDownloader::~nsNewsDownloader()
{
if (m_listener)
m_listener->OnStopRunningUrl(/* don't have a url */nullptr, m_status);
if (m_newsDB)
{
m_newsDB->Commit(nsMsgDBCommitType::kLargeCommit);
m_newsDB = nullptr;
}
}
NS_IMETHODIMP nsNewsDownloader::OnStartRunningUrl(nsIURI* url)
{
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloader::OnStopRunningUrl(nsIURI* url, nsresult exitCode)
{
bool stopped = false;
if (m_window)
m_window->GetStopped(&stopped);
if (stopped)
exitCode = NS_BINDING_ABORTED;
nsresult rv = exitCode;
if (NS_SUCCEEDED(exitCode) || exitCode == NS_MSG_NEWS_ARTICLE_NOT_FOUND)
rv = DownloadNext(false);
return rv;
}
nsresult nsNewsDownloader::DownloadNext(bool firstTimeP)
{
nsresult rv;
if (!firstTimeP)
{
bool moreHeaders = GetNextHdrToRetrieve();
if (!moreHeaders)
{
if (m_listener)
m_listener->OnStopRunningUrl(nullptr, NS_OK);
return NS_OK;
}
}
StartDownload();
m_wroteAnyP = false;
nsCOMPtr <nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID,&rv);
NS_ENSURE_SUCCESS(rv, rv);
return nntpService->FetchMessage(m_folder, m_keyToDownload, m_window, nullptr, this, nullptr);
}
bool DownloadNewsArticlesToOfflineStore::GetNextHdrToRetrieve()
{
nsresult rv;
if (m_downloadFromKeys)
return nsNewsDownloader::GetNextHdrToRetrieve();
if (m_headerEnumerator == nullptr)
rv = m_newsDB->EnumerateMessages(getter_AddRefs(m_headerEnumerator));
bool hasMore = false;
while (NS_SUCCEEDED(rv = m_headerEnumerator->HasMoreElements(&hasMore)) && hasMore)
{
nsCOMPtr <nsISupports> supports;
rv = m_headerEnumerator->GetNext(getter_AddRefs(supports));
m_newsHeader = do_QueryInterface(supports);
NS_ENSURE_SUCCESS(rv, false);
uint32_t hdrFlags;
m_newsHeader->GetFlags(&hdrFlags);
if (hdrFlags & nsMsgMessageFlags::Marked)
{
m_newsHeader->GetMessageKey(&m_keyToDownload);
break;
}
else
{
m_newsHeader = nullptr;
}
}
return hasMore;
}
void nsNewsDownloader::Abort() {}
void nsNewsDownloader::Complete() {}
bool nsNewsDownloader::GetNextHdrToRetrieve()
{
nsresult rv;
if (m_downloadFromKeys)
{
if (m_numwrote >= (int32_t) m_keysToDownload.Length())
return false;
m_keyToDownload = m_keysToDownload[m_numwrote++];
int32_t percent;
percent = (100 * m_numwrote) / (int32_t) m_keysToDownload.Length();
int64_t nowMS = 0;
if (percent < 100) // always need to do 100%
{
nowMS = PR_IntervalToMilliseconds(PR_IntervalNow());
if (nowMS - m_lastProgressTime < 750)
return true;
}
m_lastProgressTime = nowMS;
nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(m_folder);
nsCOMPtr<nsIStringBundleService> bundleService =
mozilla::services::GetStringBundleService();
NS_ENSURE_TRUE(bundleService, false);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(NEWS_MSGS_URL, getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, false);
nsAutoString firstStr;
firstStr.AppendInt(m_numwrote);
nsAutoString totalStr;
totalStr.AppendInt(int(m_keysToDownload.Length()));
nsString prettiestName;
nsString statusString;
m_folder->GetPrettiestName(prettiestName);
const char16_t *formatStrings[3] = { firstStr.get(), totalStr.get(), prettiestName.get() };
rv = bundle->FormatStringFromName(u"downloadingArticlesForOffline",
formatStrings, 3, getter_Copies(statusString));
NS_ENSURE_SUCCESS(rv, false);
ShowProgress(statusString.get(), percent);
return true;
}
NS_ASSERTION(false, "shouldn't get here if we're not downloading from keys.");
return false; // shouldn't get here if we're not downloading from keys.
}
nsresult nsNewsDownloader::ShowProgress(const char16_t *progressString, int32_t percent)
{
if (!m_statusFeedback)
{
if (m_window)
m_window->GetStatusFeedback(getter_AddRefs(m_statusFeedback));
}
if (m_statusFeedback)
{
m_statusFeedback->ShowStatusString(nsDependentString(progressString));
if (percent != m_lastPercent)
{
m_statusFeedback->ShowProgress(percent);
m_lastPercent = percent;
}
}
return NS_OK;
}
NS_IMETHODIMP DownloadNewsArticlesToOfflineStore::OnStartRunningUrl(nsIURI* url)
{
return NS_OK;
}
NS_IMETHODIMP DownloadNewsArticlesToOfflineStore::OnStopRunningUrl(nsIURI* url, nsresult exitCode)
{
m_status = exitCode;
if (m_newsHeader != nullptr)
{
#ifdef DEBUG_bienvenu
// XP_Trace("finished retrieving %ld\n", m_newsHeader->GetMessageKey());
#endif
if (m_newsDB)
{
nsMsgKey msgKey;
m_newsHeader->GetMessageKey(&msgKey);
m_newsDB->MarkMarked(msgKey, false, nullptr);
}
}
m_newsHeader = nullptr;
return nsNewsDownloader::OnStopRunningUrl(url, exitCode);
}
int DownloadNewsArticlesToOfflineStore::FinishDownload()
{
return 0;
}
NS_IMETHODIMP nsNewsDownloader::OnSearchHit(nsIMsgDBHdr *header, nsIMsgFolder *folder)
{
NS_ENSURE_ARG(header);
uint32_t msgFlags;
header->GetFlags(&msgFlags);
// only need to download articles we don't already have...
if (! (msgFlags & nsMsgMessageFlags::Offline))
{
nsMsgKey key;
header->GetMessageKey(&key);
m_keysToDownload.AppendElement(key);
}
return NS_OK;
}
NS_IMETHODIMP nsNewsDownloader::OnSearchDone(nsresult status)
{
if (m_keysToDownload.IsEmpty())
{
if (m_listener)
return m_listener->OnStopRunningUrl(nullptr, NS_OK);
}
nsresult rv = DownloadArticles(m_window, m_folder,
/* we've already set m_keysToDownload, so don't pass it in */ nullptr);
if (NS_FAILED(rv))
if (m_listener)
m_listener->OnStopRunningUrl(nullptr, rv);
return rv;
}
NS_IMETHODIMP nsNewsDownloader::OnNewSearch()
{
return NS_OK;
}
int DownloadNewsArticlesToOfflineStore::StartDownload()
{
m_newsDB->GetMsgHdrForKey(m_keyToDownload, getter_AddRefs(m_newsHeader));
return 0;
}
DownloadNewsArticlesToOfflineStore::DownloadNewsArticlesToOfflineStore(nsIMsgWindow *window, nsIMsgDatabase *db, nsIUrlListener *listener)
: nsNewsDownloader(window, db, listener)
{
m_newsDB = db;
}
DownloadNewsArticlesToOfflineStore::~DownloadNewsArticlesToOfflineStore()
{
}
DownloadMatchingNewsArticlesToNewsDB::DownloadMatchingNewsArticlesToNewsDB
(nsIMsgWindow *window, nsIMsgFolder *folder, nsIMsgDatabase *newsDB,
nsIUrlListener *listener) :
DownloadNewsArticlesToOfflineStore(window, newsDB, listener)
{
m_window = window;
m_folder = folder;
m_newsDB = newsDB;
m_downloadFromKeys = true; // search term matching means downloadFromKeys.
}
DownloadMatchingNewsArticlesToNewsDB::~DownloadMatchingNewsArticlesToNewsDB()
{
}
NS_IMPL_ISUPPORTS(nsMsgDownloadAllNewsgroups, nsIUrlListener)
nsMsgDownloadAllNewsgroups::nsMsgDownloadAllNewsgroups(nsIMsgWindow *window, nsIUrlListener *listener)
{
m_window = window;
m_listener = listener;
m_downloaderForGroup = new DownloadMatchingNewsArticlesToNewsDB(window, nullptr, nullptr, this);
NS_IF_ADDREF(m_downloaderForGroup);
m_downloadedHdrsForCurGroup = false;
}
nsMsgDownloadAllNewsgroups::~nsMsgDownloadAllNewsgroups()
{
NS_IF_RELEASE(m_downloaderForGroup);
}
NS_IMETHODIMP nsMsgDownloadAllNewsgroups::OnStartRunningUrl(nsIURI* url)
{
return NS_OK;
}
NS_IMETHODIMP
nsMsgDownloadAllNewsgroups::OnStopRunningUrl(nsIURI* url, nsresult exitCode)
{
nsresult rv = exitCode;
if (NS_SUCCEEDED(exitCode) || exitCode == NS_MSG_NEWS_ARTICLE_NOT_FOUND)
{
if (m_downloadedHdrsForCurGroup)
{
bool savingArticlesOffline = false;
nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(m_currentFolder);
if (newsFolder)
newsFolder->GetSaveArticleOffline(&savingArticlesOffline);
m_downloadedHdrsForCurGroup = false;
if (savingArticlesOffline) // skip this group - we're saving to it already
rv = ProcessNextGroup();
else
rv = DownloadMsgsForCurrentGroup();
}
else
{
rv = ProcessNextGroup();
}
}
else if (m_listener) // notify main observer.
m_listener->OnStopRunningUrl(url, exitCode);
return rv;
}
/**
* Leaves m_currentServer at the next nntp "server" that
* might have folders to download for offline use. If no more servers,
* m_currentServer will be left at nullptr and the function returns false.
* Also, sets up m_serverEnumerator to enumerate over the server.
* If no servers found, m_serverEnumerator will be left at null.
*/
bool nsMsgDownloadAllNewsgroups::AdvanceToNextServer()
{
nsresult rv;
if (!m_allServers)
{
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ASSERTION(accountManager && NS_SUCCEEDED(rv), "couldn't get account mgr");
if (!accountManager || NS_FAILED(rv))
return false;
rv = accountManager->GetAllServers(getter_AddRefs(m_allServers));
NS_ENSURE_SUCCESS(rv, false);
}
uint32_t serverIndex = 0;
if (m_currentServer)
{
rv = m_allServers->IndexOf(0, m_currentServer, &serverIndex);
if (NS_FAILED(rv))
serverIndex = -1;
++serverIndex;
}
m_currentServer = nullptr;
uint32_t numServers;
m_allServers->GetLength(&numServers);
nsCOMPtr <nsIMsgFolder> rootFolder;
while (serverIndex < numServers)
{
nsCOMPtr<nsIMsgIncomingServer> server = do_QueryElementAt(m_allServers, serverIndex);
serverIndex++;
nsCOMPtr <nsINntpIncomingServer> newsServer = do_QueryInterface(server);
if (!newsServer) // we're only looking for news servers
continue;
if (server)
{
m_currentServer = server;
server->GetRootFolder(getter_AddRefs(rootFolder));
if (rootFolder)
{
rv = rootFolder->GetDescendants(getter_AddRefs(m_allFolders));
if (NS_SUCCEEDED(rv))
{
rv = m_allFolders->Enumerate(getter_AddRefs(m_serverEnumerator));
if (NS_SUCCEEDED(rv) && m_serverEnumerator)
{
bool hasMore = false;
rv = m_serverEnumerator->HasMoreElements(&hasMore);
if (NS_SUCCEEDED(rv) && hasMore)
return true;
}
}
}
}
}
return false;
}
/**
* Sets m_currentFolder to the next usable folder.
*
* @return False if no more folders found, otherwise true.
*/
bool nsMsgDownloadAllNewsgroups::AdvanceToNextGroup()
{
nsresult rv = NS_OK;
if (m_currentFolder)
{
nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(m_currentFolder);
if (newsFolder)
newsFolder->SetSaveArticleOffline(false);
nsCOMPtr<nsIMsgMailSession> session =
do_GetService(NS_MSGMAILSESSION_CONTRACTID, &rv);
if (NS_SUCCEEDED(rv) && session)
{
bool folderOpen;
uint32_t folderFlags;
m_currentFolder->GetFlags(&folderFlags);
session->IsFolderOpenInWindow(m_currentFolder, &folderOpen);
if (!folderOpen && ! (folderFlags & (nsMsgFolderFlags::Trash | nsMsgFolderFlags::Inbox)))
m_currentFolder->SetMsgDatabase(nullptr);
}
m_currentFolder = nullptr;
}
bool hasMore = false;
if (m_currentServer)
m_serverEnumerator->HasMoreElements(&hasMore);
if (!hasMore)
hasMore = AdvanceToNextServer();
if (hasMore)
{
nsCOMPtr<nsISupports> supports;
rv = m_serverEnumerator->GetNext(getter_AddRefs(supports));
if (NS_SUCCEEDED(rv))
m_currentFolder = do_QueryInterface(supports);
}
return m_currentFolder;
}
nsresult DownloadMatchingNewsArticlesToNewsDB::RunSearch(nsIMsgFolder *folder, nsIMsgDatabase *newsDB, nsIMsgSearchSession *searchSession)
{
m_folder = folder;
m_newsDB = newsDB;
m_searchSession = searchSession;
m_keysToDownload.Clear();
NS_ENSURE_ARG(searchSession);
NS_ENSURE_ARG(folder);
searchSession->RegisterListener(this,
nsIMsgSearchSession::allNotifications);
nsresult rv = searchSession->AddScopeTerm(nsMsgSearchScope::localNews, folder);
NS_ENSURE_SUCCESS(rv, rv);
return searchSession->Search(m_window);
}
nsresult nsMsgDownloadAllNewsgroups::ProcessNextGroup()
{
bool done = false;
while (!done)
{
done = !AdvanceToNextGroup();
if (!done && m_currentFolder)
{
uint32_t folderFlags;
m_currentFolder->GetFlags(&folderFlags);
if (folderFlags & nsMsgFolderFlags::Offline)
break;
}
}
if (done)
{
if (m_listener)
return m_listener->OnStopRunningUrl(nullptr, NS_OK);
}
m_downloadedHdrsForCurGroup = true;
return m_currentFolder ? m_currentFolder->GetNewMessages(m_window, this) : NS_ERROR_NOT_INITIALIZED;
}
nsresult nsMsgDownloadAllNewsgroups::DownloadMsgsForCurrentGroup()
{
NS_ENSURE_TRUE(m_downloaderForGroup, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr <nsIMsgDatabase> db;
nsCOMPtr <nsIMsgDownloadSettings> downloadSettings;
m_currentFolder->GetMsgDatabase(getter_AddRefs(db));
nsresult rv = m_currentFolder->GetDownloadSettings(getter_AddRefs(downloadSettings));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr <nsIMsgNewsFolder> newsFolder = do_QueryInterface(m_currentFolder);
if (newsFolder)
newsFolder->SetSaveArticleOffline(true);
nsCOMPtr <nsIMsgSearchSession> searchSession = do_CreateInstance(NS_MSGSEARCHSESSION_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
bool downloadByDate, downloadUnreadOnly;
uint32_t ageLimitOfMsgsToDownload;
downloadSettings->GetDownloadByDate(&downloadByDate);
downloadSettings->GetDownloadUnreadOnly(&downloadUnreadOnly);
downloadSettings->GetAgeLimitOfMsgsToDownload(&ageLimitOfMsgsToDownload);
nsCOMPtr <nsIMsgSearchTerm> term;
nsCOMPtr <nsIMsgSearchValue> value;
rv = searchSession->CreateTerm(getter_AddRefs(term));
NS_ENSURE_SUCCESS(rv, rv);
term->GetValue(getter_AddRefs(value));
if (downloadUnreadOnly)
{
value->SetAttrib(nsMsgSearchAttrib::MsgStatus);
value->SetStatus(nsMsgMessageFlags::Read);
searchSession->AddSearchTerm(nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, value, true, nullptr);
}
if (downloadByDate)
{
value->SetAttrib(nsMsgSearchAttrib::AgeInDays);
value->SetAge(ageLimitOfMsgsToDownload);
searchSession->AddSearchTerm(nsMsgSearchAttrib::AgeInDays, nsMsgSearchOp::IsLessThan, value, nsMsgSearchBooleanOp::BooleanAND, nullptr);
}
value->SetAttrib(nsMsgSearchAttrib::MsgStatus);
value->SetStatus(nsMsgMessageFlags::Offline);
searchSession->AddSearchTerm(nsMsgSearchAttrib::MsgStatus, nsMsgSearchOp::Isnt, value, nsMsgSearchBooleanOp::BooleanAND, nullptr);
m_downloaderForGroup->RunSearch(m_currentFolder, db, searchSession);
return rv;
}

View file

@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef _nsNewsDownloader_H_
#define _nsNewsDownloader_H_
#include "nsIMsgDatabase.h"
#include "nsIUrlListener.h"
#include "nsIMsgFolder.h"
#include "nsIMsgHdr.h"
#include "nsIMsgWindow.h"
#include "nsIMsgSearchNotify.h"
#include "nsIMsgSearchSession.h"
// base class for downloading articles in a single newsgroup. Keys to download are passed in
// to DownloadArticles method.
class nsNewsDownloader : public nsIUrlListener, public nsIMsgSearchNotify
{
public:
nsNewsDownloader(nsIMsgWindow *window, nsIMsgDatabase *db, nsIUrlListener *listener);
NS_DECL_ISUPPORTS
NS_DECL_NSIURLLISTENER
NS_DECL_NSIMSGSEARCHNOTIFY
virtual nsresult DownloadArticles(nsIMsgWindow *window, nsIMsgFolder *folder, nsTArray<nsMsgKey> *pKeyArray);
bool ShouldAbort() const { return m_abort; }
protected:
virtual ~nsNewsDownloader();
virtual int32_t Write(const char * /*block*/, int32_t length) {return length;}
virtual void Abort();
virtual void Complete();
virtual bool GetNextHdrToRetrieve();
virtual nsresult DownloadNext(bool firstTimeP);
virtual int32_t FinishDownload() {return 0;}
virtual int32_t StartDownload() {return 0;}
virtual nsresult ShowProgress(const char16_t *progressString, int32_t percent);
nsTArray<nsMsgKey> m_keysToDownload;
nsCOMPtr <nsIMsgFolder> m_folder;
nsCOMPtr <nsIMsgDatabase> m_newsDB;
nsCOMPtr <nsIUrlListener> m_listener;
bool m_downloadFromKeys;
bool m_existedP;
bool m_wroteAnyP;
bool m_summaryValidP;
bool m_abort;
int32_t m_numwrote;
nsMsgKey m_keyToDownload;
nsCOMPtr <nsIMsgWindow> m_window;
nsCOMPtr <nsIMsgStatusFeedback> m_statusFeedback;
nsCOMPtr <nsIMsgSearchSession> m_searchSession;
int32_t m_lastPercent;
int64_t m_lastProgressTime;
nsresult m_status;
};
// class for downloading articles in a single newsgroup to the offline store.
class DownloadNewsArticlesToOfflineStore : public nsNewsDownloader
{
public:
DownloadNewsArticlesToOfflineStore(nsIMsgWindow *window, nsIMsgDatabase *db, nsIUrlListener *listener);
virtual ~DownloadNewsArticlesToOfflineStore();
NS_IMETHOD OnStartRunningUrl(nsIURI* url);
NS_IMETHOD OnStopRunningUrl(nsIURI* url, nsresult exitCode);
protected:
virtual int32_t StartDownload();
virtual int32_t FinishDownload();
virtual bool GetNextHdrToRetrieve();
nsCOMPtr <nsISimpleEnumerator> m_headerEnumerator;
nsCOMPtr <nsIMsgDBHdr> m_newsHeader;
};
// class for downloading all the articles that match the passed in search criteria
// for a single newsgroup.
class DownloadMatchingNewsArticlesToNewsDB : public DownloadNewsArticlesToOfflineStore
{
public:
DownloadMatchingNewsArticlesToNewsDB(nsIMsgWindow *window, nsIMsgFolder *folder, nsIMsgDatabase *newsDB, nsIUrlListener *listener);
virtual ~DownloadMatchingNewsArticlesToNewsDB();
nsresult RunSearch(nsIMsgFolder *folder, nsIMsgDatabase *newsDB, nsIMsgSearchSession *searchSession);
protected:
};
// this class iterates all the news servers for each group on the server that's configured for
// offline use, downloads the messages that meet the download criteria for that newsgroup/server
class nsMsgDownloadAllNewsgroups : public nsIUrlListener
{
public:
nsMsgDownloadAllNewsgroups(nsIMsgWindow *window, nsIUrlListener *listener);
NS_DECL_ISUPPORTS
NS_DECL_NSIURLLISTENER
nsresult ProcessNextGroup();
protected:
virtual ~nsMsgDownloadAllNewsgroups();
bool AdvanceToNextServer();
bool AdvanceToNextGroup();
nsresult DownloadMsgsForCurrentGroup();
DownloadMatchingNewsArticlesToNewsDB *m_downloaderForGroup;
nsCOMPtr <nsIMsgFolder> m_currentFolder;
nsCOMPtr <nsIMsgWindow> m_window;
nsCOMPtr <nsIArray> m_allServers;
nsCOMPtr <nsIArray> m_allFolders;
nsCOMPtr <nsIMsgIncomingServer> m_currentServer;
nsCOMPtr <nsISimpleEnumerator> m_serverEnumerator;
nsCOMPtr <nsIUrlListener> m_listener;
bool m_downloadedHdrsForCurGroup;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,147 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
Interface for representing News folders.
*/
#ifndef nsMsgNewsFolder_h__
#define nsMsgNewsFolder_h__
#include "mozilla/Attributes.h"
#include "nsMsgDBFolder.h"
#include "nsIFile.h"
#include "nsINntpIncomingServer.h" // need this for the IID
#include "nsNewsUtils.h"
#include "nsMsgKeySet.h"
#include "nsIMsgNewsFolder.h"
#include "nsCOMPtr.h"
#include "nsIMsgFilterService.h"
#include "nsIArray.h"
class nsMsgNewsFolder : public nsMsgDBFolder, public nsIMsgNewsFolder
{
public:
nsMsgNewsFolder(void);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIMSGNEWSFOLDER
// nsIUrlListener method
NS_IMETHOD OnStopRunningUrl(nsIURI * aUrl, nsresult aExitCode) override;
// nsIMsgFolder methods:
NS_IMETHOD GetSubFolders(nsISimpleEnumerator **aResult) override;
NS_IMETHOD GetMessages(nsISimpleEnumerator **result) override;
NS_IMETHOD UpdateFolder(nsIMsgWindow *aWindow) override;
NS_IMETHOD CreateSubfolder(const nsAString& folderName,
nsIMsgWindow *msgWindow) override;
NS_IMETHOD Delete() override;
NS_IMETHOD Rename(const nsAString& newName,
nsIMsgWindow *msgWindow) override;
NS_IMETHOD GetAbbreviatedName(nsAString& aAbbreviatedName) override;
NS_IMETHOD GetFolderURL(nsACString& url) override;
NS_IMETHOD GetExpungedBytesCount(int64_t *count);
NS_IMETHOD GetDeletable(bool *deletable) override;
NS_IMETHOD RefreshSizeOnDisk();
NS_IMETHOD GetSizeOnDisk(int64_t *size) override;
NS_IMETHOD GetDBFolderInfoAndDB(nsIDBFolderInfo **folderInfo,
nsIMsgDatabase **db) override;
NS_IMETHOD DeleteMessages(nsIArray *messages,
nsIMsgWindow *msgWindow, bool deleteStorage,
bool isMove, nsIMsgCopyServiceListener* listener,
bool allowUndo) override;
NS_IMETHOD GetNewMessages(nsIMsgWindow *aWindow,
nsIUrlListener *aListener) override;
NS_IMETHOD GetCanSubscribe(bool *aResult) override;
NS_IMETHOD GetCanFileMessages(bool *aResult) override;
NS_IMETHOD GetCanCreateSubfolders(bool *aResult) override;
NS_IMETHOD GetCanRename(bool *aResult) override;
NS_IMETHOD GetCanCompact(bool *aResult) override;
NS_IMETHOD OnReadChanged(nsIDBChangeListener * aInstigator) override;
NS_IMETHOD DownloadMessagesForOffline(nsIArray *messages,
nsIMsgWindow *window) override;
NS_IMETHOD Compact(nsIUrlListener *aListener,
nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD DownloadAllForOffline(nsIUrlListener *listener,
nsIMsgWindow *msgWindow) override;
NS_IMETHOD GetSortOrder(int32_t *order) override;
NS_IMETHOD SetSortOrder(int32_t order) override;
NS_IMETHOD Shutdown(bool shutdownChildren) override;
NS_IMETHOD GetFilterList(nsIMsgWindow *aMsgWindow,
nsIMsgFilterList **aFilterList) override;
NS_IMETHOD GetEditableFilterList(nsIMsgWindow *aMsgWindow,
nsIMsgFilterList **aFilterList) override;
NS_IMETHOD SetFilterList(nsIMsgFilterList *aFilterList) override;
NS_IMETHOD SetEditableFilterList(nsIMsgFilterList *aFilterList) override;
NS_IMETHOD ApplyRetentionSettings() override;
NS_IMETHOD GetIncomingServerType(nsACString& serverType) override;
protected:
virtual ~nsMsgNewsFolder();
// helper routine to parse the URI and update member variables
nsresult AbbreviatePrettyName(nsAString& prettyName, int32_t fullwords);
nsresult ParseFolder(nsIFile *path);
nsresult CreateSubFolders(nsIFile *path);
nsresult AddDirectorySeparator(nsIFile *path);
nsresult GetDatabase() override;
virtual nsresult CreateChildFromURI(const nsCString &uri,
nsIMsgFolder **folder) override;
nsresult LoadNewsrcFileAndCreateNewsgroups();
int32_t RememberLine(const nsACString& line);
nsresult RememberUnsubscribedGroup(const nsACString& newsgroup, const nsACString& setStr);
nsresult ForgetLine(void);
nsresult GetNewsMessages(nsIMsgWindow *aMsgWindow, bool getOld, nsIUrlListener *aListener);
int32_t HandleNewsrcLine(const char * line, uint32_t line_size);
virtual nsresult CreateBaseMessageURI(const nsACString& aURI) override;
protected:
int64_t mExpungedBytes;
bool mGettingNews;
bool mInitialized;
bool m_downloadMessageForOfflineUse;
bool m_downloadingMultipleMessages;
nsCString mOptionLines;
nsCString mUnsubscribedNewsgroupLines;
nsMsgKeySet *mReadSet;
nsCOMPtr<nsIFile> mNewsrcFilePath;
// used for auth news
nsCString mGroupUsername;
nsCString mGroupPassword;
// the name of the newsgroup.
nsCString mRawName;
int32_t mSortOrder;
private:
/**
* Constructs a signon url for use in login manager.
*
* @param ref The URI ref (should be null unless working with legacy).
* @param result The result of the string
*/
nsresult CreateNewsgroupUrlForSignon(const char *ref, nsAString &result);
nsCOMPtr <nsIMsgFilterList> mFilterList;
};
#endif // nsMsgNewsFolder_h__

View file

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h"
#include "nntpCore.h"
#include "nsNewsUtils.h"
#include "nsMsgUtils.h"
/* parses NewsMessageURI */
nsresult
nsParseNewsMessageURI(const char* uri, nsCString& group, nsMsgKey *key)
{
NS_ENSURE_ARG_POINTER(uri);
NS_ENSURE_ARG_POINTER(key);
nsAutoCString uriStr(uri);
int32_t keySeparator = uriStr.FindChar('#');
if(keySeparator != -1)
{
int32_t keyEndSeparator = MsgFindCharInSet(uriStr, "?&", keySeparator);
// Grab between the last '/' and the '#' for the key
group = StringHead(uriStr, keySeparator);
int32_t groupSeparator = group.RFind("/");
if (groupSeparator == -1)
return NS_ERROR_FAILURE;
// Our string APIs don't let us unescape into the same buffer from earlier,
// so escape into a temporary
nsAutoCString unescapedGroup;
MsgUnescapeString(Substring(group, groupSeparator + 1), 0, unescapedGroup);
group = unescapedGroup;
nsAutoCString keyStr;
if (keyEndSeparator != -1)
keyStr = Substring(uriStr, keySeparator + 1, keyEndSeparator - (keySeparator + 1));
else
keyStr = Substring(uriStr, keySeparator + 1);
nsresult errorCode;
*key = keyStr.ToInteger(&errorCode);
return errorCode;
}
return NS_ERROR_FAILURE;
}
nsresult nsCreateNewsBaseMessageURI(const char *baseURI, nsCString &baseMessageURI)
{
nsAutoCString tailURI(baseURI);
// chop off news:/
if (tailURI.Find(kNewsRootURI) == 0)
tailURI.Cut(0, PL_strlen(kNewsRootURI));
baseMessageURI = kNewsMessageRootURI;
baseMessageURI += tailURI;
return NS_OK;
}

View file

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NS_NEWSUTILS_H
#define NS_NEWSUTILS_H
#include "nsStringGlue.h"
#include "MailNewsTypes2.h"
class nsIMsgNewsFolder;
#define kNewsRootURI "news:/"
#define kNntpRootURI "nntp:/"
#define kNewsMessageRootURI "news-message:/"
#define kNewsURIGroupQuery "?group="
#define kNewsURIKeyQuery "&key="
#define kNewsRootURILen 6
#define kNntpRootURILen 6
#define kNewsMessageRootURILen 14
#define kNewsURIGroupQueryLen 7
#define kNewsURIKeyQueryLen 5
extern nsresult
nsParseNewsMessageURI(const char* uri, nsCString& group, nsMsgKey *key);
extern nsresult
nsCreateNewsBaseMessageURI(const char *baseURI, nsCString &baseMessageURI);
#endif //NS_NEWSUTILS_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __nsNntpIncomingServer_h
#define __nsNntpIncomingServer_h
#include "nsINntpIncomingServer.h"
#include "nsIUrlListener.h"
#include "nscore.h"
#include "nsMsgIncomingServer.h"
#include "prmem.h"
#include "plstr.h"
#include "prprf.h"
#include "nsIMsgWindow.h"
#include "nsISubscribableServer.h"
#include "nsITimer.h"
#include "nsIFile.h"
#include "nsITreeView.h"
#include "nsITreeSelection.h"
#include "nsIAtom.h"
#include "nsCOMArray.h"
#include "nsNntpMockChannel.h"
#include "nsAutoPtr.h"
class nsINntpUrl;
class nsIMsgMailNewsUrl;
/* get some implementation from nsMsgIncomingServer */
class nsNntpIncomingServer : public nsMsgIncomingServer,
public nsINntpIncomingServer,
public nsIUrlListener,
public nsISubscribableServer,
public nsITreeView
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSINNTPINCOMINGSERVER
NS_DECL_NSIURLLISTENER
NS_DECL_NSISUBSCRIBABLESERVER
NS_DECL_NSITREEVIEW
nsNntpIncomingServer();
NS_IMETHOD GetLocalStoreType(nsACString& type) override;
NS_IMETHOD GetLocalDatabaseType(nsACString& type) override;
NS_IMETHOD CloseCachedConnections() override;
NS_IMETHOD PerformBiff(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD PerformExpand(nsIMsgWindow *aMsgWindow) override;
NS_IMETHOD OnUserOrHostNameChanged(const nsACString& oldName,
const nsACString& newName,
bool hostnameChanged) override;
// for nsMsgLineBuffer
virtual nsresult HandleLine(const char *line, uint32_t line_size);
// override to clear all passwords associated with server
NS_IMETHODIMP ForgetPassword() override;
NS_IMETHOD GetCanSearchMessages(bool *canSearchMessages) override;
NS_IMETHOD GetOfflineSupportLevel(int32_t *aSupportLevel) override;
NS_IMETHOD GetDefaultCopiesAndFoldersPrefsToServer(bool *aCopiesAndFoldersOnServer) override;
NS_IMETHOD GetCanCreateFoldersOnServer(bool *aCanCreateFoldersOnServer) override;
NS_IMETHOD GetCanFileMessagesOnServer(bool *aCanFileMessagesOnServer) override;
NS_IMETHOD GetFilterScope(nsMsgSearchScopeValue *filterScope) override;
NS_IMETHOD GetSearchScope(nsMsgSearchScopeValue *searchScope) override;
NS_IMETHOD GetSocketType(int32_t *aSocketType) override; // override nsMsgIncomingServer impl
NS_IMETHOD SetSocketType(int32_t aSocketType) override; // override nsMsgIncomingServer impl
NS_IMETHOD GetSortOrder(int32_t* aSortOrder) override;
protected:
virtual ~nsNntpIncomingServer();
virtual nsresult CreateRootFolderFromUri(const nsCString &serverUri,
nsIMsgFolder **rootFolder) override;
nsresult GetNntpConnection(nsIURI *url, nsIMsgWindow *window,
nsINNTPProtocol **aNntpConnection);
nsresult CreateProtocolInstance(nsINNTPProtocol **aNntpConnection,
nsIURI *url, nsIMsgWindow *window);
bool ConnectionTimeOut(nsINNTPProtocol* aNntpConnection);
nsCOMArray<nsINNTPProtocol> mConnectionCache;
nsTArray<RefPtr<nsNntpMockChannel> > m_queuedChannels;
/**
* Downloads the newsgroup headers.
*/
nsresult DownloadMail(nsIMsgWindow *aMsgWindow);
NS_IMETHOD GetServerRequiresPasswordForBiff(bool *aServerRequiresPasswordForBiff) override;
nsresult SetupNewsrcSaveTimer();
static void OnNewsrcSaveTimer(nsITimer *timer, void *voidIncomingServer);
void WriteLine(nsIOutputStream *stream, nsCString &str);
private:
nsTArray<nsCString> mSubscribedNewsgroups;
nsTArray<nsCString> mGroupsOnServer;
nsTArray<nsCString> mSubscribeSearchResult;
bool mSearchResultSortDescending;
// the list of of subscribed newsgroups within a given
// subscribed dialog session.
// we need to keep track of them so we know what to show as "checked"
// in the search view
nsTArray<nsCString> mTempSubscribed;
nsCOMPtr<nsIAtom> mSubscribedAtom;
nsCOMPtr<nsIAtom> mNntpAtom;
nsCOMPtr<nsITreeBoxObject> mTree;
nsCOMPtr<nsITreeSelection> mTreeSelection;
bool mHasSeenBeginGroups;
bool mGetOnlyNew;
nsresult WriteHostInfoFile();
nsresult LoadHostInfoFile();
nsresult AddGroupOnServer(const nsACString &name);
bool mNewsrcHasChanged;
bool mHostInfoLoaded;
bool mHostInfoHasChanged;
nsCOMPtr <nsIFile> mHostInfoFile;
uint32_t mLastGroupDate;
int32_t mUniqueId;
uint32_t mLastUpdatedTime;
int32_t mVersion;
bool mPostingAllowed;
nsCOMPtr<nsITimer> mNewsrcSaveTimer;
nsCOMPtr <nsIMsgWindow> mMsgWindow;
nsCOMPtr <nsISubscribableServer> mInner;
nsresult EnsureInner();
nsresult ClearInner();
bool IsValidRow(int32_t row);
nsCOMPtr<nsIFile> mNewsrcFilePath;
};
#endif

View file

@ -0,0 +1,353 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsNntpMockChannel.h"
#include "msgCore.h"
#include "nsILoadInfo.h"
#include "nsNNTPProtocol.h"
#include "nsNetUtil.h"
#include "nsIInputStream.h"
#include "nsContentSecurityManager.h"
NS_IMPL_ISUPPORTS(nsNntpMockChannel, nsIChannel, nsIRequest)
nsNntpMockChannel::nsNntpMockChannel(nsIURI *aUri, nsIMsgWindow *aMsgWindow)
: m_url(aUri),
m_msgWindow(aMsgWindow),
m_channelState(CHANNEL_UNOPENED),
m_protocol(nullptr),
m_cancelStatus(NS_OK),
m_loadFlags(0),
m_contentLength(-1)
{
}
nsNntpMockChannel::nsNntpMockChannel(nsIURI *aUri, nsIMsgWindow *aMsgWindow,
nsISupports *aConsumer)
: m_url(aUri),
m_context(aConsumer),
m_msgWindow(aMsgWindow),
m_channelState(CHANNEL_OPEN_WITH_LOAD),
m_protocol(nullptr),
m_cancelStatus(NS_OK),
m_loadFlags(0),
m_contentLength(-1)
{
}
nsNntpMockChannel::~nsNntpMockChannel()
{
}
#define FORWARD_CALL(function, argument) \
if (m_protocol) \
return m_protocol->function(argument);
////////////////////////
// nsIRequest methods //
////////////////////////
NS_IMETHODIMP nsNntpMockChannel::GetName(nsACString &result)
{
FORWARD_CALL(GetName, result)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpMockChannel::IsPending(bool *result)
{
FORWARD_CALL(IsPending, result)
// We haven't been loaded yet, so we're still pending.
*result = true;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetStatus(nsresult *status)
{
FORWARD_CALL(GetStatus, status)
*status = m_cancelStatus;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::Cancel(nsresult status)
{
m_cancelStatus = status;
m_channelState = CHANNEL_CLOSED;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::Suspend()
{
NS_NOTREACHED("nsNntpMockChannel::Suspend");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpMockChannel::Resume()
{
NS_NOTREACHED("nsNntpMockChannel::Resume");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpMockChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
{
FORWARD_CALL(SetLoadGroup, aLoadGroup)
m_loadGroup = aLoadGroup;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
{
FORWARD_CALL(GetLoadGroup, aLoadGroup)
NS_IF_ADDREF(*aLoadGroup = m_loadGroup);
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
{
FORWARD_CALL(GetLoadFlags, aLoadFlags)
*aLoadFlags = m_loadFlags;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
{
FORWARD_CALL(SetLoadFlags, aLoadFlags)
m_loadFlags = aLoadFlags;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
{
FORWARD_CALL(GetLoadInfo, aLoadInfo)
NS_IF_ADDREF(*aLoadInfo = m_loadInfo);
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetLoadInfo(nsILoadInfo *aLoadInfo)
{
FORWARD_CALL(SetLoadInfo, aLoadInfo)
m_loadInfo = aLoadInfo;
return NS_OK;
}
////////////////////////
// nsIChannel methods //
////////////////////////
NS_IMETHODIMP nsNntpMockChannel::GetOriginalURI(nsIURI **aURI)
{
FORWARD_CALL(GetOriginalURI, aURI)
NS_IF_ADDREF(*aURI = m_url);
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetOriginalURI(nsIURI *aURI)
{
FORWARD_CALL(SetOriginalURI, aURI)
// News does not seem to have the notion of an original URI.
// (See bug 193317 and bug 1312314.)
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetURI(nsIURI **aURI)
{
NS_IF_ADDREF(*aURI = m_url);
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetOwner(nsISupports **owner)
{
FORWARD_CALL(GetOwner, owner)
NS_IF_ADDREF(*owner = m_owner);
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetOwner(nsISupports *aOwner)
{
FORWARD_CALL(SetOwner, aOwner)
m_owner = aOwner;
return NS_OK;
}
NS_IMETHODIMP
nsNntpMockChannel::GetNotificationCallbacks(nsIInterfaceRequestor **callbacks)
{
FORWARD_CALL(GetNotificationCallbacks, callbacks)
NS_IF_ADDREF(*callbacks = m_notificationCallbacks);
return NS_OK;
}
NS_IMETHODIMP
nsNntpMockChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
{
FORWARD_CALL(SetNotificationCallbacks, aCallbacks)
m_notificationCallbacks = aCallbacks;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::GetSecurityInfo(nsISupports **securityInfo)
{
FORWARD_CALL(GetSecurityInfo, securityInfo)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpMockChannel::GetContentType(nsACString &aContentType)
{
FORWARD_CALL(GetContentType, aContentType)
aContentType = m_contentType;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetContentType(const nsACString &aContentType)
{
FORWARD_CALL(SetContentType, aContentType)
return NS_ParseResponseContentType(aContentType, m_contentType, m_contentCharset);
}
NS_IMETHODIMP nsNntpMockChannel::GetContentCharset(nsACString &aCharset)
{
FORWARD_CALL(GetContentCharset, aCharset)
aCharset = m_contentCharset;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::SetContentCharset(const nsACString &aCharset)
{
FORWARD_CALL(SetContentCharset, aCharset)
m_contentCharset = aCharset;
return NS_OK;
}
NS_IMETHODIMP
nsNntpMockChannel::GetContentDisposition(uint32_t *aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsNntpMockChannel::SetContentDisposition(uint32_t aContentDisposition)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsNntpMockChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsNntpMockChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsNntpMockChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP nsNntpMockChannel::GetContentLength(int64_t *length)
{
FORWARD_CALL(GetContentLength, length)
*length = m_contentLength;
return NS_OK;
}
NS_IMETHODIMP
nsNntpMockChannel::SetContentLength(int64_t aLength)
{
FORWARD_CALL(SetContentLength, aLength)
m_contentLength = aLength;
return NS_OK;
}
////////////////////////////////////////
// nsIChannel and nsNNTPProtocol glue //
////////////////////////////////////////
NS_IMETHODIMP nsNntpMockChannel::Open(nsIInputStream **_retval)
{
return NS_ImplementChannelOpen(this, _retval);
}
NS_IMETHODIMP nsNntpMockChannel::Open2(nsIInputStream **_retval)
{
nsCOMPtr<nsIStreamListener> listener;
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
NS_ENSURE_SUCCESS(rv, rv);
return Open(_retval);
}
NS_IMETHODIMP nsNntpMockChannel::AsyncOpen(nsIStreamListener *listener,
nsISupports *ctxt)
{
m_channelState = CHANNEL_OPEN_WITH_ASYNC;
m_channelListener = listener;
m_context = ctxt;
return NS_OK;
}
NS_IMETHODIMP nsNntpMockChannel::AsyncOpen2(nsIStreamListener *aListener)
{
nsCOMPtr<nsIStreamListener> listener = aListener;
nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
NS_ENSURE_SUCCESS(rv, rv);
return AsyncOpen(listener, nullptr);
}
nsresult
nsNntpMockChannel::AttachNNTPConnection(nsNNTPProtocol &protocol)
{
// First things first. Were we canceled? If so, tell the protocol.
if (m_channelState == CHANNEL_CLOSED || m_channelState == CHANNEL_UNOPENED)
return NS_ERROR_FAILURE;
// We're going to active the protocol now. Note that if the user has
// interacted with us through the nsIChannel API, we need to pass it to the
// protocol instance. We also need to initialize it. For best results, we're
// going to initialize the code and then set the values.
nsresult rv = protocol.Initialize(m_url, m_msgWindow);
NS_ENSURE_SUCCESS(rv, rv);
// Variable fun
protocol.SetLoadGroup(m_loadGroup);
protocol.SetLoadFlags(m_loadFlags);
protocol.SetOwner(m_owner);
protocol.SetNotificationCallbacks(m_notificationCallbacks);
protocol.SetContentType(m_contentType);
// Now that we've set up the protocol, attach it to ourselves so that we can
// forward all future calls to the protocol instance. We do not refcount this
// instance, since the server will be owning all of them: once the server
// releases its reference, the protocol instance is no longer usable anyways.
m_protocol = &protocol;
switch (m_channelState)
{
case CHANNEL_OPEN_WITH_LOAD:
rv = protocol.LoadNewsUrl(m_url, m_context);
break;
case CHANNEL_OPEN_WITH_ASYNC:
rv = protocol.AsyncOpen(m_channelListener, m_context);
break;
default:
NS_NOTREACHED("Unknown channel state got us here.");
return NS_ERROR_FAILURE;
}
// If we fail, that means that loading the NNTP protocol failed. Since we
// essentially promised that we would load (by virtue of returning NS_OK to
// AsyncOpen), we must now tell our listener the bad news.
if (NS_FAILED(rv) && m_channelListener)
m_channelListener->OnStopRequest(this, m_context, rv);
// Returning a failure code is our way of telling the server that this URL
// isn't going to run, so it should give the connection the next URL in the
// queue.
return rv;
}

View file

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNntpMockChannel_h___
#define nsNntpMockChannel_h___
#include "nsIChannel.h"
#include "nsIMsgWindow.h"
#include "nsCOMPtr.h"
#include "nsStringGlue.h"
class nsNNTPProtocol;
class nsNntpMockChannel : public nsIChannel
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICHANNEL
NS_DECL_NSIREQUEST
nsNntpMockChannel(nsIURI *aUri, nsIMsgWindow *aMsgWindow);
nsNntpMockChannel(nsIURI *aUri, nsIMsgWindow *aMsgWindow,
nsISupports *aConsumer);
nsresult AttachNNTPConnection(nsNNTPProtocol &protocol);
protected:
virtual ~nsNntpMockChannel();
// The URL we will be running
nsCOMPtr<nsIURI> m_url;
// Variables for arguments to pass into the opening phase.
nsCOMPtr<nsIStreamListener> m_channelListener;
nsCOMPtr<nsISupports> m_context;
nsCOMPtr<nsIMsgWindow> m_msgWindow;
// The state we're in
enum
{
CHANNEL_UNOPENED, //!< No one bothered to open this yet
CHANNEL_OPEN_WITH_LOAD, //!< We should open with LoadNewsUrl
CHANNEL_OPEN_WITH_ASYNC, //!< We should open with AsyncOpen
CHANNEL_CLOSED //!< We were closed and should not open
} m_channelState;
// The protocol instance
nsNNTPProtocol *m_protocol;
// Temporary variables for accessors before we get to the actual instance.
nsresult m_cancelStatus;
nsCOMPtr<nsILoadGroup> m_loadGroup;
nsCOMPtr<nsILoadInfo> m_loadInfo;
nsLoadFlags m_loadFlags;
nsCOMPtr<nsISupports> m_owner;
nsCOMPtr<nsIInterfaceRequestor> m_notificationCallbacks;
nsCString m_contentType;
nsCString m_contentCharset;
int64_t m_contentLength;
};
#endif // nsNntpMockChannel_h___

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNntpService_h___
#define nsNntpService_h___
#include "nsINntpService.h"
#include "nsIProtocolHandler.h"
#include "nsIMsgMessageService.h"
#include "nsINntpIncomingServer.h"
#include "nsIMsgIncomingServer.h"
#include "nsIFile.h"
#include "MailNewsTypes.h"
#include "nsIMsgProtocolInfo.h"
#include "nsIMsgWindow.h"
#include "nsINntpUrl.h"
#include "nsCOMPtr.h"
#include "nsIContentHandler.h"
#include "nsICacheStorage.h"
#include "nsICommandLineHandler.h"
class nsIURI;
class nsIUrlListener;
class nsNntpService : public nsINntpService,
public nsIMsgMessageService,
public nsIMsgMessageFetchPartService,
public nsIProtocolHandler,
public nsIMsgProtocolInfo,
public nsICommandLineHandler,
public nsIContentHandler
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSINNTPSERVICE
NS_DECL_NSIMSGMESSAGESERVICE
NS_DECL_NSIPROTOCOLHANDLER
NS_DECL_NSIMSGPROTOCOLINFO
NS_DECL_NSICONTENTHANDLER
NS_DECL_NSIMSGMESSAGEFETCHPARTSERVICE
NS_DECL_NSICOMMANDLINEHANDLER
// nsNntpService
nsNntpService();
protected:
virtual ~nsNntpService();
nsresult GetNntpServerByAccount(const char *aAccountKey, nsIMsgIncomingServer **aNntpServer);
nsresult SetUpNntpUrlForPosting(const char *aAccountKey, char **newsUrlSpec);
nsresult FindHostFromGroup(nsCString &host, nsCString &groupName);
nsresult FindServerWithNewsgroup(nsCString &host, nsCString &groupName);
nsresult CreateMessageIDURL(nsIMsgFolder *folder, nsMsgKey key, char **url);
nsresult GetMessageFromUrl(nsIURI *aUrl, nsIMsgWindow *aMsgWindow, nsISupports *aDisplayConsumer);
// a convience routine used to put together news urls
nsresult ConstructNntpUrl(const char * urlString, nsIUrlListener *aUrlListener, nsIMsgWindow * aMsgWindow, const char *originalMessageUri, int32_t action, nsIURI ** aUrl);
nsresult CreateNewsAccount(const char *aHostname, bool aIsSecure, int32_t aPort, nsIMsgIncomingServer **aServer);
nsresult GetServerForUri(nsIURI *aUri, nsINntpIncomingServer **aProtocol);
// a convience routine to run news urls
nsresult RunNewsUrl (nsIURI * aUrl, nsIMsgWindow *aMsgWindow, nsISupports * aConsumer);
// a convience routine to go from folder uri to msg folder
nsresult GetFolderFromUri(const char *uri, nsIMsgFolder **folder);
nsresult DecomposeNewsMessageURI(const char * aMessageURI, nsIMsgFolder ** aFolder, nsMsgKey *aMsgKey);
bool mPrintingOperation; // Flag for printing operations
bool mOpenAttachmentOperation; // Flag for opening attachments
nsCOMPtr<nsICacheStorage> mCacheStorage; // the cache storage used by news
};
#endif /* nsNntpService_h___ */

View file

@ -0,0 +1,578 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "msgCore.h" // precompiled header...
#include "nsIURL.h"
#include "nsNntpUrl.h"
#include "nsStringGlue.h"
#include "nsNewsUtils.h"
#include "nsMsgUtils.h"
#include "nntpCore.h"
#include "nsCOMPtr.h"
#include "nsIMsgDatabase.h"
#include "nsMsgDBCID.h"
#include "nsMsgNewsCID.h"
#include "nsIMsgFolder.h"
#include "nsIMsgNewsFolder.h"
#include "nsINntpService.h"
#include "nsIMsgMessageService.h"
#include "nsIMsgAccountManager.h"
#include "nsServiceManagerUtils.h"
nsNntpUrl::nsNntpUrl()
{
m_newsgroupPost = nullptr;
m_newsAction = nsINntpUrl::ActionUnknown;
m_addDummyEnvelope = false;
m_canonicalLineEnding = false;
m_filePath = nullptr;
m_getOldMessages = false;
m_key = nsMsgKey_None;
}
nsNntpUrl::~nsNntpUrl()
{
}
NS_IMPL_ADDREF_INHERITED(nsNntpUrl, nsMsgMailNewsUrl)
NS_IMPL_RELEASE_INHERITED(nsNntpUrl, nsMsgMailNewsUrl)
NS_INTERFACE_MAP_BEGIN(nsNntpUrl)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsINntpUrl)
NS_INTERFACE_MAP_ENTRY(nsINntpUrl)
NS_INTERFACE_MAP_ENTRY(nsIMsgMessageUrl)
NS_INTERFACE_MAP_ENTRY(nsIMsgI18NUrl)
NS_INTERFACE_MAP_END_INHERITING(nsMsgMailNewsUrl)
////////////////////////////////////////////////////////////////////////////////
// Begin nsINntpUrl specific support
////////////////////////////////////////////////////////////////////////////////
/* News URI parsing explanation:
* We support 3 different news URI schemes, essentially boiling down to 8
* different formats:
* news://host/group
* news://host/message
* news://host/
* news:group
* news:message
* nntp://host/group
* nntp://host/group/key
* news-message://host/group#key
*
* In addition, we use queries on the news URIs with authorities for internal
* NNTP processing. The most important one is ?group=group&key=key, for cache
* canonicalization.
*/
NS_IMETHODIMP nsNntpUrl::SetSpec(const nsACString &aSpec)
{
// For [s]news: URIs, we need to munge the spec if it is no authority, because
// the URI parser guesses the wrong thing otherwise
nsCString parseSpec(aSpec);
int32_t colon = parseSpec.Find(":");
// Our smallest scheme is 4 characters long, so colon must be at least 4
if (colon < 4 || colon + 1 == (int32_t) parseSpec.Length())
return NS_ERROR_MALFORMED_URI;
if (Substring(parseSpec, colon - 4, 4).EqualsLiteral("news") &&
parseSpec[colon + 1] != '/')
{
// To make this parse properly, we add in three slashes, which convinces the
// parser that the authority component is empty.
parseSpec = Substring(aSpec, 0, colon + 1);
parseSpec.AppendLiteral("///");
parseSpec += Substring(aSpec, colon + 1);
}
nsresult rv = nsMsgMailNewsUrl::SetSpec(parseSpec);
NS_ENSURE_SUCCESS(rv,rv);
nsAutoCString scheme;
rv = GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
if (scheme.EqualsLiteral("news") || scheme.EqualsLiteral("snews"))
rv = ParseNewsURL();
else if (scheme.EqualsLiteral("nntp") || scheme.EqualsLiteral("nntps"))
rv = ParseNntpURL();
else if (scheme.EqualsLiteral("news-message"))
{
nsAutoCString spec;
rv = GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
rv = nsParseNewsMessageURI(spec.get(), m_group, &m_key);
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
}
else
return NS_ERROR_MALFORMED_URI;
NS_ENSURE_SUCCESS(rv, rv);
rv = DetermineNewsAction();
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
nsresult nsNntpUrl::ParseNewsURL()
{
// The path here is the group/msgid portion
nsAutoCString path;
nsresult rv = GetFilePath(path);
NS_ENSURE_SUCCESS(rv, rv);
// Drop the potential beginning from the path
if (path.Length() && path[0] == '/')
path = Substring(path, 1);
// The presence of an `@' is a sign we have a msgid
if (path.Find("@") != -1 || path.Find("%40") != -1)
{
MsgUnescapeString(path, 0, m_messageID);
// Set group, key for ?group=foo&key=123 uris
nsAutoCString spec;
rv = GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
int32_t groupPos = spec.Find(kNewsURIGroupQuery); // find ?group=
int32_t keyPos = spec.Find(kNewsURIKeyQuery); // find &key=
if (groupPos != kNotFound && keyPos != kNotFound)
{
// get group name and message key
m_group = Substring(spec, groupPos + kNewsURIGroupQueryLen,
keyPos - groupPos - kNewsURIGroupQueryLen);
nsCString keyStr(Substring(spec, keyPos + kNewsURIKeyQueryLen));
m_key = keyStr.ToInteger(&rv, 10);
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
}
}
else
MsgUnescapeString(path, 0, m_group);
return NS_OK;
}
nsresult nsNntpUrl::ParseNntpURL()
{
nsAutoCString path;
nsresult rv = GetFilePath(path);
NS_ENSURE_SUCCESS(rv, rv);
if (path.Length() > 0 && path[0] == '/')
path = Substring(path, 1);
if (path.IsEmpty())
return NS_ERROR_MALFORMED_URI;
int32_t slash = path.FindChar('/');
if (slash == -1)
{
m_group = path;
m_key = nsMsgKey_None;
}
else
{
m_group = Substring(path, 0, slash);
nsAutoCString keyStr;
keyStr = Substring(path, slash + 1);
m_key = keyStr.ToInteger(&rv, 10);
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
// Keys must be at least one
if (m_key == 0)
return NS_ERROR_MALFORMED_URI;
}
return NS_OK;
}
nsresult nsNntpUrl::DetermineNewsAction()
{
nsAutoCString path;
nsresult rv = nsMsgMailNewsUrl::GetPath(path);
NS_ENSURE_SUCCESS(rv,rv);
nsAutoCString query;
rv = GetQuery(query);
NS_ENSURE_SUCCESS(rv, rv);
if (query.EqualsLiteral("cancel"))
{
m_newsAction = nsINntpUrl::ActionCancelArticle;
return NS_OK;
}
if (query.EqualsLiteral("list-ids"))
{
m_newsAction = nsINntpUrl::ActionListIds;
return NS_OK;
}
if (query.EqualsLiteral("newgroups"))
{
m_newsAction = nsINntpUrl::ActionListNewGroups;
return NS_OK;
}
if (StringBeginsWith(query, NS_LITERAL_CSTRING("search")))
{
m_newsAction = nsINntpUrl::ActionSearch;
return NS_OK;
}
if (StringBeginsWith(query, NS_LITERAL_CSTRING("part=")) ||
query.Find("&part=") > 0)
{
// news://news.mozilla.org:119/3B98D201.3020100%40cs.com?part=1
// news://news.mozilla.org:119/b58dme%24aia2%40ripley.netscape.com?header=print&part=1.2&type=image/jpeg&filename=Pole.jpg
m_newsAction = nsINntpUrl::ActionFetchPart;
return NS_OK;
}
if (!m_messageID.IsEmpty() || m_key != nsMsgKey_None)
{
m_newsAction = nsINntpUrl::ActionFetchArticle;
return NS_OK;
}
if (m_group.Find("*") >= 0)
{
// If the group is a wildmat, list groups instead of grabbing a group.
m_newsAction = nsINntpUrl::ActionListGroups;
return NS_OK;
}
if (!m_group.IsEmpty())
{
m_newsAction = nsINntpUrl::ActionGetNewNews;
return NS_OK;
}
// At this point, we have a URI that contains neither a query, a group, nor a
// message ID. Ergo, we don't know what it is.
m_newsAction = nsINntpUrl::ActionUnknown;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::SetGetOldMessages(bool aGetOldMessages)
{
m_getOldMessages = aGetOldMessages;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetGetOldMessages(bool * aGetOldMessages)
{
NS_ENSURE_ARG(aGetOldMessages);
*aGetOldMessages = m_getOldMessages;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetNewsAction(nsNewsAction *aNewsAction)
{
if (aNewsAction)
*aNewsAction = m_newsAction;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::SetNewsAction(nsNewsAction aNewsAction)
{
m_newsAction = aNewsAction;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetGroup(nsACString &group)
{
group = m_group;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetMessageID(nsACString &messageID)
{
messageID = m_messageID;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetKey(nsMsgKey *key)
{
NS_ENSURE_ARG_POINTER(key);
*key = m_key;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetPrincipalSpec(nsACString& aPrincipalSpec)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpUrl::SetUri(const char * aURI)
{
mURI = aURI;
return NS_OK;
}
// from nsIMsgMessageUrl
NS_IMETHODIMP nsNntpUrl::GetUri(char ** aURI)
{
nsresult rv = NS_OK;
// if we have been given a uri to associate with this url, then use it
// otherwise try to reconstruct a URI on the fly....
if (mURI.IsEmpty()) {
nsAutoCString spec;
rv = GetSpec(spec);
NS_ENSURE_SUCCESS(rv,rv);
mURI = spec;
}
*aURI = ToNewCString(mURI);
if (!*aURI) return NS_ERROR_OUT_OF_MEMORY;
return rv;
}
NS_IMPL_GETSET(nsNntpUrl, AddDummyEnvelope, bool, m_addDummyEnvelope)
NS_IMPL_GETSET(nsNntpUrl, CanonicalLineEnding, bool, m_canonicalLineEnding)
NS_IMETHODIMP nsNntpUrl::SetMessageFile(nsIFile * aFile)
{
m_messageFile = aFile;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetMessageFile(nsIFile ** aFile)
{
if (aFile)
NS_IF_ADDREF(*aFile = m_messageFile);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
// End nsINntpUrl specific support
////////////////////////////////////////////////////////////////////////////////
nsresult nsNntpUrl::SetMessageToPost(nsINNTPNewsgroupPost *post)
{
m_newsgroupPost = post;
if (post)
SetNewsAction(nsINntpUrl::ActionPostArticle);
return NS_OK;
}
nsresult nsNntpUrl::GetMessageToPost(nsINNTPNewsgroupPost **aPost)
{
NS_ENSURE_ARG_POINTER(aPost);
NS_IF_ADDREF(*aPost = m_newsgroupPost);
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::SetMessageHeader(nsIMsgDBHdr *aMsgHdr)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP nsNntpUrl::GetMessageHeader(nsIMsgDBHdr ** aMsgHdr)
{
nsresult rv;
nsCOMPtr <nsINntpService> nntpService = do_GetService(NS_NNTPSERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsCOMPtr <nsIMsgMessageService> msgService = do_QueryInterface(nntpService, &rv);
NS_ENSURE_SUCCESS(rv,rv);
nsAutoCString spec(mOriginalSpec);
if (spec.IsEmpty()) {
// Handle the case where necko directly runs an internal news:// URL,
// one that looks like news://host/message-id?group=mozilla.announce&key=15
// Other sorts of URLs -- e.g. news://host/message-id -- will not succeed.
rv = GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
}
return msgService->MessageURIToMsgHdr(spec.get(), aMsgHdr);
}
NS_IMETHODIMP nsNntpUrl::IsUrlType(uint32_t type, bool *isType)
{
NS_ENSURE_ARG(isType);
switch(type)
{
case nsIMsgMailNewsUrl::eDisplay:
*isType = (m_newsAction == nsINntpUrl::ActionFetchArticle);
break;
default:
*isType = false;
};
return NS_OK;
}
NS_IMETHODIMP
nsNntpUrl::GetOriginalSpec(char **aSpec)
{
NS_ENSURE_ARG_POINTER(aSpec);
*aSpec = ToNewCString(mOriginalSpec);
if (!*aSpec) return NS_ERROR_OUT_OF_MEMORY;
return NS_OK;
}
NS_IMETHODIMP
nsNntpUrl::SetOriginalSpec(const char *aSpec)
{
mOriginalSpec = aSpec;
return NS_OK;
}
NS_IMETHODIMP
nsNntpUrl::GetServer(nsIMsgIncomingServer **aServer)
{
NS_ENSURE_ARG_POINTER(aServer);
nsresult rv;
nsAutoCString scheme, user, host;
GetScheme(scheme);
GetUsername(user);
GetHost(host);
// No authority -> no server
if (host.IsEmpty())
{
*aServer = nullptr;
return NS_OK;
}
// Looking up the server...
// news-message is used purely internally, so it can never refer to the real
// attribute. nntp is never used internally, so it probably refers to the real
// one. news is used both internally and externally, so it could refer to
// either one. We'll assume it's an internal one first, though.
bool isNews = scheme.EqualsLiteral("news") || scheme.EqualsLiteral("snews");
bool isNntp = scheme.EqualsLiteral("nntp") || scheme.EqualsLiteral("nntps");
bool tryReal = isNntp;
nsCOMPtr<nsIMsgAccountManager> accountManager =
do_GetService(NS_MSGACCOUNTMANAGER_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Ignoring return results: it is perfectly acceptable for the server to not
// exist, but FindServer (and not FindRealServer) throws NS_ERROR_UNEXPECTED
// in this case.
*aServer = nullptr;
if (tryReal)
accountManager->FindRealServer(user, host, NS_LITERAL_CSTRING("nntp"), 0,
aServer);
else
accountManager->FindServer(user, host, NS_LITERAL_CSTRING("nntp"), aServer);
if (!*aServer && (isNews || isNntp))
{
// Didn't find it, try the other option
if (tryReal)
accountManager->FindServer(user, host, NS_LITERAL_CSTRING("nntp"),
aServer);
else
accountManager->FindRealServer(user, host, NS_LITERAL_CSTRING("nntp"), 0,
aServer);
}
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::GetFolder(nsIMsgFolder **msgFolder)
{
NS_ENSURE_ARG_POINTER(msgFolder);
nsresult rv;
nsCOMPtr<nsIMsgIncomingServer> server;
rv = GetServer(getter_AddRefs(server));
NS_ENSURE_SUCCESS(rv, rv);
// Need a server and a group to get the folder
if (!server || m_group.IsEmpty())
{
*msgFolder = nullptr;
return NS_OK;
}
// Find the group on the server
nsCOMPtr<nsINntpIncomingServer> nntpServer = do_QueryInterface(server, &rv);
NS_ENSURE_SUCCESS(rv, rv);
bool hasGroup = false;
rv = nntpServer->ContainsNewsgroup(m_group, &hasGroup);
NS_ENSURE_SUCCESS(rv, rv);
if (!hasGroup)
{
*msgFolder = nullptr;
return NS_OK;
}
nsCOMPtr<nsIMsgNewsFolder> newsFolder;
rv = nntpServer->FindGroup(m_group, getter_AddRefs(newsFolder));
NS_ENSURE_SUCCESS(rv, rv);
return newsFolder->QueryInterface(NS_GET_IID(nsIMsgFolder), (void**)msgFolder);
}
NS_IMETHODIMP
nsNntpUrl::GetFolderCharset(char **aCharacterSet)
{
nsCOMPtr<nsIMsgFolder> folder;
nsresult rv = GetFolder(getter_AddRefs(folder));
// don't assert here. this can happen if there is no message folder
// like when we display a news://host/message-id url
if (NS_FAILED(rv) || !folder)
return rv;
nsCString tmpStr;
rv = folder->GetCharset(tmpStr);
*aCharacterSet = ToNewCString(tmpStr);
return rv;
}
NS_IMETHODIMP nsNntpUrl::GetFolderCharsetOverride(bool * aCharacterSetOverride)
{
nsCOMPtr<nsIMsgFolder> folder;
nsresult rv = GetFolder(getter_AddRefs(folder));
NS_ENSURE_SUCCESS(rv,rv);
NS_ENSURE_TRUE(folder, NS_ERROR_FAILURE);
rv = folder->GetCharsetOverride(aCharacterSetOverride);
NS_ENSURE_SUCCESS(rv,rv);
return rv;
}
NS_IMETHODIMP nsNntpUrl::GetCharsetOverRide(char ** aCharacterSet)
{
if (!mCharsetOverride.IsEmpty())
*aCharacterSet = ToNewCString(mCharsetOverride);
else
*aCharacterSet = nullptr;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::SetCharsetOverRide(const char * aCharacterSet)
{
mCharsetOverride = aCharacterSet;
return NS_OK;
}
NS_IMETHODIMP nsNntpUrl::CloneInternal(uint32_t aRefHandlingMode,
const nsACString& newRef,
nsIURI **_retval)
{
nsresult rv;
rv = nsMsgMailNewsUrl::CloneInternal(aRefHandlingMode, newRef, _retval);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIMsgMessageUrl> newsurl = do_QueryInterface(*_retval, &rv);
NS_ENSURE_SUCCESS(rv, rv);
return newsurl->SetUri(mURI.get());
}

View file

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsNntpUrl_h__
#define nsNntpUrl_h__
#include "nsINntpUrl.h"
#include "nsMsgMailNewsUrl.h"
#include "nsINNTPNewsgroupPost.h"
#include "nsIFile.h"
class nsNntpUrl : public nsINntpUrl, public nsMsgMailNewsUrl, public nsIMsgMessageUrl, public nsIMsgI18NUrl
{
public:
NS_DECL_NSINNTPURL
NS_DECL_NSIMSGMESSAGEURL
NS_DECL_NSIMSGI18NURL
// nsIURI over-ride...
NS_IMETHOD SetSpec(const nsACString &aSpec) override;
NS_IMETHOD IsUrlType(uint32_t type, bool *isType) override;
// nsIMsgMailNewsUrl overrides
NS_IMETHOD GetServer(nsIMsgIncomingServer **server) override;
NS_IMETHOD GetFolder(nsIMsgFolder **msgFolder) override;
NS_IMETHOD CloneInternal(uint32_t aRefHandlingMode,
const nsACString& newRef,nsIURI **_retval) override;
// nsNntpUrl
nsNntpUrl();
NS_DECL_ISUPPORTS_INHERITED
private:
virtual ~nsNntpUrl();
nsresult DetermineNewsAction();
nsresult ParseNewsURL();
nsresult ParseNntpURL();
nsCOMPtr<nsINNTPNewsgroupPost> m_newsgroupPost;
nsNewsAction m_newsAction; // the action this url represents...parse mailbox, display messages, etc.
nsCString mURI; // the RDF URI associated with this url.
nsCString mCharsetOverride; // used by nsIMsgI18NUrl...
nsCString mOriginalSpec;
nsCOMPtr <nsIFile> m_filePath;
// used by save message to disk
nsCOMPtr<nsIFile> m_messageFile;
bool m_addDummyEnvelope;
bool m_canonicalLineEnding;
bool m_getOldMessages;
nsCString m_group;
nsCString m_messageID;
nsMsgKey m_key;
};
#endif // nsNntpUrl_h__