1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
|
/* -*-C++-*- -*-coding: utf-8-unix;-*-
Classified Ads is Copyright (c) Antti Järvinen 2013-2017.
This file is part of Classified Ads.
Classified Ads is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
Classified Ads 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with Classified Ads; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @mainpage Classified ads
*
* Classified ads is internet communications program that works
* in distributed manner, requiring and supporting no concept of
* "server". Classified ads supports
* - Concept of operator, that is identified by encryption key and
* can contain also other data like real name that human being
* operating the profile wants to publish.
* - Making some data available to listed operators only, this is
* done by marking a operator profile private.
* - Sending and receiving
* -# Public messages, that are called "classified ads" due to
* classification that they carry,
* -# Private messages between operators,
* -# Comments regarding operators, readable by group that see
* profile of the commented operator.
* - Basic word-based search functions.
* - Voice calls between operator nodes.
*
* For more information see http://katiska.org/classified-ads/. In
* order to use classified ads in meaningful manner, user needs to
* have the operated instance of this program to connect to some other
* program instance over some network. Classified ads tries to do
* that automatically but it may be necessary to ask for network address
* of node operated by a friend to get connected and started.
*
* Classified ads is released under LGPL license.
*
* \copyright Antti Järvinen and others 2013-2016.
*/
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QtGui>
#include <QBoxLayout>
#include <QUrl>
#include "mcontroller.h"
#include "net/protocol.h" // for ProtocolItemType
#include "datamodel/netrequestexecutor.h"
class FrontWidget ;
class PublishingEngine ;
class RetrievalEngine ;
class DbRecordRetrievalEngine ;
class QMainWindow ;
class QMenu ;
class VoiceCallEngine ;
class QSharedMemory ;
#ifdef WIN32
class QLocalServer ;
#endif
class QFileDialog ;
/**
* @brief Class for keeping app state.
*
* C of MVC-pattern is considered here.
* UI events are routed
* via this class and this implements scheduling of events
* so that things happen in correct order.
*/
class Controller : public MController {
Q_OBJECT
public:
/**
* constructor. see also method @init.
*/
Controller(QApplication& app) ;
/**
* Destructor
*/
~Controller() ;
/**
* Constructor extras. Constructor may fail but there is no way to
* communicate that. Design is now so that constructor only allocates
* memory and initializes member variables, this method here, @init
* contains constructor logic and it may fail.
*
* @return true if initialization is ok
*/
bool init() ;
/**
* method that starts actions regarding content fetch from
* network
* @param aReq specifies the content,at least iRequestType and
* iRequestedItem need to be there
* @param aIsBackgroundDl is true if the retrieval may be
* queued into background as a low-priority item
*/
virtual void startRetrievingContent(NetworkRequestExecutor::NetworkRequestQueueItem aReq,
bool aIsBackgroundDl,
ProtocolItemType aTypeOfExpectedObject) ;
/**
* Variant of "start fetch" method that starts fetch of db records.
* @param aSearchTerms Database query that fetched record should
* satisfy
*/
virtual void startRetrievingContent( CaDbRecord::SearchTerms aSearchTerms ) ;
/**
* From MController.
*
* Method for requesting different things to take place in UI.
* controller mostly routes these to FrontWidget but other actions
* may be in order too..
* @param aRequest users orders
* @param aHashConcerned possible hash parameter ; can be
* null hash if action is not about specific hash
* @param aFetchFromNode possible node hash parameter ; if
* concerning item is not found from local storage,
* try to fetch it from given node ; is KNullHash,
* then just do fetch using normal algorithm.
* @param aAdditionalInformation possible explanation or other info
* @return none
*/
virtual void userInterfaceAction ( CAUserInterfaceRequest aRequest,
const Hash& aHashConcerned = KNullHash,
const Hash& aFetchFromNode = KNullHash,
const QString* aAdditionalInformation = NULL) ;
/**
* method for hiding UI
*/
virtual void hideUI() ;
/**
* method for showing UI
*/
virtual void showUI() ;
/**
* method selecting user profile in use.
*/
virtual void setProfileInUse(const Hash& aProfileHash) ;
/**
* method getting user profile in use.
*/
virtual const Hash& profileInUse() ;
/**
* method for setting passwd used to open private content encryption
* rsa key. this password is stored in controller
* and is then used by content-open/sign-operations when crypto lib
* asks for password.
*/
virtual void setContentKeyPasswd(QString aPasswd) ;
/**
* method for getting passwd of private content keys previously set, see method
* @ref Controller::setContentKeyPasswd
*/
virtual QString contentKeyPasswd() const ;
public: // methods
/**
* Method for node ; this may be changed during startup-phase
* but not after that
*/
virtual Node& getNode() const ;
/**
* method for network listener ; it is parent of all connections,
* also the outgoing
*/
virtual NetworkListener *networkListener() const ;
/**
* method for getting datamodel
*/
virtual Model &model() const ;
/**
* method for setting an URL to open. Url is opened only
* if it is of classified-ads URL scheme, currently
* supported protocols are caprofile, caad, cacomment and cablob
* and if URL scheme is not among those, this method does
* no thing. Host part contains hash of object, other parts
* are ignored.
*
* @param aClassifiedAdsObject object to bring visible to user
*/
void addObjectToOpen(QUrl aClassifiedAdsObject) ;
/**
* method called if old instance of this program is signaled
* from new instace, calling for this instance to bring
* itself to front, and, in this method, to check if
* there is object mentioned in shared memory segment
* that needs to be displayed
*/
void checkForSharedMemoryContents() ;
signals:
void userProfileSelected(const Hash& aProfile) ;
/** used for signalling possible wait dialog about dismissal */
void waitDialogToBeDismissed() ;
void startGettingFileName(QString aSuggestedFileName,bool aIsSaveFile) ; /**< signal for launching file selection dlg*/
public slots:
virtual void exitApp() ; /**< quitting */
virtual void displayAboutBox() ; /**< bragging */
virtual void displayFront() ; /**< this initializes the "normal" display */
virtual void changeProfilePasswd() ; /**< name says it all. initiates UI sequence */
virtual void createProfile() ; /**< Initiates UI sequence for new profile*/
virtual void deleteProfile() ; /**< Initiates UI sequence for deleting profile*/
virtual void selectProfile() ; /**< Initiates UI sequence for selecting profile*/
virtual void displaySettings() ; /**< Slot for displaying node settings */
virtual void displayStatus() ; /**< Slot for displaying network status */
virtual void displaySearch() ; /**< Slot for displaying search dialog */
/* tcl-related UI slots */
virtual void displayTclProgs() ; /**< Slot for displaying TCL library */
virtual void displayTclConsole() ; /**< Slot for displaying TCL console */
/**
* Method for handling errors inside application.
* @param aError Reason for error call, from error enum above
* @param aExplanation NULL or human-readable description about what went
* wrong.
*/
virtual void handleError(MController::CAErrorSituation aError,
const QString& aExplanation) ;
/**
* This is receiving slot of signals sent from actual content handlers ;
* when we receive new content, this method is hit, reason for this
* is that we may be waiting for specific content somewhere
* @param aHashOfContent item that was requested
* @param aTypeOfReceivedContent item type requested
*/
void notifyOfContentReceived(const Hash& aHashOfContent,
const ProtocolItemType aTypeOfReceivedContent );
/**
* This is receiving slot of signals sent from actual content handlers ;
* when we receive new content, this method is hit, reason for this
* is that we may be waiting for specific content somewhere.
* This overload is mostly hit by classified ads.
*
* @param aHashOfContent item that was requested
* @param aHashOfClassification of item that was requested
* @param aTypeOfReceivedContent item type requested
*/
void notifyOfContentReceived(const Hash& aHashOfContent,
const Hash& aHashOfClassification,
const ProtocolItemType aTypeOfReceivedContent );
/**
* This is receiving slot of signals sent from
* retrieval engine;
* when we try to receive content and we do not get any,
* this notifies user that time-out is due
* @param aHashOfContent item that was requested
* @param aTypeOfNotReceivdContent item type requested
*/
void notifyOfContentNotReceived(const Hash& aHashOfContent,
const ProtocolItemType aTypeOfNotReceivdContent );
/**
* Method for persisting profile private data inside datamodel.
* Tnis is supposed to be called every time after private data
* changes.
*
* lock the datamodel before calling this method
*
* @param aPublishTrustListToo if set to true, has selected profiles
* trust list to be updated profile data and profile published
* with the new trust list.
*/
virtual void storePrivateDataOfSelectedProfile(bool aPublishTrustListToo = false) ;
/**
* method for restoring private data of profile currently in use.
* shall be called after new profile is selected in frontwidget.
*/
virtual void reStorePrivateDataOfSelectedProfile() ;
/**
* method for checking if a profile is found from contact
* list of selected user
*/
virtual bool isContactInContactList(const Hash& aFingerPrint) const ;
/**
* method for producing a displayable version of a profile.
* in practice this utilitizes the contacts of the selected profile
* and a cache that is collected from private messages,
* ads, profile comments and profiles
*/
virtual QString displayableNameForProfile(const Hash& aProfileFingerPrint) const ;
/**
* method for keeping profile hash<->displayname relation up to date.
* this is called when display names are seen in profiles, ads,
* private messages etc.
*/
virtual void offerDisplayNameForProfile(const Hash& aProfileFingerPrint,
const QString& aDisplayName,
const bool iUpdatePersistenStorage=false) ;
/**
* method that puts dialog or similar on display, about a published file
*/
virtual void displayFileInfoOnUi(const BinaryFile& aFileMetadata) ;
/**
* Method for getting voice call engine, if there is any.
* From MController interface.
* @return engine or null
*/
virtual VoiceCallEngine* voiceCallEngine() ;
/**
* Method for getting voice call engine, if there is any.
* From MController interface.
* @return engine or mockup. In normal runtime this just calls @ref voiceCallEngine.
*/
virtual MVoiceCallEngine* voiceCallEngineInterface() ;
/**
* Method for getting tcl wrapper instance. If there is no instance
* one will be created.
* From @ref MController interface.
*/
virtual TclWrapper &tclWrapper() ;
/**
* Method for getting front-widget, to be used as parent of dialogs
* spawned from non-ui threads. From MController interface.
*/
virtual QWidget *frontWidget() ;
/**
* method for sending a poll around network regarding possible
* update for a profile and possible addition of comments about
* given profile.
*
* datamodel should not be locked when this is called.
*
* in practice this is called after user selects a profile to
* be viewed ; it could be called periodically too for selected
* profiles..
*
* @param aProfileFingerPrint is fingerprint of the profile concerned.
* @param aProfileNodeFingerPrint fingerprint of node that is suspected to
* be the node where profile is published from.
* this is naturally good candidate for
* sending the query.
*/
void sendProfileUpdateQuery(const Hash& aProfileFingerPrint,
const Hash& aProfileNodeFingerPrint = KNullHash ) ;
#ifdef WIN32
void newInstanceConnected() ; /**< WIN32 IPC callback */
#endif
/**
* Method for getting file name. Method displays file selection
* dialog and returns the selected file. Idea of this method is
* that it may be called from background threads and it will
* display the dialog in UI thread, then report results back.
* This is a blocking method that will suspend execution of the
* calling thread for the duration while user is doing the selection.
*
* @param aSuccess is set to true if operation ends all right.
* @param aIsSaveFile if set to true, "file save" dialog is
* shown, otherwise "file open" dialog.
* @param aSuggestedFileName file name (pattern). If given empty,
* any file is suggested in dialog, if "*.jpg" is given, then
* dialog shall suggest only files with .jpg ending and
* if "foobar.txt" is given, then dialog will suggest literal
* file name "foobar.txt".
* @return file system file name or empty if aSuccess is set to false.
*/
virtual QString getFileName(bool& aSuccess,
bool aIsSaveFile = false ,
QString aSuggestedFileName = QString()) ;
private:
void createMenus(); /**< menus here */
int createPidFile(); /**< leave a mark to filesystem about instance */
void deletePidFile(); /**< remove mark from filesystem about instance */
/**
* creates and possibly populates a shared memory segment
* for IPC needs
*/
bool createSharedMemSegment(QString& aSegmentName);
private slots:
void checkForObjectToOpen(const Hash& aIgnored) ; /** processing of method addObjectToOpen */
/**
* worker-slot for @ref getFileName method ; this slot will be called
* in queued manner and have its code run in UI thread.
*/
void getFileNameSlot(QString aSuggestedFileName,bool aIsSaveFile) ;
private:
QMainWindow* iWin ;
FrontWidget* iCurrentWidget ; /**< normally points to "frontwidget" instance */
QApplication& iApp ;
QBoxLayout* iLayout ;
QMenu *iFileMenu;
QAction *iExitAct;
QAction *iAboutAct;
QAction *iPwdChangeAct;
QAction *iProfileDeleteAct;
QAction *iProfileCreateAct;
QAction *iProfileSelectAct;
QAction *iDisplaySettingsAct;
QAction *iDisplayStatusAct;
QAction *iDisplaySearchAct;
QMenu *iTclMenu;
QAction *iTclLibraryAct; /**< Menu item for opening tcl lib dialog */
QAction *iTclConsoleAct; /**< Menu item for opening tcl console dialog */
Node *iNode ; /**< our network presence object, there is single instance */
Model *iModel ; /**< data storage animal */
NetworkListener *iListener ; /**< Incoming connections handler, for ipv4 */
NetworkConnectorEngine *iNetEngine ; /**< Outgoing connections handler */
QString iContentKeyPasswd ; /** passwd used to protect profile private RSA key */
Hash iProfileHash ; /**< fingerprint of profile currently in use */
PublishingEngine *iPubEngine ; /**< Logic for handling content publish */
RetrievalEngine* iRetrievalEngine ;/**< Logic for fetcing stuff from other nodes */
DbRecordRetrievalEngine* iDbRetrievalEngine ;/**< Logic for fetcing db records from other nodes */
/**
* if user requests for item that we do not have, lets put a
* wait dialog in place and start wait for the object to appear
* from network. in order to properly dismiss the dialog,
* have here type (and later hash) of the objects that we're waiting
* for */
ProtocolItemType iTypeOfObjectBeingWaitedFor ;
/**
* hash of object that user needs to wait.
*/
Hash iHashOfObjectBeingWaitedFor ;
/**
* hash of profile comment that user needs to wait. This is
* used in two-stage fetch process of profile comment where
* the profile may need to be retrieved first, then the
* comment: we store there the profile comment hash for
* duration of profile fetch
*/
Hash iHashOfProfileCommentBeingWaitedFor ;
/**
* Node where to ask for profile comment once profile
* has been fetched
*/
Hash iNodeForCommentBeingWaitedFor ;
/**
* profile hash<->display_name mapping
*/
QMap<Hash,QString> iHashDisplaynameMapping ;
/**
* Currently there is support for one voice call at time
*/
VoiceCallEngine* iVoiceCallEngine ;
/**
* Flag for destructor. If this is on, don't allocate more objects
*/
bool iInsideDestructor ;
/**
* pending object to open
*/
QUrl iObjectToOpen ;
/**
* Shared memory block for receiving iObjectToOpen from
* external process.
*/
QSharedMemory* iSharedMemory ;
#ifdef WIN32
QLocalServer* iLocalServer ; /**< In WIN32 use named pipe for IPC */
#endif
TclWrapper* iTclWrapper ; /**< wraps TCL interpreter */
/** variable used in @ref getFileName wrapper: holds result string */
QString iGetFileNameResult ;
/** variable used in @ref getFileName wrapper: points to dialog */
QFileDialog* iGetFileNameDialog ;
/** variable used in @ref getFileName wrapper: mutex that is locked
for duration while iGetFileNameDialog is on display */
QSemaphore iGetFileNameSemaphore ;
/** variable used in @ref getFileName wrapper: result from file
selection dialog */
bool iGetFileNameSuccess ;
} ;
#endif
|