RetroShare/retroshare-nogui/src/menu/menus.cc
drbob d3787cb324 Make rs-nogui+SSH compile against the trunk.
* converted to new flags format for File Operations.
 * converted from PUBLIC to VISIBLE lobbies. NB: This required name changes to protobuf definitions.
 * converted DataRates to new function.
 * directory sharing shifted to using OTHERS flags (text menus) - No support for group Flags yet.
 * Added == operator to Flags Type.



git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@6000 b45a01b8-16f6-495d-af2f-9b41ad6348cc
2012-12-17 01:24:16 +00:00

834 lines
18 KiB
C++

/*
* RetroShare External Interface.
*
* Copyright 2012-2012 by Robert Fernie.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License Version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*
* Please report all bugs and problems to "retroshare@lunamutt.com".
*
*/
#include <retroshare/rspeers.h>
#include <retroshare/rsfiles.h>
#include <retroshare/rsturtle.h>
#include "util/rsstring.h"
#include "util/rsdir.h"
#include "menu/menus.h"
// Can't use: Q, H, T, U (universal)
// or L, N, P (list ops).
// or 0-9,a-f (list selection).
#define MENU_FRIENDS_KEY_ADD 'a'
#define MENU_FRIENDS_KEY_VIEW 'v'
#define MENU_FRIENDS_KEY_REMOVE 'd'
#define MENU_FRIENDS_KEY_CHAT 'c'
#define MENU_TRANSFER_KEY_STOP 's'
#define MENU_TRANSFER_KEY_CANCEL 'c'
#define MENU_SEARCH_KEY_ADD 'a'
#define MENU_SEARCH_KEY_REMOVE 'd'
#define MENU_SEARCH_KEY_VIEW 'v'
#define MENU_SEARCH_KEY_DOWNLOAD 'g'
#define MENU_FORUMS_KEY_ADD 'a'
#define MENU_FORUMS_KEY_VIEW 'v'
#define MENU_FORUMS_KEY_REMOVE 'd'
#define MENU_FORUMS_KEY_CHAT 'c'
#define MENU_SHARED_KEY_EXPAND 'e'
#define MENU_SHARED_KEY_UNSHARE 's'
#define MENU_SHARED_KEY_ADD 'a'
#define MENU_SHARED_KEY_PUBLIC 'c'
#define MENU_SHARED_KEY_BROWSABLE 'b'
#define MENU_TOPLEVEL_KEY_FRIENDS 'f'
#define MENU_TOPLEVEL_KEY_NETWORK 'w'
#define MENU_TOPLEVEL_KEY_TRANSFER 'd'
#define MENU_TOPLEVEL_KEY_SEARCH 's'
#define MENU_TOPLEVEL_KEY_FORUMS 'o'
#define MENU_TOPLEVEL_KEY_SHARED 'k' //If you know of a key which fits better, just change it ;-)
#define MENU_TOPLEVEL_KEY_UPLOADS 'e'
Menu *CreateMenuStructure(NotifyTxt *notify)
{
/* construct Friends Menu */
MenuList *friends = new MenuListFriends();
// No Friends Operations Completed Yet!
//friends->addMenuItem(MENU_FRIENDS_KEY_ADD, new MenuOpFriendsAdd());
//friends->addMenuItem(MENU_FRIENDS_KEY_VIEW, new MenuOpFriendsViewDetail());
//friends->addMenuItem(MENU_FRIENDS_KEY_REMOVE, new MenuOpFriendsRemove());
//friends->addMenuItem(MENU_FRIENDS_KEY_CHAT, new MenuOpFriendsChat());
MenuList *network = new MenuListNetwork();
MenuList *transfers = new MenuListTransfer();
//transfers->addMenuItem(MENU_TRANSFER_KEY_STOP, new MenuOpTransferStop());
transfers->addMenuItem(MENU_TRANSFER_KEY_CANCEL, new MenuOpTransferCancel());
MenuList *search = new MenuListSearch(notify);
MenuList *searchlist = new MenuListSearchList(notify);
search->addMenuItem(MENU_SEARCH_KEY_ADD, new MenuOpSearchNew(notify));
//search->addMenuItem(MENU_SEARCH_KEY_REMOVE, new MenuOpSearchDelete());
search->addMenuItem(MENU_SEARCH_KEY_VIEW, searchlist);
searchlist->addMenuItem(MENU_SEARCH_KEY_DOWNLOAD, new MenuOpSearchListDownload());
// Forums - TODO.
//MenuList *forums = new MenuListForums();
//forums->addMenuItem(MENU_FRIENDS_KEY_ADD, new MenuOpFriendsAdd());
//forums->addMenuItem(MENU_FRIENDS_KEY_VIEW, new MenuOpFriendsViewDetail());
//forums->addMenuItem(MENU_FRIENDS_KEY_REMOVE, new MenuOpFriendsRemove());
//forums->addMenuItem(MENU_FRIENDS_KEY_CHAT, new MenuOpFriendsChat());
// Shared folders Menu
MenuList *shared = new MenuListShared();
shared->addMenuItem(MENU_SHARED_KEY_ADD , new MenuListSharedAddShare());
shared->addMenuItem(MENU_SHARED_KEY_UNSHARE , new MenuListSharedUnshare());
shared->addMenuItem(MENU_SHARED_KEY_PUBLIC , new MenuListSharedTogglePublic());
shared->addMenuItem(MENU_SHARED_KEY_BROWSABLE , new MenuListSharedToggleBrowsable());
/* Top Level Menu */
Menu *tlm = new Menu("Top Level Menu");
tlm->addMenuItem(MENU_TOPLEVEL_KEY_FRIENDS, friends);
tlm->addMenuItem(MENU_TOPLEVEL_KEY_NETWORK, network);
tlm->addMenuItem(MENU_TOPLEVEL_KEY_TRANSFER, transfers);
tlm->addMenuItem(MENU_TOPLEVEL_KEY_SEARCH, search);
//tlm->addMenuItem(MENU_TOPLEVEL_KEY_FORUMS, forums);
tlm->addMenuItem(MENU_TOPLEVEL_KEY_SHARED, shared);
return tlm;
}
/************
* Friends Menu
*/
uint32_t MenuListFriends::op()
{
MenuList::op();
rsPeers->getGPGAcceptedList(mList);
//rsPeers->getGPGValidList(mList);
return MENU_OP_SUBMENU;
}
int MenuListFriends::getEntryDesc(int idx, std::string &desc)
{
std::string gpgId;
if (!getListEntry(idx, gpgId))
{
/* error */
return 0;
}
RsPeerDetails details;
if (rsPeers->getPeerDetails(gpgId, details))
{
if (details.accept_connection)
{
desc = "Friend: ";
}
else
{
desc = "Neighbour: ";
}
desc += "<" + gpgId + "> ";
desc += details.name;
}
return 1;
}
uint32_t MenuListNetwork::op()
{
MenuList::op();
rsPeers->getGPGValidList(mList);
//rsPeers->getGPGAcceptedList(mList);
return MENU_OP_SUBMENU;
}
uint32_t MenuOpFriendsAdd::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpFriendsViewDetail::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpFriendsRemove::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpFriendsChat::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
/************
* Transfer Menu
*/
uint32_t MenuListTransfer::op()
{
MenuList::op();
/* load friend list*/
rsFiles->FileDownloads(mList);
return MENU_OP_SUBMENU;
}
int MenuListTransfer::getEntryDesc(int idx, std::string &desc)
{
std::string hash;
if (!getListEntry(idx, hash))
{
std::cout << "MenuListTransfer::getEntryDesc() No ListEntry";
std::cout << std::endl;
return 0;
}
FileInfo info;
if (!rsFiles->FileDetails(hash, RS_FILE_HINTS_DOWNLOAD, info))
{
std::cout << "MenuListTransfer::getEntryDesc() No FileDetails";
std::cout << std::endl;
return 0;
}
float frac = 100.0 * (float) info.transfered / info.size;
if (frac != 1.0)
{
if (info.tfRate > 0)
{
rs_sprintf(desc, "<%s> Downloading %3.2f%% from %d Peers @%3.1fKB/s. Name: %s",
info.hash.c_str(), frac, info.peers.size(), info.tfRate, info.fname.c_str());
}
else
{
rs_sprintf(desc, "<%s> Stalled %3.2f%% Name: %s",
info.hash.c_str(), frac, info.fname.c_str());
}
}
else
{
rs_sprintf(desc, "<%s> Done! Name: %s", info.hash.c_str(), info.fname.c_str());
}
return MENU_OP_INSTANT;
}
uint32_t MenuOpTransferStop::op_basic(std::string key)
{
rsFiles->FileCancel(key);
parent()->setOpMessage("Stopped Transfer");
return MENU_OP_INSTANT;
}
uint32_t MenuOpTransferCancel::op_basic(std::string key)
{
rsFiles->FileCancel(key);
parent()->setOpMessage("Stopped Transfer");
return MENU_OP_INSTANT;
}
/************
* Search Menu
*/
uint32_t MenuListSearch::op()
{
mSelectIdx = -1;
mCursor = 0;
/* Don't reset List -> done dynamically */
return MENU_OP_SUBMENU;
}
int MenuListSearch::getEntryDesc(int idx, std::string &desc)
{
std::string strSearchId;
if (!getListEntry(idx, strSearchId))
{
/* error */
return 0;
}
std::map<std::string, std::string>::iterator it;
std::map<std::string, uint32_t>::iterator sit;
it = mSearchTerms.find(strSearchId);
sit = mSearchIds.find(strSearchId);
if ((it == mSearchTerms.end()) || (sit == mSearchIds.end()))
{
/* error */
return 0;
}
rs_sprintf(desc, "Search(\"%s\") Found %d matches so far",
it->second.c_str(), mNotify->getSearchResultCount(sit->second));
return 1;
}
int MenuListSearch::getCurrentSearchId(uint32_t &id)
{
std::string strSearchId;
if (!getListEntry(mSelectIdx, strSearchId))
{
/* error */
return 0;
}
std::map<std::string, uint32_t>::iterator sit;
sit = mSearchIds.find(strSearchId);
if (sit == mSearchIds.end())
{
/* error */
return 0;
}
id = sit->second;
return 1;
}
int MenuListSearch::storeSearch(uint32_t searchId, std::string match_string)
{
std::cout << "MenuListSearch::storeSearch(" << searchId << " => ";
std::cout << match_string;
std::cout << std::endl;
std::string strSearchId;
rs_sprintf(strSearchId, "%lu", searchId);
mList.push_back(strSearchId);
mSearchTerms[strSearchId] = match_string;
mSearchIds[strSearchId] = searchId;
return 1;
}
int MenuListSearch::removeSearch(std::string strSearchId)
{
std::cout << "MenuListSearch::removeSearch(" << strSearchId << ")";
std::cout << std::endl;
std::map<std::string, uint32_t>::iterator it;
it = mSearchIds.find(strSearchId);
if (it != mSearchIds.end())
{
/* cancel search */
// CAN'T DO!!!
/* clear results from Notify Collector */
mNotify->clearSearchId(it->second);
/* cleanup local maps */
mSearchIds.erase(it);
/* cleanup terms maps (TODO) */
}
return 1;
}
uint32_t MenuOpSearchNew::drawPage(uint32_t drawFlags, std::string &buffer)
{
buffer += "Enter New Search Term > ";
return 1;
}
uint32_t MenuOpSearchNew::process_lines(std::string input)
{
/* launch search */
if (input.size() < 4)
{
std::cout << "MenuOpSearchNew::process_lines() ERROR Input too small";
std::cout << std::endl;
return MENU_PROCESS_ERROR;
}
std::string search = input.substr(0, input.size() - 1); // remove \n.
uint32_t searchId = (uint32_t) rsTurtle->turtleSearch(search);
mNotify->collectSearchResults(searchId);
/* store request in parent */
MenuListSearch *ms = dynamic_cast<MenuListSearch *>(parent());
if (ms)
{
ms->storeSearch(searchId, search);
}
return MENU_PROCESS_DONE;
}
uint32_t MenuOpSearchDelete::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuListSearchList::op()
{
MenuList::op();
return refresh();
}
uint32_t MenuListSearchList::refresh()
{
Menu* p = parent();
MenuListSearch *mls = dynamic_cast<MenuListSearch *>(p);
if (!mls)
{
std::cout << "MenuListSearchList::refresh() mls not there";
std::cout << std::endl;
return MENU_OP_ERROR;
}
/* load friend list*/
mList.clear();
uint32_t searchId;
if (!mls->getCurrentSearchId(searchId))
{
std::cout << "MenuListSearchList::refresh() currentIdx invalid";
std::cout << std::endl;
return MENU_OP_ERROR;
}
std::cout << "MenuListSearchList::refresh() searchId: " << searchId;
std::cout << std::endl;
std::list<TurtleFileInfo>::iterator it;
mNotify->getSearchResults(searchId, mSearchResults);
/* convert into useful list */
for(it = mSearchResults.begin(); it != mSearchResults.end(); it++)
{
mList.push_back(it->hash);
}
mSelectIdx = -1;
mCursor = 0;
return MENU_OP_SUBMENU;
}
int MenuListSearchList::getEntryDesc(int idx, std::string &desc)
{
std::list<TurtleFileInfo>::iterator it;
int i = 0;
for (it = mSearchResults.begin();
(i < idx) && (it != mSearchResults.end()); it++, i++) ;
if (it != mSearchResults.end())
{
rs_sprintf(desc, "<%s> Size: %llu Name:%s",
it->hash.c_str(), it->size, it->name.c_str());
return MENU_ENTRY_OKAY;
}
return MENU_ENTRY_NONE;
}
int MenuListSearchList::downloadSelected()
{
if (mSelectIdx < 0)
{
std::cout << "MenuListSearchList::downloadSelected() Invalid Selection";
std::cout << std::endl;
return MENU_ENTRY_NONE;
}
std::list<TurtleFileInfo>::iterator it;
int i = 0;
for (it = mSearchResults.begin();
(i < mSelectIdx) && (it != mSearchResults.end()); it++, i++) ;
if (it != mSearchResults.end())
{
std::list<std::string> srcIds;
if (rsFiles -> FileRequest(it->name, it->hash, it->size,
"", RS_FILE_REQ_ANONYMOUS_ROUTING, srcIds))
{
std::cout << "MenuListSearchList::downloadSelected() Download Started";
std::cout << std::endl;
}
else
{
std::cout << "MenuListSearchList::downloadSelected() Error Starting Download";
std::cout << std::endl;
}
return MENU_ENTRY_OKAY;
}
return MENU_ENTRY_NONE;
}
uint32_t MenuOpSearchListDownload::op_basic(std::string key)
{
Menu* p = parent();
MenuListSearchList *mlsl = dynamic_cast<MenuListSearchList *>(p);
if (!mlsl)
{
std::cout << "MenuOpSearchListDownload::op_basic() ERROR";
std::cout << std::endl;
return MENU_OP_ERROR;
}
mlsl->downloadSelected();
return MENU_OP_INSTANT;
}
/************
* Forums Menu
*/
uint32_t MenuListForums::op()
{
/* load friend list*/
mList.clear();
rsPeers->getGPGAcceptedList(mList);
mSelectIdx = 0;
return MENU_OP_SUBMENU;
}
int MenuListForums::getEntryDesc(int idx, std::string &desc)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumDetails::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumSubscribe::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumUnsubscribe::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumCreate::op_basic(std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuListForumMsgs::op()
{
/* load friend list*/
mList.clear();
rsPeers->getGPGAcceptedList(mList);
mSelectIdx = 0;
return MENU_OP_SUBMENU;
}
int MenuListForumMsgs::getEntryDesc(int idx, std::string &desc)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumMsgView::op_twokeys(std::string parentkey, std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumMsgReply::op_twokeys(std::string parentkey, std::string key)
{
return MENU_OP_INSTANT;
}
uint32_t MenuOpForumMsgWrite::op_twokeys(std::string parentkey, std::string key)
{
return MENU_OP_INSTANT;
}
/************
* Shared folders Menu
*/
uint32_t MenuListShared::op()
{
MenuList::op();
mList.clear();
std::list<SharedDirInfo> dirs;
rsFiles->getSharedDirectories(dirs);
std::list<SharedDirInfo>::iterator it;
for(it = dirs.begin(); it != dirs.end(); it++)
{
mList.push_back ((*it).virtualname) ;
}
return MENU_OP_SUBMENU;
}
int MenuListShared::getEntryDesc(int idx, std::string &desc)
{
std::list<SharedDirInfo> dirs;
rsFiles->getSharedDirectories(dirs);
std::list<SharedDirInfo>::iterator it;
std::string shareflag;
int i=0;
for (it = dirs.begin(); (i < idx) && (it != dirs.end()); it++, i++);
if (it != dirs.end())
{
bool networkwide = (it->shareflags & DIR_FLAGS_NETWORK_WIDE_OTHERS);
bool browsable = (it->shareflags & DIR_FLAGS_BROWSABLE_OTHERS);
if (networkwide && browsable)
{
shareflag = "networkwide - browsable";
}
else if (browsable)
{
shareflag = "private - browsable";
}
else if (networkwide)
{
shareflag = "networkwide - anonymous";
}
else
{
shareflag = "not shared";
}
rs_sprintf(desc, "Path: %s Share Type:%s", it->filename.c_str(), shareflag.c_str());
return MENU_ENTRY_OKAY;
}
return MENU_ENTRY_NONE;
}
int MenuListShared::unshareSelected()
{
if (mSelectIdx < 0)
{
std::cout << "MenuListSearchList::unshareSelected() Invalid Selection";
std::cout << std::endl;
return MENU_ENTRY_NONE;
}
std::list<SharedDirInfo> dirs;
rsFiles->getSharedDirectories(dirs);
std::list<SharedDirInfo>::iterator it;
int i=0;
for (it = dirs.begin(); (i < mSelectIdx) && (it != dirs.end()); it++, i++);
if (it != dirs.end())
{
rsFiles->removeSharedDirectory(it->filename);
return MENU_ENTRY_OKAY;
}
return MENU_ENTRY_NONE;
}
int MenuListShared::toggleFlagSelected(FileStorageFlags shareflags)
{
if (mSelectIdx < 0)
{
std::cout << "MenuListSearchList::unshareSelected() Invalid Selection";
std::cout << std::endl;
return MENU_ENTRY_NONE;
}
std::list<SharedDirInfo> dirs;
rsFiles->getSharedDirectories(dirs);
std::list<SharedDirInfo>::iterator it;
int i=0;
for (it = dirs.begin(); (i < mSelectIdx) && (it != dirs.end()); it++, i++);
if (it != dirs.end())
{
if(FileStorageFlags(it->shareflags & shareflags) == shareflags)
{
it->shareflags = FileStorageFlags(it->shareflags & ~shareflags); //disable shareflags
rsFiles->updateShareFlags(*it);
}
else
{
it->shareflags = FileStorageFlags(it->shareflags | shareflags); //anable shareflags
rsFiles->updateShareFlags(*it);
}
return MENU_ENTRY_OKAY;
}
return MENU_ENTRY_NONE;
}
uint32_t MenuListSharedUnshare::op_basic(std::string key)
{
Menu* p = parent();
MenuListShared *mls = dynamic_cast<MenuListShared *>(p);
if (!mls)
{
std::cout << "MenuListShared::op_basic() ERROR";
std::cout << std::endl;
return MENU_OP_ERROR;
}
mls->unshareSelected();
return MENU_OP_INSTANT;
}
uint32_t MenuListSharedTogglePublic::op_basic(std::string key)
{
Menu* p = parent();
MenuListShared *mls = dynamic_cast<MenuListShared *>(p);
if (!mls)
{
std::cout << "MenuListShared::op_basic() ERROR";
std::cout << std::endl;
return MENU_OP_ERROR;
}
mls->toggleFlagSelected(DIR_FLAGS_NETWORK_WIDE_OTHERS);
return MENU_OP_INSTANT;
}
uint32_t MenuListSharedToggleBrowsable::op_basic(std::string key)
{
Menu* p = parent();
MenuListShared *mls = dynamic_cast<MenuListShared *>(p);
if (!mls)
{
std::cout << "MenuListShared::op_basic() ERROR";
std::cout << std::endl;
return MENU_OP_ERROR;
}
mls->toggleFlagSelected(DIR_FLAGS_BROWSABLE_OTHERS);
return MENU_OP_INSTANT;
}
uint32_t MenuListSharedAddShare::drawPage(uint32_t drawFlags, std::string &buffer)
{
buffer += "Enter New path 'path' 'virtualfolder' > ";
return 1;
}
uint32_t MenuListSharedAddShare::process_lines(std::string input)
{
/* launch search */
if (input.size() < 4)
{
std::cout << "MenuOpSearchNew::process_lines() ERROR Input too small";
std::cout << std::endl;
return MENU_PROCESS_ERROR;
}
std::string dir = input.substr(0, input.size() - 1); // remove \n.
// check that the directory exists!
if (!RsDirUtil::checkDirectory(dir))
{
std::cout << "MenuOpSearchNew::process_lines() ERROR Directory doesn't exist";
std::cout << std::endl;
return MENU_PROCESS_ERROR;
}
// extract top level as the virtual name.
std::string topdir = RsDirUtil::getTopDir(input);
if (topdir.size() < 1)
{
std::cout << "MenuOpSearchNew::process_lines() ERROR TopDir is invalid";
std::cout << std::endl;
return MENU_PROCESS_ERROR;
}
SharedDirInfo shareddir;
shareddir.filename = dir;
shareddir.virtualname = topdir;
shareddir.shareflags = FileStorageFlags(0x0);
if (!rsFiles->addSharedDirectory(shareddir))
{
std::cout << "MenuOpSearchNew::process_lines() ERROR Adding SharedDir";
std::cout << std::endl;
return MENU_PROCESS_ERROR;
}
return MENU_PROCESS_DONE;
}