Browse Source

Ported to mastodon-cpp 0.105.0.

master
tastytea 7 months ago
parent
commit
64f78e0300
Signed by: tastytea <tastytea@tastytea.de> GPG Key ID: CFC39497F1B26E07
10 changed files with 117 additions and 137 deletions
  1. +1
    -1
      .drone.yml
  2. +20
    -24
      CMakeLists.txt
  3. +1
    -1
      README.md
  4. +2
    -1
      build_manpage.sh
  5. +3
    -3
      src/configjson.cpp
  6. +3
    -3
      src/configjson.hpp
  7. +14
    -14
      src/expandurl-mastodon.hpp
  8. +10
    -8
      src/main.cpp
  9. +60
    -79
      src/masto.cpp
  10. +3
    -3
      src/url.cpp

+ 1
- 1
.drone.yml View File

@@ -2,7 +2,7 @@ pipeline:
download:
image: plugins/download
pull: true
source: https://schlomp.space/attachments/5ab8f994-669a-47f8-8ac7-ed5902ad0339
source: https://schlomp.space/attachments/e1c1e64b-1192-4037-aad4-95238ad648b0
destination: mastodon-cpp.deb

gcc6:

+ 20
- 24
CMakeLists.txt View File

@@ -1,8 +1,8 @@
cmake_minimum_required (VERSION 3.7)
project (expandurl-mastodon
VERSION 0.9.14
LANGUAGES CXX
)
VERSION 0.9.14
LANGUAGES CXX
)

include(GNUInstallDirs)
find_package(CURL REQUIRED)
@@ -15,14 +15,10 @@ set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall")
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# uint_fast16_t can be bigger than 16 bit, but that doesn't matter because
# everything but the last 16 bit is padded with zeroes.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format")
endif()
set(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpedantic -ftrapv \
-fsanitize=undefined -g -Og -fno-omit-frame-pointer")

include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${PROJECT_BINARY_DIR})

include_directories(${CURL_INCLUDE_DIRS})
@@ -37,26 +33,26 @@ link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS})

# Write version in header
configure_file (
"${PROJECT_SOURCE_DIR}/src/version.hpp.in"
"${PROJECT_BINARY_DIR}/version.hpp"
)
"${PROJECT_SOURCE_DIR}/src/version.hpp.in"
"${PROJECT_BINARY_DIR}/version.hpp"
)

