Skip to content

Commit

Permalink
TgBot++: Initial windows client app
Browse files Browse the repository at this point in the history
  • Loading branch information
Royna2544 committed Jun 2, 2024
1 parent 767d01d commit c81299c
Show file tree
Hide file tree
Showing 24 changed files with 1,375 additions and 0 deletions.
4 changes: 4 additions & 0 deletions clientapp/windows/TgBotClient/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TgBotClient/
x64/
x86/
*.vcxproj.user
17 changes: 17 additions & 0 deletions clientapp/windows/TgBotClient/About.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "UIComponents.h"

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;

case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
30 changes: 30 additions & 0 deletions clientapp/windows/TgBotClient/AbseilLogging.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#define _CRT_SECURE_NO_WARNINGS
#include <absl/log/initialize.h>
#include <absl/log/log_sink.h>
#include <absl/log/log_sink_registry.h>
#include <absl/strings/str_split.h>
#include <mutex>
#include <Windows.h>

struct WindowSinkBase : absl::LogSink {
void Send(const absl::LogEntry& entry) override {
for (absl::string_view line : absl::StrSplit(
entry.text_message_with_prefix(), absl::ByChar('\n'))) {
const std::lock_guard<std::mutex> lock(m);
OutputDebugStringA(line.data());
}
}
WindowSinkBase() = default;
~WindowSinkBase() override = default;

protected:
std::mutex m;
};

inline void initLogging() {
static WindowSinkBase sink;
absl::InitializeLog();
absl::AddLogSink(&sink);
}
72 changes: 72 additions & 0 deletions clientapp/windows/TgBotClient/DestinationIP.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@

#define _CRT_SECURE_NO_WARNINGS
#include "TgBotSocketIntf.h"
#include "UIComponents.h"
#include <CommCtrl.h>

INT_PTR CALLBACK DestinationIP(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam) {
static HWND hIPAddr;
static HWND hUseINet4;
static HWND hUseINet6;
static std::optional<SocketConfig> config;

UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
hIPAddr = GetDlgItem(hDlg, IDC_IPADDR);
hUseINet4 = GetDlgItem(hDlg, IDC_INET_4);
hUseINet6 = GetDlgItem(hDlg, IDC_INET_6);
SendMessage(hUseINet4, BM_SETCHECK, BST_CHECKED, 0);
config.emplace();
config->mode = SocketConfig::Mode::USE_IPV4;
return DIALOG_OK;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_INET_4:
config->mode = SocketConfig::Mode::USE_IPV4;
break;
case IDC_INET_6:
config->mode = SocketConfig::Mode::USE_IPV6;
break;
case IDC_IPADDR: {
DWORD dwAddr;
SendMessage(hIPAddr, IPM_GETADDRESS, 0, (LPARAM)&dwAddr);

// Extract the individual parts of the IP address
BYTE b1 = FIRST_IPADDRESS(dwAddr);
BYTE b2 = SECOND_IPADDRESS(dwAddr);
BYTE b3 = THIRD_IPADDRESS(dwAddr);
BYTE b4 = FOURTH_IPADDRESS(dwAddr);

CHAR szIpAddress[16];
sprintf(szIpAddress, "%d.%d.%d.%d", b1, b2, b3, b4);
config->address = szIpAddress;
break;
}
case IDOK: {
if (config->address.empty()) {
MessageBoxA(hDlg, "addressempty",
"Kys when?",
MB_ICONWARNING | MB_OK);
} else {
setSocketConfig(config.value());
config.reset();
EndDialog(hDlg, LOWORD(wParam));
}
break;
}
case IDCANCEL:
config.reset();
EndDialog(hDlg, LOWORD(wParam));
break;
default:
return DIALOG_NO;
};
return DIALOG_OK;
default:
break;
}
return DIALOG_NO;
}
Binary file added clientapp/windows/TgBotClient/Icon.ico
Binary file not shown.
121 changes: 121 additions & 0 deletions clientapp/windows/TgBotClient/SendFileToChat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@

#define _CRT_SECURE_NO_WARNINGS
#include <array>
#include <cstdint>

#include "../../../src/include/TryParseStr.hpp"
#include "TgBotSocketIntf.h"
#include "UIComponents.h"
#include <optional>
#include <tchar.h>
#include <absl/log/log.h>

namespace {

std::optional<std::wstring> OpenFilePicker(HWND hwnd) {
OPENFILENAME ofn; // Common dialog box structure
wchar_t szFile[MAX_PATH_SIZE]; // Buffer for file name
HANDLE hf; // File handle

// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not use the
// contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

// Display the Open dialog box
if (GetOpenFileName(&ofn) == TRUE)
return ofn.lpstrFile;
return std::nullopt;
}

} // namespace


