2017-01-14 23:20:42 +01:00
|
|
|
#pragma once
|
|
|
|
/*
|
|
|
|
* GXS Mailing Service
|
|
|
|
* Copyright (C) 2016-2017 Gioacchino Mazzurco <gio@eigenlab.org>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdint.h>
|
2017-02-22 13:34:36 +01:00
|
|
|
#include <unordered_map>
|
|
|
|
#include <map>
|
2017-01-14 23:20:42 +01:00
|
|
|
|
|
|
|
#include "retroshare/rsgxsifacetypes.h" // For RsGxsId, RsGxsCircleId
|
|
|
|
#include "gxs/gxstokenqueue.h" // For GxsTokenQueue
|
|
|
|
#include "serialiser/rsgxsmailitems.h" // For RS_SERVICE_TYPE_GXS_MAIL
|
|
|
|
#include "services/p3idservice.h" // For p3IdService
|
2017-02-21 12:02:27 +01:00
|
|
|
#include "util/rsthreads.h"
|
2017-01-14 23:20:42 +01:00
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
struct p3GxsMails;
|
2017-01-30 15:18:12 +01:00
|
|
|
struct GxsMailsClient
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* This will be called by p3GxsMails to dispatch mails to the subservice
|
2017-02-07 20:33:06 +01:00
|
|
|
* @param originalMessage message as received from GXS backend (encrypted)
|
|
|
|
* @param data buffer containing the decrypted data
|
|
|
|
* @param dataSize size of the buffer
|
2017-01-30 15:18:12 +01:00
|
|
|
* @return true if dispatching goes fine, false otherwise
|
|
|
|
*/
|
2017-02-21 12:02:27 +01:00
|
|
|
virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage,
|
2017-02-09 16:11:53 +01:00
|
|
|
const uint8_t* data, uint32_t dataSize ) = 0;
|
2017-01-30 15:18:12 +01:00
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage,
|
|
|
|
GxsMailStatus status ) = 0;
|
|
|
|
};
|
2017-02-09 16:11:53 +01:00
|
|
|
|
2017-02-26 00:46:02 +01:00
|
|
|
struct p3GxsMails : RsGenExchange, GxsTokenQueue, p3Config
|
2017-01-14 23:20:42 +01:00
|
|
|
{
|
|
|
|
p3GxsMails( RsGeneralDataService* gds, RsNetworkExchangeService* nes,
|
2017-01-30 15:18:12 +01:00
|
|
|
p3IdService& identities ) :
|
2017-01-14 23:20:42 +01:00
|
|
|
RsGenExchange( gds, nes, new RsGxsMailSerializer(),
|
2017-01-30 15:18:12 +01:00
|
|
|
RS_SERVICE_TYPE_GXS_MAIL, &identities,
|
2017-02-09 16:11:53 +01:00
|
|
|
AuthenPolicy(), GXS_STORAGE_PERIOD ),
|
2017-02-07 20:33:06 +01:00
|
|
|
GxsTokenQueue(this), idService(identities),
|
2017-02-21 12:02:27 +01:00
|
|
|
servClientsMutex("p3GxsMails client services map mutex"),
|
|
|
|
outgoingMutex("p3GxsMails outgoing queue map mutex"),
|
|
|
|
ingoingMutex("p3GxsMails ingoing queue map mutex") {}
|
2017-02-26 00:46:02 +01:00
|
|
|
~p3GxsMails();
|
2017-01-30 15:18:12 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Send an email to recipient, in the process author of the email is
|
|
|
|
* disclosed to the network (because the sent GXS item is signed), while
|
|
|
|
* recipient is not @see RsGxsMailBaseItem::recipientsHint for details on
|
|
|
|
* recipient protection.
|
|
|
|
* This method is part of the public interface of this service.
|
|
|
|
* @return true if the mail will be sent, false if not
|
|
|
|
*/
|
2017-02-21 12:02:27 +01:00
|
|
|
bool sendMail( RsGxsMailId& mailId,
|
2017-02-26 00:46:02 +01:00
|
|
|
GxsMailSubServices service,
|
2017-01-30 15:18:12 +01:00
|
|
|
const RsGxsId& own_gxsid, const RsGxsId& recipient,
|
|
|
|
const uint8_t* data, uint32_t size,
|
2017-02-21 12:02:27 +01:00
|
|
|
RsGxsMailEncryptionMode cm = RsGxsMailEncryptionMode::RSA
|
2017-01-30 15:18:12 +01:00
|
|
|
);
|
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
/**
|
|
|
|
* This method is part of the public interface of this service.
|
|
|
|
* @return false if mail is not found in outgoing queue, true otherwise
|
|
|
|
*/
|
|
|
|
bool querySendMailStatus( RsGxsMailId mailId, GxsMailStatus& st );
|
|
|
|
|
2017-01-30 15:18:12 +01:00
|
|
|
/**
|
|
|
|
* Register a client service to p3GxsMails to receive mails via
|
|
|
|
* GxsMailsClient::receiveGxsMail(...) callback
|
2017-02-21 12:02:27 +01:00
|
|
|
* This method is part of the public interface of this service.
|
2017-01-30 15:18:12 +01:00
|
|
|
*/
|
2017-02-26 00:46:02 +01:00
|
|
|
void registerGxsMailsClient( GxsMailSubServices serviceType,
|
2017-02-07 20:33:06 +01:00
|
|
|
GxsMailsClient* service );
|
2017-01-14 23:20:42 +01:00
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
/// @see RsGenExchange::getServiceInfo()
|
|
|
|
virtual RsServiceInfo getServiceInfo() { return RsServiceInfo( RS_SERVICE_TYPE_GXS_MAIL, "GXS Mails", 0, 1, 0, 1 ); }
|
2017-02-09 16:11:53 +01:00
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
private:
|
2017-02-09 16:11:53 +01:00
|
|
|
/** Time interval of inactivity before a distribution group is unsubscribed.
|
|
|
|
* Approximatively 3 months seems ok ATM. */
|
|
|
|
const static int32_t UNUSED_GROUP_UNSUBSCRIBE_INTERVAL = 0x76A700;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This should be as little as possible as the size of the database can grow
|
|
|
|
* very fast taking in account we are handling mails for the whole network.
|
|
|
|
* We do prefer to resend a not acknowledged yet mail after
|
|
|
|
* GXS_STORAGE_PERIOD has passed and keep it little.
|
2017-02-21 12:02:27 +01:00
|
|
|
* Tought it can't be too little as this may cause signed receipts to
|
2017-02-09 16:11:53 +01:00
|
|
|
* get lost thus causing resend and fastly grow perceived async latency, in
|
|
|
|
* case two sporadically connected users sends mails each other.
|
2017-02-26 00:46:02 +01:00
|
|
|
* While it is ok for signed acknowledged to stays in the DB for a
|
2017-02-09 16:11:53 +01:00
|
|
|
* full GXS_STORAGE_PERIOD, mails should be removed as soon as a valid
|
|
|
|
* signed acknowledged is received for each of them.
|
|
|
|
* Two weeks seems fair ATM.
|
|
|
|
*/
|
|
|
|
const static uint32_t GXS_STORAGE_PERIOD = 0x127500;
|
2017-01-14 23:20:42 +01:00
|
|
|
|
2017-02-09 16:11:53 +01:00
|
|
|
/// Define how the backend should handle authentication based on signatures
|
|
|
|
static uint32_t AuthenPolicy();
|
2017-01-14 23:20:42 +01:00
|
|
|
|
2017-01-31 20:14:17 +01:00
|
|
|
/// Types to mark queries in tokens queue
|
|
|
|
enum GxsReqResTypes
|
|
|
|
{
|
|
|
|
GROUPS_LIST = 1,
|
|
|
|
GROUP_CREATE = 2,
|
|
|
|
MAILS_UPDATE = 3
|
|
|
|
};
|
2017-01-14 23:20:42 +01:00
|
|
|
|
2017-01-30 15:18:12 +01:00
|
|
|
/// Store the id of the preferred GXS group to send emails
|
2017-01-14 23:20:42 +01:00
|
|
|
RsGxsGroupId preferredGroupId;
|
|
|
|
|
2017-01-30 15:18:12 +01:00
|
|
|
/// Used for items {de,en}cryption
|
|
|
|
p3IdService& idService;
|
|
|
|
|
|
|
|
/// Stores pointers to client services to notify them about new mails
|
2017-02-26 00:46:02 +01:00
|
|
|
std::map<GxsMailSubServices, GxsMailsClient*> servClients;
|
2017-02-07 20:33:06 +01:00
|
|
|
RsMutex servClientsMutex;
|
|
|
|
|
2017-02-26 00:46:02 +01:00
|
|
|
/**
|
|
|
|
* @brief Keep track of outgoing mails.
|
|
|
|
* Records enter the queue when a mail is sent, and are removed when a
|
|
|
|
* receipt has been received or sending is considered definetly failed.
|
|
|
|
* Items are saved in config for consistence accross RetroShare shutdowns.
|
|
|
|
*/
|
2017-02-21 12:02:27 +01:00
|
|
|
typedef std::map<RsGxsMailId, OutgoingRecord> prMap;
|
|
|
|
prMap outgoingQueue;
|
|
|
|
RsMutex outgoingMutex;
|
|
|
|
void processOutgoingRecord(OutgoingRecord& r);
|
|
|
|
|
2017-02-26 00:46:02 +01:00
|
|
|
/**
|
|
|
|
* @brief Ingoing mail and receipt processing queue.
|
|
|
|
* Items are saved in config and then deleted in destructor for consistence
|
|
|
|
* accross RetroShare shutdowns.
|
|
|
|
*/
|
2017-02-22 13:34:36 +01:00
|
|
|
typedef std::unordered_multimap<RsGxsMailId, RsGxsMailBaseItem*> inMap;
|
2017-02-21 12:02:27 +01:00
|
|
|
inMap ingoingQueue;
|
|
|
|
RsMutex ingoingMutex;
|
2017-01-30 15:18:12 +01:00
|
|
|
|
2017-02-26 00:46:02 +01:00
|
|
|
/// @see GxsTokenQueue::handleResponse(uint32_t token, uint32_t req_type)
|
|
|
|
virtual void handleResponse(uint32_t token, uint32_t req_type);
|
|
|
|
|
|
|
|
/// @see RsGenExchange::service_tick()
|
|
|
|
virtual void service_tick();
|
|
|
|
|
|
|
|
/// @see RsGenExchange::service_CreateGroup(...)
|
|
|
|
RsGenExchange::ServiceCreate_Return service_CreateGroup(
|
|
|
|
RsGxsGrpItem* grpItem, RsTlvSecurityKeySet& );
|
|
|
|
|
|
|
|
/// @see RsGenExchange::notifyChanges(std::vector<RsGxsNotify *> &changes)
|
|
|
|
void notifyChanges(std::vector<RsGxsNotify *> &changes);
|
|
|
|
|
|
|
|
/// @see p3Config::setupSerialiser()
|
|
|
|
virtual RsSerialiser* setupSerialiser();
|
|
|
|
|
|
|
|
/// @see p3Config::saveList(bool &cleanup, std::list<RsItem *>&)
|
|
|
|
virtual bool saveList(bool &cleanup, std::list<RsItem *>&saveList);
|
|
|
|
|
|
|
|
/// @see p3Config::saveDone()
|
|
|
|
void saveDone();
|
|
|
|
|
|
|
|
/// @see p3Config::loadList(std::list<RsItem *>&)
|
|
|
|
virtual bool loadList(std::list<RsItem *>& loadList);
|
|
|
|
|
2017-01-14 23:20:42 +01:00
|
|
|
/// Request groups list to GXS backend. Async method.
|
2017-01-30 15:18:12 +01:00
|
|
|
bool requestGroupsData(const std::list<RsGxsGroupId>* groupIds = NULL);
|
2017-01-14 23:20:42 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if current preferredGroupId is the best against potentialGrId, if
|
|
|
|
* the passed one is better update it.
|
|
|
|
* Useful when GXS backend notifies groups changes, or when a reponse to an
|
|
|
|
* async grop request (@see GXS_REQUEST_TYPE_GROUP_*) is received.
|
|
|
|
* @return true if preferredGroupId has been supeseded by potentialGrId
|
|
|
|
* false otherwise.
|
|
|
|
*/
|
|
|
|
bool inline supersedePreferredGroup(const RsGxsGroupId& potentialGrId)
|
|
|
|
{
|
|
|
|
if(preferredGroupId < potentialGrId)
|
|
|
|
{
|
2017-01-30 15:18:12 +01:00
|
|
|
std::cerr << "supersedePreferredGroup(...) " << potentialGrId
|
|
|
|
<< " supersed " << preferredGroupId << std::endl;
|
2017-01-14 23:20:42 +01:00
|
|
|
preferredGroupId = potentialGrId;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-01-30 15:18:12 +01:00
|
|
|
|
2017-02-09 16:11:53 +01:00
|
|
|
/** @return true if has passed more then interval seconds between timeStamp
|
|
|
|
* and ref. @param ref by default now is taked as reference. */
|
|
|
|
bool static inline olderThen(time_t timeStamp, int32_t interval,
|
|
|
|
time_t ref = time(NULL))
|
|
|
|
{ return (timeStamp + interval) < ref; }
|
2017-02-07 20:33:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
/// Decrypt email content and pass it to dispatchDecryptedMail(...)
|
2017-02-09 16:11:53 +01:00
|
|
|
bool handleEcryptedMail(const RsGxsMailItem* mail);
|
2017-02-07 20:33:06 +01:00
|
|
|
|
|
|
|
/// Dispatch the message to the recipient service
|
2017-02-09 16:11:53 +01:00
|
|
|
bool dispatchDecryptedMail( const RsGxsMailItem* received_msg,
|
|
|
|
const uint8_t* decrypted_data,
|
2017-02-07 20:33:06 +01:00
|
|
|
uint32_t decrypted_data_size );
|
2017-02-18 20:32:25 +01:00
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
void notifyClientService(const OutgoingRecord& pr);
|
2017-01-14 23:20:42 +01:00
|
|
|
};
|
|
|
|
|
2017-02-21 12:02:27 +01:00
|
|
|
struct TestGxsMailClientService : GxsMailsClient, RsSingleJobThread
|
2017-02-09 16:11:53 +01:00
|
|
|
{
|
2017-02-21 12:02:27 +01:00
|
|
|
TestGxsMailClientService( p3GxsMails& gxsMailService,
|
|
|
|
p3IdService& gxsIdService ) :
|
|
|
|
mailService(gxsMailService), idService(gxsIdService)
|
2017-02-09 16:11:53 +01:00
|
|
|
{
|
2017-02-21 12:02:27 +01:00
|
|
|
mailService.registerGxsMailsClient( GxsMailSubServices::TEST_SERVICE,
|
|
|
|
this );
|
2017-02-09 16:11:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// @see GxsMailsClient::receiveGxsMail(...)
|
2017-02-21 12:02:27 +01:00
|
|
|
virtual bool receiveGxsMail( const RsGxsMailItem& originalMessage,
|
2017-02-09 16:11:53 +01:00
|
|
|
const uint8_t* data, uint32_t dataSize )
|
|
|
|
{
|
|
|
|
std::cout << "TestGxsMailClientService::receiveGxsMail(...) got message"
|
2017-02-21 12:02:27 +01:00
|
|
|
<< " from: " << originalMessage.meta.mAuthorId << std::endl
|
|
|
|
<< "\t>" << std::string((char*)data, dataSize) << "<"
|
|
|
|
<< std::endl;
|
2017-02-09 16:11:53 +01:00
|
|
|
return true;
|
|
|
|
}
|
2017-02-21 12:02:27 +01:00
|
|
|
|
|
|
|
/// @see GxsMailsClient::notifyMailStatus(...)
|
|
|
|
virtual bool notifySendMailStatus( const RsGxsMailItem& originalMessage,
|
|
|
|
GxsMailStatus status )
|
|
|
|
{
|
|
|
|
std::cout << "TestGxsMailClientService::notifyMailsStatus(...) for: "
|
|
|
|
<< originalMessage.mailId << " status: "
|
|
|
|
<< static_cast<uint>(status) << std::endl;
|
|
|
|
if( status == GxsMailStatus::RECEIPT_RECEIVED )
|
|
|
|
std::cout << "\t It mean Receipt has been Received!" << std::endl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @see RsSingleJobThread::run()
|
|
|
|
virtual void run()
|
|
|
|
{
|
2017-02-26 00:46:02 +01:00
|
|
|
#if 0
|
2017-02-21 12:02:27 +01:00
|
|
|
usleep(10*1000*1000);
|
|
|
|
RsGxsId gxsidA("d0df7474bdde0464679e6ef787890287");
|
|
|
|
RsGxsId gxsidB("d060bea09dfa14883b5e6e517eb580cd");
|
|
|
|
RsGxsMailId mailId = 0;
|
|
|
|
if(idService.isOwnId(gxsidA))
|
|
|
|
{
|
|
|
|
std::string ciao("CiAone!");
|
2017-02-26 00:46:02 +01:00
|
|
|
mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE,
|
|
|
|
gxsidA, gxsidB,
|
2017-02-21 12:02:27 +01:00
|
|
|
reinterpret_cast<const uint8_t*>(ciao.data()),
|
|
|
|
ciao.size() );
|
|
|
|
}
|
|
|
|
else if(idService.isOwnId(gxsidB))
|
|
|
|
{
|
|
|
|
std::string ciao("CiBuono!");
|
2017-02-26 00:46:02 +01:00
|
|
|
mailService.sendMail( mailId, GxsMailSubServices::TEST_SERVICE,
|
|
|
|
gxsidB, gxsidA,
|
2017-02-21 12:02:27 +01:00
|
|
|
reinterpret_cast<const uint8_t*>(ciao.data()),
|
|
|
|
ciao.size() );
|
|
|
|
}
|
2017-02-26 00:46:02 +01:00
|
|
|
#endif
|
2017-02-21 12:02:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
p3GxsMails& mailService;
|
|
|
|
p3IdService& idService;
|
2017-02-09 16:11:53 +01:00
|
|
|
};
|