file(GLOB sources src/*.cpp)
add_executable(expandurl-mastodon ${sources})
target_link_libraries(expandurl-mastodon
${CURLPP_LIBRARIES} ${JSONCPP_LIBRARIES}
${LIBXDG_BASEDIR_LIBRARIES} mastodon-cpp pthread stdc++fs)
${CURLPP_LIBRARIES} ${JSONCPP_LIBRARIES} ${LIBXDG_BASEDIR_LIBRARIES}
mastodon-cpp pthread stdc++fs)
install(TARGETS expandurl-mastodon DESTINATION ${CMAKE_INSTALL_BINDIR})

set(WITH_MAN "YES" CACHE STRING "WITH_MAN defaults to \"YES\"")
if (WITH_MAN)
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
DEPENDS "${CMAKE_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.1.adoc"
COMMAND ${CMAKE_SOURCE_DIR}/build_manpage.sh
ARGS ${PROJECT_VERSION})
add_custom_target(run ALL
DEPENDS "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}"
DEPENDS "${CMAKE_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.1.adoc"
COMMAND ${CMAKE_SOURCE_DIR}/build_manpage.sh
ARGS ${PROJECT_VERSION})
add_custom_target(run ALL
DEPENDS "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
endif()

+ 1
- 1
README.md View File

@@ -65,7 +65,7 @@ Have a look at the [manpage](https://schlomp.space/tastytea/expandurl-mastodon/s
# Copyright

```PLAIN
Copyright © 2018 tastytea <tastytea@tastytea.de>.
Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>.
License GPLv3: GNU GPL version 3 <https://www.gnu.org/licenses/gpl-3.0.html>.
This program comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.

+ 2
- 1
build_manpage.sh View File

@@ -4,8 +4,9 @@ name="expandurl-mastodon"

if [ -n "${1}" ]; then
dir="$(dirname ${0})"
version="${1}"
cp -vf "${dir}/${name}.1.adoc" .
sed -Ei "s/(Revision: +)[0-9]+\.[0-9]\.[0-9]/\1${1}/" "${name}.1.adoc"
sed -Ei "s/(Revision: +)[0-9]+\.[0-9]\.[0-9]/\1${version}/" "${name}.1.adoc"
a2x --doctype manpage --format manpage --no-xmllint "${name}.1.adoc"
else
echo "usage: ${0} VERSION" >&2

+ 3
- 3
src/configjson.cpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ ConfigJSON::ConfigJSON(const string &filename, const string &subdir)
_filepath += '/' + filename;
}

const bool ConfigJSON::read()
bool ConfigJSON::read()
{
std::ifstream file(_filepath);
if (file.is_open())
@@ -60,7 +60,7 @@ const bool ConfigJSON::read()
}
}

const bool ConfigJSON::write()
bool ConfigJSON::write()
{
std::ofstream file(_filepath);
if (file.is_open())

+ 3
- 3
src/configjson.hpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,14 +43,14 @@ public:
*
* @return `true` on success
*/
const bool read();
bool read();

/*!
* @brief Write the file
*
* @return `true` on success
*/
const bool write();
bool write();

/*!
* @brief Returns a reference to the config as Json::Value

+ 14
- 14
src/expandurl-mastodon.hpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,15 +27,15 @@
#include <jsoncpp/json/json.h>
#include "configjson.hpp"

using namespace Mastodon;

using std::string;
using Mastodon::API;
using Mastodon::Easy;

extern ConfigJSON configfile;

void signal_handler(int signum);


/*!
* @brief Extract URLs from HTML
*
@@ -54,7 +54,7 @@ const string expand(const string &url);

/*!
* @brief Filters out tracking stuff
*
*
* Currently removes all arguments beginning with `utm_`
*
* @param url URL to filter
@@ -70,7 +70,7 @@ const string strip(const string &url);
* inserted.
*
*/
const void init_replacements();
void init_replacements();


class Listener
@@ -82,24 +82,24 @@ public:
/*!
* @brief Starts listening on Mastodon
*/
const void start();
void start();
/*!
* @brief Stops listening on Mastodon
*/
const void stop();
void stop();

const std::vector<Easy::Notification> get_new_messages();
const std::vector<Easy::Notification> catchup();
Easy::Status get_status(const string &id);
const bool send_reply(const Easy::Status &to_status, const string &message);
bool send_reply(const Easy::Status &to_status, const string &message);
const string get_parent_id(const Easy::Notification &notif);

const bool stillrunning() const;
bool stillrunning() const;

private:
string _instance;
string _access_token;
std::unique_ptr<Easy> _masto;
std::unique_ptr<Easy::API> _masto;
string _stream;
std::unique_ptr<API::http> _ptr;
std::thread _thread;
@@ -109,10 +109,10 @@ private:
string _proxy_password;
Json::Value &_config;

const void read_config();
const bool write_config();
const bool register_app();
const void set_proxy(Easy &masto);
void read_config();
bool write_config();
bool register_app();
void set_proxy(Easy::API &masto);
};

#endif // EXPANDURL_MASTODON_HPP

+ 10
- 8
src/main.cpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,14 +18,16 @@
#include <chrono>
#include <csignal>
#include <regex>
#include <numeric>
#include <syslog.h>
#include <unistd.h> // getuid()
#include <curlpp/cURLpp.hpp>
#include "configjson.hpp"
#include "expandurl-mastodon.hpp"

using namespace Mastodon;

using std::string;
using Mastodon::Easy;

bool running = true;
ConfigJSON configfile("expandurl-mastodon.json");
@@ -50,7 +52,7 @@ void signal_handler(int signum)
}
}