INT_PTR CALLBACK SendFileToChat(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam) {
static HWND hChatId;
static HWND hFileText;
static HWND hFileButton;

UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
hChatId = GetDlgItem(hDlg, IDC_CHATID);
hFileButton = GetDlgItem(hDlg, IDC_BROWSE);
hFileText = GetDlgItem(hDlg, IDC_SEL_FILE);
SetFocus(hChatId);
return (INT_PTR)TRUE;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDSEND: {
ChatId chatid = 0;
std::array<TCHAR, 64 + 1> chatidbuf = {};
std::array<TCHAR, MAX_PATH_SIZE> pathbuf = {};
StringLoader::String errtext;
bool fail = false;
auto& loader = StringLoader::getInstance();

GetDlgItemText(hDlg, IDC_CHATID, chatidbuf.data(),
chatidbuf.size() - 1);

if (Length(chatidbuf.data()) == 0) {
errtext = loader.getString(IDS_CHATID_EMPTY);
fail = true;
} else if (!try_parse(chatidbuf.data(), &chatid)) {
errtext = loader.getString(IDS_CHATID_NOTINT);
fail = true;
}
if (!fail) {
std::string serverReason;
GetDlgItemText(hDlg, IDC_SEL_FILE, pathbuf.data(), pathbuf.size());
fail = !sendFileToChat(
chatid, pathbuf.data(),
[&serverReason](const GenericAck* data) {
serverReason = data->error_msg;
});
if (fail) {
errtext = loader.getString(IDS_CMD_FAILED_SVR) + kLineBreak;
errtext += loader.getString(IDS_CMD_FAILED_SVR_RSN);
errtext += StringLoader::String(serverReason.begin(), serverReason.end());
} else {
MessageBox(
hDlg,
loader.getString(IDS_SUCCESS_FILESENT).c_str(),
loader.getString(IDS_SUCCESS).c_str(),
MB_ICONINFORMATION | MB_OK);
}
}
if (fail) {
MessageBox(hDlg, errtext.c_str(),
loader.getString(IDS_FAILED).c_str(),
MB_ICONERROR | MB_OK);
}
}

break;
case IDC_BROWSE:
if (const auto f = OpenFilePicker(hDlg); f) {
SetDlgItemText(hDlg, IDC_SEL_FILE, f->c_str());
}
return (INT_PTR)TRUE;

case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
};
break;
}
return (INT_PTR)FALSE;
}
82 changes: 82 additions & 0 deletions clientapp/windows/TgBotClient/SendMessageToChat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

#define _CRT_SECURE_NO_WARNINGS
#include <array>

#include "../../../src/include/TryParseStr.hpp"
#include "TgBotSocketIntf.h"
#include "UIComponents.h"

INT_PTR CALLBACK SendMsgToChat(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam) {
static HWND hChatId;
static HWND hMsgText;

UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
hChatId = GetDlgItem(hDlg, IDC_CHATID);
hMsgText = GetDlgItem(hDlg, IDC_MESSAGETXT);
return (INT_PTR)TRUE;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDSEND: {
ChatId chatid = 0;
std::array<char, MAX_MSG_SIZE> msgbuf = {};
std::array<TCHAR, 64 + 1> chatidbuf = {};
StringLoader::String errtext;
bool fail = false;
auto& loader = StringLoader::getInstance();

GetDlgItemText(hDlg, IDC_CHATID, chatidbuf.data(),
chatidbuf.size());
GetDlgItemTextA(hDlg, IDC_MESSAGETXT, msgbuf.data(),
msgbuf.size());
if (Length(chatidbuf.data()) == 0) {
errtext = loader.getString(IDS_CHATID_EMPTY);
fail = true;
} else if (Length(msgbuf.data()) == 0) {
errtext = loader.getString(IDS_MSG_EMPTY);
fail = true;
} else if (!try_parse(chatidbuf.data(), &chatid)) {
errtext = loader.getString(IDS_CHATID_NOTINT);
fail = true;
}
if (!fail) {
std::string serverReason;
fail = !sendMessageToChat(
chatid, msgbuf.data(),
[&serverReason](const GenericAck* data) {
serverReason = data->error_msg;
});
if (fail) {
errtext = loader.getString(IDS_CMD_FAILED_SVR) +
kLineBreak;
errtext += loader.getString(IDS_CMD_FAILED_SVR_RSN);
errtext += StringLoader::String(
serverReason.begin(), serverReason.end());
} else {
MessageBox(
hDlg,
loader.getString(IDS_SUCCESS_MSGSENT).c_str(),
loader.getString(IDS_SUCCESS).c_str(),
MB_ICONINFORMATION | MB_OK);
}
}
if (fail) {
MessageBox(hDlg, errtext.c_str(),
loader.getString(IDS_FAILED).c_str(),
MB_ICONERROR | MB_OK);
}
}

break;

case IDCANCEL:
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
};
break;
}
return (INT_PTR)FALSE;
}
5 changes: 5 additions & 0 deletions clientapp/windows/TgBotClient/SendMessageToChat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once
#include "resource.h"
#include <Windows.h>

INT_PTR CALLBACK SendMsgToChat(HWND, UINT, WPARAM, LPARAM);
3 changes: 3 additions & 0 deletions clientapp/windows/TgBotClient/StringLoader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "UIComponents.h"

StringLoader StringLoader::instance;
Binary file added clientapp/windows/TgBotClient/TgBotClient.aps
Binary file not shown.
Loading

0 comments on commit c81299c

Please sign in to comment.