From 6e068a8e83709544a39009623a345808f18655ca Mon Sep 17 00:00:00 2001 From: Maurice ONeal Date: Sun, 8 Mar 2020 14:58:51 -0400 Subject: [PATCH] New versioning system, type ids and a few bug fixes Changed the versioning system to a 4 number system that have the first 2 numbers as major.minor for the host application itself and the next 2 numbers (tcp_rev.mod_rev) used by clients and modules to determine compatibility. A full description of this new system has been edited into protocol.md. This new system offically starts at v3.0.0.0. Added the PROMPT data type id that will work exactly like PRIV_TEXT except it tells the client that the command is asking for non-private information from the user. Added PROG and PROG_LAST type ids that can be used by commands to notify the client of the progress of the command if it is long running. The long running fs_* commands were updated to use these instead of TEXT for progress updates. PUB_IPC, PRIV_IPC and PUB_IPC_WITH_FEEDBACK have all been combined into one: ASYNC_PAYLOAD. This type id is now the only means at which module commands can now run async commands. The command process object will now determine where to direct the async payload (public, private or public with feedback) based on the async command id being requested. A description for TERM_CMD was missing in data_types.md so it was added. Refactored HALT_CMD to YIELD_CMD. The new name just seems more appropriate or the effect it has on the command. Module commands can now do input hooking using the new ASYNC_HOOK_INPUT and ASYNC_UNHOOK async commands. input hooking basically makes it so all client data gets redirected to the module command that initiated the hook. This can be used to implement something like a EULA agreement that blocks all actions that can place during the session until the user accepts or anything else to that effect. The command process object will now check the open sub-channels list being sent by ASYNC_CAST or ASYNC_LIMITED_CAST in any order and will not be required match exactly to open sub-channels list in the session object. It however cannot contain sub-channels not already listed in session's list or else the async payload will be blocked. Fixed the CmdProcess::validAsync() function that was comparing the input aysnc command id with the process's command id in some places which is invalid logic for this function. Fixed the 'cast' core command that was outputting a malformed async payload that didn't include the open writable sub-channels list. Fixed a bug that caused all casted payloads to be forwared to the clients even when the sub-channel(s) are closed. Fixed the 'set_disp_name' core command so it can now see the -new_name argument properly. --- docs/async.md | 54 +++++++++-------- docs/protocol.md | 46 ++++++++++---- docs/type_ids.md | 108 ++++++++++++++++++--------------- linux_build.sh | 2 +- src/async_funcs.cpp | 55 ++++++++--------- src/cmd_object.cpp | 65 +++++++++++++++++--- src/cmd_object.h | 9 ++- src/cmd_proc.cpp | 104 ++++++++++++++++++++----------- src/cmd_proc.h | 4 +- src/commands/acct_recovery.cpp | 2 +- src/commands/admin.cpp | 40 ++++++------ src/commands/auth.cpp | 18 +++--- src/commands/cast.cpp | 12 ++-- src/commands/certs.cpp | 4 +- src/commands/channels.cpp | 28 ++++----- src/commands/cmd_ranks.cpp | 4 +- src/commands/fs.cpp | 83 ++++++++++++------------- src/commands/fs.h | 5 -- src/commands/mods.cpp | 4 +- src/commands/p2p.cpp | 8 +-- src/commands/table_viewer.cpp | 6 +- src/commands/users.cpp | 14 ++--- src/common.cpp | 31 ++++++++-- src/common.h | 78 +++++++++++++----------- src/db.h | 2 +- src/main.cpp | 2 +- src/session.cpp | 20 +++++- src/session.h | 1 + 28 files changed, 479 insertions(+), 330 deletions(-) diff --git a/docs/async.md b/docs/async.md index 4776ddf..40571fb 100644 --- a/docs/async.md +++ b/docs/async.md @@ -9,33 +9,29 @@ Here is a describtion of what the keywords in the list mean: client - this means the async command id will be used to forward data of any type to client if needed. -internal - this means the async command will be responded by the - session object but the data will not be forwarded to the - client or converted to an entirely different async - command before sending to the client. +internal - this means the async command used by internal host + objects only so it never gets forwarded to a client at + any time. -public - this means the session objects will respond to this async - command if sent with PUB_IPC or PUB_IPC_WITH_FEEDBACK - from the module. +public - this means the aysnc command will be broadcasted to all + session objects currently connected to the host. which + sessions will resond to it depends on the data being + sent. some async's broadcasted this way will also feed + back to source session depending on the data. -private - this means only the session object that has a direct IPC - connection with the module that sends the async command - via PRIV_IPC will respond to it. +private - this means the async command will only be sent to the + local session. -none - this means none of the session objects will respond to - this async command no matter which of the IPC data types - are used. it is resevered for just the session object to - send to the client. - -retricted - this means the session object will actively block this - async command from being sent from the module (any mode). +retricted - this means the async command will be used by the local + session object only. any modules/commands sending it + will be ignored or blocked. ``` ``` enum AsyncCommands : quint16 { - ASYNC_RDY = 1, // client | none - ASYNC_SYS_MSG = 2, // client | none + ASYNC_RDY = 1, // client | retricted + ASYNC_SYS_MSG = 2, // client | retricted ASYNC_EXIT = 3, // internal | private ASYNC_CAST = 4, // client | public ASYNC_MAXSES = 5, // internal | private @@ -49,7 +45,7 @@ enum AsyncCommands : quint16 ASYNC_DISABLE_MOD = 13, // internal | public ASYNC_END_SESSION = 14, // internal | private ASYNC_USER_LOGIN = 15, // internal | private - ASYNC_TO_PEER = 16, // client | public | retricted + ASYNC_TO_PEER = 16, // client | retricted ASYNC_LIMITED_CAST = 17, // client | public ASYNC_RW_MY_INFO = 18, // internal | public ASYNC_P2P = 19, // client | public @@ -68,15 +64,17 @@ enum AsyncCommands : quint16 ASYNC_SUB_CH_LEVEL_CHG = 32, // client | public ASYNC_ADD_RDONLY = 33, // client | public ASYNC_RM_RDONLY = 34, // client | public - ASYNC_ADD_CMD = 35, // client | none - ASYNC_RM_CMD = 36, // client | none + ASYNC_ADD_CMD = 35, // client | retricted + ASYNC_RM_CMD = 36, // client | retricted ASYNC_USER_RENAMED = 37, // internal | public ASYNC_PING_PEERS = 38, // internal | private ASYNC_OPEN_SUBCH = 39, // internal | private ASYNC_CLOSE_SUBCH = 40, // internal | private ASYNC_KEEP_ALIVE = 42, // internal | private ASYNC_SET_DIR = 43, // internal | private - ASYNC_DEBUG_TEXT = 44 // internal | private + ASYNC_DEBUG_TEXT = 44, // internal | private + ASYNC_HOOK_INPUT = 45, // internal | private + ASYNC_UNHOOK = 46 // internal | private }; ``` @@ -140,7 +138,7 @@ This internal only async commmand doesn't carry any data. It is used by modules This command carries a 32byte user id hash. This can be used by modules to tell the session object to login as this user. ```ASYNC_TO_PEER (16)``` -This is an async command that carry an embedded data frame directly to/from peer sessions without any restrictions. It is prepended with the 224bit hash of the target session id; however, it drops that session id before arriving at the client so it will apppear as a regular mrci frame of any data type. Modules do not have direct access to this, the host internal objects will handle this. +This is an async command that carry an embedded data frame directly to/from peer sessions without any restrictions. It is prepended with the 224bit hash of the target session id; however, it drops that session id before arriving at the client so it will apppear as a regular mrci frame of any data type. modules do not have direct access to this, the host internal objects will handle it. ``` from_module: [28bytes(sessionId)][1byte(typeId)][rest-of-bytes(payload)] to_client: [type_id][cmd_id(16)][branch_id(0)][size_of_payload][payload] @@ -292,11 +290,17 @@ This is the other half to ASYNC_OPEN_SUBCH that tells the session to close the r This internal only async command doesn't carry any data. The session object normally sends a [KILL_CMD](type_ids.md) to the module when it detects that the module process has not sent an IPC frame in 2 minutes to terminate the module process. If desired, the module can send this async command in regular intervals to reset this 2 minute idle timer to prevent auto termination. ```ASYNC_SET_DIR (43)``` -This internal only async command carries a [TEXT](type_ids.md) path that sets the working directory for the session object. All module processes started by the session will use this directory as the working directory and it is not shared among peer sessions. nothing happens if the path is invalid or does not exists. +This internal only async command carries a [TEXT](type_ids.md) path that sets the working directory for the local session. All module processes started by the session will use this directory as the working directory and it is not shared among peer sessions. nothing happens if the path is invalid or does not exists. ```ASYNC_DEBUG_TEXT (44)``` This internal only async command carries a [TEXT](type_ids.md) debug message to be logged into the host debug log from the module. Modules can use this to help with debugging issues if it doesn't have direct access to the host database. +```ASYNC_HOOK_INPUT (45)``` +This async command doesn't carry any data. This just indicate to the local session that the module command is requesting to hook the tcp data input from the client. when the tcp input is hooked, all data sent from the client is redirected to the command object/process that initiated the hook until reqested to unhook. If the command that initiated the hook terminates in anyway with an active hook, the hook will automatically be removed. + +```ASYNC_UNHOOK (46)``` +This async command doesn't carry any data. Any module command that sends it tells the local session to unhook the tcp input data from the client if there is an active hook. This doesn't need to come from the command that initiated the hook. + ### 5.3 Open Sub-Channel List ### An open sub-channel list is a binary data structure that string togeather up to 6 channel-sub combinations that indicate which channel id and sub id combinations are currently open. Each sub-channel are 9bytes long and the list itself maintians a fixed length of 54bytes so it is padded with 0x00 chars to maintain the fixed length (this padding can appear anywhere in 9byte increments within the list). Each sub-channel is formatted like this: diff --git a/docs/protocol.md b/docs/protocol.md index f4ea291..841fed2 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -26,13 +26,34 @@ notes: ### 1.3 Versioning System ### -The host uses the typical 3 number versioning system: Major.Minor.Patch +The host uses a 4 number versioning system that indicate rev numbers for the host application itself, the tcp interface and the module interface: +``` +[Major][Minor][TCP_Rev][Mod_Rev] + 3 . 0 . 0 . 0 + +Major - this indicate any changes to the host application that would cause + clients to need to change behaviour to maintain compatibility. + changes to the core command names, type id format changes, etc. + will cause the version major to increment. + +Minor - this indicate any changes to the host application that clients will + not see and would not need behaviour changes to maintain + compatibility. documentation changes, bug fixes, security patches, + etc. will cause the version minor to increment. + +TCP_Rev - this indicate any changes to the MRCI protocol that interface the + host with the clients via the TCP connection. any changes to the + MRCI frames, host/client headers, etc. will cause this rev to + increment. + +Mod_Rev - this indicate any changes to the IPC protocol that interface the + host with the modules via named pipes. any changes to the IPC + frames, NEW_CMD/CMD_ID type ids, etc. will cause this rev to + increment. + +``` -* **Major** - this indicates any major changes to the code of the application that renders versions of different majors incompatible with each other. -* **Minor** - this indicates only minor changes to the code that may require a few conditional blocks to maintain compatibility. -* **Patch** - this indicates changes that won't require any behaviour changes at all to maintain compatibility. - -Any increments to the major resets the minor and patch to 0. Any 3rd party client applications connecting to a MRCI host need to be aware of this versioning but does not need to adopt it as it's own version number. +Any increments to the Major resets the Minor to 0. Any 3rd party client applications connecting to a MRCI host need to be aware of this versioning but does not need to adopt it as it's own version number. ### 1.4 Client Header ### @@ -57,13 +78,14 @@ notes: ``` Format: -[reply][major][minor][patch][sesId] +[reply][major][minor][tcp_rev][mod_rev][sesId] -reply - 1byte - 8bit little endian unsigned int -major - 2bytes - 16bit little endian unsigned int -minor - 2bytes - 16bit little endian unsigned int -patch - 2bytes - 16bit little endian unsigned int -sesId - 28bytes - 224bit sha3 hash +reply - 1byte - 8bit little endian unsigned int +major - 2bytes - 16bit little endian unsigned int +minor - 2bytes - 16bit little endian unsigned int +tcp_rev - 2bytes - 16bit little endian unsigned int +mod_rev - 2bytes - 16bit little endian unsigned int +sesId - 28bytes - 224bit sha3 hash ``` notes: diff --git a/docs/type_ids.md b/docs/type_ids.md index 3ab4f99..c4ff2d7 100644 --- a/docs/type_ids.md +++ b/docs/type_ids.md @@ -5,35 +5,36 @@ All mrci frames transferred throughout this application have an 8bit numeric val ``` enum TypeID : quint8 { - GEN_FILE = 1, - TEXT = 2, - ERR = 3, - PRIV_TEXT = 4, - IDLE = 5, - HOST_CERT = 6, - FILE_INFO = 7, - PEER_INFO = 8, - MY_INFO = 9, - PEER_STAT = 10, - P2P_REQUEST = 11, - P2P_CLOSE = 12, - P2P_OPEN = 13, - BYTES = 14, - SESSION_ID = 15, - NEW_CMD = 16, - CMD_ID = 17, - BIG_TEXT = 18, - TERM_CMD = 19, - HOST_VER = 20, - PRIV_IPC = 21, - PUB_IPC = 22, - PUB_IPC_WITH_FEEDBACK = 23, - PING_PEERS = 24, - CH_MEMBER_INFO = 25, - CH_ID = 26, - KILL_CMD = 27, - HALT_CMD = 28, - RESUME_CMD = 29 + GEN_FILE = 1, + TEXT = 2, + ERR = 3, + PRIV_TEXT = 4, + IDLE = 5, + HOST_CERT = 6, + FILE_INFO = 7, + PEER_INFO = 8, + MY_INFO = 9, + PEER_STAT = 10, + P2P_REQUEST = 11, + P2P_CLOSE = 12, + P2P_OPEN = 13, + BYTES = 14, + SESSION_ID = 15, + NEW_CMD = 16, + CMD_ID = 17, + BIG_TEXT = 18, + TERM_CMD = 19, + HOST_VER = 20, + PING_PEERS = 21, + CH_MEMBER_INFO = 22, + CH_ID = 23, + KILL_CMD = 24, + YIELD_CMD = 25, + RESUME_CMD = 26, + PROMPT_TEXT = 27, + PROG = 28, + PROG_LAST = 29, + ASYNC_PAYLOAD = 30 }; ``` @@ -71,13 +72,16 @@ arguments: This type id is similar to TEXT except it indicates that this is an error message that can be displayed directly to the user if needed. ```PRIV_TEXT``` -This id can be treated exactly like TEXT except this should tell the client to hide or do not echo the next TEXT data that the host is expecting, like a password or other sensitive text data. +This id can be treated exactly like TEXT except this tells the client that the command is prompting for private information from the user so it sould hide or do not echo the next TEXT data that the command is expecting, like a password or other sensitive data. + +```PROMPT_TEXT``` +This is similar to PRIV_TEXT expect it is not asking for private information. It is simply prompting for non-sensitive information from the user. ```BIG_TEXT``` Also formatted exactly like TEXT but this indicates to the client that this is a large body of text that is recommended to be word wrapped when displaying to the user. It can contain line breaks so clients are also recommended to honor those line breaks. ```IDLE``` -All commands started during the session returns this type id when it has finished it's task. by default, it carries a 16bit unsigned integer indicating the result of the task that the command was running. +All commands started during the session returns this type id when it has finished it's task. It carries a 16bit unsigned integer indicating the result of the task that the command was running. ``` enum RetCode : quint16 @@ -94,35 +98,39 @@ enum RetCode : quint16 notes: 1. the custom return code can be additional data added to the end of the 16bit integer that can carry additional data about the result of the task. it can - be any format that the module itself decides it should be. nothing is + be any format that the module itself decides it can should be. nothing is stopping modules from defining return codes beyond the value of 7 but it is advised not to because this enum might be expanded in the future. ``` -```KILL_CMD``` -This doesn't carry any actual data, instead can be sent by the client or session object to tell the command-branch id sent in the frame to terminate the module process. Modules that receive this need to send a IDLE frame if a command is still running and then terminate itself. The module will have 3 seconds to do this before it is force killed by the session. +```TERM_CMD``` +This type id doesn't carry any actual data. It is used to tell the host to stop/terminate the command id and branch id that was used to send it. It does not actually terminate the module's process within the host, it only simply tells it to stop what it is currently doing. This will also terminate any commands in a prompt/more input state. -```HALT_CMD``` -This doesn't carry any actual data, instead can be sent by the client or session object to tell the command-branch id sent in the frame to pause/halt the current task that the command is currently running. All modules are not obligated to support this feature but highly recommended. +```KILL_CMD``` +This works similarly to TERM_CMD except it will also terminate the module process. The module process will have 3 seconds to shutdown gracefully before it is force killed by the host session. + +```YIELD_CMD``` +This type id doesn't carry any actual data, instead can be used to tell the host to pause/yield the command id and branch id that was used to send it. All modules are not obligated to support this feature but it is highly recommended to do so. ```RESUME_CMD``` -This is the other half of HALT_CMD that tells the module to resume the command task it was running. +This is the other half of YIELD_CMD that tells the host to resume the command that was running. ```HOST_CERT``` Just as the name implies, this data type is used by the host to send the host SSL certificate while setting up an SSL connection. ```HOST_VER``` -This data structure carries 3 numeric values that represent the host version as described in section [1.3](protocol.md). +This data structure carries 4 numeric values that represent the host version as described in section [1.3](protocol.md). ``` format: 1. bytes[0-1] - version major (16bit little endian uint) 2. bytes[2-3] - version minor (16bit little endian uint) - 3. bytes[4-5] - version patch (16bit little endian uint) + 3. bytes[4-5] - tcp interface rev (16bit little endian uint) + 4. bytes[6-7] - module interface rev (16bit little endian uint) ``` -```PRIV_IPC``` -This is a data structure used to by modules to run async commands on the local session object only. +```ASYNC_PAYLOAD``` +This is a data structure that can be used by modules to run async commands. Each async command have a specific 16bit command id followed by a payload that can contain any data of any format depending on the async command id. A full discribtion of the async commands and the data they carry can found in section [5.1](async.md) and [5.2](async.md). ``` format: @@ -130,12 +138,6 @@ This is a data structure used to by modules to run async commands on the local s 2. bytes[2-n] - payload (data to be processed by async command) ``` -```PUB_IPC``` -This is formatted exactly like PRIV_IPC except it is used by modules to run async commands on all peer session objects in the host while avoiding a run on the local session object. - -```PUB_IPC_WITH_FEEDBACK``` -This has the same functionality as PUB_IPC except it is also feedback into the local session object. - ```FILE_INFO``` This is a data structure that carries information about a file system object (file,dir,link). @@ -192,7 +194,7 @@ This carry some user account and session information about a peer client connect ``` ```PING_PEERS``` -This is formatted extactly as PEER_INFO except it can be used the ASYNC_LIMITED_CAST [async](async.md) command to tell all peer sessions that receive it to send a PEER_INFO frame about you to their own clients and return PEER_INFO frames about themselves to you. +This is formatted extactly as PEER_INFO except it is used by the ASYNC_LIMITED_CAST [async](async.md) command to tell all peer sessions that receive it to send a PEER_INFO frame about the local session to their own clients and return PEER_INFO frames about themselves to the local session. ```MY_INFO``` This contains all of the information found in ```PEER_INFO``` for the local session but also includes the following: @@ -240,7 +242,7 @@ This type id carries a 64bit unsighed LE int indicating the channel id. format: ```8bytes - 64bit LE unsigned int (channel id)``` ```SESSION_ID``` -This is a fixed length 28byte(224bit) sha3 hash of a client's session id connected to the host. This is unique to just the client's tcp connection with the host. This can change upon re-connection. +This is a fixed length 28byte(224bit) sha3 hash of a client's session id connected to the host. This is unique to just the client's tcp connection with the host. This changes upon re-connection. format: ```28bytes - session id (224bit sha3 hash)``` @@ -307,6 +309,14 @@ This contains public information about a channel member. data type. ``` +```PROG``` +This is a 8bit integer value from 0-100 indicating the percentage progress of the command. All long running module commands are encouraged to use this to update the client on command progress; sending it in a 1-5 second pulse rate. + +format: ```1byte - 8bit integer (0-100)``` + +```PROG_LAST``` +This is formatted and treated exactly like PROG except it indicates to the client that this is the last progress update for the current string of progress updates. So at the client side, progress strings/pulses should appear with a single or multiple PROG frame(s) and then end with PROG_LAST. Receiving an IDLE should also end the progress string if seen before PROG_LAST. + ### 3.3 GEN_FILE Example ### Setup: diff --git a/linux_build.sh b/linux_build.sh index 8395609..6ee18b7 100644 --- a/linux_build.sh +++ b/linux_build.sh @@ -5,7 +5,7 @@ installer_file="$2" src_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" bin_name="mrci" -app_version="2.2.3" +app_version="3.0.0.0" app_name="MRCI" install_dir="/opt/$bin_name" var_dir="/var/opt/$bin_name" diff --git a/src/async_funcs.cpp b/src/async_funcs.cpp index 17b2607..22a38cb 100644 --- a/src/async_funcs.cpp +++ b/src/async_funcs.cpp @@ -78,13 +78,12 @@ void Session::castCatch(const QByteArray &data) { // format: [54bytes(chIds)][1byte(typeId)][rest-of-bytes(payload)] - if (matchChs(openSubChs, data.data())) + if (matchAnyCh(openSubChs, data.data())) { - int payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; - quint8 typeId = static_cast(data[payloadOffs - 1]); - quint32 len = static_cast(data.size() - payloadOffs); - - const char *payload = data.data() + payloadOffs; + auto payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; + auto typeId = static_cast(data[payloadOffs - 1]); + auto len = static_cast(data.size() - payloadOffs); + auto *payload = data.data() + payloadOffs; asyncToClient(ASYNC_CAST, rdFromBlock(payload, len), typeId); } @@ -96,11 +95,10 @@ void Session::directDataFromPeer(const QByteArray &data) if (memcmp(sessionId, data.data(), BLKSIZE_SESSION_ID) == 0) { - int payloadOffs = BLKSIZE_SESSION_ID + 1; - quint8 typeId = static_cast(data[payloadOffs - 1]); - quint32 len = static_cast(data.size() - payloadOffs); - - const char *payload = data.data() + payloadOffs; + auto payloadOffs = BLKSIZE_SESSION_ID + 1; + auto typeId = static_cast(data[payloadOffs - 1]); + auto len = static_cast(data.size() - payloadOffs); + auto *payload = data.data() + payloadOffs; asyncToClient(ASYNC_TO_PEER, rdFromBlock(payload, len), typeId); } @@ -112,13 +110,11 @@ void Session::p2p(const QByteArray &data) if (memcmp(sessionId, data.data(), BLKSIZE_SESSION_ID) == 0) { - int payloadOffs = (BLKSIZE_SESSION_ID * 2) + 1; - - const char *src = data.data() + BLKSIZE_SESSION_ID; - const char *payload = data.data() + payloadOffs; - - quint32 len = static_cast(data.size() - payloadOffs); - quint8 typeId = static_cast(data[payloadOffs - 1]); + auto payloadOffs = (BLKSIZE_SESSION_ID * 2) + 1; + auto *src = data.data() + BLKSIZE_SESSION_ID; + auto *payload = data.data() + payloadOffs; + auto len = static_cast(data.size() - payloadOffs); + auto typeId = static_cast(data[payloadOffs - 1]); if (typeId == P2P_REQUEST) { @@ -173,13 +169,12 @@ void Session::limitedCastCatch(const QByteArray &data) { // format: [54bytes(chIds)][1byte(typeId)][rest-of-bytes(payload)] - if (rd8BitFromBlock(activeUpdate) && matchChs(openSubChs, data.data())) + if (rd8BitFromBlock(activeUpdate) && matchAnyCh(openSubChs, data.data())) { - int payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; - quint32 len = static_cast(data.size() - payloadOffs); - quint8 typeId = static_cast(data[payloadOffs - 1]); - - const char *payload = data.data() + payloadOffs; + auto payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; + auto len = static_cast(data.size() - payloadOffs); + auto typeId = static_cast(data[payloadOffs - 1]); + auto *payload = data.data() + payloadOffs; if (typeId == PING_PEERS) { @@ -187,9 +182,9 @@ void Session::limitedCastCatch(const QByteArray &data) // async command to also send PEER_INFO of this session to the session // that requested the ping using ASYNC_TO_PEER. - QByteArray peerId = rdFromBlock(payload, BLKSIZE_SESSION_ID); - QByteArray typeId = wrInt(PEER_INFO, 8); - QByteArray info = createPeerInfoFrame(); + auto peerId = rdFromBlock(payload, BLKSIZE_SESSION_ID); + auto typeId = wrInt(PEER_INFO, 8); + auto info = createPeerInfoFrame(); emit asyncToPeers(ASYNC_TO_PEER, peerId + typeId + info); @@ -330,7 +325,7 @@ void Session::subChannelUpdated(quint16 cmdId, const QByteArray &data) void Session::addModule(const QByteArray &data) { - QString modApp = fromTEXT(data); + auto modApp = fromTEXT(data); if (!modCmdNames.contains(modApp)) { @@ -340,7 +335,7 @@ void Session::addModule(const QByteArray &data) void Session::rmModule(const QByteArray &data) { - QString modApp = fromTEXT(data); + auto modApp = fromTEXT(data); if (modCmdNames.contains(modApp) && (modApp != QCoreApplication::applicationFilePath())) { @@ -362,7 +357,7 @@ void Session::rmModule(const QByteArray &data) void Session::closeSubChannel(const QByteArray &data) { - QByteArray oldSubChs = QByteArray(openSubChs, MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL); + auto oldSubChs = QByteArray(openSubChs, MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL); if (rmBlockFromBlockset(data.data(), openSubChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL)) { diff --git a/src/cmd_object.cpp b/src/cmd_object.cpp index 3d083bd..7e92894 100644 --- a/src/cmd_object.cpp +++ b/src/cmd_object.cpp @@ -82,6 +82,9 @@ CmdObject::CmdObject(QObject *parent) : MemShare(parent) { ipcWorker = new IPCWorker(pipe, nullptr); keepAliveTimer = new QTimer(this); + progTimer = new QTimer(this); + progCurrent = 0; + progMax = 0; auto *thr = new QThread(nullptr); @@ -94,6 +97,7 @@ CmdObject::CmdObject(QObject *parent) : MemShare(parent) connect(this, &CmdObject::procOut, ipcWorker, &IPCWorker::dataIn); connect(keepAliveTimer, &QTimer::timeout, this, &CmdObject::keepAlive); + connect(progTimer, &QTimer::timeout, this, &CmdObject::sendProg); connect(ipcWorker, &IPCWorker::dataOut, this, &CmdObject::preProc); connect(ipcWorker, &IPCWorker::termProc, this, &CmdObject::kill); @@ -102,6 +106,8 @@ CmdObject::CmdObject(QObject *parent) : MemShare(parent) keepAliveTimer->setSingleShot(false); keepAliveTimer->setInterval(30000); //30sec keep alive + progTimer->setSingleShot(false); + progTimer->setInterval(1000); // 1sec progress updater ipcWorker->moveToThread(thr); thr->start(); } @@ -113,7 +119,7 @@ CmdObject::CmdObject(QObject *parent) : MemShare(parent) void CmdObject::term() { - if (flags & (MORE_INPUT | HALT_STATE | LOOPING)) + if (flags & (MORE_INPUT | YIELD_STATE | LOOPING)) { flags = 0; retCode = ABORTED; @@ -140,20 +146,20 @@ void CmdObject::preProc(const QByteArray &data, quint8 typeId) { kill(); } - else if (typeId == HALT_CMD) + else if (typeId == YIELD_CMD) { if (flags & LOOPING) { - flags |= HALT_STATE; + flags |= YIELD_STATE; flags &= ~LOOPING; } } else if (typeId == RESUME_CMD) { - if (flags & HALT_STATE) + if (flags & YIELD_STATE) { flags |= LOOPING; - flags &= ~HALT_STATE; + flags &= ~YIELD_STATE; } } else @@ -174,7 +180,7 @@ void CmdObject::postProc() { preProc(QByteArray(), TEXT); } - else if (flags & (MORE_INPUT | HALT_STATE)) + else if (flags & (MORE_INPUT | YIELD_STATE)) { keepAliveTimer->start(); } @@ -182,6 +188,11 @@ void CmdObject::postProc() { keepAliveTimer->stop(); + if (progTimer->isActive()) + { + stopProgPulse(); + } + emit procOut(wrInt(retCode, 16), IDLE); retCode = NO_ERRORS; @@ -208,14 +219,50 @@ void CmdObject::bigTxt(const QString &txt) emit procOut(toTEXT(txt), BIG_TEXT); } -void CmdObject::async(quint16 asyncId, quint8 asyncType, const QByteArray &data) +void CmdObject::promptTxt(const QString &txt) { - emit procOut(wrInt(asyncId, 16) + data, asyncType); + emit procOut(toTEXT(txt), PROMPT_TEXT); +} + +void CmdObject::async(quint16 asyncId, const QByteArray &data) +{ + emit procOut(wrInt(asyncId, 16) + data, ASYNC_PAYLOAD); } void CmdObject::keepAlive() { - async(ASYNC_KEEP_ALIVE, PRIV_IPC); + async(ASYNC_KEEP_ALIVE); +} + +void CmdObject::startProgPulse() +{ + progCurrent = 0; + + progTimer->start(); +} + +void CmdObject::stopProgPulse() +{ + progTimer->stop(); + + emit procOut(wrInt(100, 8), PROG_LAST); + + progCurrent = 0; + progMax = 0; +} + +void CmdObject::sendProg() +{ + quint8 percent = progCurrent / progMax * 100; + + if ((progMax == 0) || (percent >= 100)) + { + stopProgPulse(); + } + else + { + emit procOut(wrInt(percent, 8), PROG); + } } QString CmdObject::libName() diff --git a/src/cmd_object.h b/src/cmd_object.h index 15336ee..ca1ce6c 100644 --- a/src/cmd_object.h +++ b/src/cmd_object.h @@ -65,15 +65,21 @@ class CmdObject : public MemShare protected: QTimer *keepAliveTimer; + QTimer *progTimer; IPCWorker *ipcWorker; quint32 flags; quint16 retCode; + qint64 progCurrent; + qint64 progMax; void mainTxt(const QString &txt); void errTxt(const QString &txt); void privTxt(const QString &txt); void bigTxt(const QString &txt); - void async(quint16 asyncId, quint8 asyncType, const QByteArray &data = QByteArray()); + void promptTxt(const QString &txt); + void async(quint16 asyncId, const QByteArray &data = QByteArray()); + void startProgPulse(); + void stopProgPulse(); void postProc(); QString libName(); @@ -83,6 +89,7 @@ protected: protected slots: void preProc(const QByteArray &data, quint8 typeId); + void sendProg(); void keepAlive(); void term(); void kill(); diff --git a/src/cmd_proc.cpp b/src/cmd_proc.cpp index 0976c63..58c256f 100644 --- a/src/cmd_proc.cpp +++ b/src/cmd_proc.cpp @@ -128,13 +128,13 @@ void ModProcess::onDataFromProc(quint8 typeId, const QByteArray &data) { // a valid NEW_CMD must have a minimum of 259 bytes. - QString cmdName = fromTEXT(data.mid(3, 128)).trimmed().toLower(); + auto cmdName = fromTEXT(data.mid(3, 128)).trimmed().toLower(); if (isCmdLoaded(cmdName)) { if (!allowCmdLoad(cmdName)) { - quint16 cmdId = cmdRealNames->key(cmdName); + auto cmdId = cmdRealNames->key(cmdName); cmdIds->removeOne(cmdId); cmdRealNames->remove(cmdId); @@ -152,9 +152,9 @@ void ModProcess::onDataFromProc(quint8 typeId, const QByteArray &data) } else if (allowCmdLoad(cmdName)) { - quint16 cmdId = genCmdId(); - QByteArray cmdIdBa = wrInt(cmdId, 16); - QString unique = makeCmdUnique(cmdName); + auto cmdId = genCmdId(); + auto cmdIdBa = wrInt(cmdId, 16); + auto unique = makeCmdUnique(cmdName); cmdIds->append(cmdId); cmdRealNames->insert(cmdId, cmdName); @@ -167,12 +167,12 @@ void ModProcess::onDataFromProc(quint8 typeId, const QByteArray &data) } else { - QStringList list = QStringList() << cmdName; + auto list = QStringList() << cmdName; modCmdNames->insert(program(), list); } - QByteArray frame = cmdIdBa + data.mid(2, 1) + fixedToTEXT(unique, 128) + data.mid(131); + auto frame = cmdIdBa + data.mid(2, 1) + fixedToTEXT(unique, 128) + data.mid(131); emit dataToClient(toCmdId32(ASYNC_ADD_CMD, 0), frame, NEW_CMD); } @@ -397,8 +397,9 @@ CmdProcess::CmdProcess(quint32 id, const QString &cmd, const QString &modApp, co cmdIdle = false; } -void CmdProcess::setSessionParams(QSharedMemory *mem, char *sesId, char *wrableSubChs) +void CmdProcess::setSessionParams(QSharedMemory *mem, char *sesId, char *wrableSubChs, quint32 *hookCmd) { + hook = hookCmd; sesMem = mem; sessionId = sesId; openWritableSubChs = wrableSubChs; @@ -466,7 +467,7 @@ void CmdProcess::dataFromSession(quint32 id, const QByteArray &data, quint8 dTyp bool CmdProcess::validAsync(quint16 async, const QByteArray &data, QTextStream &errMsg) { - bool ret = true; + auto ret = true; if ((async == ASYNC_USER_DELETED) || (async == ASYNC_RW_MY_INFO) || (async == ASYNC_USER_LOGIN)) { @@ -505,35 +506,31 @@ bool CmdProcess::validAsync(quint16 async, const QByteArray &data, QTextStream & } else if ((async == ASYNC_CAST) || (async == ASYNC_LIMITED_CAST)) { - int payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; + auto payloadOffs = (MAX_OPEN_SUB_CHANNELS * BLKSIZE_SUB_CHANNEL) + 1; sesMem->lock(); if (data.size() < payloadOffs) { - ret = false; errMsg << "cast header is not at least " << payloadOffs << " bytes long."; + ret = false; errMsg << "the cast header is not at least " << payloadOffs << " bytes long."; } - else if (memcmp(data.data(), openWritableSubChs, static_cast(payloadOffs - 1)) != 0) + else if (!fullMatchChs(openWritableSubChs, data.data())) { - ret = false; errMsg << "the open sub-channels (writable) does not match the actual open sub-channels."; + ret = false; errMsg << "the sub-channels header contain a sub-channel that is not actually open for writing."; } else if (rd8BitFromBlock(data.data() + (payloadOffs - 1)) == PING_PEERS) { - // casting PING_PEERS to active update sessions are blocked. - // command processes should use ASYNC_PING_PEERS instead. + // casting PING_PEERS directly is blocked. command processes should use + // ASYNC_PING_PEERS instead. ret = false; errMsg << "attempted to cast PING_PEERS which is forbidden for module commands."; } sesMem->unlock(); } - else if (async == ASYNC_TO_PEER) - { - ret = false; errMsg << "ASYNC_TO_PEER is forbidden for module commands."; - } else if (async == ASYNC_P2P) { - int payloadOffs = ((BLKSIZE_SESSION_ID * 2) + 1); + auto payloadOffs = ((BLKSIZE_SESSION_ID * 2) + 1); if (data.size() < payloadOffs) { @@ -578,62 +575,90 @@ bool CmdProcess::validAsync(quint16 async, const QByteArray &data, QTextStream & ret = false; errMsg << "a 72bit sub-channel id header is not present."; } } - else if ((cmdId == ASYNC_NEW_CH_MEMBER) || (cmdId == ASYNC_INVITED_TO_CH) || - (cmdId == ASYNC_INVITE_ACCEPTED) || (cmdId == ASYNC_RM_CH_MEMBER) || - (cmdId == ASYNC_MEM_LEVEL_CHANGED)) + else if ((async == ASYNC_NEW_CH_MEMBER) || (async == ASYNC_INVITED_TO_CH) || + (async == ASYNC_INVITE_ACCEPTED) || (async == ASYNC_RM_CH_MEMBER) || + (async == ASYNC_MEM_LEVEL_CHANGED)) { if (data.size() < (BLKSIZE_USER_ID + BLKSIZE_CHANNEL_ID)) { ret = false; errMsg << "the channel member info header is not at least " << (BLKSIZE_USER_ID + BLKSIZE_CHANNEL_ID) << "bytes long."; } } - else if ((cmdId == ASYNC_RENAME_CH) || (cmdId == ASYNC_DEL_CH)) + else if ((async == ASYNC_RENAME_CH) || (async == ASYNC_DEL_CH)) { if (data.size() < BLKSIZE_CHANNEL_ID) { ret = false; errMsg << "a 64bit channel id header was not found."; } } + else if ((async == ASYNC_RDY) || (async == ASYNC_SYS_MSG) || (async == ASYNC_TO_PEER) || + (async == ASYNC_ADD_CMD) || (async == ASYNC_RM_CMD)) + { + ret = false; errMsg << "all modules are not allowed to send this async command directly."; + } + else if ((async < 1) || (async > 46)) + { + ret = false; errMsg << "undefined async command id."; + } return ret; } +void CmdProcess::asyncDirector(quint16 id, const QByteArray &payload) +{ + if ((id == ASYNC_EXIT) || (id == ASYNC_MAXSES) || (id == ASYNC_LOGOUT) || (id == ASYNC_RESTART) || + (id == ASYNC_END_SESSION) || (id == ASYNC_USER_LOGIN) || (id == ASYNC_OPEN_SUBCH) || (id == ASYNC_CLOSE_SUBCH) || + (id == ASYNC_KEEP_ALIVE) || (id == ASYNC_SET_DIR) || (id == ASYNC_DEBUG_TEXT)) + { + emit privIPC(id, payload); + } + else if ((id == ASYNC_CAST) || (id == ASYNC_LIMITED_CAST) || (id == ASYNC_P2P) || (id == ASYNC_CLOSE_P2P) || + (id == ASYNC_PING_PEERS)) + { + emit pubIPC(id, payload); + } + else if ((id == ASYNC_USER_DELETED) || (id == ASYNC_DISP_RENAMED) || (id == ASYNC_USER_RANK_CHANGED) || (id == ASYNC_CMD_RANKS_CHANGED) || + (id == ASYNC_ENABLE_MOD) || (id == ASYNC_DISABLE_MOD) || (id == ASYNC_RW_MY_INFO) || (id == ASYNC_NEW_CH_MEMBER) || + (id == ASYNC_DEL_CH) || (id == ASYNC_RENAME_CH) || (id == ASYNC_CH_ACT_FLAG) || (id == ASYNC_NEW_SUB_CH) || + (id == ASYNC_RM_SUB_CH) || (id == ASYNC_RENAME_SUB_CH) || (id == ASYNC_INVITED_TO_CH) || (id == ASYNC_RM_CH_MEMBER) || + (id == ASYNC_INVITE_ACCEPTED) || (id == ASYNC_MEM_LEVEL_CHANGED) || (id == ASYNC_SUB_CH_LEVEL_CHG) || (id == ASYNC_ADD_RDONLY) || + (id == ASYNC_RM_RDONLY) || (id == ASYNC_USER_RENAMED)) + { + emit pubIPCWithFeedBack(id, payload); + } +} + void CmdProcess::onDataFromProc(quint8 typeId, const QByteArray &data) { - if ((typeId == PRIV_IPC) || (typeId == PUB_IPC) || (typeId == PUB_IPC_WITH_FEEDBACK)) + if (typeId == ASYNC_PAYLOAD) { if (data.size() >= 2) { - quint16 async = rd16BitFromBlock(data.data()); + auto async = rd16BitFromBlock(data.data()); // ASYNC_KEEP_ALIVE is blocked but not considered an error. it has already done // it's job by getting transffered so it doesn't need to go any further. if (async != ASYNC_KEEP_ALIVE) { - QByteArray payload = rdFromBlock(data.data() + 2, static_cast(data.size() - 2)); + auto payload = rdFromBlock(data.data() + 2, static_cast(data.size() - 2)); QString errMsg; QTextStream errTxt(&errMsg); - if (async == ASYNC_DEBUG_TEXT) - { - typeId = PRIV_IPC; - } - if (validAsync(async, payload, errTxt)) { - if (typeId == PRIV_IPC) + if (async == ASYNC_HOOK_INPUT) { - emit privIPC(async, payload); + *hook = cmdId; } - else if (typeId == PUB_IPC) + else if (async == ASYNC_UNHOOK) { - emit pubIPC(async, payload); + *hook = 0; } else { - emit pubIPCWithFeedBack(async, payload); + asyncDirector(async, payload); } } else @@ -649,6 +674,11 @@ void CmdProcess::onDataFromProc(quint8 typeId, const QByteArray &data) { cmdIdle = true; + if (*hook == cmdId) + { + *hook = 0; + } + if (data.isEmpty()) { emit dataToClient(cmdId, wrInt(NO_ERRORS, 16), typeId); diff --git a/src/cmd_proc.h b/src/cmd_proc.h index ac1e298..6ef17f3 100644 --- a/src/cmd_proc.h +++ b/src/cmd_proc.h @@ -107,12 +107,14 @@ private: quint32 cmdId; QString cmdName; bool cmdIdle; + quint32 *hook; QSharedMemory *sesMem; char *sessionId; char *openWritableSubChs; void onReady(); void onFailToStart(); + void asyncDirector(quint16 id, const QByteArray &payload); void onFinished(int exitCode, QProcess::ExitStatus exitStatus); void onDataFromProc(quint8 typeId, const QByteArray &data); bool validAsync(quint16 async, const QByteArray &data, QTextStream &errMsg); @@ -132,7 +134,7 @@ public: explicit CmdProcess(quint32 id, const QString &cmd, const QString &modApp, const QString &memSes, const QString &memHos, const QString &pipe, QObject *parent = nullptr); void dataFromSession(quint32 id, const QByteArray &data, quint8 dType); - void setSessionParams(QSharedMemory *mem, char *sesId, char *wrableSubChs); + void setSessionParams(QSharedMemory *mem, char *sesId, char *wrableSubChs, quint32 *hookCmd); bool startCmdProc(); signals: diff --git a/src/commands/acct_recovery.cpp b/src/commands/acct_recovery.cpp index 46d2e1b..6e2ca61 100644 --- a/src/commands/acct_recovery.cpp +++ b/src/commands/acct_recovery.cpp @@ -292,7 +292,7 @@ void VerifyEmail::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_RW_MY_INFO, PUB_IPC_WITH_FEEDBACK, uId); + async(ASYNC_RW_MY_INFO, uId); flags &= ~MORE_INPUT; } diff --git a/src/commands/admin.cpp b/src/commands/admin.cpp index f927800..a9fb702 100644 --- a/src/commands/admin.cpp +++ b/src/commands/admin.cpp @@ -36,7 +36,7 @@ void CloseHost::procIn(const QByteArray &binIn, quint8 dType) { flags &= ~MORE_INPUT; - async(ASYNC_EXIT, PRIV_IPC); + async(ASYNC_EXIT); } else if (input.isEmpty()) { @@ -46,14 +46,14 @@ void CloseHost::procIn(const QByteArray &binIn, quint8 dType) else { errTxt("err: Invalid response. you need to type 'CLOSE' exactly as shown without the quotes.\n"); - mainTxt("Enter 'CLOSE' to proceed or leave blank to cancel: "); + promptTxt("Enter 'CLOSE' to proceed or leave blank to cancel: "); } } else { flags |= MORE_INPUT; - mainTxt("You are about to shutdown the host instance, type: 'CLOSE' to proceed or leave blank to cancel: "); + promptTxt("You are about to shutdown the host instance, type: 'CLOSE' to proceed or leave blank to cancel: "); } } } @@ -70,7 +70,7 @@ void RestartHost::procIn(const QByteArray &binIn, quint8 dType) { flags &= ~MORE_INPUT; - async(ASYNC_RESTART, PRIV_IPC); + async(ASYNC_RESTART); } else if (input.isEmpty()) { @@ -80,14 +80,14 @@ void RestartHost::procIn(const QByteArray &binIn, quint8 dType) else if (!input.isEmpty()) { errTxt("err: Invalid response. you need to type 'RESTART' exactly as shown without the quotes.\n"); - mainTxt("Enter 'RESTART' to proceed or leave blank to cancel: "); + promptTxt("Enter 'RESTART' to proceed or leave blank to cancel: "); } } else { flags |= MORE_INPUT; - mainTxt("You are about to re-start the host instance, type: 'RESTART' to proceed or leave blank to cancel: "); + promptTxt("You are about to re-start the host instance, type: 'RESTART' to proceed or leave blank to cancel: "); } } } @@ -150,7 +150,7 @@ void ServSettings::printOptions() level = 1; - mainTxt(txt); + promptTxt(txt); } } @@ -322,7 +322,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) txtOut << "" << endl << "Select an option: "; } - mainTxt(txt); + promptTxt(txt); } else if (level == 2) { @@ -343,12 +343,12 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (!ok) { errTxt("err: Invalid 32bit unsigned integer. valid range: 1-4294967295.\n"); - mainTxt("Enter a new value (leave blank to cancel): "); + promptTxt("Enter a new value (leave blank to cancel): "); } else if (num == 0) { errTxt("err: This value cannot be 0, valid range: 1-4294967295.\n"); - mainTxt("Enter a new value (leave blank to cancel): "); + promptTxt("Enter a new value (leave blank to cancel): "); } else { @@ -364,7 +364,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (select == 2) { - async(ASYNC_MAXSES, PRIV_IPC, wrInt(num, BLKSIZE_HOST_LOAD * 8)); + async(ASYNC_MAXSES, wrInt(num, BLKSIZE_HOST_LOAD * 8)); } returnToStart(); @@ -375,7 +375,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (!isBool(value)) { errTxt("err: Invalid boolean value. must be 0 (false) or 1 (true).\n"); - mainTxt("Select an option (leave blank to cancel): "); + promptTxt("Select an option (leave blank to cancel): "); } else { @@ -400,7 +400,7 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (!QFile::exists(expandEnvVariables(value))) { errTxt("err: The given file: '" + value + "' does not exists.\n"); - mainTxt("Enter a new path (leave blank to cancel): "); + promptTxt("Enter a new path (leave blank to cancel): "); } else { @@ -418,17 +418,17 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (!value.contains(SUBJECT_SUB, Qt::CaseInsensitive)) { errTxt("err: The '" + QString(SUBJECT_SUB) + "' keyword is missing.\n"); - mainTxt("Enter a new command line (leave blank to cancel): "); + promptTxt("Enter a new command line (leave blank to cancel): "); } else if (!value.contains(TARGET_EMAIL_SUB, Qt::CaseInsensitive)) { errTxt("err: The '" + QString(TARGET_EMAIL_SUB) + "' keyword is missing.\n"); - mainTxt("Enter a new command line (leave blank to cancel): "); + promptTxt("Enter a new command line (leave blank to cancel): "); } else if (!value.contains(MSG_SUB, Qt::CaseInsensitive)) { errTxt("err: The '" + QString(MSG_SUB) + "' keyword is missing.\n"); - mainTxt("Enter a new command line (leave blank to cancel): "); + promptTxt("Enter a new command line (leave blank to cancel): "); } else { @@ -446,12 +446,12 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) if (!isInt(value)) { errTxt("err: '" + value + "' is not a valid integer.\n"); - mainTxt("Enter a new value (leave blank to cancel): "); + promptTxt("Enter a new value (leave blank to cancel): "); } else if ((value.toInt() < 1) || (value.toInt() > 256)) { errTxt("err: A valid maximum sub-channels value ranges between 1-256.\n"); - mainTxt("Enter a new value (leave blank to cancel): "); + promptTxt("Enter a new value (leave blank to cancel): "); } else { @@ -475,12 +475,12 @@ void ServSettings::procIn(const QByteArray &binIn, quint8 dType) else if (!validUserName(value)) { errTxt("err: Invalid user name. it must be 2-24 chars long and contain no spaces.\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else if (!userExists(value, &uId)) { errTxt("err: The requested user name does not exists.\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else { diff --git a/src/commands/auth.cpp b/src/commands/auth.cpp index 78bd0ca..e821cca 100644 --- a/src/commands/auth.cpp +++ b/src/commands/auth.cpp @@ -105,7 +105,7 @@ void Auth::confirmAuth() flags &= ~MORE_INPUT; - async(ASYNC_USER_LOGIN, PRIV_IPC, uId); + async(ASYNC_USER_LOGIN, uId); mainTxt("Access granted.\n"); } @@ -150,7 +150,7 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) if (newUserName) { - mainTxt("Enter a new user name: "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else { @@ -170,27 +170,27 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) else if (noCaseMatch(DEFAULT_ROOT_USER, text)) { errTxt("err: '" + QString(DEFAULT_ROOT_USER) + "' is a reserved keyword. invalid for use as a user name.\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else if (validEmailAddr(text)) { errTxt("err: Invaild use rname. it looks like an email address.\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else if (!validUserName(text)) { errTxt("err: Invalid user name. it must be 2-24 chars long and contain no spaces.\n\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else if (noCaseMatch(text, uName)) { errTxt("err: You cannot re-apply your old user name.\n\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else if (userExists(text)) { errTxt("err: The requested user name already exists.\n\n"); - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else { @@ -202,7 +202,7 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_USER_RENAMED, PUB_IPC, uId + fixedToTEXT(text, BLKSIZE_USER_NAME)); + async(ASYNC_USER_RENAMED, uId + fixedToTEXT(text, BLKSIZE_USER_NAME)); uName = text; newUserName = false; @@ -236,7 +236,7 @@ void Auth::procIn(const QByteArray &binIn, quint8 dType) } else if (newUserName) { - mainTxt("Enter a new user name (leave blank to cancel): "); + promptTxt("Enter a new user name (leave blank to cancel): "); } else { diff --git a/src/commands/cast.cpp b/src/commands/cast.cpp index 641b005..2db5883 100644 --- a/src/commands/cast.cpp +++ b/src/commands/cast.cpp @@ -73,7 +73,7 @@ int lowestAcessLevel(quint64 chId, quint8 subId) void Cast::procIn(const QByteArray &binIn, quint8 dType) { - async(ASYNC_CAST, dType, binIn); + async(ASYNC_CAST, rdFromBlock(openWritableSubChs, BLKSIZE_SUB_CHANNEL * MAX_OPEN_SUB_CHANNELS) + wrInt(dType, 8) + binIn); } void OpenSubChannel::procIn(const QByteArray &binIn, quint8 dType) @@ -113,7 +113,7 @@ void OpenSubChannel::procIn(const QByteArray &binIn, quint8 dType) { retCode = NO_ERRORS; - async(ASYNC_OPEN_SUBCH, PRIV_IPC, wrInt(chId, 64) + wrInt(subId, 8)); + async(ASYNC_OPEN_SUBCH, wrInt(chId, 64) + wrInt(subId, 8)); } } } @@ -151,7 +151,7 @@ void CloseSubChannel::procIn(const QByteArray &binIn, quint8 dType) { retCode = NO_ERRORS; - async(ASYNC_CLOSE_SUBCH, PRIV_IPC, wrInt(chId, 64) + wrInt(subId, 8)); + async(ASYNC_CLOSE_SUBCH, wrInt(chId, 64) + wrInt(subId, 8)); } } } @@ -250,7 +250,7 @@ void PingPeers::procIn(const QByteArray &binIn, quint8 dType) } else { - async(ASYNC_PING_PEERS, PUB_IPC); + async(ASYNC_PING_PEERS); } } } @@ -318,7 +318,7 @@ void AddRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_ACCESS_LEVEL, level.toInt()); db.exec(); - async(ASYNC_ADD_RDONLY, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_ADD_RDONLY, frame); } } } @@ -386,7 +386,7 @@ void RemoveRDOnlyFlag::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_ACCESS_LEVEL, level.toInt()); db.exec(); - async(ASYNC_RM_RDONLY, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_RM_RDONLY, frame); } } } diff --git a/src/commands/certs.cpp b/src/commands/certs.cpp index bd40a0a..d1dc8e9 100644 --- a/src/commands/certs.cpp +++ b/src/commands/certs.cpp @@ -95,7 +95,7 @@ void AddCert::ask() { flags |= MORE_INPUT; - mainTxt("Common name: '" + coName + "' already exists. do you want to replace it? (y/n): "); + promptTxt("Common name: '" + coName + "' already exists. do you want to replace it? (y/n): "); } void AddCert::procIn(const QByteArray &binIn, quint8 dType) @@ -212,7 +212,7 @@ void RemoveCert::ask() { flags |= MORE_INPUT; - mainTxt("Are you sure you want to remove the cert for common name: " + coName + "? (y/n): "); + promptTxt("Are you sure you want to remove the cert for common name: " + coName + "? (y/n): "); } void RemoveCert::procIn(const QByteArray &binIn, quint8 dType) diff --git a/src/commands/channels.cpp b/src/commands/channels.cpp index 97bdab8..2385fd9 100644 --- a/src/commands/channels.cpp +++ b/src/commands/channels.cpp @@ -314,7 +314,7 @@ void CreateChannel::procIn(const QByteArray &binIn, uchar dType) auto frame = createChMemberAsyncFrame(chId, uId, false, OWNER, uName, dName, chName); - async(ASYNC_NEW_CH_MEMBER, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_NEW_CH_MEMBER, frame); } } } @@ -356,7 +356,7 @@ void RemoveChannel::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_CHANNEL_ID, chId); db.exec(); - async(ASYNC_DEL_CH, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64)); + async(ASYNC_DEL_CH, wrInt(chId, 64)); } } } @@ -414,7 +414,7 @@ void RenameChannel::procIn(const QByteArray &binIn, quint8 dType) QByteArray frame = wrInt(chId, 64) + nullTermTEXT(newName); - async(ASYNC_RENAME_CH, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_RENAME_CH, frame); } } } @@ -487,7 +487,7 @@ void SetActiveState::procIn(const QByteArray &binIn, quint8 dType) } else { - async(ASYNC_CH_ACT_FLAG, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + wrInt(subId, 8)); + async(ASYNC_CH_ACT_FLAG, wrInt(chId, 64) + wrInt(subId, 8)); } } } @@ -554,7 +554,7 @@ void CreateSubCh::procIn(const QByteArray &binIn, quint8 dType) auto frame = wrInt(chId, 64) + wrInt(subId, 8) + wrInt(REGULAR, 8) + wrInt(0, 8) + nullTermTEXT(subName); - async(ASYNC_NEW_SUB_CH, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_NEW_SUB_CH, frame); } } } @@ -611,7 +611,7 @@ void RemoveSubCh::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_SUB_CH_ID, subId); db.exec(); - async(ASYNC_RM_SUB_CH, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + wrInt(subId, 8)); + async(ASYNC_RM_SUB_CH, wrInt(chId, 64) + wrInt(subId, 8)); } } } @@ -680,7 +680,7 @@ void RenameSubCh::procIn(const QByteArray &binIn, quint8 dType) auto frame = wrInt(chId, 64) + wrInt(subId, 8) + nullTermTEXT(newName); - async(ASYNC_RENAME_SUB_CH, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_RENAME_SUB_CH, frame); } } } @@ -749,7 +749,7 @@ void InviteToCh::procIn(const QByteArray &binIn, quint8 dType) auto frame = createChMemberAsyncFrame(chId, uId, true, REGULAR, uName, getDispName(uId), chName); - async(ASYNC_INVITED_TO_CH, PUB_IPC_WITH_FEEDBACK, frame); + async(ASYNC_INVITED_TO_CH, frame); } } } @@ -788,7 +788,7 @@ void DeclineChInvite::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, rdFromBlock(userId, BLKSIZE_USER_ID)); db.exec(); - async(ASYNC_RM_CH_MEMBER, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + rdFromBlock(userId, BLKSIZE_USER_ID)); + async(ASYNC_RM_CH_MEMBER, wrInt(chId, 64) + rdFromBlock(userId, BLKSIZE_USER_ID)); } } } @@ -828,7 +828,7 @@ void AcceptChInvite::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, rdFromBlock(userId, BLKSIZE_USER_ID)); db.exec(); - async(ASYNC_INVITE_ACCEPTED, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + rdFromBlock(userId, BLKSIZE_USER_ID)); + async(ASYNC_INVITE_ACCEPTED, wrInt(chId, 64) + rdFromBlock(userId, BLKSIZE_USER_ID)); } } } @@ -913,7 +913,7 @@ void RemoveChMember::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_RM_CH_MEMBER, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + uId); + async(ASYNC_RM_CH_MEMBER, wrInt(chId, 64) + uId); } } } @@ -997,7 +997,7 @@ void SetMemberLevel::procIn(const QByteArray &binIn, uchar dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_MEM_LEVEL_CHANGED, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + uId + wrInt(newLevel, 8)); + async(ASYNC_MEM_LEVEL_CHANGED, wrInt(chId, 64) + uId + wrInt(newLevel, 8)); if (level.toInt() == OWNER) { @@ -1007,7 +1007,7 @@ void SetMemberLevel::procIn(const QByteArray &binIn, uchar dType) db.addCondition(COLUMN_USER_ID, owner); db.exec(); - async(ASYNC_MEM_LEVEL_CHANGED, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + owner + wrInt(ADMIN, 8)); + async(ASYNC_MEM_LEVEL_CHANGED, wrInt(chId, 64) + owner + wrInt(ADMIN, 8)); } } } @@ -1075,7 +1075,7 @@ void SetSubAcessLevel::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_CHANNEL_ID, chId); db.exec(); - async(ASYNC_SUB_CH_LEVEL_CHG, PUB_IPC_WITH_FEEDBACK, wrInt(chId, 64) + wrInt(subId, 8) + wrInt(level.toInt(), 8)); + async(ASYNC_SUB_CH_LEVEL_CHG, wrInt(chId, 64) + wrInt(subId, 8) + wrInt(level.toInt(), 8)); } } } diff --git a/src/commands/cmd_ranks.cpp b/src/commands/cmd_ranks.cpp index 20fbfcd..02e21ff 100644 --- a/src/commands/cmd_ranks.cpp +++ b/src/commands/cmd_ranks.cpp @@ -96,7 +96,7 @@ void AssignCmdRank::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_HOST_RANK, rank.toUInt()); db.exec(); - async(ASYNC_CMD_RANKS_CHANGED, PUB_IPC_WITH_FEEDBACK); + async(ASYNC_CMD_RANKS_CHANGED); } } } @@ -142,7 +142,7 @@ void RemoveCmdRank::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_MOD_MAIN, mod); db.exec(); - async(ASYNC_CMD_RANKS_CHANGED, PUB_IPC_WITH_FEEDBACK); + async(ASYNC_CMD_RANKS_CHANGED); } } } diff --git a/src/commands/fs.cpp b/src/commands/fs.cpp index 9b04e13..73a10db 100644 --- a/src/commands/fs.cpp +++ b/src/commands/fs.cpp @@ -48,7 +48,7 @@ QByteArray toFILE_INFO(const QFileInfo &info) ret.append(wrInt(info.lastModified().toMSecsSinceEpoch(), 64)); ret.append(wrInt(info.size(), 64)); ret.append(toTEXT(info.fileName()) + strTerm); - ret.append(toTEXT(info.symLinkTarget() + strTerm)); + ret.append(toTEXT(info.symLinkTarget()) + strTerm); return ret; } @@ -91,8 +91,6 @@ void DownloadFile::onTerminate() ssMode = false; paramsSet = false; - dataSent = 0; - len = 0; flags = 0; } @@ -109,13 +107,11 @@ void DownloadFile::sendChunk() } else { - dataSent += data.size(); + progCurrent += data.size(); emit procOut(data, GEN_FILE); - mainTxt(QString::number(dataSent) + " / " + QString::number(len) + "\n"); - - if ((dataSent >= len) || file->atEnd()) + if ((progCurrent >= progMax) || file->atEnd()) { onTerminate(); } @@ -173,20 +169,24 @@ void DownloadFile::procIn(const QByteArray &binIn, quint8 dType) } else { - len = lenStr.toLongLong(); + progMax = lenStr.toLongLong(); ssMode = argExists("-single_step", args); paramsSet = true; retCode = NO_ERRORS; flags |= MORE_INPUT; - if ((len == 0) || (len > file->size())) + if ((progMax == 0) || (progMax > file->size())) { - len = file->size(); + progMax = file->size(); } file->seek(offStr.toLongLong()); - emit procOut(toTEXT("-len " + QString::number(len)), GEN_FILE); + emit mainTxt("dl_file: " + path + "\n"); + emit mainTxt("bytes: " + QString::number(progMax) + "\n"); + emit procOut(toTEXT("-len " + QString::number(progMax)), GEN_FILE); + + startProgPulse(); } } } @@ -195,14 +195,12 @@ void UploadFile::onTerminate() { file->close(); - force = false; - confirm = false; - ssMode = false; - dataReceived = 0; - len = 0; - flags = 0; - offs = 0; - mode = nullptr; + force = false; + confirm = false; + ssMode = false; + flags = 0; + offs = 0; + mode = nullptr; } void UploadFile::wrToFile(const QByteArray &data) @@ -218,11 +216,9 @@ void UploadFile::wrToFile(const QByteArray &data) } else { - dataReceived += written; + progCurrent += written; - mainTxt(QString::number(dataReceived) + " / " + QString::number(len) + "\n"); - - if (dataReceived >= len) + if (progCurrent >= progMax) { onTerminate(); } @@ -237,7 +233,7 @@ void UploadFile::ask() { confirm = true; - mainTxt("'" + file->fileName() + "' already exists, do you want to overwrite? (y/n): "); + promptTxt("'" + file->fileName() + "' already exists, do you want to overwrite? (y/n): "); } void UploadFile::run() @@ -322,13 +318,15 @@ void UploadFile::procIn(const QByteArray &binIn, quint8 dType) force = argExists("-force", args); ssMode = argExists("-single_step", args); - len = lenStr.toLongLong(); + progMax = lenStr.toLongLong(); offs = offStr.toLongLong(); retCode = NO_ERRORS; flags |= MORE_INPUT; file->setFileName(dst); + emit mainTxt("ul_file: " + dst + "\n"); + emit mainTxt("bytes: " + QString::number(progMax) + "\n"); emit procOut(QByteArray(), GEN_FILE); if (QFileInfo(dst).exists() && !force) @@ -347,7 +345,7 @@ void Delete::ask() { flags |= MORE_INPUT; - mainTxt("Are you sure you want to delete the object? (y/n): "); + promptTxt("Are you sure you want to delete the file/folder/symmlink? (y/n): "); } void Delete::run() @@ -419,7 +417,7 @@ void Delete::procIn(const QByteArray &binIn, uchar dType) } else if (!QFileInfo(path).exists()) { - errTxt("err: Object not found.\n"); + errTxt("err: file/folder/symlink not found.\n"); } else if (!QFileInfo(path).isWritable()) { @@ -435,11 +433,10 @@ void Delete::procIn(const QByteArray &binIn, uchar dType) void Copy::onTerminate() { - fromQueue = false; - procedAFile = false; - yToAll = false; - nToAll = false; - flags = 0; + fromQueue = false; + yToAll = false; + nToAll = false; + flags = 0; src->close(); dst->close(); @@ -459,7 +456,7 @@ void Copy::ask() if (fromQueue) opts = "(y/n/y-all/n-all): "; else opts = "(y/n): "; - mainTxt("'" + dstPath + "' already exists, do you want to overwrite? " + opts); + promptTxt("'" + dstPath + "' already exists, do you want to overwrite? " + opts); } bool Copy::matchingVolumeMatters() @@ -506,14 +503,10 @@ void Copy::run() } else if (QFileInfo(srcPath).isSymLink()) { - if (procedAFile) mainTxt("\n"); - mainTxt("mklink: '" + srcPath + "' --> '" + dstPath + "'\n"); if (QFile::link(QFileInfo(srcPath).symLinkTarget(), dstPath)) { - procedAFile = true; - postProcFile(); } else @@ -528,6 +521,7 @@ void Copy::run() } else if (QFileInfo(srcPath).isDir()) { + mainTxt("mkpath: '" + dstPath + "'\n"); mkPath(dstPath); listDir(queue, srcPath, dstPath); @@ -555,9 +549,8 @@ void Copy::run() } else { - if (procedAFile) mainTxt("\n"); - - mainTxt("'" + srcPath + "' --> '" + dstPath + "'\n\n"); + mainTxt("'" + srcPath + "' --> '" + dstPath + "'\n"); + startProgPulse(); flags |= LOOPING; } @@ -572,15 +565,15 @@ void Copy::procIn(const QByteArray &binIn, uchar dType) { dst->write(src->read(LOCAL_BUFFSIZE)); - mainTxt(QString::number(src->pos()) + "/" + QString::number(src->size()) + "\n"); + progMax = src->size(); + progCurrent = src->pos(); if (src->atEnd()) { - procedAFile = true; - src->close(); dst->close(); + stopProgPulse(); postProcFile(); } } @@ -716,6 +709,8 @@ bool Move::matchingVolumeMatters() void Move::runOnMatchingVolume() { + mainTxt("'" + srcPath + "' --> '" + dstPath + "'\n"); + QFileInfo dstInfo(dstPath); if (dstInfo.exists()) @@ -947,7 +942,7 @@ void ChangeDir::procIn(const QByteArray &binIn, quint8 dType) QDir::setCurrent(path); mainTxt(QDir::currentPath() + "\n"); - async(ASYNC_SET_DIR, PRIV_IPC, toTEXT(path)); + async(ASYNC_SET_DIR, toTEXT(path)); } } } diff --git a/src/commands/fs.h b/src/commands/fs.h index bda0357..c99600e 100644 --- a/src/commands/fs.h +++ b/src/commands/fs.h @@ -31,8 +31,6 @@ class DownloadFile : public CmdObject private: QFile *file; - qint64 len; - qint64 dataSent; bool ssMode; bool paramsSet; @@ -58,8 +56,6 @@ private: QFile::OpenMode mode; QFile *file; - qint64 len; - qint64 dataReceived; qint64 offs; bool ssMode; bool confirm; @@ -115,7 +111,6 @@ protected: QFile *src; QFile *dst; - bool procedAFile; bool fromQueue; bool yToAll; bool nToAll; diff --git a/src/commands/mods.cpp b/src/commands/mods.cpp index 6e8cb1f..6420cf5 100644 --- a/src/commands/mods.cpp +++ b/src/commands/mods.cpp @@ -71,7 +71,7 @@ void AddMod::procIn(const QByteArray &binIn, quint8 dType) db.addColumn(COLUMN_MOD_MAIN, path); db.exec(); - async(ASYNC_ENABLE_MOD, PUB_IPC_WITH_FEEDBACK, toTEXT(path)); + async(ASYNC_ENABLE_MOD, toTEXT(path)); } } } @@ -107,7 +107,7 @@ void DelMod::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_MOD_MAIN, path); db.exec(); - async(ASYNC_DISABLE_MOD, PUB_IPC_WITH_FEEDBACK, toTEXT(path)); + async(ASYNC_DISABLE_MOD, toTEXT(path)); } } } diff --git a/src/commands/p2p.cpp b/src/commands/p2p.cpp index a1d3ffd..2e08778 100644 --- a/src/commands/p2p.cpp +++ b/src/commands/p2p.cpp @@ -50,7 +50,7 @@ void ToPeer::procIn(const QByteArray &binIn, quint8 dType) auto data = rdFromBlock(binIn.data() + BLKSIZE_SESSION_ID, len - BLKSIZE_SESSION_ID); auto typeBa = wrInt(dType, 8); - async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + data); + async(ASYNC_P2P, dst + src + typeBa + data); } } @@ -80,7 +80,7 @@ void P2PRequest::procIn(const QByteArray &binIn, quint8 dType) auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); auto typeBa = wrInt(P2P_REQUEST, 8); - async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + createPeerInfoFrame()); + async(ASYNC_P2P, dst + src + typeBa + createPeerInfoFrame()); } } } @@ -111,7 +111,7 @@ void P2POpen::procIn(const QByteArray &binIn, quint8 dType) auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); auto typeBa = wrInt(P2P_OPEN, 8); - async(ASYNC_P2P, PUB_IPC, dst + src + typeBa + dst); + async(ASYNC_P2P, dst + src + typeBa + dst); } } } @@ -139,7 +139,7 @@ void P2PClose::procIn(const QByteArray &binIn, quint8 dType) auto src = rdFromBlock(sessionId, BLKSIZE_SESSION_ID); auto typeBa = wrInt(P2P_CLOSE, 8); - async(P2P_CLOSE, PUB_IPC, dst + src + typeBa + dst); + async(P2P_CLOSE, dst + src + typeBa + dst); } } } diff --git a/src/commands/table_viewer.cpp b/src/commands/table_viewer.cpp index 5689e6e..aa54130 100644 --- a/src/commands/table_viewer.cpp +++ b/src/commands/table_viewer.cpp @@ -122,11 +122,11 @@ void TableViewer::askDelete() { if (condAdded) { - mainTxt("This will delete rows from the table according to the parameters above. continue (y/n)?: "); + promptTxt("This will delete rows from the table according to the parameters above. continue (y/n)?: "); } else { - mainTxt("This will delete all rows in the table. continue (y/n)?: "); + promptTxt("This will delete all rows in the table. continue (y/n)?: "); } flags |= MORE_INPUT; @@ -134,7 +134,7 @@ void TableViewer::askDelete() void TableViewer::askPage() { - mainTxt("\nnext page (y/n)?: "); + promptTxt("\nnext page (y/n)?: "); flags |= MORE_INPUT; } diff --git a/src/commands/users.cpp b/src/commands/users.cpp index 91a2701..2fb1652 100644 --- a/src/commands/users.cpp +++ b/src/commands/users.cpp @@ -226,14 +226,14 @@ void RemoveUser::rm() flags &= ~MORE_INPUT; - async(ASYNC_USER_DELETED, PUB_IPC_WITH_FEEDBACK, uId); + async(ASYNC_USER_DELETED, uId); } void RemoveUser::ask() { flags |= MORE_INPUT; - mainTxt("Are you sure you want to permanently remove this user account? (y/n): "); + promptTxt("Are you sure you want to permanently remove this user account? (y/n): "); } void RemoveUser::procIn(const QByteArray &binIn, quint8 dType) @@ -365,7 +365,7 @@ void ChangeUserRank::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_USER_RANK_CHANGED, PUB_IPC_WITH_FEEDBACK, uId + wrInt(rank.toUInt(), 32)); + async(ASYNC_USER_RANK_CHANGED, uId + wrInt(rank.toUInt(), 32)); } } } @@ -449,7 +449,7 @@ void ChangeUsername::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, rdFromBlock(userId, BLKSIZE_USER_ID)); db.exec(); - async(ASYNC_USER_RENAMED, PUB_IPC_WITH_FEEDBACK, uId + newNameBa); + async(ASYNC_USER_RENAMED, uId + newNameBa); } } } @@ -463,7 +463,7 @@ void ChangeDispName::procIn(const QByteArray &binIn, quint8 dType) retCode = INVALID_PARAMS; - if (argExists("-new_name", args)) + if (!argExists("-new_name", args)) { errTxt("err: New display name argument (-new_name) not found.\n"); } @@ -485,7 +485,7 @@ void ChangeDispName::procIn(const QByteArray &binIn, quint8 dType) db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_DISP_RENAMED, PUB_IPC_WITH_FEEDBACK, uId + newNameBa); + async(ASYNC_DISP_RENAMED, uId + newNameBa); } } } @@ -536,7 +536,7 @@ void OverWriteEmail::procArgs(const QString &uName, const QString &newEmail, boo db.addCondition(COLUMN_USER_ID, uId); db.exec(); - async(ASYNC_RW_MY_INFO, PUB_IPC_WITH_FEEDBACK, uId); + async(ASYNC_RW_MY_INFO, uId); } } diff --git a/src/common.cpp b/src/common.cpp index cf31b91..807758b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -469,17 +469,40 @@ bool isInt(const QString &str) return ret; } -bool matchChs(const char *chsA, const char *chsB) +bool matchAnyCh(const char *chsA, const char *chsB) { bool ret = false; for (int i = 0; i < MAX_OPEN_SUB_CHANNELS; i += BLKSIZE_SUB_CHANNEL) { - if (posOfBlock(chsA + i, chsB, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) != -1) + if (!isEmptyBlock(chsA + i, BLKSIZE_SUB_CHANNEL)) { - ret = true; + if (posOfBlock(chsA + i, chsB, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) != -1) + { + ret = true; - break; + break; + } + } + } + + return ret; +} + +bool fullMatchChs(const char *openChs, const char *comp) +{ + bool ret = true; + + for (int i = 0; i < MAX_OPEN_SUB_CHANNELS; i += BLKSIZE_SUB_CHANNEL) + { + if (!isEmptyBlock(comp + i, BLKSIZE_SUB_CHANNEL)) + { + if (posOfBlock(comp + i, openChs, MAX_OPEN_SUB_CHANNELS, BLKSIZE_SUB_CHANNEL) == -1) + { + ret = false; + + break; + } } } diff --git a/src/common.h b/src/common.h index d959816..98877d7 100644 --- a/src/common.h +++ b/src/common.h @@ -90,8 +90,8 @@ enum AsyncCommands : quint16 { - ASYNC_RDY = 1, // client | none - ASYNC_SYS_MSG = 2, // client | none + ASYNC_RDY = 1, // client | retricted + ASYNC_SYS_MSG = 2, // client | retricted ASYNC_EXIT = 3, // internal | private ASYNC_CAST = 4, // client | public ASYNC_MAXSES = 5, // internal | private @@ -105,7 +105,7 @@ enum AsyncCommands : quint16 ASYNC_DISABLE_MOD = 13, // internal | public ASYNC_END_SESSION = 14, // internal | private ASYNC_USER_LOGIN = 15, // internal | private - ASYNC_TO_PEER = 16, // client | public | retricted + ASYNC_TO_PEER = 16, // client | retricted ASYNC_LIMITED_CAST = 17, // client | public ASYNC_RW_MY_INFO = 18, // internal | public ASYNC_P2P = 19, // client | public @@ -124,15 +124,17 @@ enum AsyncCommands : quint16 ASYNC_SUB_CH_LEVEL_CHG = 32, // client | public ASYNC_ADD_RDONLY = 33, // client | public ASYNC_RM_RDONLY = 34, // client | public - ASYNC_ADD_CMD = 35, // client | none - ASYNC_RM_CMD = 36, // client | none + ASYNC_ADD_CMD = 35, // client | retricted + ASYNC_RM_CMD = 36, // client | retricted ASYNC_USER_RENAMED = 37, // internal | public ASYNC_PING_PEERS = 38, // internal | private ASYNC_OPEN_SUBCH = 39, // internal | private ASYNC_CLOSE_SUBCH = 40, // internal | private ASYNC_KEEP_ALIVE = 42, // internal | private ASYNC_SET_DIR = 43, // internal | private - ASYNC_DEBUG_TEXT = 44 // internal | private + ASYNC_DEBUG_TEXT = 44, // internal | private + ASYNC_HOOK_INPUT = 45, // internal | private + ASYNC_UNHOOK = 46 // internal | private }; enum Flags : quint32 @@ -153,7 +155,7 @@ enum Flags : quint32 MORE_INPUT = 1 << 13, LOOPING = 1 << 14, SINGLE_STEP_MODE = 1 << 15, - HALT_STATE = 1 << 16 + YIELD_STATE = 1 << 16 }; enum FileInfoFlags : quint8 @@ -169,35 +171,36 @@ enum FileInfoFlags : quint8 enum TypeID : quint8 { - GEN_FILE = 1, - TEXT = 2, - ERR = 3, - PRIV_TEXT = 4, - IDLE = 5, - HOST_CERT = 6, - FILE_INFO = 7, - PEER_INFO = 8, - MY_INFO = 9, - PEER_STAT = 10, - P2P_REQUEST = 11, - P2P_CLOSE = 12, - P2P_OPEN = 13, - BYTES = 14, - SESSION_ID = 15, - NEW_CMD = 16, - CMD_ID = 17, - BIG_TEXT = 18, - TERM_CMD = 19, - HOST_VER = 20, - PRIV_IPC = 21, - PUB_IPC = 22, - PUB_IPC_WITH_FEEDBACK = 23, - PING_PEERS = 24, - CH_MEMBER_INFO = 25, - CH_ID = 26, - KILL_CMD = 27, - HALT_CMD = 28, - RESUME_CMD = 29 + GEN_FILE = 1, + TEXT = 2, + ERR = 3, + PRIV_TEXT = 4, + IDLE = 5, + HOST_CERT = 6, + FILE_INFO = 7, + PEER_INFO = 8, + MY_INFO = 9, + PEER_STAT = 10, + P2P_REQUEST = 11, + P2P_CLOSE = 12, + P2P_OPEN = 13, + BYTES = 14, + SESSION_ID = 15, + NEW_CMD = 16, + CMD_ID = 17, + BIG_TEXT = 18, + TERM_CMD = 19, + HOST_VER = 20, + PING_PEERS = 21, + CH_MEMBER_INFO = 22, + CH_ID = 23, + KILL_CMD = 24, + YIELD_CMD = 25, + RESUME_CMD = 26, + PROMPT_TEXT = 27, + PROG = 28, + PROG_LAST = 29, + ASYNC_PAYLOAD = 30 }; enum RetCode : quint16 @@ -265,7 +268,8 @@ bool matchedFsObjTypes(const QString &pathA, const QString &pathB); bool matchedVolume(const QString &pathA, const QString &pathB); bool noCaseMatch(const QString &strA, const QString &strB); bool argExists(const QString &key, const QStringList &args); -bool matchChs(const char *chsA, const char *chsB); +bool matchAnyCh(const char *chsA, const char *chsB); +bool fullMatchChs(const char *openChs, const char *comp); bool globalActiveFlag(); bool genSubId(quint64 chId, quint8 *newId); bool isChOwner(const QByteArray &uId); diff --git a/src/db.h b/src/db.h index c9db53a..a7ea9af 100644 --- a/src/db.h +++ b/src/db.h @@ -37,7 +37,7 @@ #include "shell.h" #define APP_NAME "MRCI" -#define APP_VER "2.2.3" +#define APP_VER "3.0.0.0" #define APP_TARGET "mrci" #ifdef Q_OS_WIN diff --git a/src/main.cpp b/src/main.cpp index f3d1822..a62d3e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) qInstallMessageHandler(msgHandler); - //args.append("-default_pw"); // debug + //args.append("-host"); // debug if (args.contains("-help", Qt::CaseInsensitive)) { diff --git a/src/session.cpp b/src/session.cpp index c09516d..e91a7c8 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -30,6 +30,7 @@ Session::Session(const QString &hostKey, QSslSocket *tcp, QObject *parent) : Mem currentDir = QDir::currentPath(); hostMemKey = hostKey; tcpSocket = tcp; + hookCmdId32 = 0; tcpFrameCmdId = 0; tcpPayloadSize = 0; tcpFrameType = 0; @@ -123,6 +124,11 @@ void Session::cmdProcFinished(quint32 cmdId) cmdProcesses.remove(cmdId); frameQueue.remove(cmdId); + if (hookCmdId32 == cmdId) + { + hookCmdId32 = 0; + } + if (flags & END_SESSION_EMPTY_PROC) { endSession(); @@ -184,7 +190,7 @@ void Session::startCmdProc(quint32 cmdId) auto *proc = new CmdProcess(cmdId, cmdRealNames[cmdId16], modApp, sesMemKey, hostMemKey, pipe, this); proc->setWorkingDirectory(currentDir); - proc->setSessionParams(sharedMem, sessionId, openWritableSubChs); + proc->setSessionParams(sharedMem, sessionId, openWritableSubChs, &hookCmdId32); connect(proc, &CmdProcess::cmdProcFinished, this, &Session::cmdProcFinished); connect(proc, &CmdProcess::cmdProcReady, this, &Session::cmdProcStarted); @@ -287,8 +293,15 @@ void Session::dataFromClient() if (flags & FRAME_RDY) { if (tcpSocket->bytesAvailable() >= tcpPayloadSize) - { - dataToCmd(tcpFrameCmdId, tcpSocket->read(tcpPayloadSize), tcpFrameType); + { + if (hookCmdId32 != 0) + { + dataToCmd(hookCmdId32, tcpSocket->read(tcpPayloadSize), tcpFrameType); + } + else + { + dataToCmd(tcpFrameCmdId, tcpSocket->read(tcpPayloadSize), tcpFrameType); + } flags ^= FRAME_RDY; @@ -323,6 +336,7 @@ void Session::dataFromClient() servHeader.append(wrInt(ver[0].toULongLong(), 16)); servHeader.append(wrInt(ver[1].toULongLong(), 16)); servHeader.append(wrInt(ver[2].toULongLong(), 16)); + servHeader.append(wrInt(ver[3].toULongLong(), 16)); servHeader.append(sessionId, BLKSIZE_SESSION_ID); addIpAction("Session Active"); diff --git a/src/session.h b/src/session.h index 97dad6b..58c1018 100644 --- a/src/session.h +++ b/src/session.h @@ -40,6 +40,7 @@ private: QHash cmdAppById; QList cmdIds; quint32 flags; + quint32 hookCmdId32; quint32 tcpPayloadSize; quint32 tcpFrameCmdId; quint8 tcpFrameType;