int main(int argc, char *argv[])
int main()
{
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
@@ -99,11 +101,11 @@ int main(int argc, char *argv[])
status = listener.get_status(id);
if (status.valid())
{
string message = "";
for (const string &url : get_urls(status.content()))
{
message += url + " \n";
}
const std::vector<string> vec = get_urls(status.content());
const string message =
std::accumulate(vec.begin(), vec.end(), string(),
[](const string &s1, const string s2)
{ return s1 + s2 + " \n"; });
if (!message.empty())
{
if (!listener.send_reply(notif.status(), message))

+ 60
- 79
src/masto.cpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@

using std::cout;
using std::string;
using std::uint8_t;

Listener::Listener()
: _instance("")
@@ -59,7 +60,7 @@ Listener::Listener()
}
}

_masto = std::make_unique<Easy>(_instance, _access_token);
_masto = std::make_unique<Easy::API>(_instance, _access_token);
_masto->set_useragent(static_cast<const string>("expandurl-mastodon/") +
global::version);
set_proxy(*_masto);
@@ -69,7 +70,7 @@ Listener::~Listener()
{
}

const void Listener::read_config()
void Listener::read_config()
{
_instance = _config["account"].asString();
_instance = _instance.substr(_instance.find('@') + 1);
@@ -79,44 +80,19 @@ const void Listener::read_config()
_proxy_password = _config["proxy"]["password"].asString();
}

const void Listener::start()
void Listener::start()
{
constexpr uint_fast8_t delay_after_error = 120;
static std::uint_fast16_t ret;
_thread = std::thread([=]
{
ret = 0;
_running = true;
Easy masto(_instance, _access_token);
masto.set_useragent(static_cast<const string>("expandurl-mastodon/") +
global::version);
set_proxy(masto);
ret = masto.get_stream(Mastodon::API::v1::streaming_user, _stream, _ptr);
syslog(LOG_DEBUG, "Connection lost.");
if (ret != 0 && ret != 14) // 14 means canceled by user
{
syslog(LOG_ERR, "Connection terminated: Error %u", ret);
syslog(LOG_INFO, "Waiting for %u seconds", delay_after_error);
std::this_thread::sleep_for(std::chrono::seconds(delay_after_error));
}
_running = false;
});
while (!_ptr)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
Easy::API masto(_instance, _access_token);
_running = true;

if (ret == 0)
{
syslog(LOG_NOTICE, "Connected to %s", _instance.c_str());
}
else if (ret != 14)
{ // If the stream thread sleeps, the main thread should sleep too
std::this_thread::sleep_for(std::chrono::seconds(delay_after_error));
}
masto.set_useragent(string("expandurl-mastodon/") + global::version);
set_proxy(masto);
masto.get_stream(Mastodon::API::v1::streaming_user, _ptr, _stream);

syslog(LOG_NOTICE, "Connecting to %s ...", _instance.c_str());
}

const void Listener::stop()
void Listener::stop()
{
if (!configfile.write())
{
@@ -150,14 +126,25 @@ const std::vector<Easy::Notification> Listener::get_new_messages()
{
for (const Easy::stream_event &event : Easy::parse_stream(_stream))
{
if (event.first == Easy::event_type::Notification)
if (event.type == Easy::event_type::Notification)
{
Easy::Notification notif(event.second);
Easy::Notification notif(event.data);
if (notif.type() == Easy::notification_type::Mention)
{
v.push_back(notif);
}
}
else if (event.type == Easy::event_type::Error)
{
constexpr uint8_t delay_after_error = 120;
syslog(LOG_DEBUG, "Connection lost.");
const Json::Value err;
syslog(LOG_ERR, "Connection terminated: Error %u",
err["error_code"].asUInt());
syslog(LOG_INFO, "Waiting for %u seconds", delay_after_error);
std::this_thread::sleep_for(std::chrono::seconds(delay_after_error));
_running = false;
}
}
_stream.clear();
lastping = system_clock::now();
@@ -183,26 +170,25 @@ const std::vector<Easy::Notification> Listener::catchup()
if (last_id != "")
{
syslog(LOG_DEBUG, "Catching up...");
API::parametermap parameter =
parameters parameter =
{
{ "since_id", { last_id } },
{ "exclude_types", { "follow", "favourite", "reblog" } }
};
string answer;
std::uint_fast16_t ret;
return_call ret;;

ret = _masto->get(API::v1::notifications, parameter, answer);
ret = _masto->get(API::v1::notifications, parameter);

if (ret == 0)
if (ret)
{
for (const string str : Easy::json_array_to_vector(answer))
for (const string str : Easy::json_array_to_vector(ret.answer))
{
v.push_back(Easy::Notification(str));
}
}
else
{
syslog(LOG_ERR, "Could not catch up: Error %u", ret);
syslog(LOG_ERR, "Could not catch up: Error %u", ret.error_code);
}
}

@@ -211,26 +197,24 @@ const std::vector<Easy::Notification> Listener::catchup()

Mastodon::Easy::Status Listener::get_status(const string &id)
{
std::uint_fast16_t ret;
string answer;
return_call ret;

ret = _masto->get(API::v1::statuses_id, {{ "id", { id }}},
answer);
if (ret == 0)
ret = _masto->get(API::v1::statuses_id, {{ "id", { id }}});
if (ret)
{
return Easy::Status(answer);
return Easy::Status(ret.answer);
}
else
{
syslog(LOG_ERR, "Error %u in %s.", ret, __FUNCTION__);
syslog(LOG_ERR, "Error %u in %s.", ret.error_code, __FUNCTION__);
return Easy::Status();
}
}

const bool Listener::send_reply(const Easy::Status &to_status,
const string &message)
bool Listener::send_reply(const Easy::Status &to_status,
const string &message)
{
std::uint_fast16_t ret = 0;
Easy::return_entity<Easy::Status> ret;

Easy::Status new_status;
if (to_status.visibility() == Easy::visibility_type::Public)
@@ -246,52 +230,49 @@ const bool Listener::send_reply(const Easy::Status &to_status,
new_status.sensitive(to_status.sensitive());
new_status.spoiler_text(to_status.spoiler_text());

_masto->send_toot(new_status, ret);
ret = _masto->send_post(new_status);

if (ret == 0)
if (ret)
{
syslog(LOG_DEBUG, "Sent reply");
return true;
}
else
{
syslog(LOG_ERR, "Error %u in %s.", ret, __FUNCTION__);
syslog(LOG_ERR, "Error %u in %s.", ret.error_code, __FUNCTION__);
return false;
}
}

const string Listener::get_parent_id(const Easy::Notification &notif)
{
string answer;
std::uint_fast16_t ret;
return_call ret;

// Retry up to 2 times
for (std::uint_fast8_t retries = 1; retries <= 2; ++retries)
{
// Fetch full status
ret = _masto->get(API::v1::search, {{ "q", { notif.status().url() }}},
answer);
if (ret > 0)
ret = _masto->get(API::v1::search, {{ "q", { notif.status().url() }}});
if (!ret)
{
syslog(LOG_ERR, "Error %u: Could not fetch status (in %s).",
ret, __FUNCTION__);
ret.error_code, __FUNCTION__);
return 0;
}

ret = _masto->get(API::v1::statuses_id,
{{ "id", { notif.status().id() }}},
answer);
{{ "id", { notif.status().id() }}});

if (ret > 0)
if (!ret)
{
syslog(LOG_ERR, "Error %u: Could not get status (in %s).",
ret, __FUNCTION__);
ret.error_code, __FUNCTION__);
return 0;
}
else
{
_config["last_id"] = notif.id();
const Easy::Status s(answer);
const Easy::Status s(ret.answer);

// If parent is found, return ID; else retry
if (!s.in_reply_to_id().empty())
@@ -309,23 +290,23 @@ const string Listener::get_parent_id(const Easy::Notification &notif)
return 0;
}

const bool Listener::stillrunning() const
bool Listener::stillrunning() const
{
return _running;
}

const bool Listener::register_app()
bool Listener::register_app()
{
cout << "Account (username@instance): ";
std::cin >> _instance;
_config["account"] = _instance;
_instance = _instance.substr(_instance.find('@') + 1);

_masto = std::make_unique<Easy>(_instance, "");
_masto = std::make_unique<Easy::API>(_instance, "");
_masto->set_useragent(static_cast<const string>("expandurl-mastodon/") +
global::version);

std::uint_fast16_t ret;
return_call ret;
string client_id, client_secret, url;
ret = _masto->register_app1("expandurl-mastodon",
"urn:ietf:wg:oauth:2.0:oob",
@@ -334,7 +315,7 @@ const bool Listener::register_app()
client_id,
client_secret,
url);
if (ret == 0)
if (ret)
{
string code;
cout << "Visit " << url << " to authorize this application.\n";
@@ -345,25 +326,25 @@ const bool Listener::register_app()
"urn:ietf:wg:oauth:2.0:oob",
code,
_access_token);
if (ret == 0)
if (ret)
{
_config["access_token"] = _access_token;
return true;
}
else
{
syslog(LOG_ERR, "register_app2(): %u", ret);
syslog(LOG_ERR, "register_app2(): %u", ret.error_code);
}
}
else
{
syslog(LOG_ERR, "register_app1(): %u", ret);
syslog(LOG_ERR, "register_app1(): %u", ret.error_code);
}

return false;
}

const void Listener::set_proxy(Mastodon::Easy &masto)
void Listener::set_proxy(Easy::API &masto)
{
if (!_proxy.empty())
{

+ 3
- 3
src/url.cpp View File

@@ -1,5 +1,5 @@
/* This file is part of expandurl-mastodon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
* Copyright © 2018, 2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@ const std::vector<string> get_urls(const string &html)
// Add URL to vector if it is not a mention.#
if (match[2].str().find("mention") == std::string::npos)
{
string url = Easy::unescape_html(match[1].str());
string url = unescape_html(match[1].str());
v.push_back(strip(expand(url)));
}
buffer = match.suffix().str();
@@ -106,7 +106,7 @@ const string strip(const string &url)
return newurl;
}

const void init_replacements()
void init_replacements()
{
using replace_pair = std::pair<const std::string, const std::string>;
Json::Value &config = configfile.get_json();

Loading…
Cancel
Save