[Git][debian-proftpd-team/proftpd-mod-msg][master] 3 commits: New upstream version 0.5.1
Hilmar Preuße (@hilmar)
gitlab at salsa.debian.org
Tue Apr 1 08:19:47 BST 2025
Hilmar Preuße pushed to branch master at Debian ProFTPD Team / proftpd-mod-msg
Commits:
eeec58e0 by Hilmar Preuße at 2025-04-01T09:14:52+02:00
New upstream version 0.5.1
- - - - -
45137190 by Hilmar Preuße at 2025-04-01T09:14:52+02:00
Update upstream source from tag 'upstream/0.5.1'
Update to upstream version '0.5.1'
with Debian dir d657f3d933a668810682455285071c299926c602
- - - - -
fbba1ea4 by Hilmar Preuße at 2025-04-01T09:18:49+02:00
Finalize for upload.
- - - - -
7 changed files:
- + .github/workflows/ci.yml
- + .gitignore
- − .travis.yml
- README.md
- debian/changelog
- debian/patches/series
- mod_msg.c
Changes:
=====================================
.github/workflows/ci.yml
=====================================
@@ -0,0 +1,155 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+ schedule:
+ - cron: '11 1 * * 0'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ compiler:
+ - clang
+ - gcc
+ container:
+ - almalinux:8
+ - alpine:3.18
+ - ubuntu:22.04
+
+ container: ${{ matrix.container }}
+
+ steps:
+ - name: Checkout ProFTPD
+ uses: actions/checkout at v3
+ with:
+ repository: proftpd/proftpd
+ path: proftpd
+
+ - name: Checkout module source code
+ uses: actions/checkout at v3
+ with:
+ path: proftpd-mod_msg
+
+ - name: Whitespace check
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
+ run: |
+ apt-get update -qq
+ apt-get install -y git
+ cd proftpd-mod_msg
+ if [[ -n $(git diff --check HEAD^) ]]; then
+ echo "You must remove whitespace before submitting a pull request"
+ echo ""
+ git diff --check HEAD^
+ exit 1
+ fi
+
+ - name: Prepare module source code
+ run: |
+ cp proftpd-mod_msg/mod_msg.c proftpd/contrib/
+
+ - name: Install Alpine packages
+ if: ${{ matrix.container == 'alpine:3.18' }}
+ run: |
+ apk update
+ # for builds
+ apk add bash build-base clang compiler-rt gcc make zlib-dev
+ # for unit tests
+ apk add check check-dev subunit subunit-dev
+
+ # for debugging
+ clang --version
+ gcc --version
+
+ - name: Install RPM packages
+ if: ${{ matrix.container == 'almalinux:8' }}
+ run: |
+ # Need to add other repos for e.g. libsodium
+ yum install -y dnf-plugins-core epel-release clang gcc make zlib-devel
+ # for unit tests
+ yum install -y check-devel https://cbs.centos.org/kojifiles/packages/subunit/1.4.0/1.el8/x86_64/subunit-1.4.0-1.el8.x86_64.rpm https://cbs.centos.org/kojifiles/packages/subunit/1.4.0/1.el8/x86_64/subunit-devel-1.4.0-1.el8.x86_64.rpm
+
+ # for debugging
+ clang --version
+ gcc --version
+
+ - name: Install Ubuntu packages
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
+ run: |
+ apt-get update -qq
+ # for builds
+ apt-get install -y clang gcc make
+ # for unit tests
+ apt-get install -y check libsubunit-dev
+
+ # for integration/regression test
+ apt-get install -y \
+ libdata-dumper-simple-perl \
+ libdatetime-perl \
+ libfile-copy-recursive-perl \
+ libfile-path-tiny-perl \
+ libfile-spec-native-perl \
+ libnet-inet6glue-perl \
+ libnet-ssh2-perl \
+ libnet-ssleay-perl \
+ libnet-telnet-perl \
+ libposix-2008-perl \
+ libtest-unit-perl \
+ libtime-hr-perl \
+ libwww-perl
+ PERL_MM_USE_DEFAULT=1 perl -MCPAN -e 'install Net::FTPSSL'
+
+ # for test code coverage
+ apt-get install -y lcov ruby
+ gem install coveralls-lcov
+ # for HTML validation
+ apt-get install -y tidy
+
+ # for debugging
+ clang --version
+ gcc --version
+
+ - name: Prepare code coverage
+ if: ${{ matrix.container == 'ubuntu:22.04' }}
+ run: |
+ lcov --directory proftpd --zerocounters
+
+ - name: Build as static module
+ env:
+ CC: ${{ matrix.compiler }}
+ run: |
+ cd proftpd
+ ./configure LIBS="-lm -lsubunit -lrt -pthread" --enable-ctrls --enable-devel=coverage --enable-tests --with-modules=mod_msg
+ make
+
+ - name: Install as static module
+ run: |
+ cd proftpd
+ make install
+
+ - name: Build as shared module
+ env:
+ CC: ${{ matrix.compiler }}
+ run: |
+ cd proftpd
+ make clean
+ ./configure LIBS="-lm -lsubunit -lrt -pthread" --enable-ctrls --enable-devel --enable-dso --with-shared=mod_msg
+ make
+
+ - name: Install as shared module
+ run: |
+ cd proftpd
+ make install
+
+ - name: Check HTML docs
+ run: |
+ cd proftpd-mod_msg
+ echo "Processing mod_msg.html"
+ tidy -errors -omit -q mod_msg.html | exit 0
=====================================
.gitignore
=====================================
@@ -0,0 +1,5 @@
+*.lo
+*~
+*.swo
+*.swp
+tests.log
=====================================
.travis.yml deleted
=====================================
@@ -1,36 +0,0 @@
-language: c
-
-compiler:
- - gcc
- - clang
-
-install:
- - sudo apt-get update -qq
- # for libarchive
- - sudo apt-get install -y libarchive-dev
- # for libbz2
- - sudo apt-get install -y libbz2-dev
- # for unit tests
- - sudo apt-get install -y check
- # for static code analysis
- - sudo apt-get install -y cppcheck rats
- # for test code coverage
- - sudo apt-get install -y lcov
- - gem install coveralls-lcov
-
-before_script:
- - cd ${TRAVIS_BUILD_DIR}
- - lcov --directory . --zerocounters
-
-script:
- # - find . -type f -name "*.c" -print | grep -v t\/ | xargs cppcheck 2>&1
- # - find . -type f -name "*.c" -print | grep -v t\/ | xargs rats --language=c
- - git clone --depth 10 https://github.com/proftpd/proftpd.git
- - cp mod_msg.c proftpd/contrib/
- - cd proftpd
- - ./configure LIBS='-lm -lrt -pthread' --enable-ctrls --enable-devel=coverage --enable-dso --enable-tests --with-shared=mod_msg
- - make
- - make clean
- - ./configure LIBS='-lm -lrt -pthread' --enable-ctrls --enable-devel=coverage --enable-tests --with-modules=mod_msg
- - make
- # Run `tidy -e -q mod_msg.html` for doc validation
=====================================
README.md
=====================================
@@ -3,7 +3,7 @@ proftpd-mod_msg
Status
------
-[](https://travis-ci.org/Castaglia/proftpd-mod_msg)
+[](https://github.com/Castaglia/proftpd-mod_msg/actions/workflows/ci.yml)
[](https://img.shields.io/badge/license-GPL-brightgreen.svg)
=====================================
debian/changelog
=====================================
@@ -1,9 +1,13 @@
-proftpd-mod-msg (0.5-4) UNRELEASED; urgency=medium
+proftpd-mod-msg (0.5.1-1) unstable; urgency=medium
+ * New upstream release.
+ - Disable patch from upstream.
+
+ [ Debian Janitor ]
* Remove constraints unnecessary since buster (oldstable):
+ Build-Depends: Drop versioned constraint on proftpd-dev.
- -- Debian Janitor <janitor at jelmer.uk> Sat, 29 Oct 2022 19:16:27 -0000
+ -- Hilmar Preuße <hille42 at debian.org> Tue, 01 Apr 2025 09:10:40 +0200
proftpd-mod-msg (0.5-3) unstable; urgency=medium
=====================================
debian/patches/series
=====================================
@@ -1 +1 @@
-01c862d404df2e6c9c06c6229efc113a6623d215.patch
+# 01c862d404df2e6c9c06c6229efc113a6623d215.patch
=====================================
mod_msg.c
=====================================
@@ -1,6 +1,6 @@
/*
* ProFTPD: mod_msg -- a module for sending messages to connected clients
- * Copyright (c) 2004-2018 TJ Saunders
+ * Copyright (c) 2004-2025 TJ Saunders
*
* 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
@@ -21,7 +21,7 @@
* resulting executable, without including the source code for OpenSSL in the
* source distribution.
*
- * This is mod_msg, contrib software for proftpd 1.2 and above.
+ * This is mod_msg, contrib software for proftpd 1.3.x and above.
* For more information contact TJ Saunders <tj at castaglia.org>.
*/
@@ -36,7 +36,7 @@
# define MSGMAX 8192
#endif /* MSGMAX */
-#define MOD_MSG_VERSION "mod_msg/0.5"
+#define MOD_MSG_VERSION "mod_msg/0.5.1"
/* Make sure the version of proftpd is as necessary. */
#if PROFTPD_VERSION_NUMBER < 0x0001030604
@@ -50,7 +50,7 @@ extern pid_t mpid;
module msg_module;
-#ifndef PR_USE_CTRLS
+#if !defined(PR_USE_CTRLS)
# error "mod_msg requires Controls support (--enable-ctrls)"
#endif /* PR_USE_CTRLS */
@@ -136,8 +136,9 @@ static int msg_recv_msg(void) {
}
msg = malloc(sizeof(struct mq_msg) + MSGMAX - sizeof(msg->mtext));
- if (!msg)
- end_login(1);
+ if (msg == NULL) {
+ pr_session_end(0);
+ }
msglen = msgrcv(msg_qid, msg, sizeof(buf), getpid(),
IPC_NOWAIT|MSG_NOERROR);
@@ -164,8 +165,9 @@ static int msg_recv_msg(void) {
#ifdef ENOMSG
errno != ENOMSG &&
#endif /* ENOMSG */
- errno != EAGAIN)
+ errno != EAGAIN) {
return -1;
+ }
return nmsgs;
}
@@ -178,8 +180,9 @@ static int msg_send_msg(pid_t dst_pid, const char *msgstr) {
size_t msglen = strlen(msgstr) + 1;
msg = malloc(sizeof(struct mq_msg) + MSGMAX - sizeof(msg->mtext));
- if (!msg)
- end_login(1);
+ if (msg == NULL) {
+ pr_session_end(0);
+ }
msg->mtype = dst_pid;
sstrncpy(msg->mtext, msgstr, msglen);
@@ -201,9 +204,10 @@ static int msg_send_msg(pid_t dst_pid, const char *msgstr) {
res = kill(dst_pid, SIGUSR2);
PRIVS_RELINQUISH
- if (res < 0)
+ if (res < 0) {
(void) pr_log_writefile(msg_logfd, MOD_MSG_VERSION,
"error sending notice: %s", strerror(errno));
+ }
return 0;
}
@@ -221,22 +225,26 @@ MODRET set_msgctrlsacls(cmd_rec *cmd) {
/* We can cheat here, and use the ctrls_parse_acl() routine to
* separate the given string...
*/
- actions = ctrls_parse_acl(cmd->tmp_pool, cmd->argv[1]);
+ actions = pr_ctrls_parse_acl(cmd->tmp_pool, cmd->argv[1]);
/* Check the second parameter to make sure it is "allow" or "deny" */
if (strcmp(cmd->argv[2], "allow") != 0 &&
- strcmp(cmd->argv[2], "deny") != 0)
+ strcmp(cmd->argv[2], "deny") != 0) {
CONF_ERROR(cmd, "second parameter must be 'allow' or 'deny'");
+ }
/* Check the third parameter to make sure it is "user" or "group" */
if (strcmp(cmd->argv[3], "user") != 0 &&
- strcmp(cmd->argv[3], "group") != 0)
+ strcmp(cmd->argv[3], "group") != 0) {
CONF_ERROR(cmd, "third parameter must be 'user' or 'group'");
+ }
- if ((bad_action = ctrls_set_module_acls(msg_acttab, msg_pool,
- actions, cmd->argv[2], cmd->argv[3], cmd->argv[4])) != NULL)
+ bad_action = pr_ctrls_set_module_acls(msg_acttab, msg_pool, actions,
+ cmd->argv[2], cmd->argv[3], cmd->argv[4]);
+ if (bad_action != NULL) {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown action: '",
bad_action, "'", NULL));
+ }
return PR_HANDLED(cmd);
}
@@ -299,7 +307,7 @@ MODRET msg_post_any(cmd_rec *cmd) {
}
/* If there are no messages pending for this process, be done now. */
- if (!msg_pending_list ||
+ if (msg_pending_list == NULL ||
msg_pending_list->nelts == 0) {
return PR_DECLINED(cmd);
}
@@ -336,7 +344,7 @@ MODRET msg_post_err_any(cmd_rec *cmd) {
}
/* If there are no messages pending for this process, be done now. */
- if (!msg_pending_list ||
+ if (msg_pending_list == NULL ||
msg_pending_list->nelts == 0) {
return PR_DECLINED(cmd);
}
@@ -377,9 +385,11 @@ static void msg_exit_ev(const void *event_data, void *user_data) {
ServerType == SERVER_STANDALONE) {
struct msqid_ds ds;
- if (msgctl(msg_qid, IPC_RMID, &ds) < 0 && errno != EINVAL)
+ if (msgctl(msg_qid, IPC_RMID, &ds) < 0 &&
+ errno != EINVAL) {
pr_log_debug(DEBUG1, MOD_MSG_VERSION ": error removing queue %d: %s",
msg_qid, strerror(errno));
+ }
}
}
@@ -391,7 +401,7 @@ static void msg_postparse_ev(const void *event_data, void *user_data) {
*/
c = find_config(main_server->conf, CONF_PARAM, "MessageLog", FALSE);
- if (c) {
+ if (c != NULL) {
const char *path = c->argv[0];
if (strcasecmp(path, "none") != 0 &&
@@ -402,43 +412,46 @@ static void msg_postparse_ev(const void *event_data, void *user_data) {
}
}
- if (msg_queue_path)
+ if (msg_queue_path != NULL) {
msg_queue_fh = pr_fsio_open(msg_queue_path, O_RDWR|O_CREAT);
- else
+ } else {
errno = EINVAL;
+ }
- if (!msg_queue_fh) {
+ if (msg_queue_fh == NULL) {
(void) pr_log_writefile(msg_logfd, MOD_MSG_VERSION,
"error opening MessageQueue: %s", strerror(errno));
} else {
msg_qid = msg_get_queue(msg_queue_path);
- if (msg_qid < 0)
+ if (msg_qid < 0) {
(void) pr_log_writefile(msg_logfd, MOD_MSG_VERSION,
"error obtaining queue ID: %s", strerror(errno));
-else
-pr_log_debug(DEBUG0, MOD_MSG_VERSION ": obtained queue ID %d", msg_qid);
+
+ } else {
+ pr_log_debug(DEBUG0, MOD_MSG_VERSION ": obtained queue ID %d", msg_qid);
+ }
}
}
static void msg_restart_ev(const void *event_data, void *user_data) {
register unsigned int i;
- if (msg_pool)
+ if (msg_pool != NULL) {
destroy_pool(msg_pool);
+ }
msg_pool = make_sub_pool(permanent_pool);
pr_pool_tag(msg_pool, MOD_MSG_VERSION);
for (i = 0; msg_acttab[i].act_action; i++) {
msg_acttab[i].act_acl = pcalloc(msg_pool, sizeof(ctrls_acl_t));
- ctrls_init_acl(msg_acttab[i].act_acl);
+ pr_ctrls_init_acl(msg_acttab[i].act_acl);
}
}
static void msg_sigusr2_ev(const void *event_data, void *user_data) {
-
/* Check the queue for any messages for us. */
int res = msg_recv_msg();
@@ -461,11 +474,12 @@ static void msg_sigusr2_ev(const void *event_data, void *user_data) {
}
static void msg_startup_ev(const void *event_data, void *user_data) {
- int res;
+ int res, xerrno;
/* Make sure the process has an fd to the scoreboard. */
PRIVS_ROOT
res = pr_open_scoreboard(O_RDWR);
+ xerrno = errno;
PRIVS_RELINQUISH
if (res < 0) {
@@ -483,7 +497,7 @@ static void msg_startup_ev(const void *event_data, void *user_data) {
break;
default:
- pr_log_debug(DEBUG0, "error opening scoreboard: %s", strerror(errno));
+ pr_log_debug(DEBUG0, "error opening scoreboard: %s", strerror(xerrno));
break;
}
}
@@ -496,20 +510,21 @@ static void msg_startup_ev(const void *event_data, void *user_data) {
static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
int res = 0, msg_errno = 0, msg_know_dst = FALSE, msg_sent = FALSE;
- if (!ctrls_check_acl(ctrl, msg_acttab, "msg")) {
+ if (!pr_ctrls_check_acl(ctrl, msg_acttab, "msg")) {
pr_ctrls_add_response(ctrl, "access denied");
return -1;
}
/* Sanity check */
- if (reqargc == 0 || reqargv == NULL) {
+ if (reqargc == 0 ||
+ reqargv == NULL) {
pr_ctrls_add_response(ctrl, "missing required parameters");
return -1;
}
/* Handle 'msg user' requests. */
if (strcmp(reqargv[0], "user") == 0) {
- register unsigned int i = 0;
+ register int i = 0;
pr_scoreboard_entry_t *score = NULL;
const char *user, *msgstr = "";
size_t msglen;
@@ -530,9 +545,10 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
* be a maximum length on this strength, depending on the maximum msg
* size allowed for SysV message queues.
*/
- for (i = 2; i < reqargc; i++)
+ for (i = 2; i < reqargc; i++) {
msgstr = pstrcat(ctrl->ctrls_tmp_pool, msgstr, *msgstr ? " " : "",
reqargv[i], NULL);
+ }
msglen = strlen(msgstr) + 1;
@@ -577,7 +593,7 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
/* Handle 'msg host' requests. */
} else if (strcmp(reqargv[0], "host") == 0) {
- register unsigned int i = 0;
+ register int i = 0;
pr_scoreboard_entry_t *score = NULL;
const char *addr, *msgstr = "";
const pr_netaddr_t *na;
@@ -596,9 +612,10 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
* be a maximum length on this strength, depending on the maximum msg
* size allowed for SysV message queues.
*/
- for (i = 2; i < reqargc; i++)
+ for (i = 2; i < reqargc; i++) {
msgstr = pstrcat(ctrl->ctrls_tmp_pool, msgstr, *msgstr ? " " : "",
reqargv[i], NULL);
+ }
if (strlen(msgstr) >= MSGMAX) {
pr_ctrls_add_response(ctrl, "message exceeds maximum length (%u). "
@@ -607,7 +624,7 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
}
na = pr_netaddr_get_addr(ctrl->ctrls_tmp_pool, reqargv[1], NULL);
- if (!na) {
+ if (na == NULL) {
pr_ctrls_add_response(ctrl, "msg host: error resolving '%s': %s",
reqargv[1], strerror(errno));
return -1;
@@ -645,7 +662,7 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
/* Handle 'msg class' requests. */
} else if (strcmp(reqargv[0], "class") == 0) {
- register unsigned int i = 0;
+ register int i = 0;
pr_scoreboard_entry_t *score;
const char *class = reqargv[1], *msgstr = "";
@@ -663,9 +680,10 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
* be a maximum length on this strength, depending on the maximum msg
* size allowed for SysV message queues.
*/
- for (i = 2; i < reqargc; i++)
+ for (i = 2; i < reqargc; i++) {
msgstr = pstrcat(ctrl->ctrls_tmp_pool, msgstr, *msgstr ? " " : "",
reqargv[i], NULL);
+ }
if (strlen(msgstr) >= MSGMAX) {
pr_ctrls_add_response(ctrl, "message exceeds maximum length (%u). "
@@ -700,7 +718,7 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
/* Handle 'msg all' requests. */
} else if (strcmp(reqargv[0], "all") == 0) {
- register unsigned int i = 0;
+ register int i = 0;
pr_scoreboard_entry_t *score;
const char *msgstr = "";
@@ -713,9 +731,10 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
* be a maximum length on this strength, depending on the maximum msg
* size allowed for SysV message queues.
*/
- for (i = 1; i < reqargc; i++)
+ for (i = 1; i < reqargc; i++) {
msgstr = pstrcat(ctrl->ctrls_tmp_pool, msgstr, *msgstr ? " " : "",
reqargv[i], NULL);
+ }
if (strlen(msgstr) >= MSGMAX) {
pr_ctrls_add_response(ctrl, "message exceeds maximum length (%u). "
@@ -751,16 +770,17 @@ static int msg_handle_msg(pr_ctrls_t *ctrl, int reqargc, char **reqargv) {
return -1;
}
- if (msg_sent)
+ if (msg_sent == TRUE) {
pr_ctrls_add_response(ctrl, "message sent");
- else if (!msg_know_dst)
+ } else if (msg_know_dst == FALSE) {
pr_ctrls_add_response(ctrl, "unable to send message: "
"no such client connected");
- else
+ } else {
pr_ctrls_add_response(ctrl, "error sending message: %s",
strerror(msg_errno));
+ }
return res;
}
@@ -776,13 +796,14 @@ static int msg_init(void) {
for (i = 0; msg_acttab[i].act_action; i++) {
msg_acttab[i].act_acl = pcalloc(msg_pool, sizeof(ctrls_acl_t));
- ctrls_init_acl(msg_acttab[i].act_acl);
+ pr_ctrls_init_acl(msg_acttab[i].act_acl);
if (pr_ctrls_register(&msg_module, msg_acttab[i].act_action,
- msg_acttab[i].act_desc, msg_acttab[i].act_cb) < 0)
+ msg_acttab[i].act_desc, msg_acttab[i].act_cb) < 0) {
pr_log_pri(PR_LOG_INFO, MOD_MSG_VERSION
": error registering '%s' control: %s",
msg_acttab[i].act_action, strerror(errno));
+ }
}
pr_event_register(&msg_module, "core.exit", msg_exit_ev, NULL);
@@ -799,7 +820,7 @@ static int msg_sess_init(void) {
/* If there was an error opening the MessageQueue, force the module to
* be inoperative. We'd much rather not operate without the MessageQueue.
*/
- if (!msg_queue_fh) {
+ if (msg_queue_fh == NULL) {
msg_engine = FALSE;
(void) pr_log_writefile(msg_logfd, MOD_MSG_VERSION,
"missing required MessageQueue, disabling module");
@@ -814,12 +835,16 @@ static int msg_sess_init(void) {
}
c = find_config(main_server->conf, CONF_PARAM, "MessageEngine", FALSE);
- if (c &&
- *((unsigned char *) c->argv[0]) == TRUE)
- msg_engine = TRUE;
+ if (c != NULL) {
+ unsigned char engine;
+
+ engine = *((unsigned char *) c->argv[0]);
+ msg_engine = engine;
+ }
- if (!msg_engine)
+ if (msg_engine == FALSE) {
return 0;
+ }
pr_event_register(&msg_module, "core.signal.USR2", msg_sigusr2_ev, NULL);
pr_event_unregister(&msg_module, "core.exit", msg_exit_ev);
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd-mod-msg/-/compare/7a9b18a082573f6adfddc348bb9418e213d14544...fbba1ea42da1dcd99cfdc3fd09d467efca0fa6a8
--
View it on GitLab: https://salsa.debian.org/debian-proftpd-team/proftpd-mod-msg/-/compare/7a9b18a082573f6adfddc348bb9418e213d14544...fbba1ea42da1dcd99cfdc3fd09d467efca0fa6a8
You're receiving this email because of your account on salsa.debian.org.
More information about the Pkg-proftpd-maintainers
mailing list